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