1 /* @(#)format.c 1.74 19/09/12 Copyright 1985-2019 J. Schilling */
2 /*
3 * format
4 * common code for printf fprintf & sprintf
5 *
6 * allows recursive printf with "%r", used in:
7 * error, comerr, comerrno, errmsg, errmsgno and the like
8 *
9 * Copyright (c) 1985-2019 J. Schilling
10 */
11 /*
12 * The contents of this file are subject to the terms of the
13 * Common Development and Distribution License, Version 1.0 only
14 * (the "License"). You may not use this file except in compliance
15 * with the License.
16 *
17 * See the file CDDL.Schily.txt in this distribution for details.
18 * A copy of the CDDL is also available via the Internet at
19 * http://www.opensource.org/licenses/cddl1.txt
20 *
21 * When distributing Covered Code, include this CDDL HEADER in each
22 * file and include the License file CDDL.Schily.txt from this distribution.
23 */
24
25 #include <schily/mconfig.h>
26 #include <schily/varargs.h>
27 #include <schily/string.h>
28 #include <schily/stdlib.h>
29 #ifdef DEBUG
30 #include <schily/unistd.h>
31 #endif
32 #if !defined(HAVE_STDLIB_H) || !defined(HAVE_GCVT)
33 extern char *gcvt __PR((double, int, char *));
34 #endif
35 #include <schily/standard.h>
36 #include <schily/utypes.h>
37 #include <schily/schily.h>
38 #include <schily/ctype.h>
39 #include "format.h"
40
41 /*
42 * As Llong is currently a 'best effort' long long, we usually need to
43 * include long long print formats.
44 * This may go away, if we implement maxint_t formats.
45 */
46 #ifndef USE_LONGLONG
47 #define USE_LONGLONG
48 #endif
49
50 #ifdef NO_LONGLONG
51 #undef USE_LONGLONG
52 #endif
53
54 #ifndef USE_NL_ARGS
55 #define USE_NL_ARGS
56 #endif
57
58 #ifdef NO_NL_ARGS
59 #undef USE_NL_ARGS
60 #endif
61
62 /*
63 * Avoid to keep copies of the variable arg list in case that
64 * format() was compiled without including NL support for
65 * argument reordering.
66 */
67 #ifdef USE_NL_ARGS
68 #define args fargs.ap /* Use working copy */
69 #else
70 #define args oargs /* Directly use format() arg */
71 #endif
72
73 /*
74 * We may need to decide whether we should check whether all
75 * flags occur according to the standard which is either directly past:
76 * "%" or directly past "%n$".
77 *
78 * This however may make printf() slower in some cases.
79 */
80 #ifdef USE_CHECKFLAG
81 #define CHECKFLAG() if (fa.flags & GOTSTAR) goto flagerror
82 #else
83 #define CHECKFLAG()
84 #endif
85
86 #ifdef NO_USER_XCVT
87 /*
88 * We cannot define our own gcvt() so we need to use a
89 * local name instead.
90 */
91 #ifndef HAVE_GCVT
92 # define gcvt js_gcvt
93 EXPORT char *gcvt __PR((double value, int ndigit, char *buf));
94 #endif
95 #endif
96
97 /*
98 * Some CPU's (e.g. PDP-11) cannot do logical shifts.
99 * They use rotate instead. Masking the low bits before,
100 * makes rotate work too.
101 */
102 #define allmask(t) ((unsigned t)~((unsigned t)0))
103 #define lowmask(t, x) ((unsigned t)~((unsigned t)((1 << (x))-1)))
104 #define rshiftmask(t, s)((allmask(t) & lowmask(t, s)) >> (s))
105
106 #define CHARMASK makemask(char)
107 #define SHORTMASK makemask(short)
108 #define INTMASK makemask(int)
109 #define LONGMASK makemask(long)
110
111 #ifdef DIVLBYS
112 extern long divlbys();
113 extern long modlbys();
114 #else
115 #define divlbys(val, base) ((val)/(base))
116 #define modlbys(val, base) ((val)%(base))
117 #endif
118
119 /*
120 * We use macros here to avoid the need to link to the international
121 * character routines.
122 * We don't need internationalization for our purpose.
123 */
124 #define is_dig(c) (((c) >= '0') && ((c) <= '9'))
125 #define is_cap(c) ((c) >= 'A' && (c) <= 'Z')
126 #define to_cap(c) (is_cap(c) ? c : c - 'a' + 'A')
127 #define cap_ty(c) (is_cap(c) ? 'L' : 'I')
128
129 #ifdef HAVE_LONGLONG
130 typedef union {
131 Ullong ll;
132 Ulong l[2];
133 char c[8];
134 } quad_u;
135 #endif
136
137 typedef struct f_args {
138 #ifdef FORMAT_BUFFER
139 #define BFSIZ 256
140 char *ptr; /* Current ptr in buf */
141 int cnt; /* Free char count in buf */
142 #else
143 void (*outf)__PR((char, void *)); /* Func from format(fun, arg) */
144 #endif
145 void *farg; /* Arg from format (fun, arg) */
146 int minusflag; /* Fieldwidth is negative */
147 int flags; /* General flags (+-#) */
148 int fldwidth; /* Field width as in %3d */
149 int signific; /* Significant chars as in %.4d */
150 int lzero; /* Left '0' pad flag */
151 char *buf; /* Out print buffer */
152 char *bufp; /* Write ptr into buffer */
153 char fillc; /* Left fill char (' ' or '0') */
154 char *prefix; /* Prefix to print before buf */
155 int prefixlen; /* Len of prefix ('+','-','0x') */
156 ssize_t maxlen;
157 #ifdef FORMAT_BUFFER
158 /* rarely used members last: */
159 char iobuf[BFSIZ]; /* buffer for stdio */
160 FILE *fp; /* FILE * for fprformat() */
161 int err; /* FILE * I/O error */
162 #endif
163 } f_args;
164
165 #define FMT_ARGMAX 30 /* Number of fast args */
166
167 LOCAL void prnum __PR((Ulong, unsigned, f_args *));
168 LOCAL void prdnum __PR((Ulong, f_args *));
169 LOCAL void pronum __PR((Ulong, f_args *));
170 LOCAL void prxnum __PR((Ulong, f_args *));
171 LOCAL void prXnum __PR((Ulong, f_args *));
172 #ifdef USE_LONGLONG
173 LOCAL void prlnum __PR((Ullong, unsigned, f_args *));
174 LOCAL void prldnum __PR((Ullong, f_args *));
175 LOCAL void prlonum __PR((Ullong, f_args *));
176 LOCAL void prlxnum __PR((Ullong, f_args *));
177 LOCAL void prlXnum __PR((Ullong, f_args *));
178 #endif
179 LOCAL int prbuf __PR((const char *, f_args *));
180 LOCAL int prc __PR((char, f_args *));
181 LOCAL int prstring __PR((const char *, f_args *));
182 #ifdef DEBUG
183 LOCAL void dbg_print __PR((char *fmt, int a, int b, int c, int d, int e, int f, int g, int h, int i));
184 #endif
185
186 #ifdef USE_NL_ARGS
187 #ifndef FORMAT_FUNC_NAME
188 #define FORMAT_IMPL
189 EXPORT void _fmtarglist __PR((const char *fmt, va_lists_t, va_lists_t arglist[]));
190 EXPORT void _fmtgetarg __PR((const char *fmt, int num, va_lists_t *));
191 #else
192 extern void _fmtarglist __PR((const char *fmt, va_lists_t, va_lists_t arglist[]));
193 extern void _fmtgetarg __PR((const char *fmt, int num, va_lists_t *));
194 #endif
195 #endif
196
197 #ifdef FORMAT_BUFFER
198 LOCAL char xflsbuf __PR((int c, f_args *ap));
199
200 LOCAL char
xflsbuf(c,ap)201 xflsbuf(c, ap)
202 int c;
203 f_args *ap;
204 {
205 *ap->ptr++ = c;
206 if (filewrite((FILE *)ap->fp, ap->iobuf, ap->ptr - ap->iobuf) < 0)
207 ap->err = 1;
208
209 ap->cnt = BFSIZ;
210 ap->ptr = ap->iobuf;
211 return (c);
212 }
213
214 #undef ofun
215 #define ofun(c, xp) (--((f_args *)xp)->cnt <= 0 ? \
216 xflsbuf(c, (f_args *)xp) : \
217 (*(((f_args *)xp)->ptr)++ = (c)))
218
219 #endif
220
221 #ifndef FORMAT_FUNC_NAME
222 #define FORMAT_FUNC_NAME format
223 #define FORMAT_FUNC_PARM
224
225 #define FORMAT_FUNC_PROTO_DECL void (*fun)(char, void *),
226 #define FORMAT_FUNC_KR_DECL register void (*fun)();
227 #define FORMAT_FUNC_KR_ARGS fun,
228
229 #define ofun(c, fp) (*fun)(c, fp)
230 #endif
231
232 #ifdef FORMAT_BUFFER
233 #define FARG ((void *)((UIntptr_t)farg|1))
234 #else
235 #define FARG farg
236 #endif
237
238 #ifdef PROTOTYPES
239 EXPORT int
FORMAT_FUNC_NAME(FORMAT_FUNC_PROTO_DECL void * farg,const char * fmt,va_list oargs)240 FORMAT_FUNC_NAME(FORMAT_FUNC_PROTO_DECL
241 void *farg,
242 const char *fmt,
243 va_list oargs)
244 #else
245 EXPORT int
246 FORMAT_FUNC_NAME(FORMAT_FUNC_KR_ARGS farg, fmt, oargs)
247 FORMAT_FUNC_KR_DECL
248 register void *farg;
249 register char *fmt;
250 va_list oargs;
251 #endif
252 {
253 #ifdef FORMAT_LOW_MEM
254 #define FORMAT_BSIZE 512
255 char buf[512+1];
256 #else
257 #define FORMAT_BSIZE 8192
258 char buf[8192+1];
259 #endif
260 const char *sfmt;
261 register int unsflag;
262 register long val;
263 register char type;
264 register char mode;
265 register char c;
266 int count;
267 int num;
268 int i;
269 short sh;
270 const char *str;
271 double dval;
272 #ifdef USE_LONGLONG
273 Llong llval = 0;
274 #endif
275 Ulong res;
276 char *rfmt;
277 f_args fa;
278 #ifdef USE_NL_ARGS
279 va_lists_t fargs; /* Used to get arguments */
280 va_lists_t sargs; /* Saved argument state */
281 va_lists_t arglist[FMT_ARGMAX+1]; /* List of fast args */
282 const char *ofmt = fmt; /* Saved original format */
283 BOOL didlist = FALSE; /* Need to scan arguments */
284 #endif
285
286 #ifdef FORMAT_BUFFER
287 if (((UIntptr_t)farg & 1) == 0) { /* Called externally */
288 fa.cnt = BFSIZ;
289 fa.ptr = fa.iobuf;
290 fa.fp = (FILE *)farg;
291 fa.err = 0;
292 farg = fa.farg = &fa;
293 } else { /* recursion */
294 farg = (void *)((UIntptr_t)farg & ~(UIntptr_t)1);
295 }
296 #endif
297 #ifdef FORMAT_FUNC_PARM
298 fa.outf = fun;
299 #endif
300 fa.farg = farg;
301 count = 0;
302
303 #ifdef USE_NL_ARGS
304 va_copy(sargs.ap, oargs); /* Keep a copy in sargs */
305 fargs = sargs; /* Make a working copy */
306 #endif
307
308 /*
309 * Main loop over the format string.
310 * Increment and check for end of string is made here.
311 */
312 for (; *fmt != '\0'; fmt++) {
313 c = *fmt;
314 while (c != '%') {
315 if (c == '\0')
316 goto out;
317 ofun(c, farg);
318 c = *(++fmt);
319 count++;
320 }
321
322 /*
323 * We reached a '%' sign.
324 */
325 buf[0] = '\0';
326 fa.buf = fa.bufp = buf;
327 fa.minusflag = 0;
328 fa.flags = 0;
329 fa.fldwidth = 0;
330 fa.signific = -1;
331 fa.lzero = 0;
332 fa.fillc = ' ';
333 fa.prefixlen = 0;
334 fa.maxlen = -1;
335 sfmt = fmt;
336 unsflag = FALSE;
337 type = '\0';
338 mode = '\0';
339 /*
340 * %<flags>f.s<length-mod><conversion-spec>
341 * %<flags>*.*<length-mod><conversion-spec>
342 * %n$<flags>f.s<length-mod><conversion-spec>
343 * %n$<flags>*n$.*n$<length-mod><conversion-spec>
344 */
345 newflag:
346 switch (*(++fmt)) {
347
348 case '+':
349 CHECKFLAG();
350 fa.flags |= PLUSFLG;
351 goto newflag;
352
353 case '-':
354 CHECKFLAG();
355 fa.minusflag++;
356 fa.flags |= MINUSFLG;
357 goto newflag;
358
359 case ' ':
360 CHECKFLAG();
361 /*
362 * If the space and the + flag are present,
363 * the space flag will be ignored.
364 */
365 fa.flags |= SPACEFLG;
366 goto newflag;
367
368 case '#':
369 CHECKFLAG();
370 fa.flags |= HASHFLG;
371 goto newflag;
372
373 case '\'':
374 CHECKFLAG();
375 fa.flags |= APOFLG;
376 goto newflag;
377
378 case '.':
379 fa.flags |= GOTDOT;
380 fa.signific = 0;
381 goto newflag;
382
383 case '*':
384 fa.flags |= GOTSTAR;
385 #ifdef USE_NL_ARGS
386 if (is_dig(fmt[1])) { /* *n$ */
387 fmt++; /* Eat up '*' */
388 goto dodig;
389 }
390 #endif
391 if (!(fa.flags & GOTDOT)) {
392 fa.fldwidth = va_arg(args, int);
393 /*
394 * A negative fieldwith is a minus flag with a
395 * positive fieldwidth.
396 */
397 if (fa.fldwidth < 0) {
398 fa.fldwidth = -fa.fldwidth;
399 fa.minusflag = 1;
400 fa.flags |= MINUSFLG;
401 }
402 } else {
403 /*
404 * A negative significance (precision) is taken
405 * as if the precision and '.' were omitted.
406 */
407 fa.signific = va_arg(args, int);
408 if (fa.signific < 0)
409 fa.signific = -1;
410 }
411 goto newflag;
412
413 case '0':
414 /*
415 * '0' may be a flag.
416 */
417 if (!(fa.flags & (GOTDOT | GOTSTAR | MINUSFLG))) {
418 fa.fillc = '0';
419 fa.flags |= PADZERO;
420 }
421 /* FALLTHRU */
422 case '1': case '2': case '3': case '4':
423 case '5': case '6': case '7': case '8': case '9':
424 #ifdef USE_NL_ARGS
425 dodig:
426 #endif
427 num = *fmt++ - '0';
428 while (c = *fmt, is_dig(c)) {
429 num *= 10;
430 num += c - '0';
431 fmt++;
432 }
433 #ifdef USE_NL_ARGS
434 if (c == '$')
435 goto doarglist;
436 #endif
437 fmt--; /* backup to last digit */
438 if (!(fa.flags & GOTDOT))
439 fa.fldwidth = num;
440 else
441 fa.signific = num;
442 goto newflag;
443
444 #ifdef USE_NL_ARGS
445 doarglist:
446 {
447 va_lists_t tmp; /* Temporary arg state */
448 if (num <= 0) /* Illegal arg offset */
449 goto newflag; /* Continue after '$' */
450 if (!didlist) { /* Need to init arglist */
451 _fmtarglist(ofmt, sargs, arglist);
452 didlist = TRUE;
453 }
454 if (num <= FMT_ARGMAX) {
455 tmp = arglist[num-1];
456 } else {
457 tmp = arglist[FMT_ARGMAX-1];
458 _fmtgetarg(ofmt, num, &tmp);
459 }
460 if (!(fa.flags & GOTSTAR)) {
461 fargs = tmp;
462 } else {
463 if (!(fa.flags & GOTDOT)) {
464 fa.fldwidth = va_arg(tmp.ap, int);
465 /*
466 * A negative fieldwith is a minus flag
467 * with a positive fieldwidth.
468 */
469 if (fa.fldwidth < 0) {
470 fa.fldwidth = -fa.fldwidth;
471 fa.minusflag = 1;
472 fa.flags |= MINUSFLG;
473 }
474 } else {
475 /*
476 * A negative significance (precision)
477 * is taken as if the precision and '.'
478 * were omitted.
479 */
480 fa.signific = va_arg(tmp.ap, int);
481 if (fa.signific < 0)
482 fa.signific = -1;
483 }
484 }
485 goto newflag;
486 }
487 #endif
488
489 #ifdef USE_CHECKFLAG
490 flagerror:
491 fmt = ++sfmt; /* Don't print '%' */
492 continue;
493 #endif
494 }
495 /*
496 * If the space and the + flag are present,
497 * the space flag will be ignored.
498 */
499 if ((fa.flags & (PLUSFLG|SPACEFLG)) == (PLUSFLG|SPACEFLG))
500 fa.flags &= ~SPACEFLG;
501 /*
502 * If the 0 and the - flag are present,
503 * the 0 flag will be ignored.
504 */
505 if ((fa.flags & (MINUSFLG|PADZERO)) == (MINUSFLG|PADZERO))
506 fa.flags &= ~PADZERO;
507
508 if (strchr("UCSIL", *fmt)) {
509 /*
510 * Enhancements to K&R and ANSI:
511 *
512 * got a type specifyer
513 *
514 * XXX 'S' in C99 is %ls, 'S' should become 'H'
515 */
516 if (*fmt == 'U') {
517 fmt++;
518 unsflag = TRUE;
519 }
520 if (!strchr("CSILZODX", *fmt)) {
521 /*
522 * Got only 'U'nsigned specifyer,
523 * use default type and mode.
524 */
525 type = 'I';
526 mode = 'D';
527 fmt--;
528 } else if (!strchr("CSIL", *fmt)) {
529 /*
530 * no type, use default
531 */
532 type = 'I';
533 mode = *fmt;
534 } else {
535 /*
536 * got CSIL type
537 */
538 type = *fmt++;
539 if (!strchr("ZODX", mode = *fmt)) {
540 /*
541 * Check long double "Le", "Lf" or "Lg"
542 */
543 if (type == 'L' &&
544 (mode == 'e' || mode == 'E' ||
545 mode == 'f' || mode == 'F' ||
546 mode == 'g' || mode == 'G'))
547 goto checkfmt;
548 fmt--;
549 mode = 'D'; /* default mode */
550 }
551 }
552 } else {
553 checkfmt:
554 switch (*fmt) {
555
556 case 'h':
557 if (!type)
558 type = 'H'; /* convert to short type */
559 goto getmode;
560
561 case 'l':
562 if (!type)
563 type = 'L'; /* convert to long type */
564 goto getmode;
565
566 case 'j':
567 if (!type)
568 type = 'J'; /* convert to intmax_t type */
569 goto getmode;
570
571 case 'z': /* size_t */
572 #if SIZEOF_SIZE_T == SIZEOF_INT
573 if (!type)
574 type = 'I'; /* convert to int type */
575 #else
576 #if SIZEOF_SIZE_T == SIZEOF_LONG_INT
577 if (!type)
578 type = 'L'; /* convert to long type */
579 #else
580 #if SIZEOF_SIZE_T == SIZEOF_LLONG
581 if (!type)
582 type = 'Q'; /* convert to long long type */
583 #else
584 error sizeof (size_t) is unknown
585 #endif
586 #endif
587 #endif
588 goto getmode;
589
590 case 't': /* ptrdiff_t */
591 #if SIZEOF_PTRDIFF_T == SIZEOF_INT
592 if (!type)
593 type = 'I'; /* convert to int type */
594 #else
595 #if SIZEOF_PTRDIFF_T == SIZEOF_LONG_INT
596 if (!type)
597 type = 'L'; /* convert to long type */
598 #else
599 #if SIZEOF_PTRDIFF_T == SIZEOF_LLONG
600 if (!type)
601 type = 'Q'; /* convert to long long type */
602 #else
603 error sizeof (ptrdiff_t) is unknown
604 #endif
605 #endif
606 #endif
607 /*
608 * XXX Future length modifiers:
609 * XXX 'L' with double: long double
610 */
611
612 getmode:
613 if (!strchr("udioxXn", *(++fmt))) {
614 /*
615 * %hhd -> char in decimal
616 */
617 if (type == 'H' && *fmt == 'h') {
618 type = 'C';
619 goto getmode;
620 }
621 #ifdef USE_LONGLONG
622 if (type == 'L' && *fmt == 'l') {
623 type = 'Q';
624 goto getmode;
625 }
626 #endif
627 fmt--;
628 mode = 'D';
629 } else { /* One of "udioxXn": */
630 mode = *fmt;
631 if (mode == 'n')
632 goto gotn;
633 if (mode != 'x')
634 mode = to_cap(mode);
635 if (mode == 'U')
636 unsflag = TRUE;
637 else if (mode == 'I') /* XXX */
638 mode = 'D';
639 }
640 break;
641 case 'x':
642 mode = 'x';
643 goto havemode;
644 case 'X':
645 mode = 'X';
646 type = 'I';
647 goto havemode;
648 case 'u':
649 unsflag = TRUE;
650 /*
651 * XXX Need to remove uppercase letters for 'long'
652 * XXX in future for POSIX/C99 compliance.
653 */
654 /* FALLTHRU */
655 case 'o': case 'O':
656 case 'd': case 'D':
657 case 'i': case 'I':
658 case 'Z':
659 mode = to_cap(*fmt);
660 havemode:
661 if (!type)
662 type = cap_ty(*fmt);
663 #ifdef DEBUG
664 dbg_print("*fmt: '%c' mode: '%c' type: '%c'\n",
665 *fmt, mode, type);
666 #endif
667 if (mode == 'I') /* XXX kann entfallen */
668 mode = 'D'; /* wenn besseres uflg */
669 break;
670 case 'p':
671 mode = 'P';
672 type = 'L';
673 break;
674
675 case '%':
676 count += prc('%', &fa);
677 continue;
678 case ' ':
679 count += prbuf("", &fa);
680 continue;
681 case 'c':
682 c = va_arg(args, int);
683 count += prc(c, &fa);
684 continue;
685 case 's':
686 str = va_arg(args, char *);
687 count += prstring(str, &fa);
688 continue;
689 case 'b':
690 str = va_arg(args, char *);
691 fa.signific = va_arg(args, int);
692 count += prstring(str, &fa);
693 continue;
694
695 #ifndef NO_FLOATINGPOINT
696 case 'e':
697 case 'E': {
698 int signific;
699 int fwidth = 0;
700
701 if (fa.signific == -1)
702 fa.signific = 6;
703 signific = fa.signific;
704 if (!fa.minusflag)
705 fwidth = fa.fldwidth;
706 if (*fmt == 'E')
707 fa.flags |= UPPERFLG;
708 if (type == 'L') {
709 #ifdef HAVE_LONGDOUBLE
710 long double ldval = va_arg(args, long double);
711
712 #if (defined(HAVE_QECVT) || defined(HAVE__LDECVT))
713 _qftoes(buf, ldval, fwidth, signific, fa.flags);
714 fa.fillc = ' ';
715 count += prbuf(buf, &fa);
716 continue;
717 #else
718 dval = ldval;
719 #endif
720 #endif
721 } else {
722 dval = va_arg(args, double);
723 }
724 _ftoes(buf, dval, fwidth, signific, fa.flags);
725 fa.fillc = ' ';
726 count += prbuf(buf, &fa);
727 continue;
728 }
729 case 'f':
730 case 'F': {
731 int signific;
732 int fwidth = 0;
733
734 if (fa.signific == -1)
735 fa.signific = 6;
736 signific = fa.signific;
737 if (!fa.minusflag)
738 fwidth = fa.fldwidth;
739 if (*fmt == 'F')
740 fa.flags |= UPPERFLG;
741 if (type == 'L') {
742 #ifdef HAVE_LONGDOUBLE
743 long double ldval = va_arg(args, long double);
744
745 #if (defined(HAVE_QFCVT) || defined(HAVE__LDFCVT))
746 _qftofs(buf, ldval, fwidth, signific, fa.flags);
747 fa.fillc = ' ';
748 count += prbuf(buf, &fa);
749 continue;
750 #else
751 dval = ldval;
752 #endif
753 #endif
754 } else {
755 dval = va_arg(args, double);
756 }
757 _ftofs(buf, dval, fwidth, signific, fa.flags);
758 fa.fillc = ' ';
759 count += prbuf(buf, &fa);
760 continue;
761 }
762 case 'g':
763 case 'G': {
764 int signific;
765 int fwidth = 0;
766
767 if (fa.signific == -1)
768 fa.signific = 6;
769 if (fa.signific == 0)
770 fa.signific = 1;
771 signific = fa.signific;
772 if (!fa.minusflag)
773 fwidth = fa.fldwidth;
774 if (*fmt == 'G')
775 fa.flags |= UPPERFLG;
776 if (type == 'L') {
777 #ifdef HAVE_LONGDOUBLE
778 long double ldval = va_arg(args, long double);
779
780 #if (defined(HAVE_QECVT) || defined(HAVE__LDECVT))
781 _qftogs(buf, ldval, fwidth, signific, fa.flags);
782 fa.fillc = ' ';
783 count += prbuf(buf, &fa);
784 continue;
785 #else
786 dval = ldval;
787 #endif
788 #endif
789 } else {
790 dval = va_arg(args, double);
791 }
792 _ftogs(buf, dval, fwidth, signific, fa.flags);
793 fa.fillc = ' ';
794 count += prbuf(buf, &fa);
795 continue;
796 }
797 #else
798 # ifdef USE_FLOATINGARGS
799 case 'e':
800 case 'E':
801 case 'f':
802 case 'F':
803 case 'g':
804 case 'G':
805 dval = va_arg(args, double);
806 continue;
807 # endif
808 #endif
809
810 case 'r': /* recursive printf */
811 case 'R': /* recursive printf */
812 rfmt = va_arg(args, char *);
813 /*
814 * I don't know any portable way to get an arbitrary
815 * C object from a var arg list so I use a
816 * system-specific routine __va_arg_list() that knows
817 * if 'va_list' is an array. You will not be able to
818 * assign the value of __va_arg_list() but it works
819 * to be used as an argument of a function.
820 * It is a requirement for recursive printf to be able
821 * to use this function argument. If your system
822 * defines va_list to be an array you need to know this
823 * via autoconf or another mechanism.
824 * It would be nice to have something like
825 * __va_arg_list() in stdarg.h
826 */
827 count += FORMAT_FUNC_NAME(FORMAT_FUNC_KR_ARGS
828 FARG, rfmt, __va_arg_list(args));
829 continue;
830
831 gotn:
832 case 'n':
833 switch (type) {
834
835 case 'C': {
836 signed char *cp = va_arg(args, signed char *);
837
838 *cp = count;
839 }
840 continue;
841 case 'H': {
842 short *sp = va_arg(args, short *);
843
844 *sp = count;
845 }
846 continue;
847 case 'L': {
848 long *lp = va_arg(args, long *);
849
850 *lp = count;
851 }
852 continue;
853 #ifdef USE_LONGLONG
854 case 'J': /* For now Intmax_t is Llong */
855 case 'Q': {
856 Llong *qp = va_arg(args, Llong *);
857
858 *qp = count;
859 }
860 continue;
861 #endif
862 default: {
863 int *ip = va_arg(args, int *);
864
865 *ip = count;
866 }
867 continue;
868 }
869
870 default: /* Unknown '%' format */
871 sfmt++; /* Dont't print '%' */
872 count += fmt - sfmt;
873 while (sfmt < fmt)
874 ofun(*(sfmt++), farg);
875 if (*fmt == '\0') {
876 fmt--;
877 continue;
878 } else {
879 ofun(*fmt, farg);
880 count++;
881 continue;
882 }
883 }
884 }
885 /*
886 * print numbers:
887 * first prepare type 'C'har, s'H'ort, 'I'nt, or 'L'ong
888 * or 'Q'ad and 'J'==maxint_t
889 */
890 switch (type) {
891
892 case 'C':
893 c = va_arg(args, int);
894 val = c; /* extend sign here */
895 if (unsflag || mode != 'D')
896 #ifdef DO_MASK
897 val &= CHARMASK;
898 #else
899 val = (unsigned char)val;
900 #endif
901 break;
902 case 'H':
903 case 'S': /* XXX remove 'S' in future */
904 sh = va_arg(args, int);
905 val = sh; /* extend sign here */
906 if (unsflag || mode != 'D')
907 #ifdef DO_MASK
908 val &= SHORTMASK;
909 #else
910 val = (unsigned short)val;
911 #endif
912 break;
913 case 'I':
914 default:
915 i = va_arg(args, int);
916 val = i; /* extend sign here */
917 if (unsflag || mode != 'D')
918 #ifdef DO_MASK
919 val &= INTMASK;
920 #else
921 val = (unsigned int)val;
922 #endif
923 break;
924 case 'P':
925 case 'L':
926 val = va_arg(args, long);
927 break;
928 #ifdef USE_LONGLONG
929 case 'J': /* For now Intmax_t is Llong */
930 type = 'Q'; /* use 'Q' for processing */
931 case 'Q':
932 llval = va_arg(args, Llong);
933 val = llval != 0;
934 break;
935 #endif
936 }
937
938 /*
939 * Final print out, take care of mode:
940 * mode is one of: 'O'ctal, 'D'ecimal, or he'X'
941 * oder 'Z'weierdarstellung.
942 */
943 fa.bufp = &buf[sizeof (buf)-1];
944 *--fa.bufp = '\0';
945
946 if (val == 0 && mode != 'D') {
947 printzero:
948 /*
949 * Printing '0' with fieldwidth 0 results in no chars.
950 */
951 fa.lzero = -1;
952 if (fa.signific >= 0)
953 fa.fillc = ' ';
954 count += prstring("0", &fa);
955 continue;
956 } else switch (mode) {
957
958 case 'D':
959 #ifdef USE_LONGLONG
960 if (type == 'Q') {
961 if (!unsflag && llval < 0) {
962 fa.prefix = "-";
963 fa.prefixlen = 1;
964 llval = -llval;
965 } else if (fa.flags & PLUSFLG) {
966 fa.prefix = "+";
967 fa.prefixlen = 1;
968 } else if (fa.flags & SPACEFLG) {
969 fa.prefix = " ";
970 fa.prefixlen = 1;
971 }
972 if (llval == 0)
973 goto printzero;
974 goto prunsigned;
975 }
976 #endif
977 if (!unsflag && val < 0) {
978 fa.prefix = "-";
979 fa.prefixlen = 1;
980 val = -val;
981 } else if (fa.flags & PLUSFLG) {
982 fa.prefix = "+";
983 fa.prefixlen = 1;
984 } else if (fa.flags & SPACEFLG) {
985 fa.prefix = " ";
986 fa.prefixlen = 1;
987 }
988 if (val == 0)
989 goto printzero;
990 /* FALLTHRU */
991 case 'U':
992 /* output a long unsigned decimal number */
993 #ifdef USE_LONGLONG
994 prunsigned:
995 if (type == 'Q')
996 prldnum(llval, &fa);
997 else
998 #endif
999 prdnum(val, &fa);
1000 break;
1001 case 'O': {
1002 /* output a long octal number */
1003
1004 char *p = fa.bufp;
1005 #ifdef USE_LONGLONG
1006 if (type == 'Q') {
1007 prlonum(llval, &fa);
1008 } else
1009 #endif
1010 {
1011
1012 pronum(val & 07, &fa);
1013 if ((res = (val>>3) & rshiftmask(long, 3)) != 0)
1014 pronum(res, &fa);
1015 }
1016 if ((fa.flags & HASHFLG) &&
1017 (p - fa.bufp) >= fa.signific) {
1018 /*
1019 * Add '0' only if not left zero filled
1020 * otherwise.
1021 */
1022 fa.prefix = "0";
1023 fa.prefixlen = 1;
1024 }
1025 break;
1026 }
1027 case 'p':
1028 case 'x':
1029 /* output a hex long */
1030 if (fa.flags & HASHFLG) {
1031 fa.prefix = "0x";
1032 fa.prefixlen = 2;
1033 }
1034 #ifdef USE_LONGLONG
1035 if (type == 'Q')
1036 prlxnum(llval, &fa);
1037 else
1038 #endif
1039 {
1040 prxnum(val & 0xF, &fa);
1041 if ((res = (val>>4) & rshiftmask(long, 4)) != 0)
1042 prxnum(res, &fa);
1043 }
1044 break;
1045 case 'P':
1046 case 'X':
1047 /* output a hex long */
1048 if (fa.flags & HASHFLG) {
1049 fa.prefix = "0X";
1050 fa.prefixlen = 2;
1051 }
1052 #ifdef USE_LONGLONG
1053 if (type == 'Q')
1054 prlXnum(llval, &fa);
1055 else
1056 #endif
1057 {
1058 prXnum(val & 0xF, &fa);
1059 if ((res = (val>>4) & rshiftmask(long, 4)) != 0)
1060 prXnum(res, &fa);
1061 }
1062 break;
1063 case 'Z':
1064 /* output a binary long */
1065 #ifdef USE_LONGLONG
1066 if (type == 'Q')
1067 prlnum(llval, 2, &fa);
1068 else
1069 #endif
1070 {
1071 prnum(val & 0x1, 2, &fa);
1072 if ((res = (val>>1) & rshiftmask(long, 1)) != 0)
1073 prnum(res, 2, &fa);
1074 }
1075 }
1076 fa.lzero = -1;
1077 /*
1078 * If a precision (fielwidth) is specified
1079 * on diouXx conversions, the '0' flag is ignored.
1080 */
1081 if (fa.signific >= 0)
1082 fa.fillc = ' ';
1083 count += prbuf(fa.bufp, &fa);
1084 }
1085 out:
1086 #ifdef FORMAT_BUFFER
1087 if (farg == &fa) { /* Top level call, flush buffer */
1088 if (fa.err)
1089 return (EOF);
1090 if ((fa.ptr != fa.iobuf) &&
1091 (filewrite(fa.fp, fa.iobuf, fa.ptr - fa.iobuf) < 0))
1092 return (EOF);
1093 }
1094 #endif
1095 return (count);
1096 }
1097
1098 /*
1099 * Routines to print (not negative) numbers in an arbitrary base
1100 */
1101 LOCAL unsigned char dtab[] = "0123456789abcdef";
1102 LOCAL unsigned char udtab[] = "0123456789ABCDEF";
1103
1104 LOCAL void
prnum(val,base,fa)1105 prnum(val, base, fa)
1106 register Ulong val;
1107 register unsigned base;
1108 f_args *fa;
1109 {
1110 register char *p = fa->bufp;
1111
1112 do {
1113 *--p = dtab[modlbys(val, base)];
1114 val = divlbys(val, base);
1115 } while (val > 0);
1116
1117 fa->bufp = p;
1118 }
1119
1120 LOCAL void
prdnum(val,fa)1121 prdnum(val, fa)
1122 register Ulong val;
1123 f_args *fa;
1124 {
1125 register char *p = fa->bufp;
1126
1127 do {
1128 *--p = dtab[modlbys(val, (unsigned)10)];
1129 val = divlbys(val, (unsigned)10);
1130 } while (val > 0);
1131
1132 fa->bufp = p;
1133 }
1134
1135 /*
1136 * We may need to use division here too (PDP-11, non two's complement ...)
1137 */
1138 LOCAL void
pronum(val,fa)1139 pronum(val, fa)
1140 register Ulong val;
1141 f_args *fa;
1142 {
1143 register char *p = fa->bufp;
1144
1145 do {
1146 *--p = dtab[val & 7];
1147 val >>= 3;
1148 } while (val > 0);
1149
1150 fa->bufp = p;
1151 }
1152
1153 LOCAL void
prxnum(val,fa)1154 prxnum(val, fa)
1155 register Ulong val;
1156 f_args *fa;
1157 {
1158 register char *p = fa->bufp;
1159
1160 do {
1161 *--p = dtab[val & 15];
1162 val >>= 4;
1163 } while (val > 0);
1164
1165 fa->bufp = p;
1166 }
1167
1168 LOCAL void
prXnum(val,fa)1169 prXnum(val, fa)
1170 register Ulong val;
1171 f_args *fa;
1172 {
1173 register char *p = fa->bufp;
1174
1175 do {
1176 *--p = udtab[val & 15];
1177 val >>= 4;
1178 } while (val > 0);
1179
1180 fa->bufp = p;
1181 }
1182
1183 #ifdef USE_LONGLONG
1184 LOCAL void
prlnum(val,base,fa)1185 prlnum(val, base, fa)
1186 register Ullong val;
1187 register unsigned base;
1188 f_args *fa;
1189 {
1190 register char *p = fa->bufp;
1191
1192 do {
1193 *--p = dtab[modlbys(val, base)];
1194 val = divlbys(val, base);
1195 } while (val > 0);
1196
1197 fa->bufp = p;
1198 }
1199
1200 LOCAL void
prldnum(val,fa)1201 prldnum(val, fa)
1202 register Ullong val;
1203 f_args *fa;
1204 {
1205 register char *p = fa->bufp;
1206
1207 do {
1208 *--p = dtab[val % (unsigned)10];
1209 val = val / (unsigned)10;
1210 } while (val > 0);
1211
1212 fa->bufp = p;
1213 }
1214
1215 LOCAL void
prlonum(val,fa)1216 prlonum(val, fa)
1217 register Ullong val;
1218 f_args *fa;
1219 {
1220 register char *p = fa->bufp;
1221
1222 do {
1223 *--p = dtab[val & 7];
1224 val >>= 3;
1225 } while (val > 0);
1226
1227 fa->bufp = p;
1228 }
1229
1230 LOCAL void
prlxnum(val,fa)1231 prlxnum(val, fa)
1232 register Ullong val;
1233 f_args *fa;
1234 {
1235 register char *p = fa->bufp;
1236
1237 do {
1238 *--p = dtab[val & 15];
1239 val >>= 4;
1240 } while (val > 0);
1241
1242 fa->bufp = p;
1243 }
1244
1245 LOCAL void
prlXnum(val,fa)1246 prlXnum(val, fa)
1247 register Ullong val;
1248 f_args *fa;
1249 {
1250 register char *p = fa->bufp;
1251
1252 do {
1253 *--p = udtab[val & 15];
1254 val >>= 4;
1255 } while (val > 0);
1256
1257 fa->bufp = p;
1258 }
1259
1260 #endif
1261
1262 /*
1263 * Final buffer print out routine.
1264 */
1265 LOCAL int
prbuf(s,fa)1266 prbuf(s, fa)
1267 register const char *s;
1268 f_args *fa;
1269 {
1270 register int diff;
1271 register int rfillc;
1272 register void *arg = fa->farg;
1273 #ifdef FORMAT_FUNC_PARM
1274 register void (*fun) __PR((char, void *)) = fa->outf;
1275 #endif
1276 register int count;
1277 register int lzero = 0;
1278
1279 if (fa->maxlen < 0)
1280 count = strlen(s);
1281 else
1282 count = fa->maxlen;
1283
1284 /*
1285 * lzero becomes the number of left fill chars needed to reach signific
1286 */
1287 if (fa->lzero < 0 && count < fa->signific)
1288 lzero = fa->signific - count;
1289 count += lzero + fa->prefixlen;
1290 diff = fa->fldwidth - count;
1291 if (diff > 0)
1292 count += diff;
1293
1294 if (fa->prefixlen && fa->fillc != ' ') {
1295 while (*fa->prefix != '\0')
1296 ofun(*fa->prefix++, arg);
1297 }
1298 if (!fa->minusflag) {
1299 rfillc = fa->fillc;
1300 while (--diff >= 0)
1301 ofun(rfillc, arg);
1302 }
1303 if (fa->prefixlen && fa->fillc == ' ') {
1304 while (*fa->prefix != '\0')
1305 ofun(*fa->prefix++, arg);
1306 }
1307 if (lzero > 0) {
1308 rfillc = '0';
1309 while (--lzero >= 0)
1310 ofun(rfillc, arg);
1311 }
1312 if (fa->maxlen < 0) {
1313 while (*s != '\0')
1314 ofun(*s++, arg);
1315 } else {
1316 register size_t len = fa->maxlen;
1317
1318 if (len > 0) {
1319 len++;
1320 while (--len > 0)
1321 ofun(*s++, arg);
1322 }
1323 }
1324 if (fa->minusflag) {
1325 rfillc = ' ';
1326 while (--diff >= 0)
1327 ofun(rfillc, arg);
1328 }
1329 return (count);
1330 }
1331
1332 /*
1333 * Print out one char, allowing prc('\0')
1334 * Similar to prbuf()
1335 */
1336 #ifdef PROTOTYPES
1337
1338 LOCAL int
prc(char c,f_args * fa)1339 prc(char c, f_args *fa)
1340
1341 #else
1342
1343 LOCAL int
1344 prc(c, fa)
1345 char c;
1346 f_args *fa;
1347 #endif
1348 {
1349 register int diff;
1350 register int rfillc;
1351 register void *arg = fa->farg;
1352 #ifdef FORMAT_FUNC_PARM
1353 register void (*fun) __PR((char, void *)) = fa->outf;
1354 #endif
1355 register int count;
1356
1357 count = 1;
1358 diff = fa->fldwidth - 1;
1359 if (diff > 0)
1360 count += diff;
1361
1362 if (!fa->minusflag) {
1363 rfillc = fa->fillc;
1364 while (--diff >= 0)
1365 ofun(rfillc, arg);
1366 }
1367 ofun(c, arg);
1368 if (fa->minusflag) {
1369 rfillc = ' ';
1370 while (--diff >= 0)
1371 ofun(rfillc, arg);
1372 }
1373 return (count);
1374 }
1375
1376 /*
1377 * String output routine.
1378 * If fa->signific is >= 0, it uses only fa->signific chars.
1379 * If fa->signific is 0, print no characters.
1380 */
1381 LOCAL int
prstring(s,fa)1382 prstring(s, fa)
1383 register const char *s;
1384 f_args *fa;
1385 {
1386 if (s == NULL)
1387 return (prbuf("(NULL POINTER)", fa));
1388
1389 if (fa->signific < 0)
1390 return (prbuf(s, fa));
1391
1392 fa->maxlen = strnlen(s, fa->signific);
1393 return (prbuf(s, fa));
1394 }
1395
1396 #ifdef DEBUG
1397 LOCAL void
dbg_print(fmt,a,b,c,d,e,f,g,h,i)1398 dbg_print(fmt, a, b, c, d, e, f, g, h, i)
1399 char *fmt;
1400 {
1401 char ff[1024];
1402
1403 sprintf(ff, fmt, a, b, c, d, e, f, g, h, i);
1404 write(STDERR_FILENO, ff, strlen(ff));
1405 }
1406 #endif
1407
1408 #ifdef USE_NL_ARGS
1409 #ifdef FORMAT_IMPL
1410 /*
1411 * The following code is shared between format() and fprformat().
1412 */
1413
1414 /*
1415 * Format argument types.
1416 * As "char" and "short" type arguments are fetched as "int"
1417 * we start with size "int" and ignore the 'h' modifier when
1418 * parsing sizes.
1419 */
1420 #define AT_NONE 0
1421 #define AT_INT 1
1422 #define AT_LONG 2
1423 #define AT_LONG_LONG 3
1424 #define AT_DOUBLE 4
1425 #define AT_LONG_DOUBLE 5
1426 #define AT_VOID_PTR 6
1427 #define AT_CHAR_PTR 7
1428 #define AT_SHORT_PTR 8
1429 #define AT_INT_PTR 9
1430 #define AT_LONG_PTR 10
1431 #define AT_LONG_LONG_PTR 11
1432 #define AT_R_FMT 12
1433 #define AT_R_VA_LIST 13
1434 #define AT_BOUNDS 14
1435
1436 #define AF_NONE 0
1437 #define AF_LONG 1
1438 #define AF_LONG_LONG 2
1439 #define AF_LONG_DOUBLE 4
1440 #define AF_STAR 8
1441
1442 static const char skips[] = "+- #'.$h1234567890";
1443 static const char *digits = &skips[8];
1444
1445 /*
1446 * Parse the format string and store the first FMT_ARGMAX args in the arglist
1447 * parameter.
1448 *
1449 * This is done in two stages:
1450 * 1 parse the format string and store the types in argtypes[].
1451 * 2 use the type list in argtypes[], fetch the args in order and
1452 * store the related va_list state in arglist[]
1453 */
1454 EXPORT void
_fmtarglist(fmt,fargs,arglist)1455 _fmtarglist(fmt, fargs, arglist)
1456 const char *fmt;
1457 va_lists_t fargs;
1458 va_lists_t arglist[];
1459 {
1460 int i;
1461 int argindex;
1462 int maxindex;
1463 int thistype;
1464 int thisflag;
1465 int argtypes[FMT_ARGMAX+1];
1466
1467 for (i = 0; i < FMT_ARGMAX; i++)
1468 argtypes[i] = AT_NONE;
1469
1470 maxindex = -1;
1471 argindex = 0;
1472 while ((fmt = strchr(fmt, '%')) != NULL) {
1473 fmt++;
1474 i = strspn(fmt, digits);
1475 if (fmt[i] == '$') {
1476 int c;
1477
1478 argindex = *fmt++ - '0';
1479 while (c = *fmt, is_dig(c)) {
1480 argindex *= 10;
1481 argindex += c - '0';
1482 fmt++;
1483 }
1484 argindex -= 1;
1485 }
1486 thistype = AT_NONE;
1487 thisflag = AF_NONE;
1488 newarg:
1489 fmt += strspn(fmt, skips);
1490 switch (*fmt++) {
1491
1492 case '%': /* %% format no arg */
1493 continue;
1494
1495 case 'l':
1496 if (thisflag & AF_LONG) {
1497 thisflag |= AF_LONG_LONG;
1498 } else {
1499 thisflag |= AF_LONG;
1500 }
1501 goto newarg;
1502 case 'j': /* intmax_t for now is long long */
1503 thisflag |= AF_LONG_LONG;
1504 goto newarg;
1505 case 'z': /* size_t */
1506 #if SIZEOF_SIZE_T == SIZEOF_INT
1507 if (thistype == AT_NONE)
1508 thistype = AT_INT;
1509 #else
1510 #if SIZEOF_SIZE_T == SIZEOF_LONG_INT
1511 if (thistype == AT_NONE)
1512 thistype = AT_LONG;
1513 #else
1514 #if SIZEOF_SIZE_T == SIZEOF_LLONG
1515 if (thistype == AT_NONE)
1516 thistype = AT_LONG_LONG;
1517 #else
1518 error sizeof (size_t) is unknown
1519 #endif
1520 #endif
1521 #endif
1522 goto newarg;
1523 case 't': /* ptrdiff_t */
1524 #if SIZEOF_PTRDIFF_T == SIZEOF_INT
1525 if (thistype == AT_NONE)
1526 thistype = AT_INT;
1527 #else
1528 #if SIZEOF_PTRDIFF_T == SIZEOF_LONG_INT
1529 if (thistype == AT_NONE)
1530 thistype = AT_LONG;
1531 #else
1532 #if SIZEOF_PTRDIFF_T == SIZEOF_LLONG
1533 if (thistype == AT_NONE)
1534 thistype = AT_LONG_LONG;
1535 #else
1536 error sizeof (ptrdiff_t) is unknown
1537 #endif
1538 #endif
1539 #endif
1540 goto newarg;
1541 #ifndef NO_UCSIL
1542 /*
1543 * Enhancements to K&R and ANSI:
1544 *
1545 * got a type specifyer
1546 *
1547 * XXX 'S' in C99 is %ls, 'S' should become 'H'
1548 */
1549 case 'U':
1550 if (!strchr("CSILZODX", *fmt)) {
1551 /*
1552 * Got only 'U'nsigned specifyer,
1553 * use default type and mode.
1554 */
1555 thistype = AT_INT;
1556 break;
1557 }
1558 if (!strchr("CSIL", *fmt)) {
1559 /*
1560 * Got 'U' and ZODX.
1561 * no type, use default
1562 */
1563 thistype = AT_INT;
1564 fmt++; /* Skip ZODX */
1565 break;
1566 }
1567 fmt++; /* Unsigned, skip 'U', get CSIL */
1568 /* FALLTHRU */
1569 case 'C':
1570 case 'S':
1571 case 'I':
1572 case 'L':
1573 fmt--; /* Undo fmt++ from switch() */
1574 {
1575 /*
1576 * got CSIL type
1577 */
1578 int type = *fmt++; /* Undo above fmt-- */
1579 int mode = *fmt;
1580 if (!strchr("ZODX", mode)) {
1581 /*
1582 * Check long double "Le", "Lf" or "Lg"
1583 */
1584 if (type == 'L' &&
1585 (mode == 'e' ||
1586 mode == 'f' ||
1587 mode == 'g')) {
1588 thisflag |= AF_LONG_DOUBLE;
1589 goto newarg;
1590 }
1591 } else {
1592 fmt++; /* Skip ZODX */
1593 }
1594 if (type == 'L')
1595 thistype = AT_LONG;
1596 else
1597 thistype = AT_INT;
1598 }
1599 break;
1600 #else
1601 case 'L':
1602 thisflag |= AF_LONG_DOUBLE;
1603 goto newarg;
1604 #endif
1605
1606 case 'e':
1607 case 'E':
1608 case 'f':
1609 case 'F':
1610 case 'g':
1611 case 'G':
1612 if (thisflag & AF_LONG_DOUBLE)
1613 thistype = AT_LONG_DOUBLE;
1614 else
1615 thistype = AT_DOUBLE;
1616 break;
1617
1618 case 'p':
1619 thistype = AT_VOID_PTR;
1620 break;
1621 case 's':
1622 thistype = AT_CHAR_PTR;
1623 break;
1624 case 'b':
1625 thistype = AT_BOUNDS;
1626 break;
1627 case 'n':
1628 if (thisflag & AF_LONG_LONG)
1629 thistype = AT_LONG_LONG_PTR;
1630 else if (thistype & AF_LONG)
1631 thistype = AT_LONG_PTR;
1632 else
1633 thistype = AT_INT_PTR;
1634 break;
1635 case 'r':
1636 thistype = AT_R_FMT;
1637 break;
1638 default:
1639 if (thistype == AT_NONE) {
1640 if (thisflag & AF_LONG_LONG)
1641 thistype = AT_LONG_LONG;
1642 else if (thistype & AF_LONG)
1643 thistype = AT_LONG;
1644 else
1645 thistype = AT_INT;
1646 }
1647 break;
1648
1649 case '*':
1650 if (is_dig(*fmt)) {
1651 int c;
1652 int starindex;
1653
1654 starindex = *fmt++ - '0';
1655 while (c = *fmt, is_dig(c)) {
1656 starindex *= 10;
1657 starindex += c - '0';
1658 fmt++;
1659 }
1660 starindex -= 1;
1661 if (starindex >= 0 && starindex < FMT_ARGMAX) {
1662 argtypes[starindex] = AT_INT;
1663 if (starindex > maxindex)
1664 maxindex = starindex;
1665 }
1666 goto newarg;
1667 }
1668 thistype = AT_INT;
1669 thisflag |= AF_STAR; /* Make sure to rescan for type */
1670 break;
1671 }
1672 if (argindex >= 0 && argindex < FMT_ARGMAX) {
1673 argtypes[argindex] = thistype;
1674 if (thistype == AT_R_FMT)
1675 argtypes[++argindex] = AT_R_VA_LIST;
1676 else if (thistype == AT_BOUNDS)
1677 argtypes[++argindex] = AT_INT;
1678
1679 if (argindex > maxindex)
1680 maxindex = argindex;
1681 }
1682 ++argindex; /* Default to next arg in list */
1683 if (thisflag & AF_STAR) { /* Found '*', continue for type */
1684 thisflag &= ~AF_STAR;
1685 goto newarg;
1686 }
1687 }
1688
1689 for (i = 0; i <= maxindex; i++) { /* Do not fetch more args than known */
1690 arglist[i] = fargs; /* Save state before fetching this */
1691
1692 switch (argtypes[i]) {
1693
1694 default:
1695 /* FALLTHRU */
1696 case AT_NONE: /* This matches '*' args */
1697 /* FALLTHRU */
1698 case AT_INT:
1699 (void) va_arg(fargs.ap, int);
1700 break;
1701 case AT_LONG:
1702 (void) va_arg(fargs.ap, long);
1703 break;
1704 case AT_LONG_LONG:
1705 (void) va_arg(fargs.ap, Llong);
1706 break;
1707 case AT_DOUBLE:
1708 (void) va_arg(fargs.ap, double);
1709 break;
1710 case AT_LONG_DOUBLE:
1711 #ifdef HAVE_LONGDOUBLE
1712 (void) va_arg(fargs.ap, long double);
1713 #endif
1714 break;
1715 case AT_VOID_PTR:
1716 (void) va_arg(fargs.ap, void *);
1717 break;
1718 case AT_CHAR_PTR:
1719 (void) va_arg(fargs.ap, char *);
1720 break;
1721 case AT_SHORT_PTR:
1722 (void) va_arg(fargs.ap, short *);
1723 break;
1724 case AT_INT_PTR:
1725 (void) va_arg(fargs.ap, int *);
1726 break;
1727 case AT_LONG_PTR:
1728 (void) va_arg(fargs.ap, long *);
1729 break;
1730 case AT_LONG_LONG_PTR:
1731 (void) va_arg(fargs.ap, Llong *);
1732 break;
1733 case AT_R_FMT:
1734 (void) va_arg(fargs.ap, char *);
1735 arglist[++i] = fargs;
1736 (void) __va_arg_list(fargs.ap);
1737 break;
1738 case AT_R_VA_LIST:
1739 break;
1740 case AT_BOUNDS:
1741 (void) va_arg(fargs.ap, char *);
1742 arglist[++i] = fargs;
1743 (void) va_arg(fargs.ap, int);
1744 break;
1745 }
1746 }
1747 }
1748
1749 /*
1750 * In case that the format references an argument > FMT_ARGMAX, we use this
1751 * implementation. It is slow (n*n - where n is (argno - FMT_ARGMAX)).
1752 * Fortunately, it is most unlikely that there are more positional args than
1753 * the current FMT_ARGMAX definition of 30.
1754 */
1755 EXPORT void
_fmtgetarg(fmt,num,fargs)1756 _fmtgetarg(fmt, num, fargs)
1757 const char *fmt;
1758 int num;
1759 va_lists_t *fargs;
1760 {
1761 const char *sfmt = fmt;
1762 int i;
1763
1764 /*
1765 * Hacky preliminary support for all int type args bejond FMT_ARGMAX.
1766 */
1767 for (i = FMT_ARGMAX; i < num; i++)
1768 (void) va_arg((*fargs).ap, int);
1769 }
1770 #endif /* FORMAT_IMPL */
1771 #endif /* USE_NL_ARGS */
1772