This is the mail archive of the newlib@sourceware.org mailing list for the newlib project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH][MSP430] Implement reduced code size printf and puts functions


For simple, "bare-metal" applications for MSP430, it is not necessary to have
reentrant printf and puts functions. The supporting functions for printf
and puts also support reading/writing from streams.
The code size penalty of including these features for a memory-constrained
device like the MSP430 is significant.

The attached patches implement reduced code size printf and puts functions, by
removing functionality from the nano versions of these functions:
- The functions are not reentrant, and the application is assumed to be
  running in a single thread
- The built-in support for streams in the supporting functions have been
  removed and the functions will always send the string to be printed to
  stdout via <<write>>, with no considerations for buffering.

The first patch only copies newlib/libc/stdio/nano-vfprintf.c to the msp430
libc subdirectory, so that it is clear in patch 2 which modifications have
been made.

The second patch makes the modifications to the printf and puts functions.

The reduced code size implementation of printf and puts can be enabled
in an application by passing "--wrap printf" and "--wrap puts" to the
GNU linker. This will replace references to "printf" and "puts" in user
code with "__wrap_printf" and "__wrap_puts" respectively.
If there is no implementation of these __wrap* functions in user code,
these "tiny" printf and puts implementations will be linked into the
final executable.

The wrapping mechanism is supposed to be invisible to the user:
- A GCC wrapper option such as "-mtiny-printf" will be added to alias
  these wrap commands.
- If the user is unaware of the "tiny" implementation, and chooses to
  implement their own __wrap_printf and __wrap_puts, their own
  implementation will be automatically chosen over the "tiny" printf and
  puts from the library.

Newlib must be configured with --enable-newlib-nano-formatted-io for 
the "tiny" printf and puts functions to be built into the library.

Size reduction examples:
printf("Hello World\n")
  baseline - msp430-elf-gcc gcc-8_3_0-release
     text    data     bss
   5638     214      26
  "tiny" puts enabled
    text    data     bss
     714      90      20

printf("Hello %d\n", a)
  baseline - msp430-elf-gcc gcc-8_3_0-release
    text    data     bss
   10916     614      28

  "tiny" printf enabled
    text    data     bss
    4632     280      20

I regtested the changes in the GCC DejaGNU testsiute with the GCC 8.3.0
release. A significant number of tests use printf, and there were no
regressions when using the tiny versions.

If the patches are acceptable, I would appreciate if someone could commit them
for me, as I do not have write access.

Thanks,
Jozef 
>From d4c48179ea3362b0dea483afba748728fdfa9310 Mon Sep 17 00:00:00 2001
From: Jozef Lawrynowicz <jozef.l@mittosystems.com>
Date: Fri, 12 Apr 2019 11:57:59 +0100
Subject: [PATCH 1/2] [MSP430][1/2] Copy prerequisite file for "tiny" printf
 implementation

Use newlib/libc/stdio/nano-vfprintf.c as baseline for tiny-printf.c
---
 newlib/libc/machine/msp430/tiny-printf.c | 661 +++++++++++++++++++++++
 1 file changed, 661 insertions(+)
 create mode 100644 newlib/libc/machine/msp430/tiny-printf.c

diff --git a/newlib/libc/machine/msp430/tiny-printf.c b/newlib/libc/machine/msp430/tiny-printf.c
new file mode 100644
index 000000000..bc7ed0743
--- /dev/null
+++ b/newlib/libc/machine/msp430/tiny-printf.c
@@ -0,0 +1,661 @@
+/*
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (c) 2012-2014 ARM Ltd
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the company may not be used to endorse or promote
+ *    products derived from this software without specific prior written
+ *    permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ARM LTD ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL ARM LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+FUNCTION
+<<vfprintf>>, <<vprintf>>, <<vsprintf>>, <<vsnprintf>>, <<vasprintf>>, <<vasnprintf>>---format argument list
+
+INDEX
+	vfprintf
+INDEX
+	_vfprintf_r
+INDEX
+	vprintf
+INDEX
+	_vprintf_r
+INDEX
+	vsprintf
+INDEX
+	_vsprintf_r
+INDEX
+	vsnprintf
+INDEX
+	_vsnprintf_r
+INDEX
+	vasprintf
+INDEX
+	_vasprintf_r
+INDEX
+	vasnprintf
+INDEX
+	_vasnprintf_r
+
+SYNOPSIS
+	#include <stdio.h>
+	#include <stdarg.h>
+	int vprintf(const char *<[fmt]>, va_list <[list]>);
+	int vfprintf(FILE *<[fp]>, const char *<[fmt]>, va_list <[list]>);
+	int vsprintf(char *<[str]>, const char *<[fmt]>, va_list <[list]>);
+	int vsnprintf(char *<[str]>, size_t <[size]>, const char *<[fmt]>,
+                      va_list <[list]>);
+	int vasprintf(char **<[strp]>, const char *<[fmt]>, va_list <[list]>);
+	char *vasnprintf(char *<[str]>, size_t *<[size]>, const char *<[fmt]>,
+                         va_list <[list]>);
+
+	int _vprintf_r(struct _reent *<[reent]>, const char *<[fmt]>,
+                        va_list <[list]>);
+	int _vfprintf_r(struct _reent *<[reent]>, FILE *<[fp]>,
+                        const char *<[fmt]>, va_list <[list]>);
+	int _vsprintf_r(struct _reent *<[reent]>, char *<[str]>,
+                        const char *<[fmt]>, va_list <[list]>);
+	int _vasprintf_r(struct _reent *<[reent]>, char **<[str]>,
+                         const char *<[fmt]>, va_list <[list]>);
+	int _vsnprintf_r(struct _reent *<[reent]>, char *<[str]>,
+                         size_t <[size]>, const char *<[fmt]>, va_list <[list]>);
+	char *_vasnprintf_r(struct _reent *<[reent]>, char *<[str]>,
+                            size_t *<[size]>, const char *<[fmt]>, va_list <[list]>);
+
+DESCRIPTION
+<<vprintf>>, <<vfprintf>>, <<vasprintf>>, <<vsprintf>>, <<vsnprintf>>,
+and <<vasnprintf>> are (respectively) variants of <<printf>>,
+<<fprintf>>, <<asprintf>>, <<sprintf>>, <<snprintf>>, and
+<<asnprintf>>.  They differ only in allowing their caller to pass the
+variable argument list as a <<va_list>> object (initialized by
+<<va_start>>) rather than directly accepting a variable number of
+arguments.  The caller is responsible for calling <<va_end>>.
+
+<<_vprintf_r>>, <<_vfprintf_r>>, <<_vasprintf_r>>, <<_vsprintf_r>>,
+<<_vsnprintf_r>>, and <<_vasnprintf_r>> are reentrant versions of the
+above.
+
+RETURNS
+The return values are consistent with the corresponding functions.
+
+PORTABILITY
+ANSI C requires <<vprintf>>, <<vfprintf>>, <<vsprintf>>, and
+<<vsnprintf>>.  The remaining functions are newlib extensions.
+
+Supporting OS subroutines required: <<close>>, <<fstat>>, <<isatty>>,
+<<lseek>>, <<read>>, <<sbrk>>, <<write>>.
+*/
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)vfprintf.c	5.50 (Berkeley) 12/16/92";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+/* Actual printf innards.
+   This code is large and complicated...  */
+#include <newlib.h>
+
+#define VFPRINTF vfprintf
+#ifdef STRING_ONLY
+# define _VFPRINTF_R _svfprintf_r
+#else
+# define _VFPRINTF_R _vfprintf_r
+#endif
+
+#include <_ansi.h>
+#include <reent.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <stdint.h>
+#include <wchar.h>
+#include <sys/lock.h>
+#include <stdarg.h>
+#include "local.h"
+#include "../stdlib/local.h"
+#include "fvwrite.h"
+#include "vfieeefp.h"
+#include "nano-vfprintf_local.h"
+
+/* The __ssputs_r function is shared between all versions of vfprintf
+   and vfwprintf.  */
+#ifdef STRING_ONLY
+int
+__ssputs_r (struct _reent *ptr,
+       FILE *fp,
+       const char *buf,
+       size_t len)
+{
+  register int w;
+
+  w = fp->_w;
+  if (len >= w && fp->_flags & (__SMBF | __SOPT))
+    {
+      /* Must be asprintf family.  */
+      unsigned char *str;
+      int curpos = (fp->_p - fp->_bf._base);
+      /* Choose a geometric growth factor to avoid
+       * quadratic realloc behavior, but use a rate less
+       * than (1+sqrt(5))/2 to accomodate malloc
+       * overhead. asprintf EXPECTS us to overallocate, so
+       * that it can add a trailing \0 without
+       * reallocating.  The new allocation should thus be
+       * max(prev_size*1.5, curpos+len+1).  */
+      int newsize = fp->_bf._size * 3 / 2;
+      if (newsize < curpos + len + 1)
+	newsize = curpos + len + 1;
+      if (fp->_flags & __SOPT)
+	{
+	  /* asnprintf leaves original buffer alone.  */
+	  str = (unsigned char *)_malloc_r (ptr, newsize);
+	  if (!str)
+	    {
+	      ptr->_errno = ENOMEM;
+	      goto err;
+	    }
+	  memcpy (str, fp->_bf._base, curpos);
+	  fp->_flags = (fp->_flags & ~__SOPT) | __SMBF;
+	}
+      else
+	{
+	  str = (unsigned char *)_realloc_r (ptr, fp->_bf._base, newsize);
+	  if (!str)
+	    {
+	      /* Free unneeded buffer.  */
+	      _free_r (ptr, fp->_bf._base);
+	      /* Ensure correct errno, even if free changed it.  */
+	      ptr->_errno = ENOMEM;
+	      goto err;
+	    }
+	}
+      fp->_bf._base = str;
+      fp->_p = str + curpos;
+      fp->_bf._size = newsize;
+      w = len;
+      fp->_w = newsize - curpos;
+    }
+  if (len < w)
+    w = len;
+
+  (void)memmove ((void *) fp->_p, (void *) buf, (size_t) (w));
+  fp->_w -= w;
+  fp->_p += w;
+  return 0;
+
+err:
+  fp->_flags |= __SERR;
+  return EOF;
+}
+/* __ssprint_r is the original implementation of __SPRINT.  In nano
+   version formatted IO it is reimplemented as __ssputs_r for non-wide
+   char output, but __ssprint_r cannot be discarded because it is used
+   by a serial of functions like svfwprintf for wide char output.  */
+int
+__ssprint_r (struct _reent *ptr,
+       FILE *fp,
+       register struct __suio *uio)
+{
+  register size_t len;
+  register int w;
+  register struct __siov *iov;
+  register const char *p = NULL;
+
+  iov = uio->uio_iov;
+  len = 0;
+
+  if (uio->uio_resid == 0)
+    {
+      uio->uio_iovcnt = 0;
+      return (0);
+    }
+
+  do
+    {
+      while (len == 0)
+	{
+	  p = iov->iov_base;
+	  len = iov->iov_len;
+	  iov++;
+	}
+      w = fp->_w;
+      if (len >= w && fp->_flags & (__SMBF | __SOPT))
+	{
+	  /* Must be asprintf family.  */
+	  unsigned char *str;
+	  int curpos = (fp->_p - fp->_bf._base);
+	  /* Choose a geometric growth factor to avoid
+	   * quadratic realloc behavior, but use a rate less
+	   * than (1+sqrt(5))/2 to accomodate malloc
+	   * overhead. asprintf EXPECTS us to overallocate, so
+	   * that it can add a trailing \0 without
+	   * reallocating.  The new allocation should thus be
+	   * max(prev_size*1.5, curpos+len+1).  */
+	  int newsize = fp->_bf._size * 3 / 2;
+	  if (newsize < curpos + len + 1)
+	    newsize = curpos + len + 1;
+
+	  if (fp->_flags & __SOPT)
+	    {
+	      /* asnprintf leaves original buffer alone.  */
+	      str = (unsigned char *)_malloc_r (ptr, newsize);
+	      if (!str)
+		{
+		  ptr->_errno = ENOMEM;
+		  goto err;
+		}
+	      memcpy (str, fp->_bf._base, curpos);
+	      fp->_flags = (fp->_flags & ~__SOPT) | __SMBF;
+	    }
+	  else
+	    {
+	      str = (unsigned char *)_realloc_r (ptr, fp->_bf._base,
+						 newsize);
+	      if (!str)
+		{
+		  /* Free unneeded buffer.  */
+		  _free_r (ptr, fp->_bf._base);
+		  /* Ensure correct errno, even if free changed it.  */
+		  ptr->_errno = ENOMEM;
+		  goto err;
+		}
+	    }
+	  fp->_bf._base = str;
+	  fp->_p = str + curpos;
+	  fp->_bf._size = newsize;
+	  w = len;
+	  fp->_w = newsize - curpos;
+	}
+      if (len < w)
+	w = len;
+
+      (void)memmove ((void *) fp->_p, (void *) p, (size_t) (w));
+      fp->_w -= w;
+      fp->_p += w;
+      /* Pretend we copied all.  */
+      w = len;
+      p += w;
+      len -= w;
+    }
+  while ((uio->uio_resid -= w) != 0);
+
+  uio->uio_resid = 0;
+  uio->uio_iovcnt = 0;
+  return 0;
+
+err:
+  fp->_flags |= __SERR;
+  uio->uio_resid = 0;
+  uio->uio_iovcnt = 0;
+  return EOF;
+}
+#else
+/* As __ssputs_r, __sprint_r is used by output functions for wide char,
+   like vfwprint.  */
+/* Flush out all the vectors defined by the given uio,
+   then reset it so that it can be reused.  */
+int
+__sprint_r (struct _reent *ptr,
+       FILE *fp,
+       register struct __suio *uio)
+{
+  register int err = 0;
+
+  if (uio->uio_resid == 0)
+    {
+      uio->uio_iovcnt = 0;
+      return 0;
+    }
+#ifdef _WIDE_ORIENT
+    if (fp->_flags2 & __SWID)
+      {
+	struct __siov *iov;
+	wchar_t *p;
+	int i, len;
+
+	iov = uio->uio_iov;
+	for (; uio->uio_resid != 0;
+	     uio->uio_resid -= len * sizeof (wchar_t), iov++)
+	  {
+	    p = (wchar_t *) iov->iov_base;
+	    len = iov->iov_len / sizeof (wchar_t);
+	    for (i = 0; i < len; i++)
+	      {
+		if (_fputwc_r (ptr, p[i], fp) == WEOF)
+		  {
+		    err = -1;
+		    goto out;
+		  }
+	      }
+	  }
+	}
+      else
+#endif
+	err = __sfvwrite_r(ptr, fp, uio);
+out:
+  uio->uio_resid = 0;
+  uio->uio_iovcnt = 0;
+  return err;
+}
+
+_NOINLINE_STATIC int
+__sfputc_r (struct _reent *ptr,
+       int c,
+       FILE *fp)
+{
+  if (--fp->_w >= 0 || (fp->_w >= fp->_lbfsize && (char)c != '\n'))
+    return (*fp->_p++ = c);
+  else
+    return (__swbuf_r(ptr, c, fp));
+}
+
+int
+__sfputs_r (struct _reent *ptr,
+       FILE *fp,
+       const char *buf,
+       size_t len)
+{
+  register int i;
+
+#ifdef _WIDE_ORIENT
+  if (fp->_flags2 & __SWID)
+    {
+      wchar_t *p;
+
+      p = (wchar_t *) buf;
+      for (i = 0; i < (len / sizeof (wchar_t)); i++)
+	{
+	  if (_fputwc_r (ptr, p[i], fp) == WEOF)
+	    return -1;
+	}
+    }
+  else
+#endif
+    {
+      for (i = 0; i < len; i++)
+	{
+	  /* Call __sfputc_r to skip _fputc_r.  */
+	  if (__sfputc_r (ptr, (int)buf[i], fp) == EOF)
+	    return -1;
+	}
+    }
+  return (0);
+}
+#endif /* STRING_ONLY.  */
+
+int _VFPRINTF_R (struct _reent *, FILE *, const char *, va_list);
+
+#ifndef STRING_ONLY
+int
+VFPRINTF (FILE * fp,
+       const char *fmt0,
+       va_list ap)
+{
+  int result;
+  result = _VFPRINTF_R (_REENT, fp, fmt0, ap);
+  return result;
+}
+
+int
+vfiprintf (FILE *, const char *, __VALIST)
+       _ATTRIBUTE ((__alias__("vfprintf")));
+#endif
+
+#ifdef STRING_ONLY
+# define __SPRINT __ssputs_r
+#else
+# define __SPRINT __sfputs_r
+#endif
+
+/* Do not need FLUSH for all sprintf functions.  */
+#ifdef STRING_ONLY
+# define FLUSH()
+#else
+# define FLUSH()
+#endif
+
+int
+_VFPRINTF_R (struct _reent *data,
+       FILE * fp,
+       const char *fmt0,
+       va_list ap)
+{
+  register char *fmt;	/* Format string.  */
+  register int n, m;	/* Handy integers (short term usage).  */
+  register char *cp;	/* Handy char pointer (short term usage).  */
+  const char *flag_chars;
+  struct _prt_data_t prt_data;	/* All data for decoding format string.  */
+  va_list ap_copy;
+
+  /* Output function pointer.  */
+  int (*pfunc)(struct _reent *, FILE *, const char *, size_t len);
+
+  pfunc = __SPRINT;
+
+#ifndef STRING_ONLY
+  /* Initialize std streams if not dealing with sprintf family.  */
+  CHECK_INIT (data, fp);
+  _newlib_flockfile_start (fp);
+
+  /* Sorry, fprintf(read_only_file, "") returns EOF, not 0.  */
+  if (cantwrite (data, fp))
+    {
+      _newlib_flockfile_exit (fp);
+      return (EOF);
+    }
+
+#else
+  /* Create initial buffer if we are called by asprintf family.  */
+  if (fp->_flags & __SMBF && !fp->_bf._base)
+    {
+      fp->_bf._base = fp->_p = _malloc_r (data, 64);
+      if (!fp->_p)
+	{
+	  data->_errno = ENOMEM;
+	  return EOF;
+	}
+      fp->_bf._size = 64;
+    }
+#endif
+
+  fmt = (char *)fmt0;
+  prt_data.ret = 0;
+  prt_data.blank = ' ';
+  prt_data.zero = '0';
+
+  /* GCC PR 14577 at https://gcc.gnu.org/bugzilla/show_bug.cgi?id=14557 */
+  va_copy (ap_copy, ap);
+
+  /* Scan the format for conversions (`%' character).  */
+  for (;;)
+    {
+      cp = fmt;
+      while (*fmt != '\0' && *fmt != '%')
+	fmt += 1;
+
+      if ((m = fmt - cp) != 0)
+	{
+	  PRINT (cp, m);
+	  prt_data.ret += m;
+	}
+      if (*fmt == '\0')
+	goto done;
+
+      fmt++;		/* Skip over '%'.  */
+
+      prt_data.flags = 0;
+      prt_data.width = 0;
+      prt_data.prec = -1;
+      prt_data.dprec = 0;
+      prt_data.l_buf[0] = '\0';
+#ifdef FLOATING_POINT
+      prt_data.lead = 0;
+#endif
+      /* The flags.  */
+      /*
+       * ``Note that 0 is taken as a flag, not as the
+       * beginning of a field width.''
+       *	-- ANSI X3J11
+       */
+      flag_chars = "#-0+ ";
+      for (; cp = memchr (flag_chars, *fmt, 5); fmt++)
+	prt_data.flags |= (1 << (cp - flag_chars));
+
+      if (prt_data.flags & SPACESGN)
+	prt_data.l_buf[0] = ' ';
+
+      /*
+       * ``If the space and + flags both appear, the space
+       * flag will be ignored.''
+       *	-- ANSI X3J11
+       */
+      if (prt_data.flags & PLUSSGN)
+	prt_data.l_buf[0] = '+';
+
+      /* The width.  */
+      if (*fmt == '*')
+	{
+	  /*
+	   * ``A negative field width argument is taken as a
+	   * - flag followed by a positive field width.''
+	   *	-- ANSI X3J11
+	   * They don't exclude field widths read from args.
+	   */
+	  prt_data.width = GET_ARG (n, ap_copy, int);
+	  if (prt_data.width < 0)
+	    {
+	      prt_data.width = -prt_data.width;
+	      prt_data.flags |= LADJUST;
+	    }
+	  fmt++;
+	}
+      else
+        {
+	  for (; is_digit (*fmt); fmt++)
+	    prt_data.width = 10 * prt_data.width + to_digit (*fmt);
+	}
+
+      /* The precision.  */
+      if (*fmt == '.')
+	{
+	  fmt++;
+	  if (*fmt == '*')
+	    {
+	      fmt++;
+	      prt_data.prec = GET_ARG (n, ap_copy, int);
+	      if (prt_data.prec < 0)
+		prt_data.prec = -1;
+	    }
+	  else
+	    {
+	      prt_data.prec = 0;
+	      for (; is_digit (*fmt); fmt++)
+		prt_data.prec = 10 * prt_data.prec + to_digit (*fmt);
+	    }
+	}
+
+      /* The length modifiers.  */
+      flag_chars = "hlL";
+      if ((cp = memchr (flag_chars, *fmt, 3)) != NULL)
+	{
+	  prt_data.flags |= (SHORTINT << (cp - flag_chars));
+	  fmt++;
+	}
+
+      /* The conversion specifiers.  */
+      prt_data.code = *fmt++;
+      cp = memchr ("efgEFG", prt_data.code, 6);
+#ifdef FLOATING_POINT
+      /* If cp is not NULL, we are facing FLOATING POINT NUMBER.  */
+      if (cp)
+	{
+	  /* Consume floating point argument if _printf_float is not
+	     linked.  */
+	  if (_printf_float == NULL)
+	    {
+	      if (prt_data.flags & LONGDBL)
+		GET_ARG (N, ap_copy, _LONG_DOUBLE);
+	      else
+		GET_ARG (N, ap_copy, double);
+	    }
+	  else
+            n = _printf_float (data, &prt_data, fp, pfunc, &ap_copy);
+	}
+      else
+#endif
+	n = _printf_i (data, &prt_data, fp, pfunc, &ap_copy);
+
+      if (n == -1)
+	goto error;
+
+      prt_data.ret += n;
+    }
+done:
+  FLUSH ();
+error:
+#ifndef STRING_ONLY
+  _newlib_flockfile_end (fp);
+#endif
+  va_end (ap_copy);
+  return (__sferror (fp) ? EOF : prt_data.ret);
+}
+
+#ifdef STRING_ONLY
+int
+_svfiprintf_r (struct _reent *, FILE *, const char *, __VALIST)
+       _ATTRIBUTE ((__alias__("_svfprintf_r")));
+#else
+int
+_vfiprintf_r (struct _reent *, FILE *, const char *, __VALIST)
+       _ATTRIBUTE ((__alias__("_vfprintf_r")));
+#endif
-- 
2.17.1

>From a9c467fe7c160273469a6843401520717fcf9ed0 Mon Sep 17 00:00:00 2001
From: Jozef Lawrynowicz <jozef.l@mittosystems.com>
Date: Fri, 12 Apr 2019 12:08:22 +0100
Subject: [PATCH 2/2] [MSP430][2/2] Implement reduced code size "tiny" printf
 and puts

"tiny" printf is derived from _vfprintf_r in libc/stdio/nano-vfprintf.c.
"tiny" puts has been implemented so that it just calls write, without
any other processing.
Support for buffering, reentrancy and streams has been removed from
these functions to achieve reduced code size.

This reduced code size implementation of printf and puts can be enabled
in an application by passing "--wrap printf" and "--wrap puts" to the
GNU linker. This will replace references to "printf" and "puts" in user
code with "__wrap_printf" and "__wrap_puts" respectively.
If there is no implementation of these __wrap* functions in user code,
these "tiny" printf and puts implementations will be linked into the
final executable.

The wrapping mechanism is supposed to be invisible to the user:
- A GCC wrapper option such as "-mtiny-printf" will be added to alias
  these wrap commands.
- If the user is unaware of the "tiny" implementation, and chooses to
  implement their own __wrap_printf and __wrap_puts, their own
  implementation will be automatically chosen over the "tiny" printf and
  puts from the library.

Newlib must be configured with --enable-newlib-nano-formatted-io for 
the "tiny" printf and puts functions to be built into the library.

Code size reduction examples:
printf("Hello World\n")
  baseline - msp430-elf-gcc gcc-8_3_0-release
     text    data     bss
   5638     214      26
  "tiny" puts enabled
    text    data     bss
     714      90      20

printf("Hello %d\n", a)
  baseline - msp430-elf-gcc gcc-8_3_0-release
    text    data     bss
   10916     614      28

  "tiny" printf enabled
    text    data     bss
    4632     280      20
---
 newlib/libc/machine/msp430/Makefile.am   |   9 +-
 newlib/libc/machine/msp430/Makefile.in   |  33 +-
 newlib/libc/machine/msp430/configure     |  28 ++
 newlib/libc/machine/msp430/configure.in  |  11 +
 newlib/libc/machine/msp430/tiny-printf.c | 459 ++---------------------
 newlib/libc/machine/msp430/tiny-puts.c   |  20 +
 6 files changed, 132 insertions(+), 428 deletions(-)
 create mode 100644 newlib/libc/machine/msp430/tiny-puts.c

diff --git a/newlib/libc/machine/msp430/Makefile.am b/newlib/libc/machine/msp430/Makefile.am
index 0b5791448..fd327f5c8 100644
--- a/newlib/libc/machine/msp430/Makefile.am
+++ b/newlib/libc/machine/msp430/Makefile.am
@@ -21,9 +21,16 @@ AM_CCASFLAGS = $(INCLUDES)
 
 noinst_LIBRARIES = lib.a
 
-lib_a_SOURCES = setjmp.S
+lib_a_SOURCES = setjmp.S $(TINY_SOURCES)
 lib_a_CCASFLAGS=$(AM_CCASFLAGS)
 lib_a_CFLAGS=$(AM_CFLAGS)
 
+# tiny-printf.c and tiny-puts.c are derived from the nano printf/puts
+# functions, so other supporting nano functions are required, and the tiny
+# printf/puts will not work without them.
+if NEWLIB_NANO_FORMATTED_IO
+TINY_SOURCES = tiny-puts.c tiny-printf.c
+endif
+
 ACLOCAL_AMFLAGS = -I ../../.. -I ../../../..
 CONFIG_STATUS_DEPENDENCIES = $(newlib_basedir)/configure.host
diff --git a/newlib/libc/machine/msp430/Makefile.in b/newlib/libc/machine/msp430/Makefile.in
index 89b36a8e4..6f837c91f 100644
--- a/newlib/libc/machine/msp430/Makefile.in
+++ b/newlib/libc/machine/msp430/Makefile.in
@@ -82,7 +82,10 @@ LIBRARIES = $(noinst_LIBRARIES)
 ARFLAGS = cru
 lib_a_AR = $(AR) $(ARFLAGS)
 lib_a_LIBADD =
-am_lib_a_OBJECTS = lib_a-setjmp.$(OBJEXT)
+@NEWLIB_NANO_FORMATTED_IO_TRUE@am__objects_1 =  \
+@NEWLIB_NANO_FORMATTED_IO_TRUE@	lib_a-tiny-puts.$(OBJEXT) \
+@NEWLIB_NANO_FORMATTED_IO_TRUE@	lib_a-tiny-printf.$(OBJEXT)
+am_lib_a_OBJECTS = lib_a-setjmp.$(OBJEXT) $(am__objects_1)
 lib_a_OBJECTS = $(am_lib_a_OBJECTS)
 DEFAULT_INCLUDES = -I.@am__isrc@
 depcomp =
@@ -195,6 +198,7 @@ pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
 psdir = @psdir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
@@ -208,15 +212,20 @@ AUTOMAKE_OPTIONS = cygnus
 INCLUDES = $(NEWLIB_CFLAGS) $(CROSS_CFLAGS) $(TARGET_CFLAGS)
 AM_CCASFLAGS = $(INCLUDES)
 noinst_LIBRARIES = lib.a
-lib_a_SOURCES = setjmp.S
+lib_a_SOURCES = setjmp.S $(TINY_SOURCES)
 lib_a_CCASFLAGS = $(AM_CCASFLAGS)
 lib_a_CFLAGS = $(AM_CFLAGS)
+
+# tiny-printf.c and tiny-puts.c are derived from the nano printf/puts
+# functions, so other supporting nano functions are required, and the tiny
+# printf/puts will not work without them.
+@NEWLIB_NANO_FORMATTED_IO_TRUE@TINY_SOURCES = tiny-puts.c tiny-printf.c
 ACLOCAL_AMFLAGS = -I ../../.. -I ../../../..
 CONFIG_STATUS_DEPENDENCIES = $(newlib_basedir)/configure.host
 all: all-am
 
 .SUFFIXES:
-.SUFFIXES: .S .o .obj
+.SUFFIXES: .S .c .o .obj
 am--refresh: Makefile
 	@:
 $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
@@ -277,6 +286,24 @@ lib_a-setjmp.o: setjmp.S
 lib_a-setjmp.obj: setjmp.S
 	$(CCAS) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CCASFLAGS) $(CCASFLAGS) -c -o lib_a-setjmp.obj `if test -f 'setjmp.S'; then $(CYGPATH_W) 'setjmp.S'; else $(CYGPATH_W) '$(srcdir)/setjmp.S'; fi`
 
+.c.o:
+	$(COMPILE) -c $<
+
+.c.obj:
+	$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+lib_a-tiny-puts.o: tiny-puts.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-tiny-puts.o `test -f 'tiny-puts.c' || echo '$(srcdir)/'`tiny-puts.c
+
+lib_a-tiny-puts.obj: tiny-puts.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-tiny-puts.obj `if test -f 'tiny-puts.c'; then $(CYGPATH_W) 'tiny-puts.c'; else $(CYGPATH_W) '$(srcdir)/tiny-puts.c'; fi`
+
+lib_a-tiny-printf.o: tiny-printf.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-tiny-printf.o `test -f 'tiny-printf.c' || echo '$(srcdir)/'`tiny-printf.c
+
+lib_a-tiny-printf.obj: tiny-printf.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-tiny-printf.obj `if test -f 'tiny-printf.c'; then $(CYGPATH_W) 'tiny-printf.c'; else $(CYGPATH_W) '$(srcdir)/tiny-printf.c'; fi`
+
 ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
 	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
 	unique=`for i in $$list; do \
diff --git a/newlib/libc/machine/msp430/configure b/newlib/libc/machine/msp430/configure
index 35078c605..9d5cd33a6 100755
--- a/newlib/libc/machine/msp430/configure
+++ b/newlib/libc/machine/msp430/configure
@@ -640,6 +640,8 @@ build
 newlib_basedir
 MAY_SUPPLY_SYSCALLS_FALSE
 MAY_SUPPLY_SYSCALLS_TRUE
+NEWLIB_NANO_FORMATTED_IO_FALSE
+NEWLIB_NANO_FORMATTED_IO_TRUE
 target_alias
 host_alias
 build_alias
@@ -681,6 +683,7 @@ SHELL'
 ac_subst_files=''
 ac_user_opts='
 enable_option_checking
+enable_newlib_nano_formatted_io
 enable_multilib
 enable_target_optspace
 enable_malloc_debugging
@@ -1318,6 +1321,7 @@ Optional Features:
   --disable-option-checking  ignore unrecognized --enable/--with options
   --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
   --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+  --enable-newlib-nano-formatted-io    Use small-footprint nano-formatted-IO implementation
   --enable-multilib         build many library versions (default)
   --enable-target-optspace  optimize for space
   --enable-malloc-debugging indicate malloc debugging requested
@@ -1837,6 +1841,26 @@ ac_configure="$SHELL $ac_aux_dir/configure"  # Please don't use this var.
 
 
 
+# Check whether --enable-newlib_nano_formatted_io was given.
+if test "${enable_newlib_nano_formatted_io+set}" = set; then :
+  enableval=$enable_newlib_nano_formatted_io; case "${enableval}" in
+   yes) newlib_nano_formatted_io=yes ;;
+   no)  newlib_nano_formatted_io=no ;;
+   *) as_fn_error $? "bad value ${enableval} for newlib-nano-formatted-io" "$LINENO" 5 ;;
+ esac
+else
+  newlib_nano_formatted_io=no
+fi
+
+ if test x$newlib_nano_formatted_io = xyes; then
+  NEWLIB_NANO_FORMATTED_IO_TRUE=
+  NEWLIB_NANO_FORMATTED_IO_FALSE='#'
+else
+  NEWLIB_NANO_FORMATTED_IO_TRUE='#'
+  NEWLIB_NANO_FORMATTED_IO_FALSE=
+fi
+
+
 
 # Make sure we can run config.sub.
 $SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
@@ -3575,6 +3599,10 @@ LIBOBJS=$ac_libobjs
 LTLIBOBJS=$ac_ltlibobjs
 
 
+if test -z "${NEWLIB_NANO_FORMATTED_IO_TRUE}" && test -z "${NEWLIB_NANO_FORMATTED_IO_FALSE}"; then
+  as_fn_error $? "conditional \"NEWLIB_NANO_FORMATTED_IO\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
 if test -z "${MAY_SUPPLY_SYSCALLS_TRUE}" && test -z "${MAY_SUPPLY_SYSCALLS_FALSE}"; then
   as_fn_error $? "conditional \"MAY_SUPPLY_SYSCALLS\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
diff --git a/newlib/libc/machine/msp430/configure.in b/newlib/libc/machine/msp430/configure.in
index 563f8a30d..4c0f864b0 100644
--- a/newlib/libc/machine/msp430/configure.in
+++ b/newlib/libc/machine/msp430/configure.in
@@ -21,6 +21,17 @@ AC_CONFIG_SRCDIR([setjmp.S])
 dnl Can't be done in NEWLIB_CONFIGURE because that confuses automake. 
 AC_CONFIG_AUX_DIR(../../../..)
 
+dnl Support --enable-newlib-nano-formatted-io required by tiny-printf.c
+dnl and tiny-puts.c
+AC_ARG_ENABLE(newlib_nano_formatted_io,
+[  --enable-newlib-nano-formatted-io    Use small-footprint nano-formatted-IO implementation],
+[case "${enableval}" in
+   yes) newlib_nano_formatted_io=yes ;;
+   no)  newlib_nano_formatted_io=no ;;
+   *) AC_MSG_ERROR(bad value ${enableval} for newlib-nano-formatted-io) ;;
+ esac],[newlib_nano_formatted_io=no])
+AM_CONDITIONAL(NEWLIB_NANO_FORMATTED_IO, test x$newlib_nano_formatted_io = xyes)
+
 NEWLIB_CONFIGURE(../../..)
 
 AC_CONFIG_FILES([Makefile])
diff --git a/newlib/libc/machine/msp430/tiny-printf.c b/newlib/libc/machine/msp430/tiny-printf.c
index bc7ed0743..f2412a0e6 100644
--- a/newlib/libc/machine/msp430/tiny-printf.c
+++ b/newlib/libc/machine/msp430/tiny-printf.c
@@ -58,100 +58,11 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-/*
-FUNCTION
-<<vfprintf>>, <<vprintf>>, <<vsprintf>>, <<vsnprintf>>, <<vasprintf>>, <<vasnprintf>>---format argument list
-
-INDEX
-	vfprintf
-INDEX
-	_vfprintf_r
-INDEX
-	vprintf
-INDEX
-	_vprintf_r
-INDEX
-	vsprintf
-INDEX
-	_vsprintf_r
-INDEX
-	vsnprintf
-INDEX
-	_vsnprintf_r
-INDEX
-	vasprintf
-INDEX
-	_vasprintf_r
-INDEX
-	vasnprintf
-INDEX
-	_vasnprintf_r
-
-SYNOPSIS
-	#include <stdio.h>
-	#include <stdarg.h>
-	int vprintf(const char *<[fmt]>, va_list <[list]>);
-	int vfprintf(FILE *<[fp]>, const char *<[fmt]>, va_list <[list]>);
-	int vsprintf(char *<[str]>, const char *<[fmt]>, va_list <[list]>);
-	int vsnprintf(char *<[str]>, size_t <[size]>, const char *<[fmt]>,
-                      va_list <[list]>);
-	int vasprintf(char **<[strp]>, const char *<[fmt]>, va_list <[list]>);
-	char *vasnprintf(char *<[str]>, size_t *<[size]>, const char *<[fmt]>,
-                         va_list <[list]>);
-
-	int _vprintf_r(struct _reent *<[reent]>, const char *<[fmt]>,
-                        va_list <[list]>);
-	int _vfprintf_r(struct _reent *<[reent]>, FILE *<[fp]>,
-                        const char *<[fmt]>, va_list <[list]>);
-	int _vsprintf_r(struct _reent *<[reent]>, char *<[str]>,
-                        const char *<[fmt]>, va_list <[list]>);
-	int _vasprintf_r(struct _reent *<[reent]>, char **<[str]>,
-                         const char *<[fmt]>, va_list <[list]>);
-	int _vsnprintf_r(struct _reent *<[reent]>, char *<[str]>,
-                         size_t <[size]>, const char *<[fmt]>, va_list <[list]>);
-	char *_vasnprintf_r(struct _reent *<[reent]>, char *<[str]>,
-                            size_t *<[size]>, const char *<[fmt]>, va_list <[list]>);
-
-DESCRIPTION
-<<vprintf>>, <<vfprintf>>, <<vasprintf>>, <<vsprintf>>, <<vsnprintf>>,
-and <<vasnprintf>> are (respectively) variants of <<printf>>,
-<<fprintf>>, <<asprintf>>, <<sprintf>>, <<snprintf>>, and
-<<asnprintf>>.  They differ only in allowing their caller to pass the
-variable argument list as a <<va_list>> object (initialized by
-<<va_start>>) rather than directly accepting a variable number of
-arguments.  The caller is responsible for calling <<va_end>>.
-
-<<_vprintf_r>>, <<_vfprintf_r>>, <<_vasprintf_r>>, <<_vsprintf_r>>,
-<<_vsnprintf_r>>, and <<_vasnprintf_r>> are reentrant versions of the
-above.
-
-RETURNS
-The return values are consistent with the corresponding functions.
-
-PORTABILITY
-ANSI C requires <<vprintf>>, <<vfprintf>>, <<vsprintf>>, and
-<<vsnprintf>>.  The remaining functions are newlib extensions.
-
-Supporting OS subroutines required: <<close>>, <<fstat>>, <<isatty>>,
-<<lseek>>, <<read>>, <<sbrk>>, <<write>>.
-*/
-
 #if defined(LIBC_SCCS) && !defined(lint)
 /*static char *sccsid = "from: @(#)vfprintf.c	5.50 (Berkeley) 12/16/92";*/
 static char *rcsid = "$Id$";
 #endif /* LIBC_SCCS and not lint */
 
-/* Actual printf innards.
-   This code is large and complicated...  */
-#include <newlib.h>
-
-#define VFPRINTF vfprintf
-#ifdef STRING_ONLY
-# define _VFPRINTF_R _svfprintf_r
-#else
-# define _VFPRINTF_R _vfprintf_r
-#endif
-
 #include <_ansi.h>
 #include <reent.h>
 #include <stdio.h>
@@ -162,310 +73,35 @@ static char *rcsid = "$Id$";
 #include <wchar.h>
 #include <sys/lock.h>
 #include <stdarg.h>
-#include "local.h"
-#include "../stdlib/local.h"
-#include "fvwrite.h"
-#include "vfieeefp.h"
-#include "nano-vfprintf_local.h"
-
-/* The __ssputs_r function is shared between all versions of vfprintf
-   and vfwprintf.  */
-#ifdef STRING_ONLY
-int
-__ssputs_r (struct _reent *ptr,
-       FILE *fp,
-       const char *buf,
-       size_t len)
-{
-  register int w;
-
-  w = fp->_w;
-  if (len >= w && fp->_flags & (__SMBF | __SOPT))
-    {
-      /* Must be asprintf family.  */
-      unsigned char *str;
-      int curpos = (fp->_p - fp->_bf._base);
-      /* Choose a geometric growth factor to avoid
-       * quadratic realloc behavior, but use a rate less
-       * than (1+sqrt(5))/2 to accomodate malloc
-       * overhead. asprintf EXPECTS us to overallocate, so
-       * that it can add a trailing \0 without
-       * reallocating.  The new allocation should thus be
-       * max(prev_size*1.5, curpos+len+1).  */
-      int newsize = fp->_bf._size * 3 / 2;
-      if (newsize < curpos + len + 1)
-	newsize = curpos + len + 1;
-      if (fp->_flags & __SOPT)
-	{
-	  /* asnprintf leaves original buffer alone.  */
-	  str = (unsigned char *)_malloc_r (ptr, newsize);
-	  if (!str)
-	    {
-	      ptr->_errno = ENOMEM;
-	      goto err;
-	    }
-	  memcpy (str, fp->_bf._base, curpos);
-	  fp->_flags = (fp->_flags & ~__SOPT) | __SMBF;
-	}
-      else
-	{
-	  str = (unsigned char *)_realloc_r (ptr, fp->_bf._base, newsize);
-	  if (!str)
-	    {
-	      /* Free unneeded buffer.  */
-	      _free_r (ptr, fp->_bf._base);
-	      /* Ensure correct errno, even if free changed it.  */
-	      ptr->_errno = ENOMEM;
-	      goto err;
-	    }
-	}
-      fp->_bf._base = str;
-      fp->_p = str + curpos;
-      fp->_bf._size = newsize;
-      w = len;
-      fp->_w = newsize - curpos;
-    }
-  if (len < w)
-    w = len;
-
-  (void)memmove ((void *) fp->_p, (void *) buf, (size_t) (w));
-  fp->_w -= w;
-  fp->_p += w;
-  return 0;
-
-err:
-  fp->_flags |= __SERR;
-  return EOF;
-}
-/* __ssprint_r is the original implementation of __SPRINT.  In nano
-   version formatted IO it is reimplemented as __ssputs_r for non-wide
-   char output, but __ssprint_r cannot be discarded because it is used
-   by a serial of functions like svfwprintf for wide char output.  */
-int
-__ssprint_r (struct _reent *ptr,
-       FILE *fp,
-       register struct __suio *uio)
-{
-  register size_t len;
-  register int w;
-  register struct __siov *iov;
-  register const char *p = NULL;
-
-  iov = uio->uio_iov;
-  len = 0;
-
-  if (uio->uio_resid == 0)
-    {
-      uio->uio_iovcnt = 0;
-      return (0);
-    }
-
-  do
-    {
-      while (len == 0)
-	{
-	  p = iov->iov_base;
-	  len = iov->iov_len;
-	  iov++;
-	}
-      w = fp->_w;
-      if (len >= w && fp->_flags & (__SMBF | __SOPT))
-	{
-	  /* Must be asprintf family.  */
-	  unsigned char *str;
-	  int curpos = (fp->_p - fp->_bf._base);
-	  /* Choose a geometric growth factor to avoid
-	   * quadratic realloc behavior, but use a rate less
-	   * than (1+sqrt(5))/2 to accomodate malloc
-	   * overhead. asprintf EXPECTS us to overallocate, so
-	   * that it can add a trailing \0 without
-	   * reallocating.  The new allocation should thus be
-	   * max(prev_size*1.5, curpos+len+1).  */
-	  int newsize = fp->_bf._size * 3 / 2;
-	  if (newsize < curpos + len + 1)
-	    newsize = curpos + len + 1;
-
-	  if (fp->_flags & __SOPT)
-	    {
-	      /* asnprintf leaves original buffer alone.  */
-	      str = (unsigned char *)_malloc_r (ptr, newsize);
-	      if (!str)
-		{
-		  ptr->_errno = ENOMEM;
-		  goto err;
-		}
-	      memcpy (str, fp->_bf._base, curpos);
-	      fp->_flags = (fp->_flags & ~__SOPT) | __SMBF;
-	    }
-	  else
-	    {
-	      str = (unsigned char *)_realloc_r (ptr, fp->_bf._base,
-						 newsize);
-	      if (!str)
-		{
-		  /* Free unneeded buffer.  */
-		  _free_r (ptr, fp->_bf._base);
-		  /* Ensure correct errno, even if free changed it.  */
-		  ptr->_errno = ENOMEM;
-		  goto err;
-		}
-	    }
-	  fp->_bf._base = str;
-	  fp->_p = str + curpos;
-	  fp->_bf._size = newsize;
-	  w = len;
-	  fp->_w = newsize - curpos;
-	}
-      if (len < w)
-	w = len;
-
-      (void)memmove ((void *) fp->_p, (void *) p, (size_t) (w));
-      fp->_w -= w;
-      fp->_p += w;
-      /* Pretend we copied all.  */
-      w = len;
-      p += w;
-      len -= w;
-    }
-  while ((uio->uio_resid -= w) != 0);
-
-  uio->uio_resid = 0;
-  uio->uio_iovcnt = 0;
-  return 0;
-
-err:
-  fp->_flags |= __SERR;
-  uio->uio_resid = 0;
-  uio->uio_iovcnt = 0;
-  return EOF;
-}
-#else
-/* As __ssputs_r, __sprint_r is used by output functions for wide char,
-   like vfwprint.  */
-/* Flush out all the vectors defined by the given uio,
-   then reset it so that it can be reused.  */
-int
-__sprint_r (struct _reent *ptr,
-       FILE *fp,
-       register struct __suio *uio)
-{
-  register int err = 0;
-
-  if (uio->uio_resid == 0)
-    {
-      uio->uio_iovcnt = 0;
-      return 0;
-    }
-#ifdef _WIDE_ORIENT
-    if (fp->_flags2 & __SWID)
-      {
-	struct __siov *iov;
-	wchar_t *p;
-	int i, len;
-
-	iov = uio->uio_iov;
-	for (; uio->uio_resid != 0;
-	     uio->uio_resid -= len * sizeof (wchar_t), iov++)
-	  {
-	    p = (wchar_t *) iov->iov_base;
-	    len = iov->iov_len / sizeof (wchar_t);
-	    for (i = 0; i < len; i++)
-	      {
-		if (_fputwc_r (ptr, p[i], fp) == WEOF)
-		  {
-		    err = -1;
-		    goto out;
-		  }
-	      }
-	  }
-	}
-      else
-#endif
-	err = __sfvwrite_r(ptr, fp, uio);
-out:
-  uio->uio_resid = 0;
-  uio->uio_iovcnt = 0;
-  return err;
-}
-
-_NOINLINE_STATIC int
-__sfputc_r (struct _reent *ptr,
-       int c,
-       FILE *fp)
-{
-  if (--fp->_w >= 0 || (fp->_w >= fp->_lbfsize && (char)c != '\n'))
-    return (*fp->_p++ = c);
-  else
-    return (__swbuf_r(ptr, c, fp));
-}
-
+#include <string.h>
+#include <newlib.h>
+#include "../../stdio/local.h"
+#include "../../stdlib/local.h"
+#include "../../stdio/fvwrite.h"
+#include "../../stdio/nano-vfprintf_local.h"
+
+/* Bypass *putc* fns called by the default _sfputs_r to save code size.
+   Among other things, this means there is no buffering of the string before
+   it is sent to <<write>>, but <<write>> does its own buffering so we won't
+   lose chars when buf is larger than sizeof(CIOBUF).  */
 int
-__sfputs_r (struct _reent *ptr,
+__tiny__sfputs_r (struct _reent *ptr,
        FILE *fp,
        const char *buf,
        size_t len)
 {
-  register int i;
-
-#ifdef _WIDE_ORIENT
-  if (fp->_flags2 & __SWID)
-    {
-      wchar_t *p;
-
-      p = (wchar_t *) buf;
-      for (i = 0; i < (len / sizeof (wchar_t)); i++)
-	{
-	  if (_fputwc_r (ptr, p[i], fp) == WEOF)
-	    return -1;
-	}
-    }
-  else
-#endif
-    {
-      for (i = 0; i < len; i++)
-	{
-	  /* Call __sfputc_r to skip _fputc_r.  */
-	  if (__sfputc_r (ptr, (int)buf[i], fp) == EOF)
-	    return -1;
-	}
-    }
-  return (0);
-}
-#endif /* STRING_ONLY.  */
-
-int _VFPRINTF_R (struct _reent *, FILE *, const char *, va_list);
-
-#ifndef STRING_ONLY
-int
-VFPRINTF (FILE * fp,
-       const char *fmt0,
-       va_list ap)
-{
-  int result;
-  result = _VFPRINTF_R (_REENT, fp, fmt0, ap);
-  return result;
+  return write (1, buf, len);
 }
 
+/* VFPRINTF_R from nano-vfprintf.c but:
+   - No support for reentrancy
+   - No support for streams
+   - __SINGLE_THREAD__ assumed.
+   - No STRING_ONLY variant (either way the formatted string would end up
+     being sent to <<write>> via <<__tiny__sfputs_r>>.
+   Basically, format the string as normal, and send it to write.  */
 int
-vfiprintf (FILE *, const char *, __VALIST)
-       _ATTRIBUTE ((__alias__("vfprintf")));
-#endif
-
-#ifdef STRING_ONLY
-# define __SPRINT __ssputs_r
-#else
-# define __SPRINT __sfputs_r
-#endif
-
-/* Do not need FLUSH for all sprintf functions.  */
-#ifdef STRING_ONLY
-# define FLUSH()
-#else
-# define FLUSH()
-#endif
-
-int
-_VFPRINTF_R (struct _reent *data,
+__tiny_vfprintf_r (struct _reent *data,
        FILE * fp,
        const char *fmt0,
        va_list ap)
@@ -480,33 +116,7 @@ _VFPRINTF_R (struct _reent *data,
   /* Output function pointer.  */
   int (*pfunc)(struct _reent *, FILE *, const char *, size_t len);
 
-  pfunc = __SPRINT;
-
-#ifndef STRING_ONLY
-  /* Initialize std streams if not dealing with sprintf family.  */
-  CHECK_INIT (data, fp);
-  _newlib_flockfile_start (fp);
-
-  /* Sorry, fprintf(read_only_file, "") returns EOF, not 0.  */
-  if (cantwrite (data, fp))
-    {
-      _newlib_flockfile_exit (fp);
-      return (EOF);
-    }
-
-#else
-  /* Create initial buffer if we are called by asprintf family.  */
-  if (fp->_flags & __SMBF && !fp->_bf._base)
-    {
-      fp->_bf._base = fp->_p = _malloc_r (data, 64);
-      if (!fp->_p)
-	{
-	  data->_errno = ENOMEM;
-	  return EOF;
-	}
-      fp->_bf._size = 64;
-    }
-#endif
+  pfunc = __tiny__sfputs_r;
 
   fmt = (char *)fmt0;
   prt_data.ret = 0;
@@ -641,21 +251,22 @@ _VFPRINTF_R (struct _reent *data,
       prt_data.ret += n;
     }
 done:
-  FLUSH ();
 error:
-#ifndef STRING_ONLY
-  _newlib_flockfile_end (fp);
-#endif
   va_end (ap_copy);
   return (__sferror (fp) ? EOF : prt_data.ret);
 }
 
-#ifdef STRING_ONLY
 int
-_svfiprintf_r (struct _reent *, FILE *, const char *, __VALIST)
-       _ATTRIBUTE ((__alias__("_svfprintf_r")));
-#else
-int
-_vfiprintf_r (struct _reent *, FILE *, const char *, __VALIST)
-       _ATTRIBUTE ((__alias__("_vfprintf_r")));
-#endif
+__wrap_printf (const char *__restrict fmt, ...)
+{
+  int ret;
+  va_list ap;
+  struct _reent *ptr = _REENT;
+
+  va_start (ap, fmt);
+  ret = __tiny_vfprintf_r (ptr, _stdout_r (ptr), fmt, ap);
+  va_end (ap);
+  return ret;
+}
+
+int printf (const char *__restrict fmt, ...) __attribute__ ((weak, alias ("__wrap_printf")));
diff --git a/newlib/libc/machine/msp430/tiny-puts.c b/newlib/libc/machine/msp430/tiny-puts.c
new file mode 100644
index 000000000..6a59f23b0
--- /dev/null
+++ b/newlib/libc/machine/msp430/tiny-puts.c
@@ -0,0 +1,20 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <newlib.h>
+
+int write (int fd, const char *buf, int len);
+
+int
+__wrap_puts (const char * s)
+{
+  int res = write (1, s, strlen (s));
+  if (res == EOF)
+  {
+    write (1, "\n", 1);
+    return EOF;
+  }
+  return write (1, "\n", 1);
+}
+
+int puts (const char * s) __attribute__ ((weak, alias ("__wrap_puts")));
-- 
2.17.1


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]