blob: 3db8cdf67f66beaee83e2810999efd1219e76882 [file] [log] [blame]
lh9ed821d2023-04-07 01:36:19 -07001/* Copyright (C) 2002-2004 Manuel Novoa III
2 * My stdio library for linux and (soon) elks.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the Free
16 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19/* This code needs a lot of clean up. Some of that is on hold until uClibc
20 * gets a better configuration system (on Erik's todo list).
21 * The other cleanup will take place during the implementation/integration of
22 * the wide char (un)formatted i/o functions which I'm currently working on.
23 */
24
25/* ATTENTION! ATTENTION! ATTENTION! ATTENTION! ATTENTION!
26 *
27 * This code is currently under development. Also, I plan to port
28 * it to elks which is a 16-bit environment with a fairly limited
29 * compiler. Therefore, please refrain from modifying this code
30 * and, instead, pass any bug-fixes, etc. to me. Thanks. Manuel
31 *
32 * ATTENTION! ATTENTION! ATTENTION! ATTENTION! ATTENTION! */
33
34
35/* April 1, 2002
36 * Initialize thread locks for fake files in vsnprintf and vdprintf.
37 * reported by Erik Andersen (andersen@codepoet.com)
38 * Fix an arg promotion handling bug in _do_one_spec for %c.
39 * reported by Ilguiz Latypov <ilatypov@superbt.com>
40 *
41 * May 10, 2002
42 * Remove __isdigit and use new ctype.h version.
43 * Add conditional setting of QUAL_CHARS for size_t and ptrdiff_t.
44 *
45 * Aug 16, 2002
46 * Fix two problems that showed up with the python 2.2.1 tests; one
47 * involving %o and one involving %f.
48 *
49 * Oct 28, 2002
50 * Fix a problem in vasprintf (reported by vodz a while back) when built
51 * without custom stream support. In that case, it is necessary to do
52 * a va_copy.
53 * Make sure each va_copy has a matching va_end, as required by C99.
54 *
55 * Nov 4, 2002
56 * Add locale-specific grouping support for integer decimal conversion.
57 * Add locale-specific decimal point support for floating point conversion.
58 * Note: grouping will have to wait for _dtostr() rewrite.
59 * Add printf wchar support for %lc (%C) and %ls (%S).
60 * Require printf format strings to be valid multibyte strings beginning and
61 * ending in their initial shift state, as per the stds.
62 *
63 * Nov 21, 2002
64 * Add *wprintf functions. Currently they don't support floating point
65 * conversions. That will wait until the rewrite of _dtostr.
66 *
67 * Aug 1, 2003
68 * Optional hexadecimal float notation support for %a/%A.
69 * Floating point output now works for *wprintf.
70 * Support for glibc locale-specific digit grouping for floats.
71 * Misc bug fixes.
72 *
73 * Aug 31, 2003
74 * Fix precision bug for %g conversion specifier when using %f style.
75 *
76 * Sep 5, 2003
77 * Implement *s*scanf for the non-buffered stdio case with old_vfprintf.
78 *
79 * Sep 23, 2003
80 * vfprintf was not always checking for narrow stream orientation.
81 */
82
83/* TODO:
84 *
85 * Should we validate that *printf format strings are valid multibyte
86 * strings in the current locale? ANSI/ISO C99 seems to imply this
87 * and Plauger's printf implementation in his Standard C Library book
88 * treats this as an error.
89 */
90
91#define _ISOC99_SOURCE /* for ULLONG primarily... */
92#include <features.h>
93#include "_stdio.h"
94#include <stdlib.h>
95#include <string.h>
96#include <stddef.h>
97#include <ctype.h>
98#include <limits.h>
99#include <stdarg.h>
100#include <assert.h>
101#include <stdint.h>
102#include <errno.h>
103#include <locale.h>
104#include <printf.h>
105
106#ifdef __UCLIBC_HAS_THREADS__
107# include <stdio_ext.h>
108# include <pthread.h>
109#endif
110
111#ifdef __UCLIBC_HAS_WCHAR__
112# include <wchar.h>
113#endif
114
115#include <bits/uClibc_uintmaxtostr.h>
116#include <bits/uClibc_va_copy.h>
117
118/* Some older or broken gcc toolchains define LONG_LONG_MAX but not
119 * LLONG_MAX. Since LLONG_MAX is part of the standard, that's what
120 * we use. So complain if we do not have it but should.
121 */
122#if !defined(LLONG_MAX) && defined(LONG_LONG_MAX)
123#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.
124#endif
125
126/**********************************************************************/
127/* These provide some control over printf's feature set */
128
129/* This is undefined below depeding on uClibc's configuration. */
130#define __STDIO_PRINTF_FLOAT 1
131
132/* Now controlled by uClibc_stdio.h. */
133/* #define __UCLIBC_HAS_PRINTF_M_SPEC__ */
134
135
136/**********************************************************************/
137
138#if defined(__UCLIBC__) && !defined(__UCLIBC_HAS_FLOATS__)
139# undef __STDIO_PRINTF_FLOAT
140#endif
141
142#ifdef __BCC__
143# undef __STDIO_PRINTF_FLOAT
144#endif
145
146#ifdef __STDIO_PRINTF_FLOAT
147# include <float.h>
148# include <bits/uClibc_fpmax.h>
149#else
150# undef L__fpmaxtostr
151#endif
152
153
154#undef __STDIO_HAS_VSNPRINTF
155#if defined(__STDIO_BUFFERS) || defined(__USE_OLD_VFPRINTF__) || defined(__UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__)
156# define __STDIO_HAS_VSNPRINTF 1
157#endif
158
159/**********************************************************************/
160
161/* Now controlled by uClibc_stdio.h. */
162/* #define __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__ */
163
164#ifdef __UCLIBC_MJN3_ONLY__
165# ifdef L_register_printf_function
166/* emit only once */
167# warning WISHLIST: Make MAX_USER_SPEC configurable?
168# warning WISHLIST: Make MAX_ARGS_PER_SPEC configurable?
169# endif
170#endif
171
172#ifdef __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__
173# define MAX_USER_SPEC 10
174# define MAX_ARGS_PER_SPEC 5
175#else
176# undef MAX_USER_SPEC
177# define MAX_ARGS_PER_SPEC 1
178#endif
179
180#if MAX_ARGS_PER_SPEC < 1
181# error MAX_ARGS_PER_SPEC < 1!
182# undef MAX_ARGS_PER_SPEC
183# define MAX_ARGS_PER_SPEC 1
184#endif
185
186#if defined(NL_ARGMAX) && (NL_ARGMAX < 9)
187# error NL_ARGMAX < 9!
188#endif
189
190#if defined(NL_ARGMAX) && (NL_ARGMAX >= (MAX_ARGS_PER_SPEC + 2))
191# define MAX_ARGS NL_ARGMAX
192#else
193/* N for spec itself, plus 1 each for width and precision */
194# define MAX_ARGS (MAX_ARGS_PER_SPEC + 2)
195#endif
196
197/**********************************************************************/
198
199#define __PA_FLAG_INTMASK \
200 (__PA_FLAG_CHAR|PA_FLAG_SHORT|__PA_FLAG_INT|PA_FLAG_LONG|PA_FLAG_LONG_LONG)
201
202#ifdef __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__
203extern printf_function _custom_printf_handler[MAX_USER_SPEC] attribute_hidden;
204extern printf_arginfo_function *_custom_printf_arginfo[MAX_USER_SPEC] attribute_hidden;
205extern char *_custom_printf_spec attribute_hidden;
206#endif
207
208/**********************************************************************/
209
210#define SPEC_FLAGS " +0-#'I"
211enum {
212 FLAG_SPACE = 0x01,
213 FLAG_PLUS = 0x02, /* must be 2 * FLAG_SPACE */
214 FLAG_ZERO = 0x04,
215 FLAG_MINUS = 0x08, /* must be 2 * FLAG_ZERO */
216 FLAG_HASH = 0x10,
217 FLAG_THOUSANDS = 0x20,
218 FLAG_I18N = 0x40, /* only works for d, i, u */
219 FLAG_WIDESTREAM = 0x80
220};
221
222/**********************************************************************/
223
224/* float layout 01234567890123456789 TODO: B?*/
225#define SPEC_CHARS "npxXoudifFeEgGaACScs"
226enum {
227 CONV_n = 0,
228 CONV_p,
229 CONV_x, CONV_X, CONV_o, CONV_u, CONV_d, CONV_i,
230 CONV_f, CONV_F, CONV_e, CONV_E, CONV_g, CONV_G, CONV_a, CONV_A,
231 CONV_C, CONV_S, CONV_c, CONV_s,
232#ifdef __UCLIBC_HAS_PRINTF_M_SPEC__
233 CONV_m,
234#endif
235 CONV_custom0 /* must be last */
236};
237
238/* p x X o u d i */
239#define SPEC_BASE { 16, 16, 16, 8, 10, 10, 10 }
240
241#define SPEC_RANGES { CONV_n, CONV_p, CONV_i, CONV_A, \
242 CONV_C, CONV_S, CONV_c, CONV_s, CONV_custom0 }
243
244#define SPEC_OR_MASK { \
245 /* n */ (PA_FLAG_PTR|PA_INT), \
246 /* p */ PA_POINTER, \
247 /* oxXudi */ PA_INT, \
248 /* fFeEgGaA */ PA_DOUBLE, \
249 /* C */ PA_WCHAR, \
250 /* S */ PA_WSTRING, \
251 /* c */ PA_CHAR, \
252 /* s */ PA_STRING, \
253}
254
255#define SPEC_AND_MASK { \
256 /* n */ (PA_FLAG_PTR|__PA_INTMASK), \
257 /* p */ PA_POINTER, \
258 /* oxXudi */ (__PA_INTMASK), \
259 /* fFeEgGaA */ (PA_FLAG_LONG_DOUBLE|PA_DOUBLE), \
260 /* C */ (PA_WCHAR), \
261 /* S */ (PA_WSTRING), \
262 /* c */ (PA_CHAR), \
263 /* s */ (PA_STRING), \
264}
265
266/**********************************************************************/
267/*
268 * In order to ease translation to what arginfo and _print_info._flags expect,
269 * we map: 0:int 1:char 2:longlong 4:long 8:short
270 * and then _flags |= (((q << 7) + q) & 0x701) and argtype |= (_flags & 0x701)
271 */
272
273/* TODO -- Fix the table below to take into account stdint.h. */
274/* #ifndef LLONG_MAX */
275/* #error fix QUAL_CHARS for no long long! Affects 'L', 'j', 'q', 'll'. */
276/* #else */
277/* #if LLONG_MAX != INTMAX_MAX */
278/* #error fix QUAL_CHARS intmax_t entry 'j'! */
279/* #endif */
280/* #endif */
281
282#ifdef PDS
283# error PDS already defined!
284#endif
285#ifdef SS
286# error SS already defined!
287#endif
288#ifdef IMS
289# error IMS already defined!
290#endif
291
292#if PTRDIFF_MAX == INT_MAX
293# define PDS 0
294#elif PTRDIFF_MAX == LONG_MAX
295# define PDS 4
296#elif defined(LLONG_MAX) && (PTRDIFF_MAX == LLONG_MAX)
297# define PDS 8
298#else
299# error fix QUAL_CHARS ptrdiff_t entry 't'!
300#endif
301
302#if SIZE_MAX == UINT_MAX
303# define SS 0
304#elif SIZE_MAX == ULONG_MAX
305# define SS 4
306#elif defined(LLONG_MAX) && (SIZE_MAX == ULLONG_MAX)
307# define SS 8
308#else
309# error fix QUAL_CHARS size_t entries 'z', 'Z'!
310#endif
311
312#if INTMAX_MAX == INT_MAX
313# define IMS 0
314#elif INTMAX_MAX == LONG_MAX
315# define IMS 4
316#elif defined(LLONG_MAX) && (INTMAX_MAX == LLONG_MAX)
317# define IMS 8
318#else
319# error fix QUAL_CHARS intmax_t entry 'j'!
320#endif
321
322#define QUAL_CHARS { \
323 /* j:(u)intmax_t z:(s)size_t t:ptrdiff_t \0:int */ \
324 /* q:long_long Z:(s)size_t */ \
325 'h', 'l', 'L', 'j', 'z', 't', 'q', 'Z', 0, \
326 2, 4, 8, IMS, SS, PDS, 8, SS, 0, /* TODO -- fix!!! */\
327 1, 8 \
328}
329
330/**********************************************************************/
331
332#ifdef __STDIO_VA_ARG_PTR
333# ifdef __BCC__
334# define __va_arg_ptr(ap,type) (((type *)(ap += sizeof(type))) - 1)
335# endif
336
337# if 1
338# ifdef __GNUC__
339/* TODO -- need other than for 386 as well! */
340
341# ifndef __va_rounded_size
342# define __va_rounded_size(TYPE) \
343 (((sizeof (TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int))
344# endif
345# define __va_arg_ptr(AP, TYPE) \
346 (AP = (va_list) ((char *) (AP) + __va_rounded_size (TYPE)), \
347 ((void *) ((char *) (AP) - __va_rounded_size (TYPE))) \
348 )
349# endif
350# endif
351#endif /* __STDIO_VA_ARG_PTR */
352
353#ifdef __va_arg_ptr
354# define GET_VA_ARG(AP,F,TYPE,ARGS) (*(AP) = __va_arg_ptr(ARGS,TYPE))
355# define GET_ARG_VALUE(AP,F,TYPE) (*((TYPE *)(*(AP))))
356#else
357typedef union {
358 wchar_t wc;
359 unsigned int u;
360 unsigned long ul;
361# ifdef ULLONG_MAX
362 unsigned long long ull;
363# endif
364# ifdef __STDIO_PRINTF_FLOAT
365 double d;
366 long double ld;
367# endif
368 void *p;
369} argvalue_t;
370
371# define GET_VA_ARG(AU,F,TYPE,ARGS) (AU->F = va_arg(ARGS,TYPE))
372# define GET_ARG_VALUE(AU,F,TYPE) ((TYPE)((AU)->F))
373#endif
374
375typedef struct {
376 const char *fmtpos; /* TODO: move below struct?? */
377 struct printf_info info;
378#ifdef NL_ARGMAX
379 int maxposarg; /* > 0 if args are positional, 0 if not, -1 if unknown */
380#endif
381 int num_data_args; /* TODO: use sentinal??? */
382 unsigned int conv_num;
383 unsigned char argnumber[4]; /* width | prec | 1st data | unused */
384 int argtype[MAX_ARGS];
385 va_list arg;
386#ifdef __va_arg_ptr
387 void *argptr[MAX_ARGS];
388#else
389/* if defined(NL_ARGMAX) || defined(__UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__) */
390 /* While this is wasteful of space in the case where pos args aren't
391 * enabled, it is also needed to support custom printf handlers. */
392 argvalue_t argvalue[MAX_ARGS];
393#endif
394} ppfs_t; /* parse printf format state */
395
396/**********************************************************************/
397
398/* TODO: fix printf to return 0 and set errno if format error. Standard says
399 only returns -1 if sets error indicator for the stream. */
400
401#ifdef __STDIO_PRINTF_FLOAT
402typedef size_t (__fp_outfunc_t)(FILE *fp, intptr_t type, intptr_t len,
403 intptr_t buf);
404
405extern ssize_t _fpmaxtostr(FILE * fp, __fpmax_t x, struct printf_info *info,
406 __fp_outfunc_t fp_outfunc) attribute_hidden;
407#endif
408
409extern int _ppfs_init(ppfs_t *ppfs, const char *fmt0) attribute_hidden; /* validates */
410extern void _ppfs_prepargs(ppfs_t *ppfs, va_list arg) attribute_hidden; /* sets posargptrs */
411extern void _ppfs_setargs(ppfs_t *ppfs) attribute_hidden; /* sets argptrs for current spec */
412extern int _ppfs_parsespec(ppfs_t *ppfs) attribute_hidden; /* parses specifier */
413
414extern void _store_inttype(void *dest, int desttype, uintmax_t val) attribute_hidden;
415extern uintmax_t _load_inttype(int desttype, const void *src, int uflag) attribute_hidden;
416
417/**********************************************************************/
418#ifdef L_parse_printf_format
419
420#ifdef __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__
421
422/* NOTE: This function differs from the glibc version in that parsing stops
423 * upon encountering an invalid conversion specifier. Since this is the way
424 * my printf functions work, I think it makes sense to do it that way here.
425 * Unfortunately, since glibc sets the return type as size_t, we have no way
426 * of returning that the template is illegal, other than returning 0.
427 */
428
429size_t parse_printf_format(register const char *template,
430 size_t n, register int *argtypes)
431{
432 ppfs_t ppfs;
433 size_t i;
434 size_t count = 0;
435
436 if (_ppfs_init(&ppfs, template) >= 0) {
437#ifdef NL_ARGMAX
438 if (ppfs.maxposarg > 0) {
439 /* Using positional args. */
440 count = ppfs.maxposarg;
441 if (n > count) {
442 n = count;
443 }
444 for (i = 0 ; i < n ; i++) {
445 *argtypes++ = ppfs.argtype[i];
446 }
447 } else
448#endif
449 {
450 /* Not using positional args. */
451 while (*template) {
452 if ((*template == '%') && (*++template != '%')) {
453 ppfs.fmtpos = template;
454 _ppfs_parsespec(&ppfs); /* Can't fail. */
455 template = ppfs.fmtpos; /* Update to one past spec end. */
456 if (ppfs.info.width == INT_MIN) {
457 ++count;
458 if (n > 0) {
459 *argtypes++ = PA_INT;
460 --n;
461 }
462 }
463 if (ppfs.info.prec == INT_MIN) {
464 ++count;
465 if (n > 0) {
466 *argtypes++ = PA_INT;
467 --n;
468 }
469 }
470 for (i = 0 ; i < ppfs.num_data_args ; i++) {
471 if ((ppfs.argtype[i]) != __PA_NOARG) {
472 ++count;
473 if (n > 0) {
474 *argtypes++ = ppfs.argtype[i];
475 --n;
476 }
477 }
478 }
479 } else {
480 ++template;
481 }
482 }
483 }
484 }
485
486 return count;
487}
488
489#endif
490
491#endif
492/**********************************************************************/
493#ifdef L__ppfs_init
494
495int attribute_hidden _ppfs_init(register ppfs_t *ppfs, const char *fmt0)
496{
497 int r;
498
499 /* First, zero out everything... argnumber[], argtype[], argptr[] */
500 memset(ppfs, 0, sizeof(ppfs_t)); /* TODO: nonportable???? */
501#ifdef NL_ARGMAX
502 --ppfs->maxposarg; /* set to -1 */
503#endif
504 ppfs->fmtpos = fmt0;
505#ifdef __UCLIBC_MJN3_ONLY__
506# warning TODO: Make checking of the format string in C locale an option.
507#endif
508#ifdef __UCLIBC_HAS_LOCALE__
509 /* To support old programs, don't check mb validity if in C locale. */
510 if (__UCLIBC_CURLOCALE->encoding != __ctype_encoding_7_bit) {
511 /* ANSI/ISO C99 requires format string to be a valid multibyte string
512 * beginning and ending in its initial shift state. */
513 static const char invalid_mbs[] = "Invalid multibyte format string.";
514 mbstate_t mbstate;
515 const char *p;
516 mbstate.__mask = 0; /* Initialize the mbstate. */
517 p = fmt0;
518 if (mbsrtowcs(NULL, &p, SIZE_MAX, &mbstate) == ((size_t)(-1))) {
519 ppfs->fmtpos = invalid_mbs;
520 return -1;
521 }
522 }
523#endif /* __UCLIBC_HAS_LOCALE__ */
524 /* now set all argtypes to no-arg */
525 {
526#if 1
527 /* TODO - use memset here since already "paid for"? */
528 register int *p = ppfs->argtype;
529
530 r = MAX_ARGS;
531 do {
532 *p++ = __PA_NOARG;
533 } while (--r);
534#else
535 /* TODO -- get rid of this?? */
536 register char *p = (char *) ((MAX_ARGS-1) * sizeof(int));
537
538 do {
539 *((int *)(((char *)ppfs) + ((int)p) + offsetof(ppfs_t,argtype))) = __PA_NOARG;
540 p -= sizeof(int);
541 } while (p);
542#endif
543 }
544
545 /*
546 * Run through the entire format string to validate it and initialize
547 * the positional arg numbers (if any).
548 */
549 {
550 register const char *fmt = fmt0;
551
552 while (*fmt) {
553 if ((*fmt == '%') && (*++fmt != '%')) {
554 ppfs->fmtpos = fmt; /* back up to the '%' */
555 r = _ppfs_parsespec(ppfs);
556 if (r < 0) {
557 return -1;
558 }
559 fmt = ppfs->fmtpos; /* update to one past end of spec */
560 } else {
561 ++fmt;
562 }
563 }
564 ppfs->fmtpos = fmt0; /* rewind */
565 }
566
567#ifdef NL_MAX_ARG
568 /* If we have positional args, make sure we know all the types. */
569 {
570 register int *p = ppfs->argtype;
571 r = ppfs->maxposarg;
572 while (--r >= 0) {
573 if ( *p == __PA_NOARG ) { /* missing arg type!!! */
574 return -1;
575 }
576 ++p;
577 }
578 }
579#endif /* NL_MAX_ARG */
580
581 return 0;
582}
583#endif
584/**********************************************************************/
585#ifdef L__ppfs_prepargs
586void attribute_hidden _ppfs_prepargs(register ppfs_t *ppfs, va_list arg)
587{
588 int i;
589
590 va_copy(ppfs->arg, arg);
591
592#ifdef NL_ARGMAX
593 i = ppfs->maxposarg; /* init for positional args */
594 if (i > 0) {
595 ppfs->num_data_args = i;
596 ppfs->info.width = ppfs->info.prec = ppfs->maxposarg = 0;
597 _ppfs_setargs(ppfs);
598 ppfs->maxposarg = i;
599 }
600#endif
601}
602#endif
603/**********************************************************************/
604#ifdef L__ppfs_setargs
605
606void attribute_hidden _ppfs_setargs(register ppfs_t *ppfs)
607{
608#ifdef __va_arg_ptr
609 register void **p = ppfs->argptr;
610#else
611 register argvalue_t *p = ppfs->argvalue;
612#endif
613 int i;
614
615#ifdef NL_ARGMAX
616 if (ppfs->maxposarg == 0) { /* initing for or no pos args */
617#endif
618 if (ppfs->info.width == INT_MIN) {
619 ppfs->info.width =
620#ifdef __va_arg_ptr
621 *(int *)
622#endif
623 GET_VA_ARG(p,u,unsigned int,ppfs->arg);
624 }
625 if (ppfs->info.prec == INT_MIN) {
626 ppfs->info.prec =
627#ifdef __va_arg_ptr
628 *(int *)
629#endif
630 GET_VA_ARG(p,u,unsigned int,ppfs->arg);
631 }
632 i = 0;
633 while (i < ppfs->num_data_args) {
634 switch(ppfs->argtype[i++]) {
635 case (PA_INT|PA_FLAG_LONG_LONG):
636#ifdef ULLONG_MAX
637 GET_VA_ARG(p,ull,unsigned long long,ppfs->arg);
638 break;
639#endif
640 case (PA_INT|PA_FLAG_LONG):
641#if ULONG_MAX != UINT_MAX
642 GET_VA_ARG(p,ul,unsigned long,ppfs->arg);
643 break;
644#endif
645 case PA_CHAR: /* TODO - be careful */
646 /* ... users could use above and really want below!! */
647 case (PA_INT|__PA_FLAG_CHAR):/* TODO -- translate this!!! */
648 case (PA_INT|PA_FLAG_SHORT):
649 case PA_INT:
650 GET_VA_ARG(p,u,unsigned int,ppfs->arg);
651 break;
652 case PA_WCHAR: /* TODO -- assume int? */
653 /* we're assuming wchar_t is at least an int */
654 GET_VA_ARG(p,wc,wchar_t,ppfs->arg);
655 break;
656#ifdef __STDIO_PRINTF_FLOAT
657 /* PA_FLOAT */
658 case PA_DOUBLE:
659 GET_VA_ARG(p,d,double,ppfs->arg);
660 break;
661 case (PA_DOUBLE|PA_FLAG_LONG_DOUBLE):
662 GET_VA_ARG(p,ld,long double,ppfs->arg);
663 break;
664#else /* __STDIO_PRINTF_FLOAT */
665 case PA_DOUBLE:
666 case (PA_DOUBLE|PA_FLAG_LONG_DOUBLE):
667 assert(0);
668 continue;
669#endif /* __STDIO_PRINTF_FLOAT */
670 default:
671 /* TODO -- really need to ensure this can't happen */
672 assert(ppfs->argtype[i-1] & PA_FLAG_PTR);
673 case PA_POINTER:
674 case PA_STRING:
675 case PA_WSTRING:
676 GET_VA_ARG(p,p,void *,ppfs->arg);
677 break;
678 case __PA_NOARG:
679 continue;
680 }
681 ++p;
682 }
683#ifdef NL_ARGMAX
684 } else {
685 if (ppfs->info.width == INT_MIN) {
686 ppfs->info.width
687 = (int) GET_ARG_VALUE(p + ppfs->argnumber[0] - 1,u,unsigned int);
688 }
689 if (ppfs->info.prec == INT_MIN) {
690 ppfs->info.prec
691 = (int) GET_ARG_VALUE(p + ppfs->argnumber[1] - 1,u,unsigned int);
692 }
693 }
694#endif /* NL_ARGMAX */
695
696 /* Now we know the width and precision. */
697 if (ppfs->info.width < 0) {
698 ppfs->info.width = -ppfs->info.width;
699 PRINT_INFO_SET_FLAG(&(ppfs->info),left);
700 PRINT_INFO_CLR_FLAG(&(ppfs->info),space);
701 ppfs->info.pad = ' ';
702 }
703#if 0
704 /* NOTE -- keep neg for now so float knows! */
705 if (ppfs->info.prec < 0) { /* spec says treat as omitted. */
706 /* so use default prec... 1 for everything but floats and strings. */
707 ppfs->info.prec = 1;
708 }
709#endif
710}
711#endif
712/**********************************************************************/
713#ifdef L__ppfs_parsespec
714
715/* Notes: argtype differs from glibc for the following:
716 * mine glibc
717 * lc PA_WCHAR PA_CHAR the standard says %lc means %C
718 * ls PA_WSTRING PA_STRING the standard says %ls means %S
719 * {*}n {*}|PA_FLAG_PTR PA_FLAG_PTR size of n can be qualified
720 */
721
722/* TODO: store positions of positional args */
723
724/* TODO -- WARNING -- assumes aligned on integer boundaries!!! */
725
726/* TODO -- disable if not using positional args!!! */
727#define _OVERLAPPING_DIFFERENT_ARGS
728
729/* TODO -- rethink this -- perhaps we should set to largest type??? */
730
731#ifdef _OVERLAPPING_DIFFERENT_ARGS
732
733#define PROMOTED_SIZE_OF(X) ((sizeof(X) + sizeof(int) - 1) / sizeof(X))
734
735static const short int type_codes[] = {
736 __PA_NOARG, /* must be first entry */
737 PA_POINTER,
738 PA_STRING,
739 PA_WSTRING,
740 PA_CHAR,
741 PA_INT|PA_FLAG_SHORT,
742 PA_INT,
743 PA_INT|PA_FLAG_LONG,
744 PA_INT|PA_FLAG_LONG_LONG,
745 PA_WCHAR,
746#ifdef __STDIO_PRINTF_FLOAT
747 /* PA_FLOAT, */
748 PA_DOUBLE,
749 PA_DOUBLE|PA_FLAG_LONG_DOUBLE,
750#endif
751};
752
753static const unsigned char type_sizes[] = {
754 /* unknown type consumes no arg */
755 0, /* must be first entry */
756 PROMOTED_SIZE_OF(void *),
757 PROMOTED_SIZE_OF(char *),
758 PROMOTED_SIZE_OF(wchar_t *),
759 PROMOTED_SIZE_OF(char),
760 PROMOTED_SIZE_OF(short),
761 PROMOTED_SIZE_OF(int),
762 PROMOTED_SIZE_OF(long),
763#ifdef ULLONG_MAX
764 PROMOTED_SIZE_OF(long long),
765#else
766 PROMOTED_SIZE_OF(long), /* TODO -- is this correct? (above too) */
767#endif
768 PROMOTED_SIZE_OF(wchar_t),
769#ifdef __STDIO_PRINTF_FLOAT
770 /* PROMOTED_SIZE_OF(float), */
771 PROMOTED_SIZE_OF(double),
772 PROMOTED_SIZE_OF(long double),
773#endif
774};
775
776static int _promoted_size(int argtype)
777{
778 register const short int *p;
779
780 /* note -- since any unrecognized type is treated as a pointer */
781 p = type_codes + sizeof(type_codes)/sizeof(type_codes[0]);
782 do {
783 if (*--p == argtype) {
784 break;
785 }
786 } while (p > type_codes);
787
788 return type_sizes[(int)(p - type_codes)];
789}
790
791static int _is_equal_or_bigger_arg(int curtype, int newtype)
792{
793 /* Quick test */
794 if (newtype == __PA_NOARG) {
795 return 0;
796 }
797 if ((curtype == __PA_NOARG) || (curtype == newtype)) {
798 return 1;
799 }
800 /* Ok... slot is already filled and types are different in name. */
801 /* So, compare promoted sizes of curtype and newtype args. */
802 return _promoted_size(curtype) <= _promoted_size(newtype);
803}
804
805#else
806
807#define _is_equal_or_bigger_arg(C,N) (((C) == __PA_NOARG) || ((C) == (N)))
808
809#endif
810
811#ifdef __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__
812/* TODO - do this differently? */
813static char _bss_custom_printf_spec[MAX_USER_SPEC]; /* 0-init'd for us. */
814
815attribute_hidden char *_custom_printf_spec = _bss_custom_printf_spec;
816attribute_hidden printf_arginfo_function *_custom_printf_arginfo[MAX_USER_SPEC];
817attribute_hidden printf_function _custom_printf_handler[MAX_USER_SPEC];
818#endif /* __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__ */
819
820int attribute_hidden _ppfs_parsespec(ppfs_t *ppfs)
821{
822 register const char *fmt;
823 register const char *p;
824 int preci;
825 int width;
826 int flags;
827 int dataargtype;
828 int i;
829 int dpoint;
830#ifdef NL_ARGMAX
831 int maxposarg;
832#endif
833 int p_m_spec_chars;
834 int n;
835 int argtype[MAX_ARGS_PER_SPEC+2];
836 int argnumber[3]; /* width, precision, 1st data arg */
837 static const char spec_flags[] = SPEC_FLAGS;
838 static const char spec_chars[] = SPEC_CHARS;/* TODO: b? */
839 static const char spec_ranges[] = SPEC_RANGES;
840 static const short spec_or_mask[] = SPEC_OR_MASK;
841 static const short spec_and_mask[] = SPEC_AND_MASK;
842 static const char qual_chars[] = QUAL_CHARS;
843#ifdef __UCLIBC_HAS_WCHAR__
844 char buf[32];
845#endif
846
847 /* WIDE note: we can test against '%' here since we don't allow */
848 /* WIDE note: other mappings of '%' in the wide char set. */
849 preci = -1;
850 argnumber[0] = 0;
851 argnumber[1] = 0;
852 argtype[0] = __PA_NOARG;
853 argtype[1] = __PA_NOARG;
854#ifdef NL_ARGMAX
855 maxposarg = ppfs->maxposarg;
856#endif
857
858#ifdef __UCLIBC_HAS_WCHAR__
859 /* This is somewhat lame, but saves a lot of code. If we're dealing with
860 * a wide stream, that means the format is a wchar string. So, copy it
861 * char-by-char into a normal char buffer for processing. Make the buffer
862 * (buf) big enough so that any reasonable format specifier will fit.
863 * While there a legal specifiers that won't, the all involve duplicate
864 * flags or outrageous field widths/precisions. */
865 width = dpoint = 0;
866 flags = ppfs->info._flags & FLAG_WIDESTREAM;
867 if (flags == 0) {
868 fmt = ppfs->fmtpos;
869 } else {
870 fmt = buf + 1;
871 i = 0;
872 do {
873 buf[i] = (char) (((wchar_t *) ppfs->fmtpos)[i-1]);
874 if (buf[i] != (((wchar_t *) ppfs->fmtpos)[i-1])) {
875 return -1;
876 }
877 } while (buf[i++] && (i < sizeof(buf)));
878 buf[sizeof(buf)-1] = 0;
879 }
880#else /* __UCLIBC_HAS_WCHAR__ */
881 width = flags = dpoint = 0;
882 fmt = ppfs->fmtpos;
883#endif
884
885 assert(fmt[-1] == '%');
886 assert(fmt[0] != '%');
887
888 /* Process arg pos and/or flags and/or width and/or precision. */
889 width_precision:
890 p = fmt;
891 if (*fmt == '*') {
892 argtype[-dpoint] = PA_INT;
893 ++fmt;
894 }
895 i = 0;
896 while (isdigit(*fmt)) {
897 if (i < INT_MAX / 10
898 || (i == INT_MAX / 10 && (*fmt - '0') <= INT_MAX % 10)) {
899 i = (i * 10) + (*fmt - '0');
900 } else {
901 i = INT_MAX; /* best we can do... */
902 }
903 ++fmt;
904 }
905 if (p[-1] == '%') { /* Check for a position. */
906
907 /* TODO: if val not in range, then error */
908
909#ifdef NL_ARGMAX
910 if ((*fmt == '$') && (i > 0)) {/* Positional spec. */
911 ++fmt;
912 if (maxposarg == 0) {
913 return -1;
914 }
915 argnumber[2] = i;
916 if (argnumber[2] > maxposarg) {
917 maxposarg = i;
918 }
919 /* Now fall through to check flags. */
920 } else {
921 if (maxposarg > 0) {
922# ifdef __UCLIBC_HAS_PRINTF_M_SPEC__
923# ifdef __UCLIBC_MJN3_ONLY__
924# warning TODO: Support prec and width for %m when positional args used
925 /* Actually, positional arg processing will fail in general
926 * for specifiers that don't require an arg. */
927# endif
928 if (*fmt == 'm') {
929 goto PREC_WIDTH;
930 }
931# endif /* __UCLIBC_HAS_PRINTF_M_SPEC__ */
932 return -1;
933 }
934 maxposarg = 0; /* Possible redundant store, but cuts size. */
935
936 if ((fmt > p) && (*p != '0')) {
937 goto PREC_WIDTH;
938 }
939
940 fmt = p; /* Back up for possible '0's flag. */
941 /* Now fall through to check flags. */
942 }
943#else /* NL_ARGMAX */
944 if (*fmt == '$') { /* Positional spec. */
945 return -1;
946 }
947
948 if ((fmt > p) && (*p != '0')) {
949 goto PREC_WIDTH;
950 }
951
952 fmt = p; /* Back up for possible '0's flag. */
953 /* Now fall through to check flags. */
954#endif /* NL_ARGMAX */
955
956 restart_flags: /* Process flags. */
957 i = 1;
958 p = spec_flags;
959
960 do {
961 if (*fmt == *p++) {
962 ++fmt;
963 flags |= i;
964 goto restart_flags;
965 }
966 i += i; /* Better than i <<= 1 for bcc */
967 } while (*p);
968 i = 0;
969
970 /* If '+' then ignore ' ', and if '-' then ignore '0'. */
971 /* Note: Need to ignore '0' when prec is an arg with val < 0, */
972 /* but that test needs to wait until the arg is retrieved. */
973 flags &= ~((flags & (FLAG_PLUS|FLAG_MINUS)) >> 1);
974 /* Note: Ignore '0' when prec is specified < 0 too (in printf). */
975
976 if (fmt[-1] != '%') { /* If we've done anything, loop for width. */
977 goto width_precision;
978 }
979 }
980 PREC_WIDTH:
981 if (*p == '*') { /* Prec or width takes an arg. */
982#ifdef NL_ARGMAX
983 if (maxposarg) {
984 if ((*fmt++ != '$') || (i <= 0)) {
985 /* Using pos args and no $ or invalid arg number. */
986 return -1;
987 }
988 argnumber[-dpoint] = i;
989 } else
990#endif
991 if (++p != fmt) {
992 /* Not using pos args but digits followed *. */
993 return -1;
994 }
995 i = INT_MIN;
996 }
997
998 if (!dpoint) {
999 width = i;
1000 if (*fmt == '.') {
1001 ++fmt;
1002 dpoint = -1; /* To use as default precison. */
1003 goto width_precision;
1004 }
1005 } else {
1006 preci = i;
1007 }
1008
1009 /* Process qualifier. */
1010 p = qual_chars;
1011 do {
1012 if (*fmt == *p) {
1013 ++fmt;
1014 break;
1015 }
1016 } while (*++p);
1017 if ((p - qual_chars < 2) && (*fmt == *p)) {
1018 p += ((sizeof(qual_chars)-2) / 2);
1019 ++fmt;
1020 }
1021 dataargtype = ((int)(p[(sizeof(qual_chars)-2) / 2])) << 8;
1022
1023 /* Process conversion specifier. */
1024 if (!*fmt) {
1025 return -1;
1026 }
1027
1028 p = spec_chars;
1029
1030 do {
1031 if (*fmt == *p) {
1032 p_m_spec_chars = p - spec_chars;
1033
1034 if ((p_m_spec_chars >= CONV_c)
1035 && (dataargtype & PA_FLAG_LONG)) {
1036 p_m_spec_chars -= 2; /* lc -> C and ls -> S */
1037 }
1038
1039 ppfs->conv_num = p_m_spec_chars;
1040 p = spec_ranges-1;
1041 while (p_m_spec_chars > *++p) {}
1042
1043 i = p - spec_ranges;
1044 argtype[2] = (dataargtype | spec_or_mask[i]) & spec_and_mask[i];
1045 p = spec_chars;
1046 break;
1047 }
1048 } while(*++p);
1049
1050 ppfs->info.spec = *fmt;
1051 ppfs->info.prec = preci;
1052 ppfs->info.width = width;
1053 ppfs->info.pad = ((flags & FLAG_ZERO) ? '0' : ' ');
1054 ppfs->info._flags = (flags & ~FLAG_ZERO) | (dataargtype & __PA_INTMASK);
1055 ppfs->num_data_args = 1;
1056
1057 if (!*p) {
1058#ifdef __UCLIBC_HAS_PRINTF_M_SPEC__
1059 if (*fmt == 'm') {
1060 ppfs->conv_num = CONV_m;
1061 ppfs->num_data_args = 0;
1062 } else
1063#endif
1064 {
1065#ifndef __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__
1066 return -1; /* Error */
1067#else
1068 /* Handle custom arg -- WARNING -- overwrites p!!! */
1069 ppfs->conv_num = CONV_custom0;
1070 p = _custom_printf_spec;
1071 while (1) {
1072 if (*p == *fmt) {
1073 printf_arginfo_function *fp = _custom_printf_arginfo[(int)(p - _custom_printf_spec)];
1074 ppfs->num_data_args = fp(&(ppfs->info), MAX_ARGS_PER_SPEC, argtype + 2);
1075 if (ppfs->num_data_args > MAX_ARGS_PER_SPEC) {
1076 return -1; /* Error -- too many args! */
1077 }
1078 break;
1079 }
1080 if (++p >= (_custom_printf_spec + MAX_USER_SPEC))
1081 return -1; /* Error */
1082 }
1083#endif
1084 }
1085 }
1086
1087#ifdef NL_ARGMAX
1088 if (maxposarg > 0) {
1089 i = 0;
1090 do {
1091 /* Update maxposarg and check that NL_ARGMAX is not exceeded. */
1092 n = ((i <= 2)
1093 ? (ppfs->argnumber[i] = argnumber[i])
1094 : argnumber[2] + (i-2));
1095 if (n > maxposarg) {
1096 maxposarg = n;
1097 if (maxposarg > NL_ARGMAX) {
1098 return -1;
1099 }
1100 }
1101 --n;
1102 /* Record argtype with largest size (current, new). */
1103 if (_is_equal_or_bigger_arg(ppfs->argtype[n], argtype[i])) {
1104 ppfs->argtype[n] = argtype[i];
1105 }
1106 } while (++i < ppfs->num_data_args + 2);
1107 } else
1108#endif /* NL_ARGMAX */
1109 {
1110 ppfs->argnumber[2] = 1;
1111 memcpy(ppfs->argtype, argtype + 2, ppfs->num_data_args * sizeof(int));
1112 }
1113
1114#ifdef NL_ARGMAX
1115 ppfs->maxposarg = maxposarg;
1116#endif
1117
1118#ifdef __UCLIBC_HAS_WCHAR__
1119 flags = ppfs->info._flags & FLAG_WIDESTREAM;
1120 if (flags == 0) {
1121 ppfs->fmtpos = ++fmt;
1122 } else {
1123 ppfs->fmtpos = (const char *) (((const wchar_t *)(ppfs->fmtpos))
1124 + (fmt - buf) );
1125 }
1126#else /* __UCLIBC_HAS_WCHAR__ */
1127 ppfs->fmtpos = ++fmt;
1128#endif
1129
1130 return ppfs->num_data_args + 2;
1131}
1132
1133#endif
1134/**********************************************************************/
1135#ifdef L_register_printf_function
1136
1137#ifdef __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__
1138
1139int register_printf_function(int spec, printf_function handler,
1140 printf_arginfo_function arginfo)
1141{
1142 register char *r;
1143 register char *p;
1144
1145 if (spec && (arginfo != NULL)) { /* TODO -- check if spec is valid char */
1146 r = NULL;
1147 p = _custom_printf_spec + MAX_USER_SPEC;
1148 do {
1149 --p;
1150 if (!*p) {
1151 r = p;
1152 }
1153#ifdef __BCC__
1154 else /* bcc generates less code with fall-through */
1155#endif
1156 if (*p == spec) {
1157 r = p;
1158 p = _custom_printf_spec;
1159 }
1160 } while (p > _custom_printf_spec);
1161
1162 if (r) {
1163 if (handler) {
1164 *r = spec;
1165 _custom_printf_handler[(int)(r - p)] = handler;
1166 _custom_printf_arginfo[(int)(r - p)] = arginfo;
1167 } else {
1168 *r = 0;
1169 }
1170 return 0;
1171 }
1172 /* TODO -- if asked to unregister a non-existent spec, return what? */
1173 }
1174 return -1;
1175}
1176
1177#endif
1178
1179#endif
1180/**********************************************************************/
1181#if defined(L__vfprintf_internal) || defined(L__vfwprintf_internal)
1182
1183/* We only support ascii digits (or their USC equivalent codes) in
1184 * precision and width settings in *printf (wide) format strings.
1185 * In other words, we don't currently support glibc's 'I' flag.
1186 * We do accept it, but it is currently ignored. */
1187
1188static size_t _charpad(FILE * __restrict stream, int padchar, size_t numpad);
1189
1190#ifdef L__vfprintf_internal
1191
1192#define VFPRINTF_internal _vfprintf_internal
1193#define FMT_TYPE char
1194#define OUTNSTR _outnstr
1195#define STRLEN strlen
1196#define _PPFS_init _ppfs_init
1197#define OUTPUT(F,S) fputs_unlocked(S,F)
1198/* #define _outnstr(stream, string, len) __stdio_fwrite(string, len, stream) */
1199#define _outnstr(stream, string, len) ((len > 0) ? __stdio_fwrite((const unsigned char *)(string), len, stream) : 0)
1200#define FP_OUT _fp_out_narrow
1201
1202#ifdef __STDIO_PRINTF_FLOAT
1203
1204static size_t _fp_out_narrow(FILE *fp, intptr_t type, intptr_t len, intptr_t buf)
1205{
1206 size_t r = 0;
1207
1208 if (type & 0x80) { /* Some type of padding needed. */
1209 int buflen = strlen((const char *) buf);
1210 len -= buflen;
1211 if (len > 0) {
1212 r = _charpad(fp, (type & 0x7f), len);
1213 if (r != len) {
1214 return r;
1215 }
1216 }
1217 len = buflen;
1218 }
1219 return r + OUTNSTR(fp, (const char *) buf, len);
1220}
1221
1222#endif /* __STDIO_PRINTF_FLOAT */
1223
1224#else /* L__vfprintf_internal */
1225
1226#define VFPRINTF_internal _vfwprintf_internal
1227#define FMT_TYPE wchar_t
1228#define OUTNSTR _outnwcs
1229#define STRLEN wcslen
1230#define _PPFS_init _ppwfs_init
1231/* Pulls in fseek: */
1232#define OUTPUT(F,S) fputws(S,F)
1233/* TODO: #define OUTPUT(F,S) _wstdio_fwrite((S),wcslen(S),(F)) */
1234#define _outnwcs(stream, wstring, len) _wstdio_fwrite((const wchar_t *)(wstring), len, stream)
1235#define FP_OUT _fp_out_wide
1236
1237static size_t _outnstr(FILE *stream, const char *s, size_t wclen)
1238{
1239 /* NOTE!!! len here is the number of wchars we want to generate!!! */
1240 wchar_t wbuf[64];
1241 mbstate_t mbstate;
1242 size_t todo, r, n;
1243
1244 mbstate.__mask = 0;
1245 todo = wclen;
1246
1247 while (todo) {
1248 r = mbsrtowcs(wbuf, &s,
1249 ((todo <= sizeof(wbuf)/sizeof(wbuf[0]))
1250 ? todo
1251 : sizeof(wbuf)/sizeof(wbuf[0])),
1252 &mbstate);
1253 assert(((ssize_t)r) > 0);
1254 n = _outnwcs(stream, wbuf, r);
1255 todo -= n;
1256 if (n != r) {
1257 break;
1258 }
1259 }
1260
1261 return wclen - todo;
1262}
1263
1264#ifdef __STDIO_PRINTF_FLOAT
1265
1266#ifdef __UCLIBC_MJN3_ONLY__
1267#warning TODO: Move defines from _fpmaxtostr. Put them in a common header.
1268#endif
1269
1270/* The following defines are from _fpmaxtostr.*/
1271#define DIGITS_PER_BLOCK 9
1272#define NUM_DIGIT_BLOCKS ((DECIMAL_DIG+DIGITS_PER_BLOCK-1)/DIGITS_PER_BLOCK)
1273#define BUF_SIZE ( 3 + NUM_DIGIT_BLOCKS * DIGITS_PER_BLOCK )
1274
1275static size_t _fp_out_wide(FILE *fp, intptr_t type, intptr_t len, intptr_t buf)
1276{
1277 wchar_t wbuf[BUF_SIZE];
1278 const char *s = (const char *) buf;
1279 size_t r = 0;
1280 int i;
1281
1282 if (type & 0x80) { /* Some type of padding needed */
1283 int buflen = strlen(s);
1284 len -= buflen;
1285 if (len > 0) {
1286 r = _charpad(fp, (type & 0x7f), len);
1287 if (r != len) {
1288 return r;
1289 }
1290 }
1291 len = buflen;
1292 }
1293
1294 if (len > 0) {
1295 i = 0;
1296 do {
1297#ifdef __LOCALE_C_ONLY
1298 wbuf[i] = s[i];
1299#else
1300
1301# ifdef __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__
1302 if (s[i] == ',') {
1303 wbuf[i] = __UCLIBC_CURLOCALE->thousands_sep_wc;
1304 } else
1305# endif
1306 if (s[i] == '.') {
1307 wbuf[i] = __UCLIBC_CURLOCALE->decimal_point_wc;
1308 } else {
1309 wbuf[i] = s[i];
1310 }
1311#endif /* __LOCALE_C_ONLY */
1312
1313 } while (++i < len);
1314
1315 r += OUTNSTR(fp, wbuf, len);
1316 }
1317
1318 return r;
1319}
1320
1321#endif /* __STDIO_PRINTF_FLOAT */
1322
1323static int _ppwfs_init(register ppfs_t *ppfs, const wchar_t *fmt0)
1324{
1325 static const wchar_t invalid_wcs[] = L"Invalid wide format string.";
1326 int r;
1327
1328 /* First, zero out everything... argnumber[], argtype[], argptr[] */
1329 memset(ppfs, 0, sizeof(ppfs_t)); /* TODO: nonportable???? */
1330#ifdef NL_ARGMAX
1331 --ppfs->maxposarg; /* set to -1 */
1332#endif
1333 ppfs->fmtpos = (const char *) fmt0;
1334 ppfs->info._flags = FLAG_WIDESTREAM;
1335
1336 {
1337 mbstate_t mbstate;
1338 const wchar_t *p;
1339 mbstate.__mask = 0; /* Initialize the mbstate. */
1340 p = fmt0;
1341 if (wcsrtombs(NULL, &p, SIZE_MAX, &mbstate) == ((size_t)(-1))) {
1342 ppfs->fmtpos = (const char *) invalid_wcs;
1343 return -1;
1344 }
1345 }
1346
1347 /* now set all argtypes to no-arg */
1348 {
1349#if 1
1350 /* TODO - use memset here since already "paid for"? */
1351 register int *p = ppfs->argtype;
1352
1353 r = MAX_ARGS;
1354 do {
1355 *p++ = __PA_NOARG;
1356 } while (--r);
1357#else
1358 /* TODO -- get rid of this?? */
1359 register char *p = (char *) ((MAX_ARGS-1) * sizeof(int));
1360
1361 do {
1362 *((int *)(((char *)ppfs) + ((int)p) + offsetof(ppfs_t,argtype))) = __PA_NOARG;
1363 p -= sizeof(int);
1364 } while (p);
1365#endif
1366 }
1367
1368 /*
1369 * Run through the entire format string to validate it and initialize
1370 * the positional arg numbers (if any).
1371 */
1372 {
1373 register const wchar_t *fmt = fmt0;
1374
1375 while (*fmt) {
1376 if ((*fmt == '%') && (*++fmt != '%')) {
1377 ppfs->fmtpos = (const char *) fmt; /* back up to the '%' */
1378 r = _ppfs_parsespec(ppfs);
1379 if (r < 0) {
1380 return -1;
1381 }
1382 fmt = (const wchar_t *) ppfs->fmtpos; /* update to one past end of spec */
1383 } else {
1384 ++fmt;
1385 }
1386 }
1387 ppfs->fmtpos = (const char *) fmt0; /* rewind */
1388 }
1389
1390#ifdef NL_ARGMAX
1391 /* If we have positional args, make sure we know all the types. */
1392 {
1393 register int *p = ppfs->argtype;
1394 r = ppfs->maxposarg;
1395 while (--r >= 0) {
1396 if ( *p == __PA_NOARG ) { /* missing arg type!!! */
1397 return -1;
1398 }
1399 ++p;
1400 }
1401 }
1402#endif /* NL_ARGMAX */
1403
1404 return 0;
1405}
1406
1407#endif /* L__vfprintf_internal */
1408
1409
1410static size_t _charpad(FILE * __restrict stream, int padchar, size_t numpad)
1411{
1412 size_t todo = numpad;
1413
1414 /* TODO -- Use a buffer to cut down on function calls... */
1415 FMT_TYPE pad[1];
1416
1417 *pad = padchar;
1418 while (todo && (OUTNSTR(stream, (const char *) pad, 1) == 1)) {
1419 --todo;
1420 }
1421
1422 return numpad - todo;
1423}
1424
1425/* TODO -- Dynamically allocate work space to accomodate stack-poor archs? */
1426static int _do_one_spec(FILE * __restrict stream,
1427 register ppfs_t *ppfs, int *count)
1428{
1429 static const char spec_base[] = SPEC_BASE;
1430#ifdef L__vfprintf_internal
1431 static const char prefix[] = "+\0-\0 \0000x\0000X";
1432 /* 0 2 4 6 9 11*/
1433#else
1434 static const wchar_t prefix[] = L"+\0-\0 \0000x\0000X";
1435#endif
1436 enum {
1437 PREFIX_PLUS = 0,
1438 PREFIX_MINUS = 2,
1439 PREFIX_SPACE = 4,
1440 PREFIX_LWR_X = 6,
1441 PREFIX_UPR_X = 9,
1442 PREFIX_NONE = 11
1443 };
1444
1445#ifdef __va_arg_ptr
1446 const void * const *argptr;
1447#else
1448 const void * argptr[MAX_ARGS_PER_SPEC];
1449#endif
1450 int *argtype;
1451#ifdef __UCLIBC_HAS_WCHAR__
1452 const wchar_t *ws = NULL;
1453 mbstate_t mbstate;
1454#endif
1455 size_t slen;
1456#ifdef L__vfprintf_internal
1457#define SLEN slen
1458#else
1459 size_t SLEN;
1460 wchar_t wbuf[2];
1461#endif
1462 int base;
1463 int numpad;
1464 int alphacase;
1465 int numfill = 0; /* TODO: fix */
1466 int prefix_num = PREFIX_NONE;
1467 char padchar = ' ';
1468#ifdef __UCLIBC_MJN3_ONLY__
1469#warning TODO: Determine appropriate buf size.
1470#endif
1471 /* TODO: buf needs to be big enough for any possible error return strings
1472 * and also for any locale-grouped long long integer strings generated.
1473 * This should be large enough for any of the current archs/locales, but
1474 * eventually this should be handled robustly. */
1475 char buf[128];
1476
1477#ifdef NDEBUG
1478 _ppfs_parsespec(ppfs);
1479#else
1480 if (_ppfs_parsespec(ppfs) < 0) { /* TODO: just for debugging */
1481 abort();
1482 }
1483#endif
1484 _ppfs_setargs(ppfs);
1485
1486 argtype = ppfs->argtype + ppfs->argnumber[2] - 1;
1487 /* Deal with the argptr vs argvalue issue. */
1488#ifdef __va_arg_ptr
1489 argptr = (const void * const *) ppfs->argptr;
1490# ifdef NL_ARGMAX
1491 if (ppfs->maxposarg > 0) { /* Using positional args... */
1492 argptr += ppfs->argnumber[2] - 1;
1493 }
1494# endif
1495#else
1496 /* Need to build a local copy... */
1497 {
1498 register argvalue_t *p = ppfs->argvalue;
1499 int i;
1500# ifdef NL_ARGMAX
1501 if (ppfs->maxposarg > 0) { /* Using positional args... */
1502 p += ppfs->argnumber[2] - 1;
1503 }
1504# endif
1505 for (i = 0 ; i < ppfs->num_data_args ; i++ ) {
1506 argptr[i] = (void *) p++;
1507 }
1508 }
1509#endif
1510 {
1511 register char *s = NULL; /* TODO: Should s be unsigned char * ? */
1512
1513 if (ppfs->conv_num == CONV_n) {
1514 _store_inttype(*(void **)*argptr,
1515 ppfs->info._flags & __PA_INTMASK,
1516 (intmax_t) (*count));
1517 return 0;
1518 }
1519 if (ppfs->conv_num <= CONV_i) { /* pointer or (un)signed int */
1520 alphacase = __UIM_LOWER;
1521
1522#ifdef __UCLIBC_MJN3_ONLY__
1523#ifdef L__vfprintf_internal
1524#warning CONSIDER: Should we ignore these flags if stub locale? What about custom specs?
1525#endif
1526#endif
1527 base = spec_base[(int)(ppfs->conv_num - CONV_p)];
1528 if (base == 10) {
1529 if (PRINT_INFO_FLAG_VAL(&(ppfs->info),group)) {
1530 alphacase = __UIM_GROUP;
1531 }
1532 if (PRINT_INFO_FLAG_VAL(&(ppfs->info),i18n)) {
1533 alphacase |= 0x80;
1534 }
1535 }
1536
1537 if (ppfs->conv_num <= CONV_u) { /* pointer or unsigned int */
1538 if (ppfs->conv_num == CONV_X) {
1539 alphacase = __UIM_UPPER;
1540 }
1541 if (ppfs->conv_num == CONV_p) { /* pointer */
1542 prefix_num = PREFIX_LWR_X;
1543 } else { /* unsigned int */
1544 }
1545 } else { /* signed int */
1546 base = -base;
1547 }
1548 if (ppfs->info.prec < 0) { /* Ignore '0' flag if prec specified. */
1549 padchar = ppfs->info.pad;
1550 }
1551#ifdef __UCLIBC_MJN3_ONLY__
1552#ifdef L__vfprintf_internal
1553#warning CONSIDER: If using outdigits and/or grouping, how should we interpret precision?
1554#endif
1555#endif
1556 s = _uintmaxtostr(buf + sizeof(buf) - 1,
1557 (uintmax_t)
1558 _load_inttype(ppfs->conv_num == CONV_p ? PA_FLAG_LONG : *argtype & __PA_INTMASK,
1559 *argptr, base), base, alphacase);
1560 if (ppfs->conv_num > CONV_u) { /* signed int */
1561 if (*s == '-') {
1562 PRINT_INFO_SET_FLAG(&(ppfs->info),showsign);
1563 ++s; /* handle '-' in the prefix string */
1564 prefix_num = PREFIX_MINUS;
1565 } else if (PRINT_INFO_FLAG_VAL(&(ppfs->info),showsign)) {
1566 prefix_num = PREFIX_PLUS;
1567 } else if (PRINT_INFO_FLAG_VAL(&(ppfs->info),space)) {
1568 prefix_num = PREFIX_SPACE;
1569 }
1570 }
1571 slen = (char *)(buf + sizeof(buf) - 1) - s;
1572#ifdef L__vfwprintf_internal
1573 {
1574 const char *q = s;
1575 mbstate.__mask = 0; /* Initialize the mbstate. */
1576 SLEN = mbsrtowcs(NULL, &q, 0, &mbstate);
1577 }
1578#endif
1579 numfill = ((ppfs->info.prec < 0) ? 1 : ppfs->info.prec);
1580 if (PRINT_INFO_FLAG_VAL(&(ppfs->info),alt)) {
1581 if (ppfs->conv_num <= CONV_x) { /* x or p */
1582 prefix_num = PREFIX_LWR_X;
1583 }
1584 if (ppfs->conv_num == CONV_X) {
1585 prefix_num = PREFIX_UPR_X;
1586 }
1587 if ((ppfs->conv_num == CONV_o) && (numfill <= SLEN)) {
1588 numfill = ((*s == '0') ? 1 : SLEN + 1);
1589 }
1590 }
1591 if (*s == '0') {
1592 if (prefix_num >= PREFIX_LWR_X) {
1593 prefix_num = PREFIX_NONE;
1594 }
1595 if (ppfs->conv_num == CONV_p) {/* null pointer */
1596 s = "(nil)";
1597#ifdef L__vfwprintf_internal
1598 SLEN =
1599#endif
1600 slen = 5;
1601 numfill = 0;
1602 } else if (numfill == 0) { /* if precision 0, no output */
1603#ifdef L__vfwprintf_internal
1604 SLEN =
1605#endif
1606 slen = 0;
1607 }
1608 }
1609 numfill = ((numfill > SLEN) ? numfill - SLEN : 0);
1610 } else if (ppfs->conv_num <= CONV_A) { /* floating point */
1611#ifdef __STDIO_PRINTF_FLOAT
1612 ssize_t nf;
1613 nf = _fpmaxtostr(stream,
1614 (__fpmax_t)
1615 (PRINT_INFO_FLAG_VAL(&(ppfs->info),is_long_double)
1616 ? *(long double *) *argptr
1617 : (long double) (* (double *) *argptr)),
1618 &ppfs->info, FP_OUT );
1619 if (nf < 0) {
1620 return -1;
1621 }
1622 *count += nf;
1623
1624 return 0;
1625#else /* __STDIO_PRINTF_FLOAT */
1626 return -1; /* TODO -- try to continue? */
1627#endif
1628 } else if (ppfs->conv_num <= CONV_S) { /* wide char or string */
1629#ifdef L__vfprintf_internal
1630
1631#ifdef __UCLIBC_HAS_WCHAR__
1632 mbstate.__mask = 0; /* Initialize the mbstate. */
1633 if (ppfs->conv_num == CONV_S) { /* wide string */
1634 ws = *((const wchar_t **) *argptr);
1635 if (!ws) {
1636 goto NULL_STRING;
1637 }
1638 /* We use an awful uClibc-specific hack here, passing
1639 * (char*) &ws as the conversion destination. This signals
1640 * uClibc's wcsrtombs that we want a "restricted" length
1641 * such that the mbs fits in a buffer of the specified
1642 * size with no partial conversions. */
1643 slen = wcsrtombs((char *) &ws, &ws, /* Use awful hack! */
1644 ((ppfs->info.prec >= 0)
1645 ? ppfs->info.prec
1646 : SIZE_MAX),
1647 &mbstate);
1648 if (slen == ((size_t)-1)) {
1649 return -1; /* EILSEQ */
1650 }
1651 } else { /* wide char */
1652 s = buf;
1653 slen = wcrtomb(s, (*((const wchar_t *) *argptr)), &mbstate);
1654 if (slen == ((size_t)-1)) {
1655 return -1; /* EILSEQ */
1656 }
1657 s[slen] = 0; /* TODO - Is this necessary? */
1658 }
1659#else /* __UCLIBC_HAS_WCHAR__ */
1660 return -1;
1661#endif
1662 } else if (ppfs->conv_num <= CONV_s) { /* char or string */
1663 if (ppfs->conv_num == CONV_s) { /* string */
1664 s = *((char **) (*argptr));
1665 if (s) {
1666#ifdef __UCLIBC_HAS_PRINTF_M_SPEC__
1667 SET_STRING_LEN:
1668#endif
1669 slen = strnlen(s, ((ppfs->info.prec >= 0)
1670 ? ppfs->info.prec : SIZE_MAX));
1671 } else {
1672#ifdef __UCLIBC_HAS_WCHAR__
1673 NULL_STRING:
1674#endif
1675 s = "(null)";
1676 slen = 6;
1677 /* Use an empty string rather than truncation if precision is too small. */
1678 if (ppfs->info.prec >= 0 && ppfs->info.prec < slen)
1679 slen = 0;
1680 }
1681 } else { /* char */
1682 s = buf;
1683 *s = (unsigned char)(*((const int *) *argptr));
1684 s[1] = 0;
1685 slen = 1;
1686 }
1687
1688#else /* L__vfprintf_internal */
1689
1690 if (ppfs->conv_num == CONV_S) { /* wide string */
1691 ws = *((wchar_t **) (*argptr));
1692 if (!ws) {
1693 goto NULL_STRING;
1694 }
1695 SLEN = wcsnlen(ws, ((ppfs->info.prec >= 0)
1696 ? ppfs->info.prec : SIZE_MAX));
1697 } else { /* wide char */
1698 *wbuf = (wchar_t)(*((const wint_t *) *argptr));
1699 CHAR_CASE:
1700 ws = wbuf;
1701 wbuf[1] = 0;
1702 SLEN = 1;
1703 }
1704
1705 } else if (ppfs->conv_num <= CONV_s) { /* char or string */
1706
1707 if (ppfs->conv_num == CONV_s) { /* string */
1708#ifdef __UCLIBC_MJN3_ONLY__
1709#warning TODO: Fix %s for _vfwprintf_internal... output upto illegal sequence?
1710#endif
1711 s = *((char **) (*argptr));
1712 if (s) {
1713#ifdef __UCLIBC_HAS_PRINTF_M_SPEC__
1714 SET_STRING_LEN:
1715#endif
1716 /* We use an awful uClibc-specific hack here, passing
1717 * (wchar_t*) &mbstate as the conversion destination.
1718 * This signals uClibc's mbsrtowcs that we want a
1719 * "restricted" length such that the mbs fits in a buffer
1720 * of the specified size with no partial conversions. */
1721 {
1722 const char *q = s;
1723 mbstate.__mask = 0; /* Initialize the mbstate. */
1724 SLEN = mbsrtowcs((wchar_t *) &mbstate, &q,
1725 ((ppfs->info.prec >= 0)
1726 ? ppfs->info.prec : SIZE_MAX),
1727 &mbstate);
1728 }
1729 if (SLEN == ((size_t)(-1))) {
1730 return -1; /* EILSEQ */
1731 }
1732 } else {
1733 NULL_STRING:
1734 s = "(null)";
1735 SLEN = slen = 6;
1736 /* Use an empty string rather than truncation if precision is too small. */
1737 if (ppfs->info.prec >= 0 && ppfs->info.prec < slen)
1738 SLEN = slen = 0;
1739 }
1740 } else { /* char */
1741 *wbuf = btowc( (unsigned char)(*((const int *) *argptr)) );
1742 goto CHAR_CASE;
1743 }
1744
1745#endif /* L__vfprintf_internal */
1746
1747#ifdef __UCLIBC_HAS_PRINTF_M_SPEC__
1748 } else if (ppfs->conv_num == CONV_m) {
1749 s = __glibc_strerror_r(errno, buf, sizeof(buf));
1750 goto SET_STRING_LEN;
1751#endif
1752 } else {
1753#ifdef __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__
1754 assert(ppfs->conv_num == CONV_custom0);
1755
1756 s = _custom_printf_spec;
1757 do {
1758 if (*s == ppfs->info.spec) {
1759 int rv;
1760 /* TODO -- check return value for sanity? */
1761 rv = (*_custom_printf_handler
1762 [(int)(s-_custom_printf_spec)])
1763 (stream, &ppfs->info, argptr);
1764 if (rv < 0) {
1765 return -1;
1766 }
1767 *count += rv;
1768 return 0;
1769 }
1770 } while (++s < (_custom_printf_spec + MAX_USER_SPEC));
1771#endif /* __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__ */
1772 assert(0);
1773 return -1;
1774 }
1775
1776#ifdef __UCLIBC_MJN3_ONLY__
1777#ifdef L__vfprintf_internal
1778#warning CONSIDER: If using outdigits and/or grouping, how should we pad?
1779#endif
1780#endif
1781 {
1782 size_t t;
1783
1784 t = SLEN + numfill;
1785 if (prefix_num != PREFIX_NONE) {
1786 t += ((prefix_num < PREFIX_LWR_X) ? 1 : 2);
1787 }
1788 numpad = ((ppfs->info.width > t) ? (ppfs->info.width - t) : 0);
1789 *count += t + numpad;
1790 }
1791 if (padchar == '0') { /* TODO: check this */
1792 numfill += numpad;
1793 numpad = 0;
1794 }
1795
1796 /* Now handle the output itself. */
1797 if (!PRINT_INFO_FLAG_VAL(&(ppfs->info),left)) {
1798 if (_charpad(stream, ' ', numpad) != numpad) {
1799 return -1;
1800 }
1801 numpad = 0;
1802 }
1803 OUTPUT(stream, prefix + prefix_num);
1804
1805 if (_charpad(stream, '0', numfill) != numfill) {
1806 return -1;
1807 }
1808
1809#ifdef L__vfprintf_internal
1810
1811# ifdef __UCLIBC_HAS_WCHAR__
1812 if (!ws) {
1813 assert(s);
1814 if (_outnstr(stream, s, slen) != slen) {
1815 return -1;
1816 }
1817 } else { /* wide string */
1818 size_t t;
1819 mbstate.__mask = 0; /* Initialize the mbstate. */
1820 while (slen) {
1821 t = (slen <= sizeof(buf)) ? slen : sizeof(buf);
1822 t = wcsrtombs(buf, &ws, t, &mbstate);
1823 assert(t != ((size_t)(-1)));
1824 if (_outnstr(stream, buf, t) != t) {
1825 return -1;
1826 }
1827 slen -= t;
1828 }
1829 }
1830# else /* __UCLIBC_HAS_WCHAR__ */
1831 if (_outnstr(stream, (const unsigned char *) s, slen) != slen) {
1832 return -1;
1833 }
1834# endif
1835
1836#else /* L__vfprintf_internal */
1837
1838 if (!ws) {
1839 assert(s);
1840 if (_outnstr(stream, s, SLEN) != SLEN) {
1841 return -1;
1842 }
1843 } else {
1844 if (_outnwcs(stream, ws, SLEN) != SLEN) {
1845 return -1;
1846 }
1847 }
1848
1849#endif /* L__vfprintf_internal */
1850 if (_charpad(stream, ' ', numpad) != numpad) {
1851 return -1;
1852 }
1853 }
1854
1855 return 0;
1856}
1857
1858
1859int VFPRINTF_internal (FILE * __restrict stream,
1860 const FMT_TYPE * __restrict format,
1861 va_list arg)
1862{
1863 ppfs_t ppfs;
1864 int count, r;
1865 register const FMT_TYPE *s;
1866
1867 count = 0;
1868 s = format;
1869
1870 if (_PPFS_init(&ppfs, format) < 0) { /* Bad format string. */
1871 OUTNSTR(stream, (const char *) ppfs.fmtpos,
1872 STRLEN((const FMT_TYPE *)(ppfs.fmtpos)));
1873#if defined(L__vfprintf_internal) && !defined(NDEBUG)
1874 fprintf(stderr,"\nIMbS: \"%s\"\n\n", format);
1875#endif
1876 count = -1;
1877 } else {
1878 _ppfs_prepargs(&ppfs, arg); /* This did a va_copy!!! */
1879
1880 do {
1881 while (*format && (*format != '%')) {
1882 ++format;
1883 }
1884
1885 if (format - s) { /* output any literal text in format string */
1886 r = OUTNSTR(stream, (const char *) s, format - s);
1887 if (r != (format - s)) {
1888 count = -1;
1889 break;
1890 }
1891 count += r;
1892 }
1893
1894 if (!*format) { /* we're done */
1895 break;
1896 }
1897
1898 if (format[1] != '%') { /* if we get here, *format == '%' */
1899 /* TODO: _do_one_spec needs to know what the output funcs are!!! */
1900 ppfs.fmtpos = (const char *)(++format);
1901 /* TODO: check -- should only fail on stream error */
1902 r = _do_one_spec(stream, &ppfs, &count);
1903 if (r < 0) {
1904 count = -1;
1905 break;
1906 }
1907 s = format = (const FMT_TYPE *) ppfs.fmtpos;
1908 } else { /* %% means literal %, so start new string */
1909 s = ++format;
1910 ++format;
1911 }
1912 } while (1);
1913
1914 va_end(ppfs.arg); /* Need to clean up after va_copy! */
1915 }
1916
1917/* #if defined(L__vfprintf_internal) && defined(__UCLIBC_HAS_WCHAR__) */
1918/* DONE: */
1919/* #endif */
1920
1921 return count;
1922}
1923#endif /* defined(L__vfprintf_internal) || defined(L__vfwprintf_internal) */
1924
1925
1926/**********************************************************************/
1927#if defined(L_vfprintf) || defined(L_vfwprintf)
1928
1929/* This is just a wrapper around VFPRINTF_internal.
1930 * Factoring out vfprintf internals allows:
1931 * (1) vdprintf and vsnprintf don't need to setup fake locking,
1932 * (2) __STDIO_STREAM_TRANS_TO_WRITE is not used in vfprintf internals,
1933 * and thus fseek etc is not pulled in by vdprintf and vsnprintf.
1934 *
1935 * In order to not pull in fseek through fputs, OUTPUT() macro
1936 * is using __stdio_fwrite (TODO: do the same for wide functions).
1937 */
1938#ifdef L_vfprintf
1939# define VFPRINTF vfprintf
1940# define VFPRINTF_internal _vfprintf_internal
1941# define FMT_TYPE char
1942#else
1943# define VFPRINTF vfwprintf
1944# define VFPRINTF_internal _vfwprintf_internal
1945# define FMT_TYPE wchar_t
1946#endif
1947
1948libc_hidden_proto(VFPRINTF)
1949int VFPRINTF (FILE * __restrict stream,
1950 const FMT_TYPE * __restrict format,
1951 va_list arg)
1952{
1953 int count;
1954 __STDIO_AUTO_THREADLOCK_VAR;
1955
1956 __STDIO_AUTO_THREADLOCK(stream);
1957
1958 if
1959#ifdef L_vfprintf
1960 (!__STDIO_STREAM_IS_NARROW_WRITING(stream)
1961 && __STDIO_STREAM_TRANS_TO_WRITE(stream, __FLAG_NARROW))
1962#else
1963 (!__STDIO_STREAM_IS_WIDE_WRITING(stream)
1964 && __STDIO_STREAM_TRANS_TO_WRITE(stream, __FLAG_WIDE))
1965#endif
1966 {
1967 count = -1;
1968 } else {
1969 count = VFPRINTF_internal(stream, format, arg);
1970 }
1971
1972 __STDIO_AUTO_THREADUNLOCK(stream);
1973
1974 return count;
1975}
1976libc_hidden_def(VFPRINTF)
1977#endif /* defined(L_vfprintf) || defined(L_vfwprintf) */
1978
1979/**********************************************************************/