• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*-
2  * Copyright (c) 1990 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Chris Torek.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 
33 #include <sys/mman.h>
34 #include <sys/types.h>
35 
36 #include <errno.h>
37 #include <float.h>
38 #include <langinfo.h>
39 #include <limits.h>
40 #include <locale.h>
41 #include <math.h>
42 #include <stdarg.h>
43 #include <stddef.h>
44 #include <stdint.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <unistd.h>
49 #include <wchar.h>
50 
51 #include "fvwrite.h"
52 #include "gdtoa.h"
53 #include "local.h"
54 
55 union arg {
56   int intarg;
57   unsigned int uintarg;
58   long longarg;
59   unsigned long ulongarg;
60   long long longlongarg;
61   unsigned long long ulonglongarg;
62   ptrdiff_t ptrdiffarg;
63   size_t sizearg;
64   ssize_t ssizearg;
65   intmax_t intmaxarg;
66   uintmax_t uintmaxarg;
67   void* pvoidarg;
68   char* pchararg;
69   signed char* pschararg;
70   short* pshortarg;
71   int* pintarg;
72   long* plongarg;
73   long long* plonglongarg;
74   ptrdiff_t* pptrdiffarg;
75   ssize_t* pssizearg;
76   intmax_t* pintmaxarg;
77   double doublearg;
78   long double longdoublearg;
79   wint_t wintarg;
80   wchar_t* pwchararg;
81 };
82 
83 // Helper function for `fprintf to unbuffered unix file': creates a
84 // temporary buffer.  We only work on write-only files; this avoids
85 // worries about ungetc buffers and so forth.
__sbprintf(FILE * fp,const CHAR_TYPE * fmt,va_list ap)86 static int __sbprintf(FILE* fp, const CHAR_TYPE* fmt, va_list ap) {
87   FILE fake;
88   struct __sfileext fakeext;
89   unsigned char buf[BUFSIZ];
90 
91   _FILEEXT_SETUP(&fake, &fakeext);
92   /* copy the important variables */
93   fake._flags = fp->_flags & ~__SNBF;
94   fake._file = fp->_file;
95   fake._cookie = fp->_cookie;
96   fake._write = fp->_write;
97 
98   /* set up the buffer */
99   fake._bf._base = fake._p = buf;
100   fake._bf._size = fake._w = sizeof(buf);
101   fake._lbfsize = 0; /* not actually used, but Just In Case */
102 
103   /* do the work, then copy any error status */
104   int ret = FUNCTION_NAME(&fake, fmt, ap);
105   if (ret >= 0 && __sflush(&fake)) ret = EOF;
106   if (fake._flags & __SERR) fp->_flags |= __SERR;
107   return ret;
108 }
109 
110 static int __find_arguments(const CHAR_TYPE* fmt0, va_list ap, union arg** argtable, size_t* argtablesiz);
111 static int __grow_type_table(unsigned char** typetable, int* tablesize);
112 
113 #define DEFPREC 6
114 
115 #define to_digit(c) ((c) - '0')
116 #define is_digit(c) ((unsigned)to_digit(c) <= 9)
117 #define to_char(n) ((CHAR_TYPE)((n) + '0'))
118 
119 template <typename CharT>
exponent(CharT * p0,int exp,int fmtch)120 static int exponent(CharT* p0, int exp, int fmtch) {
121   CharT* p = p0;
122   *p++ = fmtch;
123   if (exp < 0) {
124     exp = -exp;
125     *p++ = '-';
126   } else {
127     *p++ = '+';
128   }
129 
130   CharT expbuf[MAXEXPDIG];
131   CharT* t = expbuf + MAXEXPDIG;
132   if (exp > 9) {
133     do {
134       *--t = to_char(exp % 10);
135     } while ((exp /= 10) > 9);
136     *--t = to_char(exp);
137     for (; t < expbuf + MAXEXPDIG; *p++ = *t++) /* nothing */;
138   } else {
139     /*
140      * Exponents for decimal floating point conversions
141      * (%[eEgG]) must be at least two characters long,
142      * whereas exponents for hexadecimal conversions can
143      * be only one character long.
144      */
145     if (fmtch == 'e' || fmtch == 'E') *p++ = '0';
146     *p++ = to_char(exp);
147   }
148   return (p - p0);
149 }
150 
151 #define PAD(howmany, with)     \
152   do {                         \
153     if ((n = (howmany)) > 0) { \
154       while (n > PADSIZE) {    \
155         PRINT(with, PADSIZE);  \
156         n -= PADSIZE;          \
157       }                        \
158       PRINT(with, n);          \
159     }                          \
160   } while (0)
161 
162 #define PRINTANDPAD(p, ep, len, with)       \
163   do {                                      \
164     n2 = (ep) - (p);                        \
165     if (n2 > (len)) n2 = (len);             \
166     if (n2 > 0) PRINT((p), n2);             \
167     PAD((len) - (n2 > 0 ? n2 : 0), (with)); \
168   } while (0)
169 
170 /*
171  * The size of the buffer we use as scratch space for integer
172  * conversions, among other things.  Technically, we would need the
173  * most space for base 10 conversions with thousands' grouping
174  * characters between each pair of digits.  100 bytes is a
175  * conservative overestimate even for a 128-bit uintmax_t.
176  */
177 #define BUF 100
178 
179 #define STATIC_ARG_TBL_SIZE 8 /* Size of static argument table. */
180 
181 /*
182  * Flags used during conversion.
183  */
184 #define ALT 0x0001      /* alternate form */
185 #define LADJUST 0x0004  /* left adjustment */
186 #define LONGDBL 0x0008  /* long double */
187 #define LONGINT 0x0010  /* long integer */
188 #define LLONGINT 0x0020 /* long long integer */
189 #define SHORTINT 0x0040 /* short integer */
190 #define ZEROPAD 0x0080  /* zero (as opposed to blank) pad */
191 #define FPT 0x0100      /* Floating point number */
192 #define PTRINT 0x0200   /* (unsigned) ptrdiff_t */
193 #define SIZEINT 0x0400  /* (signed) size_t */
194 #define CHARINT 0x0800  /* 8 bit integer */
195 #define MAXINT 0x1000   /* largest integer size (intmax_t) */
196 
197 /*
198  * Type ids for argument type table.
199  */
200 #define T_UNUSED 0
201 #define T_SHORT 1
202 #define T_U_SHORT 2
203 #define TP_SHORT 3
204 #define T_INT 4
205 #define T_U_INT 5
206 #define TP_INT 6
207 #define T_LONG 7
208 #define T_U_LONG 8
209 #define TP_LONG 9
210 #define T_LLONG 10
211 #define T_U_LLONG 11
212 #define TP_LLONG 12
213 #define T_DOUBLE 13
214 #define T_LONG_DOUBLE 14
215 #define TP_CHAR 15
216 #define TP_VOID 16
217 #define T_PTRINT 17
218 #define TP_PTRINT 18
219 #define T_SIZEINT 19
220 #define T_SSIZEINT 20
221 #define TP_SSIZEINT 21
222 #define T_MAXINT 22
223 #define T_MAXUINT 23
224 #define TP_MAXINT 24
225 #define T_CHAR 25
226 #define T_U_CHAR 26
227 #define T_WINT 27
228 #define TP_WCHAR 28
229 
230 // To extend shorts properly, we need both signed and unsigned
231 // argument extraction methods.
232 #define SARG()                                                                               \
233   ((intmax_t)(flags & MAXINT                                                                 \
234                   ? GETARG(intmax_t)                                                         \
235                   : flags & LLONGINT                                                         \
236                         ? GETARG(long long)                                                  \
237                         : flags & LONGINT                                                    \
238                               ? GETARG(long)                                                 \
239                               : flags & PTRINT                                               \
240                                     ? GETARG(ptrdiff_t)                                      \
241                                     : flags & SIZEINT                                        \
242                                           ? GETARG(ssize_t)                                  \
243                                           : flags & SHORTINT                                 \
244                                                 ? (short)GETARG(int)                         \
245                                                 : flags & CHARINT ? (signed char)GETARG(int) \
246                                                                   : GETARG(int)))
247 #define UARG()                                                                                \
248   ((uintmax_t)(flags & MAXINT                                                                 \
249                    ? GETARG(uintmax_t)                                                        \
250                    : flags & LLONGINT                                                         \
251                          ? GETARG(unsigned long long)                                         \
252                          : flags & LONGINT                                                    \
253                                ? GETARG(unsigned long)                                        \
254                                : flags & PTRINT ? (uintptr_t)GETARG(ptrdiff_t) : /* XXX */    \
255                                      flags & SIZEINT                                          \
256                                          ? GETARG(size_t)                                     \
257                                          : flags & SHORTINT                                   \
258                                                ? (unsigned short)GETARG(int)                  \
259                                                : flags & CHARINT ? (unsigned char)GETARG(int) \
260                                                                  : GETARG(unsigned int)))
261 
262 // Append a digit to a value and check for overflow.
263 #define APPEND_DIGIT(val, dig)                            \
264   do {                                                    \
265     if ((val) > INT_MAX / 10) goto overflow;              \
266     (val) *= 10;                                          \
267     if ((val) > INT_MAX - to_digit((dig))) goto overflow; \
268     (val) += to_digit((dig));                             \
269   } while (0)
270 
271 // Get * arguments, including the form *nn$.  Preserve the nextarg
272 // that the argument can be gotten once the type is determined.
273 #define GETASTER(val)                                                     \
274   n2 = 0;                                                                 \
275   cp = fmt;                                                               \
276   while (is_digit(*cp)) {                                                 \
277     APPEND_DIGIT(n2, *cp);                                                \
278     cp++;                                                                 \
279   }                                                                       \
280   if (*cp == '$') {                                                       \
281     int hold = nextarg;                                                   \
282     if (argtable == NULL) {                                               \
283       argtable = statargtable;                                            \
284       if (__find_arguments(fmt0, orgap, &argtable, &argtablesiz) == -1) { \
285         ret = -1;                                                         \
286         goto error;                                                       \
287       }                                                                   \
288     }                                                                     \
289     nextarg = n2;                                                         \
290     val = GETARG(int);                                                    \
291     nextarg = hold;                                                       \
292     fmt = ++cp;                                                           \
293   } else {                                                                \
294     val = GETARG(int);                                                    \
295   }
296 
297 // Get the argument indexed by nextarg.   If the argument table is
298 // built, use it to get the argument.  If its not, get the next
299 // argument (and arguments must be gotten sequentially).
300 #define GETARG(type) \
301   ((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : (nextarg++, va_arg(ap, type)))
302 
303 /*
304  * Find all arguments when a positional parameter is encountered.  Returns a
305  * table, indexed by argument number, of pointers to each arguments.  The
306  * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries.
307  * It will be replaced with a mmap-ed one if it overflows (malloc cannot be
308  * used since we are attempting to make snprintf thread safe, and alloca is
309  * problematic since we have nested functions..)
310  */
__find_arguments(const CHAR_TYPE * fmt0,va_list ap,union arg ** argtable,size_t * argtablesiz)311 static int __find_arguments(const CHAR_TYPE* fmt0, va_list ap, union arg** argtable,
312                             size_t* argtablesiz) {
313   int ch;                   /* character from fmt */
314   int n, n2;                /* handy integer (short term usage) */
315   int flags;                /* flags as above */
316   unsigned char* typetable; /* table of types */
317   unsigned char stattypetable[STATIC_ARG_TBL_SIZE];
318   int tablesize; /* current size of type table */
319   int tablemax;  /* largest used index in table */
320   int nextarg;   /* 1-based argument index */
321   int ret = 0;   /* return value */
322 
323   /*
324    * Add an argument type to the table, expanding if necessary.
325    */
326 #define ADDTYPE(type)                                                      \
327   ((nextarg >= tablesize) ? __grow_type_table(&typetable, &tablesize) : 0, \
328    (nextarg > tablemax) ? tablemax = nextarg : 0, typetable[nextarg++] = type)
329 
330 #define ADDSARG()                                                                             \
331   ((flags & MAXINT)                                                                           \
332        ? ADDTYPE(T_MAXINT)                                                                    \
333        : ((flags & PTRINT) ? ADDTYPE(T_PTRINT)                                                \
334                            : ((flags & SIZEINT)                                               \
335                                   ? ADDTYPE(T_SSIZEINT)                                       \
336                                   : ((flags & LLONGINT)                                       \
337                                          ? ADDTYPE(T_LLONG)                                   \
338                                          : ((flags & LONGINT)                                 \
339                                                 ? ADDTYPE(T_LONG)                             \
340                                                 : ((flags & SHORTINT)                         \
341                                                        ? ADDTYPE(T_SHORT)                     \
342                                                        : ((flags & CHARINT) ? ADDTYPE(T_CHAR) \
343                                                                             : ADDTYPE(T_INT))))))))
344 
345 #define ADDUARG()                                                                  \
346   ((flags & MAXINT)                                                                \
347        ? ADDTYPE(T_MAXUINT)                                                        \
348        : ((flags & PTRINT)                                                         \
349               ? ADDTYPE(T_PTRINT)                                                  \
350               : ((flags & SIZEINT)                                                 \
351                      ? ADDTYPE(T_SIZEINT)                                          \
352                      : ((flags & LLONGINT)                                         \
353                             ? ADDTYPE(T_U_LLONG)                                   \
354                             : ((flags & LONGINT)                                   \
355                                    ? ADDTYPE(T_U_LONG)                             \
356                                    : ((flags & SHORTINT)                           \
357                                           ? ADDTYPE(T_U_SHORT)                     \
358                                           : ((flags & CHARINT) ? ADDTYPE(T_U_CHAR) \
359                                                                : ADDTYPE(T_U_INT))))))))
360 
361   /*
362    * Add * arguments to the type array.
363    */
364 #define ADDASTER()         \
365   n2 = 0;                  \
366   cp = fmt;                \
367   while (is_digit(*cp)) {  \
368     APPEND_DIGIT(n2, *cp); \
369     cp++;                  \
370   }                        \
371   if (*cp == '$') {        \
372     int hold = nextarg;    \
373     nextarg = n2;          \
374     ADDTYPE(T_INT);        \
375     nextarg = hold;        \
376     fmt = ++cp;            \
377   } else {                 \
378     ADDTYPE(T_INT);        \
379   }
380   CHAR_TYPE* fmt = const_cast<CHAR_TYPE*>(fmt0);
381   CHAR_TYPE* cp;
382   typetable = stattypetable;
383   tablesize = STATIC_ARG_TBL_SIZE;
384   tablemax = 0;
385   nextarg = 1;
386   memset(typetable, T_UNUSED, STATIC_ARG_TBL_SIZE);
387 
388   /*
389    * Scan the format for conversions (`%' character).
390    */
391   for (;;) {
392     for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) continue;
393     if (ch == '\0') goto done;
394     fmt++; /* skip over '%' */
395 
396     flags = 0;
397 
398   rflag:
399     ch = *fmt++;
400   reswitch:
401     switch (ch) {
402       case ' ':
403       case '#':
404       case '\'':
405         goto rflag;
406       case '*':
407         ADDASTER();
408         goto rflag;
409       case '-':
410       case '+':
411         goto rflag;
412       case '.':
413         if ((ch = *fmt++) == '*') {
414           ADDASTER();
415           goto rflag;
416         }
417         while (is_digit(ch)) {
418           ch = *fmt++;
419         }
420         goto reswitch;
421       case '0':
422         goto rflag;
423       case '1':
424       case '2':
425       case '3':
426       case '4':
427       case '5':
428       case '6':
429       case '7':
430       case '8':
431       case '9':
432         n = 0;
433         do {
434           APPEND_DIGIT(n, ch);
435           ch = *fmt++;
436         } while (is_digit(ch));
437         if (ch == '$') {
438           nextarg = n;
439           goto rflag;
440         }
441         goto reswitch;
442       case 'L':
443         flags |= LONGDBL;
444         goto rflag;
445       case 'h':
446         if (*fmt == 'h') {
447           fmt++;
448           flags |= CHARINT;
449         } else {
450           flags |= SHORTINT;
451         }
452         goto rflag;
453       case 'j':
454         flags |= MAXINT;
455         goto rflag;
456       case 'l':
457         if (*fmt == 'l') {
458           fmt++;
459           flags |= LLONGINT;
460         } else {
461           flags |= LONGINT;
462         }
463         goto rflag;
464       case 'q':
465         flags |= LLONGINT;
466         goto rflag;
467       case 't':
468         flags |= PTRINT;
469         goto rflag;
470       case 'z':
471         flags |= SIZEINT;
472         goto rflag;
473       case 'C':
474         flags |= LONGINT;
475         /*FALLTHROUGH*/
476       case 'c':
477         if (flags & LONGINT)
478           ADDTYPE(T_WINT);
479         else
480           ADDTYPE(T_INT);
481         break;
482       case 'D':
483         flags |= LONGINT;
484         /*FALLTHROUGH*/
485       case 'd':
486       case 'i':
487         ADDSARG();
488         break;
489       case 'a':
490       case 'A':
491       case 'e':
492       case 'E':
493       case 'f':
494       case 'F':
495       case 'g':
496       case 'G':
497         if (flags & LONGDBL)
498           ADDTYPE(T_LONG_DOUBLE);
499         else
500           ADDTYPE(T_DOUBLE);
501         break;
502 #ifndef NO_PRINTF_PERCENT_N
503       case 'n':
504         if (flags & LLONGINT)
505           ADDTYPE(TP_LLONG);
506         else if (flags & LONGINT)
507           ADDTYPE(TP_LONG);
508         else if (flags & SHORTINT)
509           ADDTYPE(TP_SHORT);
510         else if (flags & PTRINT)
511           ADDTYPE(TP_PTRINT);
512         else if (flags & SIZEINT)
513           ADDTYPE(TP_SSIZEINT);
514         else if (flags & MAXINT)
515           ADDTYPE(TP_MAXINT);
516         else
517           ADDTYPE(TP_INT);
518         continue; /* no output */
519 #endif            /* NO_PRINTF_PERCENT_N */
520       case 'O':
521         flags |= LONGINT;
522         /*FALLTHROUGH*/
523       case 'o':
524         ADDUARG();
525         break;
526       case 'p':
527         ADDTYPE(TP_VOID);
528         break;
529       case 'S':
530         flags |= LONGINT;
531         /*FALLTHROUGH*/
532       case 's':
533         ADDTYPE((flags & LONGINT) ? TP_WCHAR : TP_CHAR);
534         break;
535       case 'U':
536         flags |= LONGINT;
537         /*FALLTHROUGH*/
538       case 'u':
539       case 'X':
540       case 'x':
541         ADDUARG();
542         break;
543       default: /* "%?" prints ?, unless ? is NUL */
544         if (ch == '\0') goto done;
545         break;
546     }
547   }
548 done:
549   /*
550    * Build the argument table.
551    */
552   if (tablemax >= STATIC_ARG_TBL_SIZE) {
553     *argtablesiz = sizeof(union arg) * (tablemax + 1);
554     *argtable = static_cast<arg*>(mmap(NULL, *argtablesiz,
555                                        PROT_WRITE | PROT_READ,
556                                        MAP_ANON | MAP_PRIVATE, -1, 0));
557     if (*argtable == MAP_FAILED) return -1;
558   }
559 
560   for (n = 1; n <= tablemax; n++) {
561     switch (typetable[n]) {
562       case T_UNUSED:
563       case T_CHAR:
564       case T_U_CHAR:
565       case T_SHORT:
566       case T_U_SHORT:
567       case T_INT:
568         (*argtable)[n].intarg = va_arg(ap, int);
569         break;
570       case TP_SHORT:
571         (*argtable)[n].pshortarg = va_arg(ap, short*);
572         break;
573       case T_U_INT:
574         (*argtable)[n].uintarg = va_arg(ap, unsigned int);
575         break;
576       case TP_INT:
577         (*argtable)[n].pintarg = va_arg(ap, int*);
578         break;
579       case T_LONG:
580         (*argtable)[n].longarg = va_arg(ap, long);
581         break;
582       case T_U_LONG:
583         (*argtable)[n].ulongarg = va_arg(ap, unsigned long);
584         break;
585       case TP_LONG:
586         (*argtable)[n].plongarg = va_arg(ap, long*);
587         break;
588       case T_LLONG:
589         (*argtable)[n].longlongarg = va_arg(ap, long long);
590         break;
591       case T_U_LLONG:
592         (*argtable)[n].ulonglongarg = va_arg(ap, unsigned long long);
593         break;
594       case TP_LLONG:
595         (*argtable)[n].plonglongarg = va_arg(ap, long long*);
596         break;
597       case T_DOUBLE:
598         (*argtable)[n].doublearg = va_arg(ap, double);
599         break;
600       case T_LONG_DOUBLE:
601         (*argtable)[n].longdoublearg = va_arg(ap, long double);
602         break;
603       case TP_CHAR:
604         (*argtable)[n].pchararg = va_arg(ap, char*);
605         break;
606       case TP_VOID:
607         (*argtable)[n].pvoidarg = va_arg(ap, void*);
608         break;
609       case T_PTRINT:
610         (*argtable)[n].ptrdiffarg = va_arg(ap, ptrdiff_t);
611         break;
612       case TP_PTRINT:
613         (*argtable)[n].pptrdiffarg = va_arg(ap, ptrdiff_t*);
614         break;
615       case T_SIZEINT:
616         (*argtable)[n].sizearg = va_arg(ap, size_t);
617         break;
618       case T_SSIZEINT:
619         (*argtable)[n].ssizearg = va_arg(ap, ssize_t);
620         break;
621       case TP_SSIZEINT:
622         (*argtable)[n].pssizearg = va_arg(ap, ssize_t*);
623         break;
624       case T_MAXINT:
625         (*argtable)[n].intmaxarg = va_arg(ap, intmax_t);
626         break;
627       case T_MAXUINT:
628         (*argtable)[n].uintmaxarg = va_arg(ap, uintmax_t);
629         break;
630       case TP_MAXINT:
631         (*argtable)[n].pintmaxarg = va_arg(ap, intmax_t*);
632         break;
633       case T_WINT:
634         (*argtable)[n].wintarg = va_arg(ap, wint_t);
635         break;
636       case TP_WCHAR:
637         (*argtable)[n].pwchararg = va_arg(ap, wchar_t*);
638         break;
639     }
640   }
641   goto finish;
642 
643 overflow:
644   errno = ENOMEM;
645   ret = -1;
646 
647 finish:
648   if (typetable != NULL && typetable != stattypetable) {
649     munmap(typetable, *argtablesiz);
650     typetable = NULL;
651   }
652   return (ret);
653 }
654 
655 /*
656  * Increase the size of the type table.
657  */
__grow_type_table(unsigned char ** typetable,int * tablesize)658 static int __grow_type_table(unsigned char** typetable, int* tablesize) {
659   unsigned char* old_table = *typetable;
660   int new_size = *tablesize * 2;
661 
662   if (new_size < getpagesize()) new_size = getpagesize();
663 
664   if (*tablesize == STATIC_ARG_TBL_SIZE) {
665     *typetable = static_cast<unsigned char*>(mmap(NULL, new_size,
666                                                   PROT_WRITE | PROT_READ,
667                                                   MAP_ANON | MAP_PRIVATE, -1, 0));
668     if (*typetable == MAP_FAILED) return -1;
669     bcopy(old_table, *typetable, *tablesize);
670   } else {
671     unsigned char* new_table = static_cast<unsigned char*>(mmap(NULL, new_size,
672                                                                 PROT_WRITE | PROT_READ,
673                                                                 MAP_ANON | MAP_PRIVATE, -1, 0));
674     if (new_table == MAP_FAILED) return -1;
675     memmove(new_table, *typetable, *tablesize);
676     munmap(*typetable, *tablesize);
677     *typetable = new_table;
678   }
679   memset(*typetable + *tablesize, T_UNUSED, (new_size - *tablesize));
680 
681   *tablesize = new_size;
682   return 0;
683 }
684 
685 struct helpers {
686   // Flush out all the vectors defined by the given uio,
687   // then reset it so that it can be reused.
sprinthelpers688   static int sprint(FILE* fp, struct __suio* uio) {
689     if (uio->uio_resid == 0) {
690       uio->uio_iovcnt = 0;
691       return 0;
692     }
693     int result = __sfvwrite(fp, uio);
694     uio->uio_resid = 0;
695     uio->uio_iovcnt = 0;
696     return result;
697   }
698 
699   // Convert a wide character string argument for the %ls format to a multibyte
700   // string representation. If not -1, prec specifies the maximum number of
701   // bytes to output, and also means that we can't assume that the wide char
702   // string is null-terminated.
wcsconvhelpers703   static char* wcsconv(wchar_t* wcsarg, int prec) {
704     mbstate_t mbs;
705     char buf[MB_LEN_MAX];
706     wchar_t* p;
707     char* convbuf;
708     size_t clen, nbytes;
709 
710     // Allocate space for the maximum number of bytes we could output.
711     if (prec < 0) {
712       memset(&mbs, 0, sizeof(mbs));
713       p = wcsarg;
714       nbytes = wcsrtombs(NULL, (const wchar_t**)&p, 0, &mbs);
715       if (nbytes == (size_t)-1) return NULL;
716     } else {
717       // Optimisation: if the output precision is small enough,
718       // just allocate enough memory for the maximum instead of
719       // scanning the string.
720       if (prec < 128) {
721         nbytes = prec;
722       } else {
723         nbytes = 0;
724         p = wcsarg;
725         memset(&mbs, 0, sizeof(mbs));
726         for (;;) {
727           clen = wcrtomb(buf, *p++, &mbs);
728           if (clen == 0 || clen == (size_t)-1 || nbytes + clen > (size_t)prec) break;
729           nbytes += clen;
730         }
731         if (clen == (size_t)-1) return NULL;
732       }
733     }
734     if ((convbuf = static_cast<char*>(malloc(nbytes + 1))) == NULL) return NULL;
735 
736     // Fill the output buffer.
737     p = wcsarg;
738     memset(&mbs, 0, sizeof(mbs));
739     if ((nbytes = wcsrtombs(convbuf, (const wchar_t**)&p, nbytes, &mbs)) == (size_t)-1) {
740       free(convbuf);
741       return NULL;
742     }
743     convbuf[nbytes] = '\0';
744     return convbuf;
745   }
746 
747   // Like __fputwc_unlock, but handles fake string (__SSTR) files properly.
748   // File must already be locked.
xfputwchelpers749   static wint_t xfputwc(wchar_t wc, FILE* fp) {
750     if ((fp->_flags & __SSTR) == 0) return __fputwc_unlock(wc, fp);
751 
752     char buf[MB_LEN_MAX];
753     mbstate_t mbs = {};
754     size_t len = wcrtomb(buf, wc, &mbs);
755     if (len == (size_t)-1) {
756       fp->_flags |= __SERR;
757       errno = EILSEQ;
758       return WEOF;
759     }
760 
761     struct __siov iov;
762     iov.iov_base = buf;
763     iov.iov_len = len;
764     struct __suio uio;
765     uio.uio_iov = &iov;
766     uio.uio_resid = len;
767     uio.uio_iovcnt = 1;
768     return (__sfvwrite(fp, &uio) != EOF ? (wint_t)wc : WEOF);
769   }
770 
771   // Convert a multibyte character string argument for the %s format to a wide
772   // string representation. ``prec'' specifies the maximum number of bytes
773   // to output. If ``prec'' is greater than or equal to zero, we can't assume
774   // that the multibyte character string ends in a null character.
775   //
776   // Returns NULL on failure.
777   // To find out what happened check errno for ENOMEM, EILSEQ and EINVAL.
mbsconvhelpers778   static wchar_t* mbsconv(char* mbsarg, int prec) {
779     mbstate_t mbs;
780     const char* p;
781     size_t insize, nchars, nconv;
782 
783     if (mbsarg == NULL) return NULL;
784 
785     // Supplied argument is a multibyte string; convert it to wide characters first.
786     if (prec >= 0) {
787       // String is not guaranteed to be NUL-terminated. Find the number of characters to print.
788       p = mbsarg;
789       insize = nchars = nconv = 0;
790       bzero(&mbs, sizeof(mbs));
791       while (nchars != (size_t)prec) {
792         nconv = mbrlen(p, MB_CUR_MAX, &mbs);
793         if (nconv == (size_t)0 || nconv == (size_t)-1 || nconv == (size_t)-2) break;
794         p += nconv;
795         nchars++;
796         insize += nconv;
797       }
798       if (nconv == (size_t)-1 || nconv == (size_t)-2) return (NULL);
799     } else {
800       insize = strlen(mbsarg);
801     }
802 
803     // Allocate buffer for the result and perform the conversion,
804     // converting at most `size' bytes of the input multibyte string to
805     // wide characters for printing.
806     wchar_t* convbuf = static_cast<wchar_t*>(calloc(insize + 1, sizeof(*convbuf)));
807     if (convbuf == NULL) return NULL;
808     wchar_t* wcp = convbuf;
809     p = mbsarg;
810     bzero(&mbs, sizeof(mbs));
811     nconv = 0;
812     while (insize != 0) {
813       nconv = mbrtowc(wcp, p, insize, &mbs);
814       if (nconv == 0 || nconv == (size_t)-1 || nconv == (size_t)-2) break;
815       wcp++;
816       p += nconv;
817       insize -= nconv;
818     }
819     if (nconv == (size_t)-1 || nconv == (size_t)-2) {
820       free(convbuf);
821       return NULL;
822     }
823     *wcp = '\0';
824 
825     return convbuf;
826   }
827 
828 };
829