From caed8420ef5be27f4b6e2b07a39e21642e6d1ceb Mon Sep 17 00:00:00 2001 From: "Peter S. Mazinger" Date: Mon, 13 Feb 2006 07:36:40 +0000 Subject: More renames for IMA --- libc/stdio/vfprintf.c | 1951 ------------------------------------------------- 1 file changed, 1951 deletions(-) delete mode 100644 libc/stdio/vfprintf.c (limited to 'libc/stdio/vfprintf.c') diff --git a/libc/stdio/vfprintf.c b/libc/stdio/vfprintf.c deleted file mode 100644 index a32960f2e..000000000 --- a/libc/stdio/vfprintf.c +++ /dev/null @@ -1,1951 +0,0 @@ -/* Copyright (C) 2002-2004 Manuel Novoa III - * My stdio library for linux and (soon) elks. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free - * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/* This code needs a lot of clean up. Some of that is on hold until uClibc - * gets a better configuration system (on Erik's todo list). - * The other cleanup will take place during the implementation/integration of - * the wide char (un)formatted i/o functions which I'm currently working on. - */ - -/* ATTENTION! ATTENTION! ATTENTION! ATTENTION! ATTENTION! - * - * This code is currently under development. Also, I plan to port - * it to elks which is a 16-bit environment with a fairly limited - * compiler. Therefore, please refrain from modifying this code - * and, instead, pass any bug-fixes, etc. to me. Thanks. Manuel - * - * ATTENTION! ATTENTION! ATTENTION! ATTENTION! ATTENTION! */ - - -/* April 1, 2002 - * Initialize thread locks for fake files in vsnprintf and vdprintf. - * reported by Erik Andersen (andersen@codepoet.com) - * Fix an arg promotion handling bug in _do_one_spec for %c. - * reported by Ilguiz Latypov - * - * May 10, 2002 - * Remove __isdigit and use new ctype.h version. - * Add conditional setting of QUAL_CHARS for size_t and ptrdiff_t. - * - * Aug 16, 2002 - * Fix two problems that showed up with the python 2.2.1 tests; one - * involving %o and one involving %f. - * - * Oct 28, 2002 - * Fix a problem in vasprintf (reported by vodz a while back) when built - * without custom stream support. In that case, it is necessary to do - * a va_copy. - * Make sure each va_copy has a matching va_end, as required by C99. - * - * Nov 4, 2002 - * Add locale-specific grouping support for integer decimal conversion. - * Add locale-specific decimal point support for floating point conversion. - * Note: grouping will have to wait for _dtostr() rewrite. - * Add printf wchar support for %lc (%C) and %ls (%S). - * Require printf format strings to be valid multibyte strings beginning and - * ending in their initial shift state, as per the stds. - * - * Nov 21, 2002 - * Add *wprintf functions. Currently they don't support floating point - * conversions. That will wait until the rewrite of _dtostr. - * - * Aug 1, 2003 - * Optional hexadecimal float notation support for %a/%A. - * Floating point output now works for *wprintf. - * Support for glibc locale-specific digit grouping for floats. - * Misc bug fixes. - * - * Aug 31, 2003 - * Fix precision bug for %g conversion specifier when using %f style. - * - * Sep 5, 2003 - * Implement *s*scanf for the non-buffered stdio case with old_vfprintf. - * - * Sep 23, 2003 - * vfprintf was not always checking for narrow stream orientation. - */ - -/* TODO: - * - * Should we validate that *printf format strings are valid multibyte - * strings in the current locale? ANSI/ISO C99 seems to imply this - * and Plauger's printf implementation in his Standard C Library book - * treats this as an error. - */ - -#define _ISOC99_SOURCE /* for ULLONG primarily... */ -#include -#include "_stdio.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define __PRINTF_INFO_NO_BITFIELD -#include - -#ifdef __UCLIBC_HAS_THREADS__ -#include -#include -#endif /* __UCLIBC_HAS_THREADS__ */ - -#ifdef __UCLIBC_HAS_WCHAR__ -#include -#endif /* __UCLIBC_HAS_WCHAR__ */ - -#include -#include - -libc_hidden_proto(memcpy) -libc_hidden_proto(memset) -libc_hidden_proto(strlen) -libc_hidden_proto(strnlen) -libc_hidden_proto(__glibc_strerror_r) -libc_hidden_proto(fputs_unlocked) -libc_hidden_proto(abort) -#ifdef __UCLIBC_HAS_WCHAR__ -libc_hidden_proto(wcslen) -libc_hidden_proto(wcsnlen) -libc_hidden_proto(mbsrtowcs) -libc_hidden_proto(wcsrtombs) -libc_hidden_proto(btowc) -libc_hidden_proto(wcrtomb) -libc_hidden_proto(fputws) -#endif - -/* Some older or broken gcc toolchains define LONG_LONG_MAX but not - * LLONG_MAX. Since LLONG_MAX is part of the standard, that's what - * we use. So complain if we do not have it but should. - */ -#if !defined(LLONG_MAX) && defined(LONG_LONG_MAX) -#error Apparently, LONG_LONG_MAX is defined but LLONG_MAX is not. You need to fix your toolchain headers to support the standard macros for (unsigned) long long. -#endif - -/**********************************************************************/ -/* These provide some control over printf's feature set */ - -/* This is undefined below depeding on uClibc's configuration. */ -#define __STDIO_PRINTF_FLOAT 1 - -/* Now controlled by uClibc_stdio.h. */ -/* #define __UCLIBC_HAS_PRINTF_M_SPEC__ */ - - -/**********************************************************************/ - -#if defined(__UCLIBC__) && !defined(__UCLIBC_HAS_FLOATS__) -#undef __STDIO_PRINTF_FLOAT -#endif - -#ifdef __BCC__ -#undef __STDIO_PRINTF_FLOAT -#endif - -#ifdef __STDIO_PRINTF_FLOAT -#include -#include -#else /* __STDIO_PRINTF_FLOAT */ -#undef L__fpmaxtostr -#endif /* __STDIO_PRINTF_FLOAT */ - - -#undef __STDIO_HAS_VSNPRINTF -#if defined(__STDIO_BUFFERS) || defined(__USE_OLD_VFPRINTF__) || defined(__UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__) -#define __STDIO_HAS_VSNPRINTF 1 -#endif - -/**********************************************************************/ - -/* Now controlled by uClibc_stdio.h. */ -/* #define __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__ */ - -/* TODO -- move these to a configuration section? */ -#define MAX_FIELD_WIDTH 4095 - -#ifdef __UCLIBC_MJN3_ONLY__ -#ifdef L_register_printf_function -/* emit only once */ -#warning WISHLIST: Make MAX_USER_SPEC configurable? -#warning WISHLIST: Make MAX_ARGS_PER_SPEC configurable? -#endif -#endif /* __UCLIBC_MJN3_ONLY__ */ - -#ifdef __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__ - -#define MAX_USER_SPEC 10 -#define MAX_ARGS_PER_SPEC 5 - -#else /* __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__ */ - -#undef MAX_USER_SPEC -#define MAX_ARGS_PER_SPEC 1 - -#endif /* __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__ */ - -#if MAX_ARGS_PER_SPEC < 1 -#error MAX_ARGS_PER_SPEC < 1! -#undef MAX_ARGS_PER_SPEC -#define MAX_ARGS_PER_SPEC 1 -#endif - -#if defined(NL_ARGMAX) && (NL_ARGMAX < 9) -#error NL_ARGMAX < 9! -#endif - -#if defined(NL_ARGMAX) && (NL_ARGMAX >= (MAX_ARGS_PER_SPEC + 2)) -#define MAX_ARGS NL_ARGMAX -#else -/* N for spec itself, plus 1 each for width and precision */ -#define MAX_ARGS (MAX_ARGS_PER_SPEC + 2) -#endif - -/**********************************************************************/ - -#define __PA_FLAG_INTMASK \ - (__PA_FLAG_CHAR|PA_FLAG_SHORT|__PA_FLAG_INT|PA_FLAG_LONG|PA_FLAG_LONG_LONG) - -#ifdef __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__ -extern printf_function _custom_printf_handler[MAX_USER_SPEC] attribute_hidden; -extern printf_arginfo_function *_custom_printf_arginfo[MAX_USER_SPEC] attribute_hidden; -extern char *_custom_printf_spec attribute_hidden; -#endif /* __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__ */ - -/**********************************************************************/ - -#define SPEC_FLAGS " +0-#'I" -enum { - FLAG_SPACE = 0x01, - FLAG_PLUS = 0x02, /* must be 2 * FLAG_SPACE */ - FLAG_ZERO = 0x04, - FLAG_MINUS = 0x08, /* must be 2 * FLAG_ZERO */ - FLAG_HASH = 0x10, - FLAG_THOUSANDS = 0x20, - FLAG_I18N = 0x40, /* only works for d, i, u */ - FLAG_WIDESTREAM = 0x80 -}; - -/**********************************************************************/ - -/* float layout 01234567890123456789 TODO: B?*/ -#define SPEC_CHARS "npxXoudifFeEgGaACScs" -enum { - CONV_n = 0, - CONV_p, - CONV_x, CONV_X, CONV_o, CONV_u, CONV_d, CONV_i, - CONV_f, CONV_F, CONV_e, CONV_E, CONV_g, CONV_G, CONV_a, CONV_A, - CONV_C, CONV_S, CONV_c, CONV_s, -#ifdef __UCLIBC_HAS_PRINTF_M_SPEC__ - CONV_m, -#endif - CONV_custom0 /* must be last */ -}; - -/* p x X o u d i */ -#define SPEC_BASE { 16, 16, 16, 8, 10, 10, 10 } - -#define SPEC_RANGES { CONV_n, CONV_p, CONV_i, CONV_A, \ - CONV_C, CONV_S, CONV_c, CONV_s, CONV_custom0 } - -#define SPEC_OR_MASK { \ - /* n */ (PA_FLAG_PTR|PA_INT), \ - /* p */ PA_POINTER, \ - /* oxXudi */ PA_INT, \ - /* fFeEgGaA */ PA_DOUBLE, \ - /* C */ PA_WCHAR, \ - /* S */ PA_WSTRING, \ - /* c */ PA_CHAR, \ - /* s */ PA_STRING, \ -} - -#define SPEC_AND_MASK { \ - /* n */ (PA_FLAG_PTR|__PA_INTMASK), \ - /* p */ PA_POINTER, \ - /* oxXudi */ (__PA_INTMASK), \ - /* fFeEgGaA */ (PA_FLAG_LONG_DOUBLE|PA_DOUBLE), \ - /* C */ (PA_WCHAR), \ - /* S */ (PA_WSTRING), \ - /* c */ (PA_CHAR), \ - /* s */ (PA_STRING), \ -} - -/**********************************************************************/ -/* - * In order to ease translation to what arginfo and _print_info._flags expect, - * we map: 0:int 1:char 2:longlong 4:long 8:short - * and then _flags |= (((q << 7) + q) & 0x701) and argtype |= (_flags & 0x701) - */ - -/* TODO -- Fix the table below to take into account stdint.h. */ -/* #ifndef LLONG_MAX */ -/* #error fix QUAL_CHARS for no long long! Affects 'L', 'j', 'q', 'll'. */ -/* #else */ -/* #if LLONG_MAX != INTMAX_MAX */ -/* #error fix QUAL_CHARS intmax_t entry 'j'! */ -/* #endif */ -/* #endif */ - -#ifdef PDS -#error PDS already defined! -#endif -#ifdef SS -#error SS already defined! -#endif -#ifdef IMS -#error IMS already defined! -#endif - -#if PTRDIFF_MAX == INT_MAX -#define PDS 0 -#elif PTRDIFF_MAX == LONG_MAX -#define PDS 4 -#elif defined(LLONG_MAX) && (PTRDIFF_MAX == LLONG_MAX) -#define PDS 8 -#else -#error fix QUAL_CHARS ptrdiff_t entry 't'! -#endif - -#if SIZE_MAX == UINT_MAX -#define SS 0 -#elif SIZE_MAX == ULONG_MAX -#define SS 4 -#elif defined(LLONG_MAX) && (SIZE_MAX == ULLONG_MAX) -#define SS 8 -#else -#error fix QUAL_CHARS size_t entries 'z', 'Z'! -#endif - -#if INTMAX_MAX == INT_MAX -#define IMS 0 -#elif INTMAX_MAX == LONG_MAX -#define IMS 4 -#elif defined(LLONG_MAX) && (INTMAX_MAX == LLONG_MAX) -#define IMS 8 -#else -#error fix QUAL_CHARS intmax_t entry 'j'! -#endif - -#define QUAL_CHARS { \ - /* j:(u)intmax_t z:(s)size_t t:ptrdiff_t \0:int */ \ - /* q:long_long Z:(s)size_t */ \ - 'h', 'l', 'L', 'j', 'z', 't', 'q', 'Z', 0, \ - 2, 4, 8, IMS, SS, PDS, 8, SS, 0, /* TODO -- fix!!! */\ - 1, 8 \ -} - -/**********************************************************************/ - -#ifdef __STDIO_VA_ARG_PTR -#ifdef __BCC__ -#define __va_arg_ptr(ap,type) (((type *)(ap += sizeof(type))) - 1) -#endif - -#if 1 -#ifdef __GNUC__ -/* TODO -- need other than for 386 as well! */ - -#ifndef __va_rounded_size -#define __va_rounded_size(TYPE) \ - (((sizeof (TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int)) -#endif -#define __va_arg_ptr(AP, TYPE) \ - (AP = (va_list) ((char *) (AP) + __va_rounded_size (TYPE)), \ - ((void *) ((char *) (AP) - __va_rounded_size (TYPE)))) -#endif -#endif -#endif /* __STDIO_VA_ARG_PTR */ - -#ifdef __va_arg_ptr -#define GET_VA_ARG(AP,F,TYPE,ARGS) (*(AP) = __va_arg_ptr(ARGS,TYPE)) -#define GET_ARG_VALUE(AP,F,TYPE) (*((TYPE *)(*(AP)))) -#else -typedef union { - wchar_t wc; - unsigned int u; - unsigned long ul; -#ifdef ULLONG_MAX - unsigned long long ull; -#endif -#ifdef __STDIO_PRINTF_FLOAT - double d; - long double ld; -#endif /* __STDIO_PRINTF_FLOAT */ - void *p; -} argvalue_t; - -#define GET_VA_ARG(AU,F,TYPE,ARGS) (AU->F = va_arg(ARGS,TYPE)) -#define GET_ARG_VALUE(AU,F,TYPE) ((TYPE)((AU)->F)) -#endif - -typedef struct { - const char *fmtpos; /* TODO: move below struct?? */ - struct printf_info info; -#ifdef NL_ARGMAX - int maxposarg; /* > 0 if args are positional, 0 if not, -1 if unknown */ -#endif /* NL_ARGMAX */ - int num_data_args; /* TODO: use sentinal??? */ - unsigned int conv_num; - unsigned char argnumber[4]; /* width | prec | 1st data | unused */ - int argtype[MAX_ARGS]; - va_list arg; -#ifdef __va_arg_ptr - void *argptr[MAX_ARGS]; -#else -/* if defined(NL_ARGMAX) || defined(__UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__) */ - /* While this is wasteful of space in the case where pos args aren't - * enabled, it is also needed to support custom printf handlers. */ - argvalue_t argvalue[MAX_ARGS]; -#endif -} ppfs_t; /* parse printf format state */ - -/**********************************************************************/ - -/* TODO: fix printf to return 0 and set errno if format error. Standard says - only returns -1 if sets error indicator for the stream. */ - -#ifdef __STDIO_PRINTF_FLOAT -typedef size_t (__fp_outfunc_t)(FILE *fp, intptr_t type, intptr_t len, - intptr_t buf); - -extern ssize_t _fpmaxtostr(FILE * fp, __fpmax_t x, struct printf_info *info, - __fp_outfunc_t fp_outfunc) attribute_hidden; -#endif - -extern int _ppfs_init(ppfs_t *ppfs, const char *fmt0) attribute_hidden; /* validates */ -extern void _ppfs_prepargs(ppfs_t *ppfs, va_list arg) attribute_hidden; /* sets posargptrs */ -extern void _ppfs_setargs(ppfs_t *ppfs) attribute_hidden; /* sets argptrs for current spec */ -extern int _ppfs_parsespec(ppfs_t *ppfs) attribute_hidden; /* parses specifier */ - -extern void _store_inttype(void *dest, int desttype, uintmax_t val) attribute_hidden; -extern uintmax_t _load_inttype(int desttype, const void *src, int uflag) attribute_hidden; - -/**********************************************************************/ -#ifdef L_parse_printf_format - -/* NOTE: This function differs from the glibc version in that parsing stops - * upon encountering an invalid conversion specifier. Since this is the way - * my printf functions work, I think it makes sense to do it that way here. - * Unfortunately, since glibc sets the return type as size_t, we have no way - * of returning that the template is illegal, other than returning 0. - */ - -size_t parse_printf_format(register const char *template, - size_t n, register int *argtypes) -{ - ppfs_t ppfs; - size_t i; - size_t count = 0; - - if (_ppfs_init(&ppfs, template) >= 0) { -#ifdef NL_ARGMAX - if (ppfs.maxposarg > 0) { /* Using positional args. */ - count = ppfs.maxposarg; - if (n > count) { - n = count; - } - for (i = 0 ; i < n ; i++) { - *argtypes++ = ppfs.argtype[i]; - } - } else { /* Not using positional args. */ -#endif /* NL_ARGMAX */ - while (*template) { - if ((*template == '%') && (*++template != '%')) { - ppfs.fmtpos = template; - _ppfs_parsespec(&ppfs); /* Can't fail. */ - template = ppfs.fmtpos; /* Update to one past spec end. */ - if (ppfs.info.width == INT_MIN) { - ++count; - if (n > 0) { - *argtypes++ = PA_INT; - --n; - } - } - if (ppfs.info.prec == INT_MIN) { - ++count; - if (n > 0) { - *argtypes++ = PA_INT; - --n; - } - } - for (i = 0 ; i < ppfs.num_data_args ; i++) { - if ((ppfs.argtype[i]) != __PA_NOARG) { - ++count; - if (n > 0) { - *argtypes++ = ppfs.argtype[i]; - --n; - } - } - } - } else { - ++template; - } - } -#ifdef NL_ARGMAX - } -#endif /* NL_ARGMAX */ - } - - return count; -} - -#endif -/**********************************************************************/ -#ifdef L__ppfs_init - -#ifdef __UCLIBC_HAS_LOCALE__ -libc_hidden_proto(__global_locale) -#endif - -int attribute_hidden _ppfs_init(register ppfs_t *ppfs, const char *fmt0) -{ - int r; - - /* First, zero out everything... argnumber[], argtype[], argptr[] */ - memset(ppfs, 0, sizeof(ppfs_t)); /* TODO: nonportable???? */ -#ifdef NL_ARGMAX - --ppfs->maxposarg; /* set to -1 */ -#endif /* NL_ARGMAX */ - ppfs->fmtpos = fmt0; -#ifdef __UCLIBC_MJN3_ONLY__ -#warning TODO: Make checking of the format string in C locale an option. -#endif -#ifdef __UCLIBC_HAS_LOCALE__ - /* To support old programs, don't check mb validity if in C locale. */ - if (((__UCLIBC_CURLOCALE_DATA).encoding) != __ctype_encoding_7_bit) { - /* ANSI/ISO C99 requires format string to be a valid multibyte string - * beginning and ending in its initial shift state. */ - static const char invalid_mbs[] = "Invalid multibyte format string."; - mbstate_t mbstate; - const char *p; - mbstate.__mask = 0; /* Initialize the mbstate. */ - p = fmt0; - if (mbsrtowcs(NULL, &p, SIZE_MAX, &mbstate) == ((size_t)(-1))) { - ppfs->fmtpos = invalid_mbs; - return -1; - } - } -#endif /* __UCLIBC_HAS_LOCALE__ */ - /* now set all argtypes to no-arg */ - { -#if 1 - /* TODO - use memset here since already "paid for"? */ - register int *p = ppfs->argtype; - - r = MAX_ARGS; - do { - *p++ = __PA_NOARG; - } while (--r); -#else - /* TODO -- get rid of this?? */ - register char *p = (char *) ((MAX_ARGS-1) * sizeof(int)); - - do { - *((int *)(((char *)ppfs) + ((int)p) + offsetof(ppfs_t,argtype))) = __PA_NOARG; - p -= sizeof(int); - } while (p); -#endif - } - - /* - * Run through the entire format string to validate it and initialize - * the positional arg numbers (if any). - */ - { - register const char *fmt = fmt0; - - while (*fmt) { - if ((*fmt == '%') && (*++fmt != '%')) { - ppfs->fmtpos = fmt; /* back up to the '%' */ - if ((r = _ppfs_parsespec(ppfs)) < 0) { - return -1; - } - fmt = ppfs->fmtpos; /* update to one past end of spec */ - } else { - ++fmt; - } - } - ppfs->fmtpos = fmt0; /* rewind */ - } - -#ifdef NL_MAX_ARG - /* If we have positional args, make sure we know all the types. */ - { - register int *p = ppfs->argtype; - r = ppfs->maxposarg; - while (--r >= 0) { - if ( *p == __PA_NOARG ) { /* missing arg type!!! */ - return -1; - } - ++p; - } - } -#endif /* NL_MAX_ARG */ - - return 0; -} -#endif -/**********************************************************************/ -#ifdef L__ppfs_prepargs -void attribute_hidden _ppfs_prepargs(register ppfs_t *ppfs, va_list arg) -{ - int i; - - va_copy(ppfs->arg, arg); - -#ifdef NL_ARGMAX - if ((i = ppfs->maxposarg) > 0) { /* init for positional args */ - ppfs->num_data_args = i; - ppfs->info.width = ppfs->info.prec = ppfs->maxposarg = 0; - _ppfs_setargs(ppfs); - ppfs->maxposarg = i; - } -#endif /* NL_ARGMAX */ -} -#endif -/**********************************************************************/ -#ifdef L__ppfs_setargs - -void attribute_hidden _ppfs_setargs(register ppfs_t *ppfs) -{ -#ifdef __va_arg_ptr - register void **p = ppfs->argptr; -#else - register argvalue_t *p = ppfs->argvalue; -#endif - int i; - -#ifdef NL_ARGMAX - if (ppfs->maxposarg == 0) { /* initing for or no pos args */ -#endif /* NL_ARGMAX */ - if (ppfs->info.width == INT_MIN) { - ppfs->info.width = -#ifdef __va_arg_ptr - *(int *) -#endif - GET_VA_ARG(p,u,unsigned int,ppfs->arg); - } - if (ppfs->info.prec == INT_MIN) { - ppfs->info.prec = -#ifdef __va_arg_ptr - *(int *) -#endif - GET_VA_ARG(p,u,unsigned int,ppfs->arg); - } - i = 0; - while (i < ppfs->num_data_args) { - switch(ppfs->argtype[i++]) { - case (PA_INT|PA_FLAG_LONG_LONG): -#ifdef ULLONG_MAX - GET_VA_ARG(p,ull,unsigned long long,ppfs->arg); - break; -#endif - case (PA_INT|PA_FLAG_LONG): -#if ULONG_MAX != UINT_MAX - GET_VA_ARG(p,ul,unsigned long,ppfs->arg); - break; -#endif - case PA_CHAR: /* TODO - be careful */ - /* ... users could use above and really want below!! */ - case (PA_INT|__PA_FLAG_CHAR):/* TODO -- translate this!!! */ - case (PA_INT|PA_FLAG_SHORT): - case PA_INT: - GET_VA_ARG(p,u,unsigned int,ppfs->arg); - break; - case PA_WCHAR: /* TODO -- assume int? */ - /* we're assuming wchar_t is at least an int */ - GET_VA_ARG(p,wc,wchar_t,ppfs->arg); - break; -#ifdef __STDIO_PRINTF_FLOAT - /* PA_FLOAT */ - case PA_DOUBLE: - GET_VA_ARG(p,d,double,ppfs->arg); - break; - case (PA_DOUBLE|PA_FLAG_LONG_DOUBLE): - GET_VA_ARG(p,ld,long double,ppfs->arg); - break; -#else /* __STDIO_PRINTF_FLOAT */ - case PA_DOUBLE: - case (PA_DOUBLE|PA_FLAG_LONG_DOUBLE): - assert(0); - continue; -#endif /* __STDIO_PRINTF_FLOAT */ - default: - /* TODO -- really need to ensure this can't happen */ - assert(ppfs->argtype[i-1] & PA_FLAG_PTR); - case PA_POINTER: - case PA_STRING: - case PA_WSTRING: - GET_VA_ARG(p,p,void *,ppfs->arg); - break; - case __PA_NOARG: - continue; - } - ++p; - } -#ifdef NL_ARGMAX - } else { - if (ppfs->info.width == INT_MIN) { - ppfs->info.width - = (int) GET_ARG_VALUE(p + ppfs->argnumber[0] - 1,u,unsigned int); - } - if (ppfs->info.prec == INT_MIN) { - ppfs->info.prec - = (int) GET_ARG_VALUE(p + ppfs->argnumber[1] - 1,u,unsigned int); - } - } -#endif /* NL_ARGMAX */ - - /* Now we know the width and precision. */ - if (ppfs->info.width < 0) { - ppfs->info.width = -ppfs->info.width; - PRINT_INFO_SET_FLAG(&(ppfs->info),left); - PRINT_INFO_CLR_FLAG(&(ppfs->info),space); - ppfs->info.pad = ' '; - } -#if 0 - /* NOTE -- keep neg for now so float knows! */ - if (ppfs->info.prec < 0) { /* spec says treat as omitted. */ - /* so use default prec... 1 for everything but floats and strings. */ - ppfs->info.prec = 1; - } -#endif -} -#endif -/**********************************************************************/ -#ifdef L__ppfs_parsespec - -#ifdef __UCLIBC_HAS_XLOCALE__ -libc_hidden_proto(__ctype_b_loc) -#else -libc_hidden_proto(__ctype_b) -#endif - -/* Notes: argtype differs from glibc for the following: - * mine glibc - * lc PA_WCHAR PA_CHAR the standard says %lc means %C - * ls PA_WSTRING PA_STRING the standard says %ls means %S - * {*}n {*}|PA_FLAG_PTR PA_FLAG_PTR size of n can be qualified - */ - -/* TODO: store positions of positional args */ - -/* TODO -- WARNING -- assumes aligned on integer boundaries!!! */ - -/* TODO -- disable if not using positional args!!! */ -#define _OVERLAPPING_DIFFERENT_ARGS - -/* TODO -- rethink this -- perhaps we should set to largest type??? */ - -#ifdef _OVERLAPPING_DIFFERENT_ARGS - -#define PROMOTED_SIZE_OF(X) ((sizeof(X) + sizeof(int) - 1) / sizeof(X)) - -static const short int type_codes[] = { - __PA_NOARG, /* must be first entry */ - PA_POINTER, - PA_STRING, - PA_WSTRING, - PA_CHAR, - PA_INT|PA_FLAG_SHORT, - PA_INT, - PA_INT|PA_FLAG_LONG, - PA_INT|PA_FLAG_LONG_LONG, - PA_WCHAR, -#ifdef __STDIO_PRINTF_FLOAT - /* PA_FLOAT, */ - PA_DOUBLE, - PA_DOUBLE|PA_FLAG_LONG_DOUBLE, -#endif /* __STDIO_PRINTF_FLOAT */ -}; - -static const unsigned char type_sizes[] = { - /* unknown type consumes no arg */ - 0, /* must be first entry */ - PROMOTED_SIZE_OF(void *), - PROMOTED_SIZE_OF(char *), - PROMOTED_SIZE_OF(wchar_t *), - PROMOTED_SIZE_OF(char), - PROMOTED_SIZE_OF(short), - PROMOTED_SIZE_OF(int), - PROMOTED_SIZE_OF(long), -#ifdef ULLONG_MAX - PROMOTED_SIZE_OF(long long), -#else - PROMOTED_SIZE_OF(long), /* TODO -- is this correct? (above too) */ -#endif - PROMOTED_SIZE_OF(wchar_t), -#ifdef __STDIO_PRINTF_FLOAT - /* PROMOTED_SIZE_OF(float), */ - PROMOTED_SIZE_OF(double), - PROMOTED_SIZE_OF(long double), -#endif /* __STDIO_PRINTF_FLOAT */ -}; - -static int _promoted_size(int argtype) -{ - register const short int *p; - - /* note -- since any unrecognized type is treated as a pointer */ - p = type_codes + sizeof(type_codes)/sizeof(type_codes[0]); - do { - if (*--p == argtype) { - break; - } - } while (p > type_codes); - - return type_sizes[(int)(p - type_codes)]; -} - -static int _is_equal_or_bigger_arg(int curtype, int newtype) -{ - /* Quick test */ - if (newtype == __PA_NOARG) { - return 0; - } - if ((curtype == __PA_NOARG) || (curtype == newtype)) { - return 1; - } - /* Ok... slot is already filled and types are different in name. */ - /* So, compare promoted sizes of curtype and newtype args. */ - return _promoted_size(curtype) <= _promoted_size(newtype); -} - -#else - -#define _is_equal_or_bigger_arg(C,N) (((C) == __PA_NOARG) || ((C) == (N))) - -#endif - -#ifdef __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__ -/* TODO - do this differently? */ -static char _bss_custom_printf_spec[MAX_USER_SPEC]; /* 0-init'd for us. */ - -attribute_hidden char *_custom_printf_spec = _bss_custom_printf_spec; -attribute_hidden printf_arginfo_function *_custom_printf_arginfo[MAX_USER_SPEC]; -attribute_hidden printf_function _custom_printf_handler[MAX_USER_SPEC]; -#endif /* __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__ */ - -int attribute_hidden _ppfs_parsespec(ppfs_t *ppfs) -{ - register const char *fmt; - register const char *p; - int preci; - int width; - int flags; - int dataargtype; - int i; - int dpoint; -#ifdef NL_ARGMAX - int maxposarg; -#endif /* NL_ARGMAX */ - int p_m_spec_chars; - int n; - int argtype[MAX_ARGS_PER_SPEC+2]; - int argnumber[3]; /* width, precision, 1st data arg */ - static const char spec_flags[] = SPEC_FLAGS; - static const char spec_chars[] = SPEC_CHARS;/* TODO: b? */ - static const char spec_ranges[] = SPEC_RANGES; - static const short spec_or_mask[] = SPEC_OR_MASK; - static const short spec_and_mask[] = SPEC_AND_MASK; - static const char qual_chars[] = QUAL_CHARS; -#ifdef __UCLIBC_HAS_WCHAR__ - char buf[32]; -#endif /* __UCLIBC_HAS_WCHAR__ */ - - /* WIDE note: we can test against '%' here since we don't allow */ - /* WIDE note: other mappings of '%' in the wide char set. */ - preci = -1; - argnumber[0] = 0; - argnumber[1] = 0; - argtype[0] = __PA_NOARG; - argtype[1] = __PA_NOARG; -#ifdef NL_ARGMAX - maxposarg = ppfs->maxposarg; -#endif /* NL_ARGMAX */ - -#ifdef __UCLIBC_HAS_WCHAR__ - /* This is somewhat lame, but saves a lot of code. If we're dealing with - * a wide stream, that means the format is a wchar string. So, copy it - * char-by-char into a normal char buffer for processing. Make the buffer - * (buf) big enough so that any reasonable format specifier will fit. - * While there a legal specifiers that won't, the all involve duplicate - * flags or outrageous field widths/precisions. */ - width = dpoint = 0; - if ((flags = ppfs->info._flags & FLAG_WIDESTREAM) == 0) { - fmt = ppfs->fmtpos; - } else { - fmt = buf + 1; - i = 0; - do { - if ((buf[i] = (char) (((wchar_t *) ppfs->fmtpos)[i-1])) - != (((wchar_t *) ppfs->fmtpos)[i-1]) - ) { - return -1; - } - } while (buf[i++]); - buf[sizeof(buf)-1] = 0; - } -#else /* __UCLIBC_HAS_WCHAR__ */ - width = flags = dpoint = 0; - fmt = ppfs->fmtpos; -#endif /* __UCLIBC_HAS_WCHAR__ */ - - assert(fmt[-1] == '%'); - assert(fmt[0] != '%'); - - /* Process arg pos and/or flags and/or width and/or precision. */ - width_precision: - p = fmt; - if (*fmt == '*') { - argtype[-dpoint] = PA_INT; - ++fmt; - } - i = 0; - while (isdigit(*fmt)) { - if (i < MAX_FIELD_WIDTH) { /* Avoid overflow. */ - i = (i * 10) + (*fmt - '0'); - } - ++fmt; - } - if (p[-1] == '%') { /* Check for a position. */ - - /* TODO: if val not in range, then error */ - -#ifdef NL_ARGMAX - if ((*fmt == '$') && (i > 0)) {/* Positional spec. */ - ++fmt; - if (maxposarg == 0) { - return -1; - } - if ((argnumber[2] = i) > maxposarg) { - maxposarg = i; - } - /* Now fall through to check flags. */ - } else { - if (maxposarg > 0) { -#ifdef __UCLIBC_HAS_PRINTF_M_SPEC__ -#ifdef __UCLIBC_MJN3_ONLY__ -#warning TODO: Support prec and width for %m when positional args used - /* Actually, positional arg processing will fail in general - * for specifiers that don't require an arg. */ -#endif /* __UCLIBC_MJN3_ONLY__ */ - if (*fmt == 'm') { - goto PREC_WIDTH; - } -#endif /* __UCLIBC_HAS_PRINTF_M_SPEC__ */ - return -1; - } - maxposarg = 0; /* Possible redundant store, but cuts size. */ - - if ((fmt > p) && (*p != '0')) { - goto PREC_WIDTH; - } - - fmt = p; /* Back up for possible '0's flag. */ - /* Now fall through to check flags. */ - } -#else /* NL_ARGMAX */ - if (*fmt == '$') { /* Positional spec. */ - return -1; - } - - if ((fmt > p) && (*p != '0')) { - goto PREC_WIDTH; - } - - fmt = p; /* Back up for possible '0's flag. */ - /* Now fall through to check flags. */ -#endif /* NL_ARGMAX */ - - restart_flags: /* Process flags. */ - i = 1; - p = spec_flags; - - do { - if (*fmt == *p++) { - ++fmt; - flags |= i; - goto restart_flags; - } - i += i; /* Better than i <<= 1 for bcc */ - } while (*p); - i = 0; - - /* If '+' then ignore ' ', and if '-' then ignore '0'. */ - /* Note: Need to ignore '0' when prec is an arg with val < 0, */ - /* but that test needs to wait until the arg is retrieved. */ - flags &= ~((flags & (FLAG_PLUS|FLAG_MINUS)) >> 1); - /* Note: Ignore '0' when prec is specified < 0 too (in printf). */ - - if (fmt[-1] != '%') { /* If we've done anything, loop for width. */ - goto width_precision; - } - } - PREC_WIDTH: - if (*p == '*') { /* Prec or width takes an arg. */ -#ifdef NL_ARGMAX - if (maxposarg) { - if ((*fmt++ != '$') || (i <= 0)) { - /* Using pos args and no $ or invalid arg number. */ - return -1; - } - argnumber[-dpoint] = i; - } else -#endif /* NL_ARGMAX */ - if (++p != fmt) { - /* Not using pos args but digits followed *. */ - return -1; - } - i = INT_MIN; - } - - if (!dpoint) { - width = i; - if (*fmt == '.') { - ++fmt; - dpoint = -1; /* To use as default precison. */ - goto width_precision; - } - } else { - preci = i; - } - - /* Process qualifier. */ - p = qual_chars; - do { - if (*fmt == *p) { - ++fmt; - break; - } - } while (*++p); - if ((p - qual_chars < 2) && (*fmt == *p)) { - p += ((sizeof(qual_chars)-2) / 2); - ++fmt; - } - dataargtype = ((int)(p[(sizeof(qual_chars)-2) / 2])) << 8; - - /* Process conversion specifier. */ - if (!*fmt) { - return -1; - } - - p = spec_chars; - - do { - if (*fmt == *p) { - p_m_spec_chars = p - spec_chars; - - if ((p_m_spec_chars >= CONV_c) - && (dataargtype & PA_FLAG_LONG)) { - p_m_spec_chars -= 2; /* lc -> C and ls -> S */ - } - - ppfs->conv_num = p_m_spec_chars; - p = spec_ranges-1; - while (p_m_spec_chars > *++p) {} - - i = p - spec_ranges; - argtype[2] = (dataargtype | spec_or_mask[i]) & spec_and_mask[i]; - p = spec_chars; - break; - } - } while(*++p); - - ppfs->info.spec = *fmt; - ppfs->info.prec = preci; - ppfs->info.width = width; - ppfs->info.pad = ((flags & FLAG_ZERO) ? '0' : ' '); - ppfs->info._flags = (flags & ~FLAG_ZERO) | (dataargtype & __PA_INTMASK); - ppfs->num_data_args = 1; - - if (!*p) { -#ifdef __UCLIBC_HAS_PRINTF_M_SPEC__ - if (*fmt == 'm') { - ppfs->conv_num = CONV_m; - ppfs->num_data_args = 0; - goto DONE; - } -#endif -#ifdef __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__ - - /* Handle custom arg -- WARNING -- overwrites p!!! */ - ppfs->conv_num = CONV_custom0; - p = _custom_printf_spec; - do { - if (*p == *fmt) { - if ((ppfs->num_data_args - = ((*_custom_printf_arginfo[(int)(p-_custom_printf_spec)]) - (&(ppfs->info), MAX_ARGS_PER_SPEC, argtype+2))) - > MAX_ARGS_PER_SPEC) { - break; /* Error -- too many args! */ - } - goto DONE; - } - } while (++p < (_custom_printf_spec + MAX_USER_SPEC)); -#endif /* __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__ */ - /* Otherwise error. */ - return -1; - } - -#if defined(__UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__) || defined(__UCLIBC_HAS_PRINTF_M_SPEC__) - DONE: -#endif - -#ifdef NL_ARGMAX - if (maxposarg > 0) { - i = 0; - do { - /* Update maxposarg and check that NL_ARGMAX is not exceeded. */ - n = ((i <= 2) - ? (ppfs->argnumber[i] = argnumber[i]) - : argnumber[2] + (i-2)); - if (n > maxposarg) { - if ((maxposarg = n) > NL_ARGMAX) { - return -1; - } - } - --n; - /* Record argtype with largest size (current, new). */ - if (_is_equal_or_bigger_arg(ppfs->argtype[n], argtype[i])) { - ppfs->argtype[n] = argtype[i]; - } - } while (++i < ppfs->num_data_args + 2); - } else { -#endif /* NL_ARGMAX */ - ppfs->argnumber[2] = 1; - memcpy(ppfs->argtype, argtype + 2, ppfs->num_data_args * sizeof(int)); -#ifdef NL_ARGMAX - } - - ppfs->maxposarg = maxposarg; -#endif /* NL_ARGMAX */ - -#ifdef __UCLIBC_HAS_WCHAR__ - if ((flags = ppfs->info._flags & FLAG_WIDESTREAM) == 0) { - ppfs->fmtpos = ++fmt; - } else { - ppfs->fmtpos = (const char *) (((const wchar_t *)(ppfs->fmtpos)) - + (fmt - buf) ); - } -#else /* __UCLIBC_HAS_WCHAR__ */ - ppfs->fmtpos = ++fmt; -#endif /* __UCLIBC_HAS_WCHAR__ */ - - return ppfs->num_data_args + 2; -} - -#endif -/**********************************************************************/ -#ifdef L_register_printf_function - -#ifdef __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__ - -int register_printf_function(int spec, printf_function handler, - printf_arginfo_function arginfo) -{ - register char *r; - register char *p; - - if (spec && (arginfo != NULL)) { /* TODO -- check if spec is valid char */ - r = NULL; - p = _custom_printf_spec + MAX_USER_SPEC; - do { - --p; - if (!*p) { - r = p; - } -#ifdef __BCC__ - else /* bcc generates less code with fall-through */ -#endif - if (*p == spec) { - r = p; - p = _custom_printf_spec; - } - } while (p > _custom_printf_spec); - - if (r) { - if (handler) { - *r = spec; - _custom_printf_handler[(int)(r - p)] = handler; - _custom_printf_arginfo[(int)(r - p)] = arginfo; - } else { - *r = 0; - } - return 0; - } - /* TODO -- if asked to unregister a non-existent spec, return what? */ - } - return -1; -} - -#endif - -#endif -/**********************************************************************/ -#if defined(L_vfprintf) || defined(L_vfwprintf) - -/* We only support ascii digits (or their USC equivalent codes) in - * precision and width settings in *printf (wide) format strings. - * In other words, we don't currently support glibc's 'I' flag. - * We do accept it, but it is currently ignored. */ - -static size_t _charpad(FILE * __restrict stream, int padchar, size_t numpad); - -#ifdef L_vfprintf - -#define VFPRINTF vfprintf -#define FMT_TYPE char -#define OUTNSTR _outnstr -#define STRLEN strlen -#define _PPFS_init _ppfs_init -#define OUTPUT(F,S) fputs_unlocked(S,F) -/* #define _outnstr(stream, string, len) __stdio_fwrite(string, len, stream) */ -#define _outnstr(stream, string, len) ((len > 0) ? __stdio_fwrite(string, len, stream) : 0) -#define FP_OUT _fp_out_narrow - -#ifdef __STDIO_PRINTF_FLOAT - -static size_t _fp_out_narrow(FILE *fp, intptr_t type, intptr_t len, intptr_t buf) -{ - size_t r = 0; - - if (type & 0x80) { /* Some type of padding needed. */ - int buflen = strlen((const char *) buf); - if ((len -= buflen) > 0) { - if ((r = _charpad(fp, (type & 0x7f), len)) != len) { - return r; - } - } - len = buflen; - } - return r + OUTNSTR(fp, (const char *) buf, len); -} - -#endif /* __STDIO_PRINTF_FLOAT */ - -#else /* L_vfprintf */ - -#define VFPRINTF vfwprintf -#define FMT_TYPE wchar_t -#define OUTNSTR _outnwcs -#define STRLEN wcslen -#define _PPFS_init _ppwfs_init -#define OUTPUT(F,S) fputws(S,F) -#define _outnwcs(stream, wstring, len) _wstdio_fwrite(wstring, len, stream) -#define FP_OUT _fp_out_wide - -#ifdef __UCLIBC_HAS_LOCALE__ -libc_hidden_proto(__global_locale) -#endif - -static size_t _outnstr(FILE *stream, const char *s, size_t wclen) -{ - /* NOTE!!! len here is the number of wchars we want to generate!!! */ - wchar_t wbuf[64]; - mbstate_t mbstate; - size_t todo, r, n; - - mbstate.__mask = 0; - todo = wclen; - - while (todo) { - r = mbsrtowcs(wbuf, &s, - ((todo <= sizeof(wbuf)/sizeof(wbuf[0])) - ? todo - : sizeof(wbuf)/sizeof(wbuf[0])), - &mbstate); - assert(((ssize_t)r) > 0); - n = _outnwcs(stream, wbuf, r); - todo -= n; - if (n != r) { - break; - } - } - - return wclen - todo; -} - -#ifdef __STDIO_PRINTF_FLOAT - -#ifdef __UCLIBC_MJN3_ONLY__ -#warning TODO: Move defines from _fpmaxtostr. Put them in a common header. -#endif - -/* The following defines are from _fpmaxtostr.*/ -#define DIGITS_PER_BLOCK 9 -#define NUM_DIGIT_BLOCKS ((DECIMAL_DIG+DIGITS_PER_BLOCK-1)/DIGITS_PER_BLOCK) -#define BUF_SIZE ( 3 + NUM_DIGIT_BLOCKS * DIGITS_PER_BLOCK ) - -static size_t _fp_out_wide(FILE *fp, intptr_t type, intptr_t len, intptr_t buf) -{ - wchar_t wbuf[BUF_SIZE]; - const char *s = (const char *) buf; - size_t r = 0; - int i; - - if (type & 0x80) { /* Some type of padding needed */ - int buflen = strlen(s); - if ((len -= buflen) > 0) { - if ((r = _charpad(fp, (type & 0x7f), len)) != len) { - return r; - } - } - len = buflen; - } - - if (len > 0) { - i = 0; - do { -#ifdef __LOCALE_C_ONLY - wbuf[i] = s[i]; -#else /* __LOCALE_C_ONLY */ - -#ifdef __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__ - if (s[i] == ',') { - wbuf[i] = __UCLIBC_CURLOCALE_DATA.thousands_sep_wc; - } else -#endif /* __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__ */ - if (s[i] == '.') { - wbuf[i] = __UCLIBC_CURLOCALE_DATA.decimal_point_wc; - } else { - wbuf[i] = s[i]; - } -#endif /* __LOCALE_C_ONLY */ - - } while (++i < len); - - r += OUTNSTR(fp, wbuf, len); - } - - return r; -} - -#endif /* __STDIO_PRINTF_FLOAT */ - -static int _ppwfs_init(register ppfs_t *ppfs, const wchar_t *fmt0) -{ - static const wchar_t invalid_wcs[] = L"Invalid wide format string."; - int r; - - /* First, zero out everything... argnumber[], argtype[], argptr[] */ - memset(ppfs, 0, sizeof(ppfs_t)); /* TODO: nonportable???? */ -#ifdef NL_ARGMAX - --ppfs->maxposarg; /* set to -1 */ -#endif /* NL_ARGMAX */ - ppfs->fmtpos = (const char *) fmt0; - ppfs->info._flags = FLAG_WIDESTREAM; - - { - mbstate_t mbstate; - const wchar_t *p; - mbstate.__mask = 0; /* Initialize the mbstate. */ - p = fmt0; - if (wcsrtombs(NULL, &p, SIZE_MAX, &mbstate) == ((size_t)(-1))) { - ppfs->fmtpos = (const char *) invalid_wcs; - return -1; - } - } - - /* now set all argtypes to no-arg */ - { -#if 1 - /* TODO - use memset here since already "paid for"? */ - register int *p = ppfs->argtype; - - r = MAX_ARGS; - do { - *p++ = __PA_NOARG; - } while (--r); -#else - /* TODO -- get rid of this?? */ - register char *p = (char *) ((MAX_ARGS-1) * sizeof(int)); - - do { - *((int *)(((char *)ppfs) + ((int)p) + offsetof(ppfs_t,argtype))) = __PA_NOARG; - p -= sizeof(int); - } while (p); -#endif - } - - /* - * Run through the entire format string to validate it and initialize - * the positional arg numbers (if any). - */ - { - register const wchar_t *fmt = fmt0; - - while (*fmt) { - if ((*fmt == '%') && (*++fmt != '%')) { - ppfs->fmtpos = (const char *) fmt; /* back up to the '%' */ - if ((r = _ppfs_parsespec(ppfs)) < 0) { - return -1; - } - fmt = (const wchar_t *) ppfs->fmtpos; /* update to one past end of spec */ - } else { - ++fmt; - } - } - ppfs->fmtpos = (const char *) fmt0; /* rewind */ - } - -#ifdef NL_ARGMAX - /* If we have positional args, make sure we know all the types. */ - { - register int *p = ppfs->argtype; - r = ppfs->maxposarg; - while (--r >= 0) { - if ( *p == __PA_NOARG ) { /* missing arg type!!! */ - return -1; - } - ++p; - } - } -#endif /* NL_ARGMAX */ - - return 0; -} - -#endif /* L_vfprintf */ - -static size_t _charpad(FILE * __restrict stream, int padchar, size_t numpad) -{ - size_t todo = numpad; - - /* TODO -- Use a buffer to cut down on function calls... */ - FMT_TYPE pad[1]; - - *pad = padchar; - while (todo && (OUTNSTR(stream, pad, 1) == 1)) { - --todo; - } - - return numpad - todo; -} - -/* TODO -- Dynamically allocate work space to accomodate stack-poor archs? */ -static int _do_one_spec(FILE * __restrict stream, - register ppfs_t *ppfs, int *count) -{ - static const char spec_base[] = SPEC_BASE; -#ifdef L_vfprintf - static const char prefix[] = "+\0-\0 \0000x\0000X"; - /* 0 2 4 6 9 11*/ -#else /* L_vfprintf */ - static const wchar_t prefix[] = L"+\0-\0 \0000x\0000X"; -#endif /* L_vfprintf */ - enum { - PREFIX_PLUS = 0, - PREFIX_MINUS = 2, - PREFIX_SPACE = 4, - PREFIX_LWR_X = 6, - PREFIX_UPR_X = 9, - PREFIX_NONE = 11 - }; - -#ifdef __va_arg_ptr - const void * const *argptr; -#else - const void * argptr[MAX_ARGS_PER_SPEC]; -#endif - int *argtype; -#ifdef __UCLIBC_HAS_WCHAR__ - const wchar_t *ws = NULL; - mbstate_t mbstate; -#endif /* __UCLIBC_HAS_WCHAR__ */ - size_t slen; -#ifdef L_vfprintf -#define SLEN slen -#else - size_t SLEN; - wchar_t wbuf[2]; -#endif - int base; - int numpad; - int alphacase; - int numfill = 0; /* TODO: fix */ - int prefix_num = PREFIX_NONE; - char padchar = ' '; -#ifdef __UCLIBC_MJN3_ONLY__ -#warning TODO: Determine appropriate buf size. -#endif /* __UCLIBC_MJN3_ONLY__ */ - /* TODO: buf needs to be big enough for any possible error return strings - * and also for any locale-grouped long long integer strings generated. - * This should be large enough for any of the current archs/locales, but - * eventually this should be handled robustly. */ - char buf[128]; - -#ifdef NDEBUG - _ppfs_parsespec(ppfs); -#else - if (_ppfs_parsespec(ppfs) < 0) { /* TODO: just for debugging */ - abort(); - } -#endif - _ppfs_setargs(ppfs); - - argtype = ppfs->argtype + ppfs->argnumber[2] - 1; - /* Deal with the argptr vs argvalue issue. */ -#ifdef __va_arg_ptr - argptr = (const void * const *) ppfs->argptr; -#ifdef NL_ARGMAX - if (ppfs->maxposarg > 0) { /* Using positional args... */ - argptr += ppfs->argnumber[2] - 1; - } -#endif /* NL_ARGMAX */ -#else - /* Need to build a local copy... */ - { - register argvalue_t *p = ppfs->argvalue; - int i; -#ifdef NL_ARGMAX - if (ppfs->maxposarg > 0) { /* Using positional args... */ - p += ppfs->argnumber[2] - 1; - } -#endif /* NL_ARGMAX */ - for (i = 0 ; i < ppfs->num_data_args ; i++ ) { - argptr[i] = (void *) p++; - } - } -#endif - { - register char *s = NULL; /* TODO: Should s be unsigned char * ? */ - - if (ppfs->conv_num == CONV_n) { - _store_inttype(*(void **)*argptr, - ppfs->info._flags & __PA_INTMASK, - (intmax_t) (*count)); - return 0; - } - if (ppfs->conv_num <= CONV_i) { /* pointer or (un)signed int */ - alphacase = __UIM_LOWER; - -#ifdef __UCLIBC_MJN3_ONLY__ -#ifdef L_vfprintf -#warning CONSIDER: Should we ignore these flags if stub locale? What about custom specs? -#endif -#endif /* __UCLIBC_MJN3_ONLY__ */ - if ((base = spec_base[(int)(ppfs->conv_num - CONV_p)]) == 10) { - if (PRINT_INFO_FLAG_VAL(&(ppfs->info),group)) { - alphacase = __UIM_GROUP; - } - if (PRINT_INFO_FLAG_VAL(&(ppfs->info),i18n)) { - alphacase |= 0x80; - } - } - - if (ppfs->conv_num <= CONV_u) { /* pointer or unsigned int */ - if (ppfs->conv_num == CONV_X) { - alphacase = __UIM_UPPER; - } - if (ppfs->conv_num == CONV_p) { /* pointer */ - prefix_num = PREFIX_LWR_X; - } else { /* unsigned int */ - } - } else { /* signed int */ - base = -base; - } - if (ppfs->info.prec < 0) { /* Ignore '0' flag if prec specified. */ - padchar = ppfs->info.pad; - } -#ifdef __UCLIBC_MJN3_ONLY__ -#ifdef L_vfprintf -#warning CONSIDER: If using outdigits and/or grouping, how should we interpret precision? -#endif -#endif /* __UCLIBC_MJN3_ONLY__ */ - s = _uintmaxtostr(buf + sizeof(buf) - 1, - (uintmax_t) - _load_inttype(*argtype & __PA_INTMASK, - *argptr, base), base, alphacase); - if (ppfs->conv_num > CONV_u) { /* signed int */ - if (*s == '-') { - PRINT_INFO_SET_FLAG(&(ppfs->info),showsign); - ++s; /* handle '-' in the prefix string */ - prefix_num = PREFIX_MINUS; - } else if (PRINT_INFO_FLAG_VAL(&(ppfs->info),showsign)) { - prefix_num = PREFIX_PLUS; - } else if (PRINT_INFO_FLAG_VAL(&(ppfs->info),space)) { - prefix_num = PREFIX_SPACE; - } - } - slen = (char *)(buf + sizeof(buf) - 1) - s; -#ifdef L_vfwprintf - { - const char *q = s; - mbstate.__mask = 0; /* Initialize the mbstate. */ - SLEN = mbsrtowcs(NULL, &q, 0, &mbstate); - } -#endif - numfill = ((ppfs->info.prec < 0) ? 1 : ppfs->info.prec); - if (PRINT_INFO_FLAG_VAL(&(ppfs->info),alt)) { - if (ppfs->conv_num <= CONV_x) { /* x or p */ - prefix_num = PREFIX_LWR_X; - } - if (ppfs->conv_num == CONV_X) { - prefix_num = PREFIX_UPR_X; - } - if ((ppfs->conv_num == CONV_o) && (numfill <= SLEN)) { - numfill = ((*s == '0') ? 1 : SLEN + 1); - } - } - if (*s == '0') { - if (prefix_num >= PREFIX_LWR_X) { - prefix_num = PREFIX_NONE; - } - if (ppfs->conv_num == CONV_p) {/* null pointer */ - s = "(nil)"; -#ifdef L_vfwprintf - SLEN = -#endif - slen = 5; - numfill = 0; - } else if (numfill == 0) { /* if precision 0, no output */ -#ifdef L_vfwprintf - SLEN = -#endif - slen = 0; - } - } - numfill = ((numfill > SLEN) ? numfill - SLEN : 0); - } else if (ppfs->conv_num <= CONV_A) { /* floating point */ -#ifdef __STDIO_PRINTF_FLOAT - ssize_t nf; - nf = _fpmaxtostr(stream, - (__fpmax_t) - (PRINT_INFO_FLAG_VAL(&(ppfs->info),is_long_double) - ? *(long double *) *argptr - : (long double) (* (double *) *argptr)), - &ppfs->info, FP_OUT ); - if (nf < 0) { - return -1; - } - *count += nf; - - return 0; -#else /* __STDIO_PRINTF_FLOAT */ - return -1; /* TODO -- try to continue? */ -#endif /* __STDIO_PRINTF_FLOAT */ - } else if (ppfs->conv_num <= CONV_S) { /* wide char or string */ -#ifdef L_vfprintf - -#ifdef __UCLIBC_HAS_WCHAR__ - mbstate.__mask = 0; /* Initialize the mbstate. */ - if (ppfs->conv_num == CONV_S) { /* wide string */ - if (!(ws = *((const wchar_t **) *argptr))) { - goto NULL_STRING; - } - /* We use an awful uClibc-specific hack here, passing - * (char*) &ws as the conversion destination. This signals - * uClibc's wcsrtombs that we want a "restricted" length - * such that the mbs fits in a buffer of the specified - * size with no partial conversions. */ - if ((slen = wcsrtombs((char *) &ws, &ws, /* Use awful hack! */ - ((ppfs->info.prec >= 0) - ? ppfs->info.prec - : SIZE_MAX), &mbstate)) - == ((size_t)-1) - ) { - return -1; /* EILSEQ */ - } - } else { /* wide char */ - s = buf; - slen = wcrtomb(s, (*((const wchar_t *) *argptr)), &mbstate); - if (slen == ((size_t)-1)) { - return -1; /* EILSEQ */ - } - s[slen] = 0; /* TODO - Is this necessary? */ - } -#else /* __UCLIBC_HAS_WCHAR__ */ - return -1; -#endif /* __UCLIBC_HAS_WCHAR__ */ - } else if (ppfs->conv_num <= CONV_s) { /* char or string */ - if (ppfs->conv_num == CONV_s) { /* string */ - s = *((char **) (*argptr)); - if (s) { -#ifdef __UCLIBC_HAS_PRINTF_M_SPEC__ - SET_STRING_LEN: -#endif - slen = strnlen(s, ((ppfs->info.prec >= 0) - ? ppfs->info.prec : SIZE_MAX)); - } else { -#ifdef __UCLIBC_HAS_WCHAR__ - NULL_STRING: -#endif - s = "(null)"; - slen = 6; - } - } else { /* char */ - s = buf; - *s = (unsigned char)(*((const int *) *argptr)); - s[1] = 0; - slen = 1; - } - -#else /* L_vfprintf */ - - if (ppfs->conv_num == CONV_S) { /* wide string */ - ws = *((wchar_t **) (*argptr)); - if (!ws) { - goto NULL_STRING; - } - SLEN = wcsnlen(ws, ((ppfs->info.prec >= 0) - ? ppfs->info.prec : SIZE_MAX)); - } else { /* wide char */ - *wbuf = (wchar_t)(*((const wint_t *) *argptr)); - CHAR_CASE: - ws = wbuf; - wbuf[1] = 0; - SLEN = 1; - } - - } else if (ppfs->conv_num <= CONV_s) { /* char or string */ - - if (ppfs->conv_num == CONV_s) { /* string */ -#ifdef __UCLIBC_MJN3_ONLY__ -#warning TODO: Fix %s for vfwprintf... output upto illegal sequence? -#endif /* __UCLIBC_MJN3_ONLY__ */ - s = *((char **) (*argptr)); - if (s) { -#ifdef __UCLIBC_HAS_PRINTF_M_SPEC__ - SET_STRING_LEN: -#endif - /* We use an awful uClibc-specific hack here, passing - * (wchar_t*) &mbstate as the conversion destination. - * This signals uClibc's mbsrtowcs that we want a - * "restricted" length such that the mbs fits in a buffer - * of the specified size with no partial conversions. */ - { - const char *q = s; - mbstate.__mask = 0; /* Initialize the mbstate. */ - SLEN = mbsrtowcs((wchar_t *) &mbstate, &q, - ((ppfs->info.prec >= 0) - ? ppfs->info.prec : SIZE_MAX), - &mbstate); - } - if (SLEN == ((size_t)(-1))) { - return -1; /* EILSEQ */ - } - } else { - NULL_STRING: - s = "(null)"; - SLEN = slen = 6; - } - } else { /* char */ - *wbuf = btowc( (unsigned char)(*((const int *) *argptr)) ); - goto CHAR_CASE; - } - -#endif /* L_vfprintf */ - -#ifdef __UCLIBC_HAS_PRINTF_M_SPEC__ - } else if (ppfs->conv_num == CONV_m) { - s = __glibc_strerror_r(errno, buf, sizeof(buf)); - goto SET_STRING_LEN; -#endif - } else { -#ifdef __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__ - assert(ppfs->conv_num == CONV_custom0); - - s = _custom_printf_spec; - do { - if (*s == ppfs->info.spec) { - int rv; - /* TODO -- check return value for sanity? */ - rv = (*_custom_printf_handler - [(int)(s-_custom_printf_spec)]) - (stream, &ppfs->info, argptr); - if (rv < 0) { - return -1; - } - *count += rv; - return 0; - } - } while (++s < (_custom_printf_spec + MAX_USER_SPEC)); -#endif /* __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__ */ - assert(0); - return -1; - } - -#ifdef __UCLIBC_MJN3_ONLY__ -#ifdef L_vfprintf -#warning CONSIDER: If using outdigits and/or grouping, how should we pad? -#endif -#endif /* __UCLIBC_MJN3_ONLY__ */ - { - size_t t; - - t = SLEN + numfill; - if (prefix_num != PREFIX_NONE) { - t += ((prefix_num < PREFIX_LWR_X) ? 1 : 2); - } - numpad = ((ppfs->info.width > t) ? (ppfs->info.width - t) : 0); - *count += t + numpad; - } - if (padchar == '0') { /* TODO: check this */ - numfill += numpad; - numpad = 0; - } - - /* Now handle the output itself. */ - if (!PRINT_INFO_FLAG_VAL(&(ppfs->info),left)) { - if (_charpad(stream, ' ', numpad) != numpad) { - return -1; - } - numpad = 0; - } - OUTPUT(stream, prefix + prefix_num); - if (_charpad(stream, '0', numfill) != numfill) { - return -1; - } - -#ifdef L_vfprintf - -#ifdef __UCLIBC_HAS_WCHAR__ - if (!ws) { - assert(s); - if (_outnstr(stream, s, slen) != slen) { - return -1; - } - } else { /* wide string */ - size_t t; - mbstate.__mask = 0; /* Initialize the mbstate. */ - while (slen) { - t = (slen <= sizeof(buf)) ? slen : sizeof(buf); - t = wcsrtombs(buf, &ws, t, &mbstate); - assert (t != ((size_t)(-1))); - if (_outnstr(stream, buf, t) != t) { - return -1; - } - slen -= t; - } - } -#else /* __UCLIBC_HAS_WCHAR__ */ - if (_outnstr(stream, s, slen) != slen) { - return -1; - } -#endif /* __UCLIBC_HAS_WCHAR__ */ - -#else /* L_vfprintf */ - - if (!ws) { - assert(s); - if (_outnstr(stream, s, SLEN) != SLEN) { - return -1; - } - } else { - if (_outnwcs(stream, ws, SLEN) != SLEN) { - return -1; - } - } - -#endif /* L_vfprintf */ - if (_charpad(stream, ' ', numpad) != numpad) { - return -1; - } - } - - return 0; -} - -libc_hidden_proto(fprintf) - -libc_hidden_proto(VFPRINTF) -int VFPRINTF (FILE * __restrict stream, - register const FMT_TYPE * __restrict format, - va_list arg) -{ - ppfs_t ppfs; - int count, r; - register const FMT_TYPE *s; - __STDIO_AUTO_THREADLOCK_VAR; - - __STDIO_AUTO_THREADLOCK(stream); - - count = 0; - s = format; - - if -#ifdef L_vfprintf - (!__STDIO_STREAM_IS_NARROW_WRITING(stream) - && __STDIO_STREAM_TRANS_TO_WRITE(stream, __FLAG_NARROW)) -#else - (!__STDIO_STREAM_IS_WIDE_WRITING(stream) - && __STDIO_STREAM_TRANS_TO_WRITE(stream, __FLAG_WIDE)) -#endif - { - count = -1; - } else if (_PPFS_init(&ppfs, format) < 0) { /* Bad format string. */ - OUTNSTR(stream, (const FMT_TYPE *) ppfs.fmtpos, - STRLEN((const FMT_TYPE *)(ppfs.fmtpos))); -#if defined(L_vfprintf) && !defined(NDEBUG) - fprintf(stderr,"\nIMbS: \"%s\"\n\n", format); -#endif - count = -1; - } else { - _ppfs_prepargs(&ppfs, arg); /* This did a va_copy!!! */ - - do { - while (*format && (*format != '%')) { - ++format; - } - - if (format-s) { /* output any literal text in format string */ - if ( (r = OUTNSTR(stream, s, format-s)) != (format-s)) { - count = -1; - break; - } - count += r; - } - - if (!*format) { /* we're done */ - break; - } - - if (format[1] != '%') { /* if we get here, *format == '%' */ - /* TODO: _do_one_spec needs to know what the output funcs are!!! */ - ppfs.fmtpos = (const char *)(++format); - /* TODO: check -- should only fail on stream error */ - if ( (r = _do_one_spec(stream, &ppfs, &count)) < 0) { - count = -1; - break; - } - s = format = (const FMT_TYPE *) ppfs.fmtpos; - } else { /* %% means literal %, so start new string */ - s = ++format; - ++format; - } - } while (1); - - va_end(ppfs.arg); /* Need to clean up after va_copy! */ - } - -/* #if defined(L_vfprintf) && defined(__UCLIBC_HAS_WCHAR__) */ -/* DONE: */ -/* #endif */ - - __STDIO_AUTO_THREADUNLOCK(stream); - - return count; -} -libc_hidden_def(VFPRINTF) -#endif -/**********************************************************************/ -- cgit v1.2.3