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