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