summaryrefslogtreecommitdiffstats
path: root/newlib/libc/stdio/nano-vfprintf_i.c
diff options
context:
space:
mode:
Diffstat (limited to 'newlib/libc/stdio/nano-vfprintf_i.c')
-rw-r--r--newlib/libc/stdio/nano-vfprintf_i.c248
1 files changed, 248 insertions, 0 deletions
diff --git a/newlib/libc/stdio/nano-vfprintf_i.c b/newlib/libc/stdio/nano-vfprintf_i.c
new file mode 100644
index 000000000..b1b0d1d67
--- /dev/null
+++ b/newlib/libc/stdio/nano-vfprintf_i.c
@@ -0,0 +1,248 @@
+/*
+ * 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.
+ */
+
+#include <newlib.h>
+
+#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"
+
+/* Decode and print non-floating point data. */
+int
+_printf_common (struct _reent *data,
+ struct _prt_data_t *pdata,
+ int *realsz,
+ FILE *fp,
+ int (*pfunc)(struct _reent *, FILE *,
+ _CONST char *, size_t len))
+{
+ int n;
+ /*
+ * All reasonable formats wind up here. At this point, `cp'
+ * points to a string which (if not flags&LADJUST) should be
+ * padded out to `width' places. If flags&ZEROPAD, it should
+ * first be prefixed by any sign or other prefix; otherwise,
+ * it should be blank padded before the prefix is emitted.
+ * After any left-hand padding and prefixing, emit zeroes
+ * required by a decimal [diouxX] precision, then print the
+ * string proper, then emit zeroes required by any leftover
+ * floating precision; finally, if LADJUST, pad with blanks.
+ * If flags&FPT, ch must be in [aAeEfg].
+ *
+ * Compute actual size, so we know how much to pad.
+ * size excludes decimal prec; realsz includes it.
+ */
+ *realsz = pdata->dprec > pdata->size ? pdata->dprec : pdata->size;
+ if (pdata->l_buf[0])
+ (*realsz)++;
+
+ if (pdata->flags & HEXPREFIX)
+ *realsz += 2;
+
+ /* Right-adjusting blank padding. */
+ if ((pdata->flags & (LADJUST|ZEROPAD)) == 0)
+ PAD (pdata->width - *realsz, pdata->blank);
+
+ /* Prefix. */
+ n = 0;
+ if (pdata->l_buf[0])
+ n++;
+
+ if (pdata->flags & HEXPREFIX)
+ {
+ pdata->l_buf[n++] = '0';
+ pdata->l_buf[n++] = pdata->l_buf[2];
+ }
+
+ PRINT (pdata->l_buf, n);
+ n = pdata->width - *realsz;
+ if ((pdata->flags & (LADJUST|ZEROPAD)) != ZEROPAD || n < 0)
+ n = 0;
+
+ if (pdata->dprec > pdata->size)
+ n += pdata->dprec - pdata->size;
+
+ PAD (n, pdata->zero);
+ return 0;
+error:
+ return -1;
+}
+int
+_printf_i (struct _reent *data, struct _prt_data_t *pdata, FILE *fp,
+ int (*pfunc)(struct _reent *, FILE *, _CONST char *, size_t len),
+ va_list *ap)
+{
+ /* Field size expanded by dprec. */
+ int realsz;
+ u_quad_t _uquad;
+ int base;
+ int n;
+ char *cp = pdata->buf + BUF;
+ char *xdigs = "0123456789ABCDEF";
+
+ /* Decoding the conversion specifier. */
+ switch (pdata->code)
+ {
+ case 'c':
+ *--cp = GET_ARG (N, *ap, int);
+ pdata->size = 1;
+ goto non_number_nosign;
+ case 'd':
+ case 'i':
+ _uquad = SARG (pdata->flags);
+ if ((long) _uquad < 0)
+ {
+ _uquad = -_uquad;
+ pdata->l_buf[0] = '-';
+ }
+ base = 10;
+ goto number;
+ case 'u':
+ case 'o':
+ _uquad = UARG (pdata->flags);
+ base = (pdata->code == 'o') ? 8 : 10;
+ goto nosign;
+ case 'X':
+ pdata->l_buf[2] = 'X';
+ goto hex;
+ case 'p':
+ /*
+ * ``The argument shall be a pointer to void. The
+ * value of the pointer is converted to a sequence
+ * of printable characters, in an implementation-
+ * defined manner.''
+ * -- ANSI X3J11
+ */
+ /* NOSTRICT. */
+ pdata->flags |= HEXPREFIX;
+ case 'x':
+ pdata->l_buf[2] = 'x';
+ xdigs = "0123456789abcdef";
+hex:
+ _uquad = UARG (pdata->flags);
+ base = 16;
+ if (pdata->flags & ALT)
+ pdata->flags |= HEXPREFIX;
+
+ /* Leading 0x/X only if non-zero. */
+ if (_uquad == 0)
+ pdata->flags &= ~HEXPREFIX;
+
+ /* Unsigned conversions. */
+nosign:
+ pdata->l_buf[0] = '\0';
+ /*
+ * ``... diouXx conversions ... if a precision is
+ * specified, the 0 flag will be ignored.''
+ * -- ANSI X3J11
+ */
+number:
+ if ((pdata->dprec = pdata->prec) >= 0)
+ pdata->flags &= ~ZEROPAD;
+
+ /*
+ * ``The result of converting a zero value with an
+ * explicit precision of zero is no characters.''
+ * -- ANSI X3J11
+ */
+ if (_uquad != 0 || pdata->prec != 0)
+ {
+ do
+ {
+ *--cp = xdigs[_uquad % base];
+ _uquad /= base;
+ }
+ while (_uquad);
+ }
+ /* For 'o' conversion, '#' increases the precision to force the first
+ digit of the result to be zero. */
+ if (base == 8 && (pdata->flags & ALT) && pdata->prec <= pdata->size)
+ *--cp = '0';
+
+ pdata->size = pdata->buf + BUF - cp;
+ break;
+ case 'n':
+ if (pdata->flags & LONGINT)
+ *GET_ARG (N, *ap, long_ptr_t) = pdata->ret;
+ else if (pdata->flags & SHORTINT)
+ *GET_ARG (N, *ap, short_ptr_t) = pdata->ret;
+ else
+ *GET_ARG (N, *ap, int_ptr_t) = pdata->ret;
+ case '\0':
+ pdata->size = 0;
+ break;
+ case 's':
+ cp = GET_ARG (N, *ap, char_ptr_t);
+ /* Precision gives the maximum number of chars to be written from a
+ string, and take prec == -1 into consideration. */
+ if ((u_int)(pdata->size = strlen (cp)) > (u_int)(pdata->prec))
+ pdata->size = pdata->prec;
+ /* Below code is kept for reading. The check is redundant because
+ pdata->prec will be set to pdata->size if it is -1 previously. */
+#if 0
+ if (pdata->prec > pdata->size)
+#endif
+ pdata->prec = pdata->size;
+ goto non_number_nosign;
+ default:
+ /* "%?" prints ?, unless ? is NUL. */
+ /* Pretend it was %c with argument ch. */
+ *--cp = pdata->code;
+ pdata->size = 1;
+non_number_nosign:
+ pdata->l_buf[0] = '\0';
+ break;
+ }
+
+ /* Output. */
+ n = _printf_common (data, pdata, &realsz, fp, pfunc);
+ if (n == -1)
+ goto error;
+
+ PRINT (cp, pdata->size);
+ /* Left-adjusting padding (always blank). */
+ if (pdata->flags & LADJUST)
+ PAD (pdata->width - realsz, pdata->blank);
+
+ return (pdata->width > realsz ? pdata->width : realsz);
+error:
+ return -1;
+}
+