xref: /minix3/external/bsd/top/dist/ap_snprintf.c (revision b89261ba018da33f0bd8cd05f5a1fe9e7a9c837b)
1*b89261baSDavid van Moolenbroek /* Licensed to the Apache Software Foundation (ASF) under one or more
2*b89261baSDavid van Moolenbroek  * contributor license agreements.  See the NOTICE file distributed with
3*b89261baSDavid van Moolenbroek  * this work for additional information regarding copyright ownership.
4*b89261baSDavid van Moolenbroek  * The ASF licenses this file to You under the Apache License, Version 2.0
5*b89261baSDavid van Moolenbroek  * (the "License"); you may not use this file except in compliance with
6*b89261baSDavid van Moolenbroek  * the License.  You may obtain a copy of the License at
7*b89261baSDavid van Moolenbroek  *
8*b89261baSDavid van Moolenbroek  *     http://www.apache.org/licenses/LICENSE-2.0
9*b89261baSDavid van Moolenbroek  *
10*b89261baSDavid van Moolenbroek  * Unless required by applicable law or agreed to in writing, software
11*b89261baSDavid van Moolenbroek  * distributed under the License is distributed on an "AS IS" BASIS,
12*b89261baSDavid van Moolenbroek  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*b89261baSDavid van Moolenbroek  * See the License for the specific language governing permissions and
14*b89261baSDavid van Moolenbroek  * limitations under the License.
15*b89261baSDavid van Moolenbroek  */
16*b89261baSDavid van Moolenbroek 
17*b89261baSDavid van Moolenbroek /*
18*b89261baSDavid van Moolenbroek  * This code is based on, and used with the permission of, the
19*b89261baSDavid van Moolenbroek  * SIO stdio-replacement strx_* functions by Panos Tsirigotis
20*b89261baSDavid van Moolenbroek  * <panos@alumni.cs.colorado.edu> for xinetd.
21*b89261baSDavid van Moolenbroek  */
22*b89261baSDavid van Moolenbroek 
23*b89261baSDavid van Moolenbroek #include "config.h"
24*b89261baSDavid van Moolenbroek #include <stdio.h>
25*b89261baSDavid van Moolenbroek #include <ctype.h>
26*b89261baSDavid van Moolenbroek #include <sys/types.h>
27*b89261baSDavid van Moolenbroek #include <stdarg.h>
28*b89261baSDavid van Moolenbroek #include <string.h>
29*b89261baSDavid van Moolenbroek #include <stdlib.h>
30*b89261baSDavid van Moolenbroek #include <math.h>
31*b89261baSDavid van Moolenbroek #include <netinet/in.h>
32*b89261baSDavid van Moolenbroek 
33*b89261baSDavid van Moolenbroek #ifdef HAVE_LIMITS_H
34*b89261baSDavid van Moolenbroek #include <limits.h>
35*b89261baSDavid van Moolenbroek #endif
36*b89261baSDavid van Moolenbroek 
37*b89261baSDavid van Moolenbroek typedef struct {
38*b89261baSDavid van Moolenbroek     char *curpos;
39*b89261baSDavid van Moolenbroek     char *endpos;
40*b89261baSDavid van Moolenbroek } ap_vformatter_buff;
41*b89261baSDavid van Moolenbroek 
42*b89261baSDavid van Moolenbroek 
43*b89261baSDavid van Moolenbroek #define API_EXPORT(type) type
44*b89261baSDavid van Moolenbroek #define API_EXPORT_NONSTD(type) type
45*b89261baSDavid van Moolenbroek 
46*b89261baSDavid van Moolenbroek #define ap_isalnum(c) (isalnum(((unsigned char)(c))))
47*b89261baSDavid van Moolenbroek #define ap_isalpha(c) (isalpha(((unsigned char)(c))))
48*b89261baSDavid van Moolenbroek #define ap_iscntrl(c) (iscntrl(((unsigned char)(c))))
49*b89261baSDavid van Moolenbroek #define ap_isdigit(c) (isdigit(((unsigned char)(c))))
50*b89261baSDavid van Moolenbroek #define ap_isgraph(c) (isgraph(((unsigned char)(c))))
51*b89261baSDavid van Moolenbroek #define ap_islower(c) (islower(((unsigned char)(c))))
52*b89261baSDavid van Moolenbroek #define ap_isprint(c) (isprint(((unsigned char)(c))))
53*b89261baSDavid van Moolenbroek #define ap_ispunct(c) (ispunct(((unsigned char)(c))))
54*b89261baSDavid van Moolenbroek #define ap_isspace(c) (isspace(((unsigned char)(c))))
55*b89261baSDavid van Moolenbroek #define ap_isupper(c) (isupper(((unsigned char)(c))))
56*b89261baSDavid van Moolenbroek #define ap_isxdigit(c) (isxdigit(((unsigned char)(c))))
57*b89261baSDavid van Moolenbroek #define ap_tolower(c) (tolower(((unsigned char)(c))))
58*b89261baSDavid van Moolenbroek #define ap_toupper(c) (toupper(((unsigned char)(c))))
59*b89261baSDavid van Moolenbroek 
60*b89261baSDavid van Moolenbroek 
61*b89261baSDavid van Moolenbroek typedef enum {
62*b89261baSDavid van Moolenbroek     NO = 0, YES = 1
63*b89261baSDavid van Moolenbroek } boolean_e;
64*b89261baSDavid van Moolenbroek 
65*b89261baSDavid van Moolenbroek #ifndef FALSE
66*b89261baSDavid van Moolenbroek #define FALSE			0
67*b89261baSDavid van Moolenbroek #endif
68*b89261baSDavid van Moolenbroek #ifndef TRUE
69*b89261baSDavid van Moolenbroek #define TRUE			1
70*b89261baSDavid van Moolenbroek #endif
71*b89261baSDavid van Moolenbroek #ifndef AP_LONGEST_LONG
72*b89261baSDavid van Moolenbroek #define AP_LONGEST_LONG		long
73*b89261baSDavid van Moolenbroek #endif
74*b89261baSDavid van Moolenbroek #define NUL			'\0'
75*b89261baSDavid van Moolenbroek #define WIDE_INT		long
76*b89261baSDavid van Moolenbroek #define WIDEST_INT		AP_LONGEST_LONG
77*b89261baSDavid van Moolenbroek 
78*b89261baSDavid van Moolenbroek typedef WIDE_INT wide_int;
79*b89261baSDavid van Moolenbroek typedef unsigned WIDE_INT u_wide_int;
80*b89261baSDavid van Moolenbroek typedef WIDEST_INT widest_int;
81*b89261baSDavid van Moolenbroek #ifdef __TANDEM
82*b89261baSDavid van Moolenbroek /* Although Tandem supports "long long" there is no unsigned variant. */
83*b89261baSDavid van Moolenbroek typedef unsigned long       u_widest_int;
84*b89261baSDavid van Moolenbroek #else
85*b89261baSDavid van Moolenbroek typedef unsigned WIDEST_INT u_widest_int;
86*b89261baSDavid van Moolenbroek #endif
87*b89261baSDavid van Moolenbroek typedef int bool_int;
88*b89261baSDavid van Moolenbroek 
89*b89261baSDavid van Moolenbroek #define S_NULL			"(null)"
90*b89261baSDavid van Moolenbroek #define S_NULL_LEN		6
91*b89261baSDavid van Moolenbroek 
92*b89261baSDavid van Moolenbroek #define FLOAT_DIGITS		6
93*b89261baSDavid van Moolenbroek #define EXPONENT_LENGTH		10
94*b89261baSDavid van Moolenbroek 
95*b89261baSDavid van Moolenbroek /*
96*b89261baSDavid van Moolenbroek  * NUM_BUF_SIZE is the size of the buffer used for arithmetic conversions
97*b89261baSDavid van Moolenbroek  *
98*b89261baSDavid van Moolenbroek  * XXX: this is a magic number; do not decrease it
99*b89261baSDavid van Moolenbroek  */
100*b89261baSDavid van Moolenbroek #define NUM_BUF_SIZE		512
101*b89261baSDavid van Moolenbroek 
102*b89261baSDavid van Moolenbroek /*
103*b89261baSDavid van Moolenbroek  * cvt.c - IEEE floating point formatting routines for FreeBSD
104*b89261baSDavid van Moolenbroek  * from GNU libc-4.6.27.  Modified to be thread safe.
105*b89261baSDavid van Moolenbroek  */
106*b89261baSDavid van Moolenbroek 
107*b89261baSDavid van Moolenbroek /*
108*b89261baSDavid van Moolenbroek  *    ap_ecvt converts to decimal
109*b89261baSDavid van Moolenbroek  *      the number of digits is specified by ndigit
110*b89261baSDavid van Moolenbroek  *      decpt is set to the position of the decimal point
111*b89261baSDavid van Moolenbroek  *      sign is set to 0 for positive, 1 for negative
112*b89261baSDavid van Moolenbroek  */
113*b89261baSDavid van Moolenbroek 
114*b89261baSDavid van Moolenbroek #define	NDIG	80
115*b89261baSDavid van Moolenbroek 
116*b89261baSDavid van Moolenbroek /* buf must have at least NDIG bytes */
ap_cvt(double arg,int ndigits,int * decpt,int * sign,int eflag,char * buf)117*b89261baSDavid van Moolenbroek static char *ap_cvt(double arg, int ndigits, int *decpt, int *sign, int eflag, char *buf)
118*b89261baSDavid van Moolenbroek {
119*b89261baSDavid van Moolenbroek     register int r2;
120*b89261baSDavid van Moolenbroek     double fi, fj;
121*b89261baSDavid van Moolenbroek     register char *p, *p1;
122*b89261baSDavid van Moolenbroek 
123*b89261baSDavid van Moolenbroek     if (ndigits >= NDIG - 1)
124*b89261baSDavid van Moolenbroek 	ndigits = NDIG - 2;
125*b89261baSDavid van Moolenbroek     r2 = 0;
126*b89261baSDavid van Moolenbroek     *sign = 0;
127*b89261baSDavid van Moolenbroek     p = &buf[0];
128*b89261baSDavid van Moolenbroek     if (arg < 0) {
129*b89261baSDavid van Moolenbroek 	*sign = 1;
130*b89261baSDavid van Moolenbroek 	arg = -arg;
131*b89261baSDavid van Moolenbroek     }
132*b89261baSDavid van Moolenbroek     arg = modf(arg, &fi);
133*b89261baSDavid van Moolenbroek     p1 = &buf[NDIG];
134*b89261baSDavid van Moolenbroek     /*
135*b89261baSDavid van Moolenbroek      * Do integer part
136*b89261baSDavid van Moolenbroek      */
137*b89261baSDavid van Moolenbroek     if (fi != 0) {
138*b89261baSDavid van Moolenbroek 	p1 = &buf[NDIG];
139*b89261baSDavid van Moolenbroek 	while (p1 > &buf[0] && fi != 0) {
140*b89261baSDavid van Moolenbroek 	    fj = modf(fi / 10, &fi);
141*b89261baSDavid van Moolenbroek 	    *--p1 = (int) ((fj + .03) * 10) + '0';
142*b89261baSDavid van Moolenbroek 	    r2++;
143*b89261baSDavid van Moolenbroek 	}
144*b89261baSDavid van Moolenbroek 	while (p1 < &buf[NDIG])
145*b89261baSDavid van Moolenbroek 	    *p++ = *p1++;
146*b89261baSDavid van Moolenbroek     }
147*b89261baSDavid van Moolenbroek     else if (arg > 0) {
148*b89261baSDavid van Moolenbroek 	while ((fj = arg * 10) < 1) {
149*b89261baSDavid van Moolenbroek 	    arg = fj;
150*b89261baSDavid van Moolenbroek 	    r2--;
151*b89261baSDavid van Moolenbroek 	}
152*b89261baSDavid van Moolenbroek     }
153*b89261baSDavid van Moolenbroek     p1 = &buf[ndigits];
154*b89261baSDavid van Moolenbroek     if (eflag == 0)
155*b89261baSDavid van Moolenbroek 	p1 += r2;
156*b89261baSDavid van Moolenbroek     *decpt = r2;
157*b89261baSDavid van Moolenbroek     if (p1 < &buf[0]) {
158*b89261baSDavid van Moolenbroek 	buf[0] = '\0';
159*b89261baSDavid van Moolenbroek 	return (buf);
160*b89261baSDavid van Moolenbroek     }
161*b89261baSDavid van Moolenbroek     while (p <= p1 && p < &buf[NDIG]) {
162*b89261baSDavid van Moolenbroek 	arg *= 10;
163*b89261baSDavid van Moolenbroek 	arg = modf(arg, &fj);
164*b89261baSDavid van Moolenbroek 	*p++ = (int) fj + '0';
165*b89261baSDavid van Moolenbroek     }
166*b89261baSDavid van Moolenbroek     if (p1 >= &buf[NDIG]) {
167*b89261baSDavid van Moolenbroek 	buf[NDIG - 1] = '\0';
168*b89261baSDavid van Moolenbroek 	return (buf);
169*b89261baSDavid van Moolenbroek     }
170*b89261baSDavid van Moolenbroek     p = p1;
171*b89261baSDavid van Moolenbroek     *p1 += 5;
172*b89261baSDavid van Moolenbroek     while (*p1 > '9') {
173*b89261baSDavid van Moolenbroek 	*p1 = '0';
174*b89261baSDavid van Moolenbroek 	if (p1 > buf)
175*b89261baSDavid van Moolenbroek 	    ++ * --p1;
176*b89261baSDavid van Moolenbroek 	else {
177*b89261baSDavid van Moolenbroek 	    *p1 = '1';
178*b89261baSDavid van Moolenbroek 	    (*decpt)++;
179*b89261baSDavid van Moolenbroek 	    if (eflag == 0) {
180*b89261baSDavid van Moolenbroek 		if (p > buf)
181*b89261baSDavid van Moolenbroek 		    *p = '0';
182*b89261baSDavid van Moolenbroek 		p++;
183*b89261baSDavid van Moolenbroek 	    }
184*b89261baSDavid van Moolenbroek 	}
185*b89261baSDavid van Moolenbroek     }
186*b89261baSDavid van Moolenbroek     *p = '\0';
187*b89261baSDavid van Moolenbroek     return (buf);
188*b89261baSDavid van Moolenbroek }
189*b89261baSDavid van Moolenbroek 
ap_ecvt(double arg,int ndigits,int * decpt,int * sign,char * buf)190*b89261baSDavid van Moolenbroek static char *ap_ecvt(double arg, int ndigits, int *decpt, int *sign, char *buf)
191*b89261baSDavid van Moolenbroek {
192*b89261baSDavid van Moolenbroek     return (ap_cvt(arg, ndigits, decpt, sign, 1, buf));
193*b89261baSDavid van Moolenbroek }
194*b89261baSDavid van Moolenbroek 
ap_fcvt(double arg,int ndigits,int * decpt,int * sign,char * buf)195*b89261baSDavid van Moolenbroek static char *ap_fcvt(double arg, int ndigits, int *decpt, int *sign, char *buf)
196*b89261baSDavid van Moolenbroek {
197*b89261baSDavid van Moolenbroek     return (ap_cvt(arg, ndigits, decpt, sign, 0, buf));
198*b89261baSDavid van Moolenbroek }
199*b89261baSDavid van Moolenbroek 
200*b89261baSDavid van Moolenbroek /*
201*b89261baSDavid van Moolenbroek  * ap_gcvt  - Floating output conversion to
202*b89261baSDavid van Moolenbroek  * minimal length string
203*b89261baSDavid van Moolenbroek  */
204*b89261baSDavid van Moolenbroek 
ap_gcvt(double number,int ndigit,char * buf,boolean_e altform)205*b89261baSDavid van Moolenbroek static char *ap_gcvt(double number, int ndigit, char *buf, boolean_e altform)
206*b89261baSDavid van Moolenbroek {
207*b89261baSDavid van Moolenbroek     int sign, decpt;
208*b89261baSDavid van Moolenbroek     register char *p1, *p2;
209*b89261baSDavid van Moolenbroek     register int i;
210*b89261baSDavid van Moolenbroek     char buf1[NDIG];
211*b89261baSDavid van Moolenbroek 
212*b89261baSDavid van Moolenbroek     p1 = ap_ecvt(number, ndigit, &decpt, &sign, buf1);
213*b89261baSDavid van Moolenbroek     p2 = buf;
214*b89261baSDavid van Moolenbroek     if (sign)
215*b89261baSDavid van Moolenbroek 	*p2++ = '-';
216*b89261baSDavid van Moolenbroek     for (i = ndigit - 1; i > 0 && p1[i] == '0'; i--)
217*b89261baSDavid van Moolenbroek 	ndigit--;
218*b89261baSDavid van Moolenbroek     if ((decpt >= 0 && decpt - ndigit > 4)
219*b89261baSDavid van Moolenbroek 	|| (decpt < 0 && decpt < -3)) {		/* use E-style */
220*b89261baSDavid van Moolenbroek 	decpt--;
221*b89261baSDavid van Moolenbroek 	*p2++ = *p1++;
222*b89261baSDavid van Moolenbroek 	*p2++ = '.';
223*b89261baSDavid van Moolenbroek 	for (i = 1; i < ndigit; i++)
224*b89261baSDavid van Moolenbroek 	    *p2++ = *p1++;
225*b89261baSDavid van Moolenbroek 	*p2++ = 'e';
226*b89261baSDavid van Moolenbroek 	if (decpt < 0) {
227*b89261baSDavid van Moolenbroek 	    decpt = -decpt;
228*b89261baSDavid van Moolenbroek 	    *p2++ = '-';
229*b89261baSDavid van Moolenbroek 	}
230*b89261baSDavid van Moolenbroek 	else
231*b89261baSDavid van Moolenbroek 	    *p2++ = '+';
232*b89261baSDavid van Moolenbroek 	if (decpt / 100 > 0)
233*b89261baSDavid van Moolenbroek 	    *p2++ = decpt / 100 + '0';
234*b89261baSDavid van Moolenbroek 	if (decpt / 10 > 0)
235*b89261baSDavid van Moolenbroek 	    *p2++ = (decpt % 100) / 10 + '0';
236*b89261baSDavid van Moolenbroek 	*p2++ = decpt % 10 + '0';
237*b89261baSDavid van Moolenbroek     }
238*b89261baSDavid van Moolenbroek     else {
239*b89261baSDavid van Moolenbroek 	if (decpt <= 0) {
240*b89261baSDavid van Moolenbroek 	    if (*p1 != '0')
241*b89261baSDavid van Moolenbroek 		*p2++ = '.';
242*b89261baSDavid van Moolenbroek 	    while (decpt < 0) {
243*b89261baSDavid van Moolenbroek 		decpt++;
244*b89261baSDavid van Moolenbroek 		*p2++ = '0';
245*b89261baSDavid van Moolenbroek 	    }
246*b89261baSDavid van Moolenbroek 	}
247*b89261baSDavid van Moolenbroek 	for (i = 1; i <= ndigit; i++) {
248*b89261baSDavid van Moolenbroek 	    *p2++ = *p1++;
249*b89261baSDavid van Moolenbroek 	    if (i == decpt)
250*b89261baSDavid van Moolenbroek 		*p2++ = '.';
251*b89261baSDavid van Moolenbroek 	}
252*b89261baSDavid van Moolenbroek 	if (ndigit < decpt) {
253*b89261baSDavid van Moolenbroek 	    while (ndigit++ < decpt)
254*b89261baSDavid van Moolenbroek 		*p2++ = '0';
255*b89261baSDavid van Moolenbroek 	    *p2++ = '.';
256*b89261baSDavid van Moolenbroek 	}
257*b89261baSDavid van Moolenbroek     }
258*b89261baSDavid van Moolenbroek     if (p2[-1] == '.' && !altform)
259*b89261baSDavid van Moolenbroek 	p2--;
260*b89261baSDavid van Moolenbroek     *p2 = '\0';
261*b89261baSDavid van Moolenbroek     return (buf);
262*b89261baSDavid van Moolenbroek }
263*b89261baSDavid van Moolenbroek 
264*b89261baSDavid van Moolenbroek /*
265*b89261baSDavid van Moolenbroek  * The INS_CHAR macro inserts a character in the buffer and writes
266*b89261baSDavid van Moolenbroek  * the buffer back to disk if necessary
267*b89261baSDavid van Moolenbroek  * It uses the char pointers sp and bep:
268*b89261baSDavid van Moolenbroek  *      sp points to the next available character in the buffer
269*b89261baSDavid van Moolenbroek  *      bep points to the end-of-buffer+1
270*b89261baSDavid van Moolenbroek  * While using this macro, note that the nextb pointer is NOT updated.
271*b89261baSDavid van Moolenbroek  *
272*b89261baSDavid van Moolenbroek  * NOTE: Evaluation of the c argument should not have any side-effects
273*b89261baSDavid van Moolenbroek  */
274*b89261baSDavid van Moolenbroek #define INS_CHAR(c, sp, bep, cc)				\
275*b89261baSDavid van Moolenbroek 	    {							\
276*b89261baSDavid van Moolenbroek 		if (sp >= bep) {				\
277*b89261baSDavid van Moolenbroek 		    vbuff->curpos = sp;                         \
278*b89261baSDavid van Moolenbroek 		    if (flush_func(vbuff))			\
279*b89261baSDavid van Moolenbroek 			return -1;				\
280*b89261baSDavid van Moolenbroek 		    sp = vbuff->curpos;				\
281*b89261baSDavid van Moolenbroek 		    bep = vbuff->endpos;			\
282*b89261baSDavid van Moolenbroek 		} 						\
283*b89261baSDavid van Moolenbroek 		*sp++ = (c);					\
284*b89261baSDavid van Moolenbroek 		cc++; 						\
285*b89261baSDavid van Moolenbroek 	    }
286*b89261baSDavid van Moolenbroek 
287*b89261baSDavid van Moolenbroek #define NUM( c )			( c - '0' )
288*b89261baSDavid van Moolenbroek 
289*b89261baSDavid van Moolenbroek #define STR_TO_DEC( str, num )		\
290*b89261baSDavid van Moolenbroek     num = NUM( *str++ ) ;		\
291*b89261baSDavid van Moolenbroek     while ( ap_isdigit( *str ) )		\
292*b89261baSDavid van Moolenbroek     {					\
293*b89261baSDavid van Moolenbroek 	num *= 10 ;			\
294*b89261baSDavid van Moolenbroek 	num += NUM( *str++ ) ;		\
295*b89261baSDavid van Moolenbroek     }
296*b89261baSDavid van Moolenbroek 
297*b89261baSDavid van Moolenbroek /*
298*b89261baSDavid van Moolenbroek  * This macro does zero padding so that the precision
299*b89261baSDavid van Moolenbroek  * requirement is satisfied. The padding is done by
300*b89261baSDavid van Moolenbroek  * adding '0's to the left of the string that is going
301*b89261baSDavid van Moolenbroek  * to be printed. We don't allow precision to be large
302*b89261baSDavid van Moolenbroek  * enough that we continue past the start of s.
303*b89261baSDavid van Moolenbroek  *
304*b89261baSDavid van Moolenbroek  * NOTE: this makes use of the magic info that s is
305*b89261baSDavid van Moolenbroek  * always based on num_buf with a size of NUM_BUF_SIZE.
306*b89261baSDavid van Moolenbroek  */
307*b89261baSDavid van Moolenbroek #define FIX_PRECISION( adjust, precision, s, s_len )	\
308*b89261baSDavid van Moolenbroek     if ( adjust ) {					\
309*b89261baSDavid van Moolenbroek         int p = precision < NUM_BUF_SIZE - 1 ? precision : NUM_BUF_SIZE - 1; \
310*b89261baSDavid van Moolenbroek 	while ( s_len < p )				\
311*b89261baSDavid van Moolenbroek 	{						\
312*b89261baSDavid van Moolenbroek 	    *--s = '0' ;				\
313*b89261baSDavid van Moolenbroek 	    s_len++ ;					\
314*b89261baSDavid van Moolenbroek 	}						\
315*b89261baSDavid van Moolenbroek     }
316*b89261baSDavid van Moolenbroek 
317*b89261baSDavid van Moolenbroek /*
318*b89261baSDavid van Moolenbroek  * Macro that does padding. The padding is done by printing
319*b89261baSDavid van Moolenbroek  * the character ch.
320*b89261baSDavid van Moolenbroek  */
321*b89261baSDavid van Moolenbroek #define PAD( width, len, ch )	do		\
322*b89261baSDavid van Moolenbroek 	{					\
323*b89261baSDavid van Moolenbroek 	    INS_CHAR( ch, sp, bep, cc ) ;	\
324*b89261baSDavid van Moolenbroek 	    width-- ;				\
325*b89261baSDavid van Moolenbroek 	}					\
326*b89261baSDavid van Moolenbroek 	while ( width > len )
327*b89261baSDavid van Moolenbroek 
328*b89261baSDavid van Moolenbroek /*
329*b89261baSDavid van Moolenbroek  * Prefix the character ch to the string str
330*b89261baSDavid van Moolenbroek  * Increase length
331*b89261baSDavid van Moolenbroek  * Set the has_prefix flag
332*b89261baSDavid van Moolenbroek  */
333*b89261baSDavid van Moolenbroek #define PREFIX( str, length, ch )	 *--str = ch ; length++ ; has_prefix = YES
334*b89261baSDavid van Moolenbroek 
335*b89261baSDavid van Moolenbroek 
336*b89261baSDavid van Moolenbroek /*
337*b89261baSDavid van Moolenbroek  * Convert num to its decimal format.
338*b89261baSDavid van Moolenbroek  * Return value:
339*b89261baSDavid van Moolenbroek  *   - a pointer to a string containing the number (no sign)
340*b89261baSDavid van Moolenbroek  *   - len contains the length of the string
341*b89261baSDavid van Moolenbroek  *   - is_negative is set to TRUE or FALSE depending on the sign
342*b89261baSDavid van Moolenbroek  *     of the number (always set to FALSE if is_unsigned is TRUE)
343*b89261baSDavid van Moolenbroek  *
344*b89261baSDavid van Moolenbroek  * The caller provides a buffer for the string: that is the buf_end argument
345*b89261baSDavid van Moolenbroek  * which is a pointer to the END of the buffer + 1 (i.e. if the buffer
346*b89261baSDavid van Moolenbroek  * is declared as buf[ 100 ], buf_end should be &buf[ 100 ])
347*b89261baSDavid van Moolenbroek  *
348*b89261baSDavid van Moolenbroek  * Note: we have 2 versions. One is used when we need to use quads
349*b89261baSDavid van Moolenbroek  * (conv_10_quad), the other when we don't (conv_10). We're assuming the
350*b89261baSDavid van Moolenbroek  * latter is faster.
351*b89261baSDavid van Moolenbroek  */
conv_10(register wide_int num,register bool_int is_unsigned,register bool_int * is_negative,char * buf_end,register int * len)352*b89261baSDavid van Moolenbroek static char *conv_10(register wide_int num, register bool_int is_unsigned,
353*b89261baSDavid van Moolenbroek 		     register bool_int *is_negative, char *buf_end,
354*b89261baSDavid van Moolenbroek 		     register int *len)
355*b89261baSDavid van Moolenbroek {
356*b89261baSDavid van Moolenbroek     register char *p = buf_end;
357*b89261baSDavid van Moolenbroek     register u_wide_int magnitude;
358*b89261baSDavid van Moolenbroek 
359*b89261baSDavid van Moolenbroek     if (is_unsigned) {
360*b89261baSDavid van Moolenbroek 	magnitude = (u_wide_int) num;
361*b89261baSDavid van Moolenbroek 	*is_negative = FALSE;
362*b89261baSDavid van Moolenbroek     }
363*b89261baSDavid van Moolenbroek     else {
364*b89261baSDavid van Moolenbroek 	*is_negative = (num < 0);
365*b89261baSDavid van Moolenbroek 
366*b89261baSDavid van Moolenbroek 	/*
367*b89261baSDavid van Moolenbroek 	 * On a 2's complement machine, negating the most negative integer
368*b89261baSDavid van Moolenbroek 	 * results in a number that cannot be represented as a signed integer.
369*b89261baSDavid van Moolenbroek 	 * Here is what we do to obtain the number's magnitude:
370*b89261baSDavid van Moolenbroek 	 *      a. add 1 to the number
371*b89261baSDavid van Moolenbroek 	 *      b. negate it (becomes positive)
372*b89261baSDavid van Moolenbroek 	 *      c. convert it to unsigned
373*b89261baSDavid van Moolenbroek 	 *      d. add 1
374*b89261baSDavid van Moolenbroek 	 */
375*b89261baSDavid van Moolenbroek 	if (*is_negative) {
376*b89261baSDavid van Moolenbroek 	    wide_int t = num + 1;
377*b89261baSDavid van Moolenbroek 
378*b89261baSDavid van Moolenbroek 	    magnitude = ((u_wide_int) -t) + 1;
379*b89261baSDavid van Moolenbroek 	}
380*b89261baSDavid van Moolenbroek 	else
381*b89261baSDavid van Moolenbroek 	    magnitude = (u_wide_int) num;
382*b89261baSDavid van Moolenbroek     }
383*b89261baSDavid van Moolenbroek 
384*b89261baSDavid van Moolenbroek     /*
385*b89261baSDavid van Moolenbroek      * We use a do-while loop so that we write at least 1 digit
386*b89261baSDavid van Moolenbroek      */
387*b89261baSDavid van Moolenbroek     do {
388*b89261baSDavid van Moolenbroek 	register u_wide_int new_magnitude = magnitude / 10;
389*b89261baSDavid van Moolenbroek 
390*b89261baSDavid van Moolenbroek 	*--p = (char) (magnitude - new_magnitude * 10 + '0');
391*b89261baSDavid van Moolenbroek 	magnitude = new_magnitude;
392*b89261baSDavid van Moolenbroek     }
393*b89261baSDavid van Moolenbroek     while (magnitude);
394*b89261baSDavid van Moolenbroek 
395*b89261baSDavid van Moolenbroek     *len = buf_end - p;
396*b89261baSDavid van Moolenbroek     return (p);
397*b89261baSDavid van Moolenbroek }
398*b89261baSDavid van Moolenbroek 
conv_10_quad(widest_int num,register bool_int is_unsigned,register bool_int * is_negative,char * buf_end,register int * len)399*b89261baSDavid van Moolenbroek static char *conv_10_quad(widest_int num, register bool_int is_unsigned,
400*b89261baSDavid van Moolenbroek 		     register bool_int *is_negative, char *buf_end,
401*b89261baSDavid van Moolenbroek 		     register int *len)
402*b89261baSDavid van Moolenbroek {
403*b89261baSDavid van Moolenbroek     register char *p = buf_end;
404*b89261baSDavid van Moolenbroek     u_widest_int magnitude;
405*b89261baSDavid van Moolenbroek 
406*b89261baSDavid van Moolenbroek     /*
407*b89261baSDavid van Moolenbroek      * We see if we can use the faster non-quad version by checking the
408*b89261baSDavid van Moolenbroek      * number against the largest long value it can be. If <=, we
409*b89261baSDavid van Moolenbroek      * punt to the quicker version.
410*b89261baSDavid van Moolenbroek      */
411*b89261baSDavid van Moolenbroek     if ((num <= ULONG_MAX && is_unsigned) || (num <= LONG_MAX && !is_unsigned))
412*b89261baSDavid van Moolenbroek     	return(conv_10( (wide_int)num, is_unsigned, is_negative,
413*b89261baSDavid van Moolenbroek 	       buf_end, len));
414*b89261baSDavid van Moolenbroek 
415*b89261baSDavid van Moolenbroek     if (is_unsigned) {
416*b89261baSDavid van Moolenbroek 	magnitude = (u_widest_int) num;
417*b89261baSDavid van Moolenbroek 	*is_negative = FALSE;
418*b89261baSDavid van Moolenbroek     }
419*b89261baSDavid van Moolenbroek     else {
420*b89261baSDavid van Moolenbroek 	*is_negative = (num < 0);
421*b89261baSDavid van Moolenbroek 
422*b89261baSDavid van Moolenbroek 	/*
423*b89261baSDavid van Moolenbroek 	 * On a 2's complement machine, negating the most negative integer
424*b89261baSDavid van Moolenbroek 	 * results in a number that cannot be represented as a signed integer.
425*b89261baSDavid van Moolenbroek 	 * Here is what we do to obtain the number's magnitude:
426*b89261baSDavid van Moolenbroek 	 *      a. add 1 to the number
427*b89261baSDavid van Moolenbroek 	 *      b. negate it (becomes positive)
428*b89261baSDavid van Moolenbroek 	 *      c. convert it to unsigned
429*b89261baSDavid van Moolenbroek 	 *      d. add 1
430*b89261baSDavid van Moolenbroek 	 */
431*b89261baSDavid van Moolenbroek 	if (*is_negative) {
432*b89261baSDavid van Moolenbroek 	    widest_int t = num + 1;
433*b89261baSDavid van Moolenbroek 
434*b89261baSDavid van Moolenbroek 	    magnitude = ((u_widest_int) -t) + 1;
435*b89261baSDavid van Moolenbroek 	}
436*b89261baSDavid van Moolenbroek 	else
437*b89261baSDavid van Moolenbroek 	    magnitude = (u_widest_int) num;
438*b89261baSDavid van Moolenbroek     }
439*b89261baSDavid van Moolenbroek 
440*b89261baSDavid van Moolenbroek     /*
441*b89261baSDavid van Moolenbroek      * We use a do-while loop so that we write at least 1 digit
442*b89261baSDavid van Moolenbroek      */
443*b89261baSDavid van Moolenbroek     do {
444*b89261baSDavid van Moolenbroek 	u_widest_int new_magnitude = magnitude / 10;
445*b89261baSDavid van Moolenbroek 
446*b89261baSDavid van Moolenbroek 	*--p = (char) (magnitude - new_magnitude * 10 + '0');
447*b89261baSDavid van Moolenbroek 	magnitude = new_magnitude;
448*b89261baSDavid van Moolenbroek     }
449*b89261baSDavid van Moolenbroek     while (magnitude);
450*b89261baSDavid van Moolenbroek 
451*b89261baSDavid van Moolenbroek     *len = buf_end - p;
452*b89261baSDavid van Moolenbroek     return (p);
453*b89261baSDavid van Moolenbroek }
454*b89261baSDavid van Moolenbroek 
455*b89261baSDavid van Moolenbroek 
456*b89261baSDavid van Moolenbroek 
conv_in_addr(struct in_addr * ia,char * buf_end,int * len)457*b89261baSDavid van Moolenbroek static char *conv_in_addr(struct in_addr *ia, char *buf_end, int *len)
458*b89261baSDavid van Moolenbroek {
459*b89261baSDavid van Moolenbroek     unsigned addr = ntohl(ia->s_addr);
460*b89261baSDavid van Moolenbroek     char *p = buf_end;
461*b89261baSDavid van Moolenbroek     bool_int is_negative;
462*b89261baSDavid van Moolenbroek     int sub_len;
463*b89261baSDavid van Moolenbroek 
464*b89261baSDavid van Moolenbroek     p = conv_10((addr & 0x000000FF)      , TRUE, &is_negative, p, &sub_len);
465*b89261baSDavid van Moolenbroek     *--p = '.';
466*b89261baSDavid van Moolenbroek     p = conv_10((addr & 0x0000FF00) >>  8, TRUE, &is_negative, p, &sub_len);
467*b89261baSDavid van Moolenbroek     *--p = '.';
468*b89261baSDavid van Moolenbroek     p = conv_10((addr & 0x00FF0000) >> 16, TRUE, &is_negative, p, &sub_len);
469*b89261baSDavid van Moolenbroek     *--p = '.';
470*b89261baSDavid van Moolenbroek     p = conv_10((addr & 0xFF000000) >> 24, TRUE, &is_negative, p, &sub_len);
471*b89261baSDavid van Moolenbroek 
472*b89261baSDavid van Moolenbroek     *len = buf_end - p;
473*b89261baSDavid van Moolenbroek     return (p);
474*b89261baSDavid van Moolenbroek }
475*b89261baSDavid van Moolenbroek 
476*b89261baSDavid van Moolenbroek 
477*b89261baSDavid van Moolenbroek 
conv_sockaddr_in(struct sockaddr_in * si,char * buf_end,int * len)478*b89261baSDavid van Moolenbroek static char *conv_sockaddr_in(struct sockaddr_in *si, char *buf_end, int *len)
479*b89261baSDavid van Moolenbroek {
480*b89261baSDavid van Moolenbroek     char *p = buf_end;
481*b89261baSDavid van Moolenbroek     bool_int is_negative;
482*b89261baSDavid van Moolenbroek     int sub_len;
483*b89261baSDavid van Moolenbroek 
484*b89261baSDavid van Moolenbroek     p = conv_10(ntohs(si->sin_port), TRUE, &is_negative, p, &sub_len);
485*b89261baSDavid van Moolenbroek     *--p = ':';
486*b89261baSDavid van Moolenbroek     p = conv_in_addr(&si->sin_addr, p, &sub_len);
487*b89261baSDavid van Moolenbroek 
488*b89261baSDavid van Moolenbroek     *len = buf_end - p;
489*b89261baSDavid van Moolenbroek     return (p);
490*b89261baSDavid van Moolenbroek }
491*b89261baSDavid van Moolenbroek 
492*b89261baSDavid van Moolenbroek 
493*b89261baSDavid van Moolenbroek 
494*b89261baSDavid van Moolenbroek /*
495*b89261baSDavid van Moolenbroek  * Convert a floating point number to a string formats 'f', 'e' or 'E'.
496*b89261baSDavid van Moolenbroek  * The result is placed in buf, and len denotes the length of the string
497*b89261baSDavid van Moolenbroek  * The sign is returned in the is_negative argument (and is not placed
498*b89261baSDavid van Moolenbroek  * in buf).
499*b89261baSDavid van Moolenbroek  */
conv_fp(register char format,register double num,boolean_e add_dp,int precision,bool_int * is_negative,char * buf,int * len)500*b89261baSDavid van Moolenbroek static char *conv_fp(register char format, register double num,
501*b89261baSDavid van Moolenbroek     boolean_e add_dp, int precision, bool_int *is_negative,
502*b89261baSDavid van Moolenbroek     char *buf, int *len)
503*b89261baSDavid van Moolenbroek {
504*b89261baSDavid van Moolenbroek     register char *s = buf;
505*b89261baSDavid van Moolenbroek     register char *p;
506*b89261baSDavid van Moolenbroek     int decimal_point;
507*b89261baSDavid van Moolenbroek     char buf1[NDIG];
508*b89261baSDavid van Moolenbroek 
509*b89261baSDavid van Moolenbroek     if (format == 'f')
510*b89261baSDavid van Moolenbroek 	p = ap_fcvt(num, precision, &decimal_point, is_negative, buf1);
511*b89261baSDavid van Moolenbroek     else			/* either e or E format */
512*b89261baSDavid van Moolenbroek 	p = ap_ecvt(num, precision + 1, &decimal_point, is_negative, buf1);
513*b89261baSDavid van Moolenbroek 
514*b89261baSDavid van Moolenbroek     /*
515*b89261baSDavid van Moolenbroek      * Check for Infinity and NaN
516*b89261baSDavid van Moolenbroek      */
517*b89261baSDavid van Moolenbroek     if (ap_isalpha(*p)) {
518*b89261baSDavid van Moolenbroek 	*len = strlen(strcpy(buf, p));
519*b89261baSDavid van Moolenbroek 	*is_negative = FALSE;
520*b89261baSDavid van Moolenbroek 	return (buf);
521*b89261baSDavid van Moolenbroek     }
522*b89261baSDavid van Moolenbroek 
523*b89261baSDavid van Moolenbroek     if (format == 'f') {
524*b89261baSDavid van Moolenbroek 	if (decimal_point <= 0) {
525*b89261baSDavid van Moolenbroek 	    *s++ = '0';
526*b89261baSDavid van Moolenbroek 	    if (precision > 0) {
527*b89261baSDavid van Moolenbroek 		*s++ = '.';
528*b89261baSDavid van Moolenbroek 		while (decimal_point++ < 0)
529*b89261baSDavid van Moolenbroek 		    *s++ = '0';
530*b89261baSDavid van Moolenbroek 	    }
531*b89261baSDavid van Moolenbroek 	    else if (add_dp)
532*b89261baSDavid van Moolenbroek 		*s++ = '.';
533*b89261baSDavid van Moolenbroek 	}
534*b89261baSDavid van Moolenbroek 	else {
535*b89261baSDavid van Moolenbroek 	    while (decimal_point-- > 0)
536*b89261baSDavid van Moolenbroek 		*s++ = *p++;
537*b89261baSDavid van Moolenbroek 	    if (precision > 0 || add_dp)
538*b89261baSDavid van Moolenbroek 		*s++ = '.';
539*b89261baSDavid van Moolenbroek 	}
540*b89261baSDavid van Moolenbroek     }
541*b89261baSDavid van Moolenbroek     else {
542*b89261baSDavid van Moolenbroek 	*s++ = *p++;
543*b89261baSDavid van Moolenbroek 	if (precision > 0 || add_dp)
544*b89261baSDavid van Moolenbroek 	    *s++ = '.';
545*b89261baSDavid van Moolenbroek     }
546*b89261baSDavid van Moolenbroek 
547*b89261baSDavid van Moolenbroek     /*
548*b89261baSDavid van Moolenbroek      * copy the rest of p, the NUL is NOT copied
549*b89261baSDavid van Moolenbroek      */
550*b89261baSDavid van Moolenbroek     while (*p)
551*b89261baSDavid van Moolenbroek 	*s++ = *p++;
552*b89261baSDavid van Moolenbroek 
553*b89261baSDavid van Moolenbroek     if (format != 'f') {
554*b89261baSDavid van Moolenbroek 	char temp[EXPONENT_LENGTH];	/* for exponent conversion */
555*b89261baSDavid van Moolenbroek 	int t_len;
556*b89261baSDavid van Moolenbroek 	bool_int exponent_is_negative;
557*b89261baSDavid van Moolenbroek 
558*b89261baSDavid van Moolenbroek 	*s++ = format;		/* either e or E */
559*b89261baSDavid van Moolenbroek 	decimal_point--;
560*b89261baSDavid van Moolenbroek 	if (decimal_point != 0) {
561*b89261baSDavid van Moolenbroek 	    p = conv_10((wide_int) decimal_point, FALSE, &exponent_is_negative,
562*b89261baSDavid van Moolenbroek 			&temp[EXPONENT_LENGTH], &t_len);
563*b89261baSDavid van Moolenbroek 	    *s++ = exponent_is_negative ? '-' : '+';
564*b89261baSDavid van Moolenbroek 
565*b89261baSDavid van Moolenbroek 	    /*
566*b89261baSDavid van Moolenbroek 	     * Make sure the exponent has at least 2 digits
567*b89261baSDavid van Moolenbroek 	     */
568*b89261baSDavid van Moolenbroek 	    if (t_len == 1)
569*b89261baSDavid van Moolenbroek 		*s++ = '0';
570*b89261baSDavid van Moolenbroek 	    while (t_len--)
571*b89261baSDavid van Moolenbroek 		*s++ = *p++;
572*b89261baSDavid van Moolenbroek 	}
573*b89261baSDavid van Moolenbroek 	else {
574*b89261baSDavid van Moolenbroek 	    *s++ = '+';
575*b89261baSDavid van Moolenbroek 	    *s++ = '0';
576*b89261baSDavid van Moolenbroek 	    *s++ = '0';
577*b89261baSDavid van Moolenbroek 	}
578*b89261baSDavid van Moolenbroek     }
579*b89261baSDavid van Moolenbroek 
580*b89261baSDavid van Moolenbroek     *len = s - buf;
581*b89261baSDavid van Moolenbroek     return (buf);
582*b89261baSDavid van Moolenbroek }
583*b89261baSDavid van Moolenbroek 
584*b89261baSDavid van Moolenbroek 
585*b89261baSDavid van Moolenbroek /*
586*b89261baSDavid van Moolenbroek  * Convert num to a base X number where X is a power of 2. nbits determines X.
587*b89261baSDavid van Moolenbroek  * For example, if nbits is 3, we do base 8 conversion
588*b89261baSDavid van Moolenbroek  * Return value:
589*b89261baSDavid van Moolenbroek  *      a pointer to a string containing the number
590*b89261baSDavid van Moolenbroek  *
591*b89261baSDavid van Moolenbroek  * The caller provides a buffer for the string: that is the buf_end argument
592*b89261baSDavid van Moolenbroek  * which is a pointer to the END of the buffer + 1 (i.e. if the buffer
593*b89261baSDavid van Moolenbroek  * is declared as buf[ 100 ], buf_end should be &buf[ 100 ])
594*b89261baSDavid van Moolenbroek  *
595*b89261baSDavid van Moolenbroek  * As with conv_10, we have a faster version which is used when
596*b89261baSDavid van Moolenbroek  * the number isn't quad size.
597*b89261baSDavid van Moolenbroek  */
conv_p2(register u_wide_int num,register int nbits,char format,char * buf_end,register int * len)598*b89261baSDavid van Moolenbroek static char *conv_p2(register u_wide_int num, register int nbits,
599*b89261baSDavid van Moolenbroek 		     char format, char *buf_end, register int *len)
600*b89261baSDavid van Moolenbroek {
601*b89261baSDavid van Moolenbroek     register int mask = (1 << nbits) - 1;
602*b89261baSDavid van Moolenbroek     register char *p = buf_end;
603*b89261baSDavid van Moolenbroek     static const char low_digits[] = "0123456789abcdef";
604*b89261baSDavid van Moolenbroek     static const char upper_digits[] = "0123456789ABCDEF";
605*b89261baSDavid van Moolenbroek     register const char *digits = (format == 'X') ? upper_digits : low_digits;
606*b89261baSDavid van Moolenbroek 
607*b89261baSDavid van Moolenbroek     do {
608*b89261baSDavid van Moolenbroek 	*--p = digits[num & mask];
609*b89261baSDavid van Moolenbroek 	num >>= nbits;
610*b89261baSDavid van Moolenbroek     }
611*b89261baSDavid van Moolenbroek     while (num);
612*b89261baSDavid van Moolenbroek 
613*b89261baSDavid van Moolenbroek     *len = buf_end - p;
614*b89261baSDavid van Moolenbroek     return (p);
615*b89261baSDavid van Moolenbroek }
616*b89261baSDavid van Moolenbroek 
conv_p2_quad(u_widest_int num,register int nbits,char format,char * buf_end,register int * len)617*b89261baSDavid van Moolenbroek static char *conv_p2_quad(u_widest_int num, register int nbits,
618*b89261baSDavid van Moolenbroek 		     char format, char *buf_end, register int *len)
619*b89261baSDavid van Moolenbroek {
620*b89261baSDavid van Moolenbroek     register int mask = (1 << nbits) - 1;
621*b89261baSDavid van Moolenbroek     register char *p = buf_end;
622*b89261baSDavid van Moolenbroek     static const char low_digits[] = "0123456789abcdef";
623*b89261baSDavid van Moolenbroek     static const char upper_digits[] = "0123456789ABCDEF";
624*b89261baSDavid van Moolenbroek     register const char *digits = (format == 'X') ? upper_digits : low_digits;
625*b89261baSDavid van Moolenbroek 
626*b89261baSDavid van Moolenbroek     if (num <= ULONG_MAX)
627*b89261baSDavid van Moolenbroek     	return(conv_p2( (u_wide_int)num, nbits, format, buf_end, len));
628*b89261baSDavid van Moolenbroek 
629*b89261baSDavid van Moolenbroek     do {
630*b89261baSDavid van Moolenbroek 	*--p = digits[num & mask];
631*b89261baSDavid van Moolenbroek 	num >>= nbits;
632*b89261baSDavid van Moolenbroek     }
633*b89261baSDavid van Moolenbroek     while (num);
634*b89261baSDavid van Moolenbroek 
635*b89261baSDavid van Moolenbroek     *len = buf_end - p;
636*b89261baSDavid van Moolenbroek     return (p);
637*b89261baSDavid van Moolenbroek }
638*b89261baSDavid van Moolenbroek 
639*b89261baSDavid van Moolenbroek 
640*b89261baSDavid van Moolenbroek /*
641*b89261baSDavid van Moolenbroek  * Do format conversion placing the output in buffer
642*b89261baSDavid van Moolenbroek  */
ap_vformatter(int (* flush_func)(ap_vformatter_buff *),ap_vformatter_buff * vbuff,const char * fmt,va_list ap)643*b89261baSDavid van Moolenbroek API_EXPORT(int) ap_vformatter(int (*flush_func)(ap_vformatter_buff *),
644*b89261baSDavid van Moolenbroek     ap_vformatter_buff *vbuff, const char *fmt, va_list ap)
645*b89261baSDavid van Moolenbroek {
646*b89261baSDavid van Moolenbroek     register char *sp;
647*b89261baSDavid van Moolenbroek     register char *bep;
648*b89261baSDavid van Moolenbroek     register int cc = 0;
649*b89261baSDavid van Moolenbroek     register int i;
650*b89261baSDavid van Moolenbroek 
651*b89261baSDavid van Moolenbroek     register char *s = NULL;
652*b89261baSDavid van Moolenbroek     char *q;
653*b89261baSDavid van Moolenbroek     int s_len;
654*b89261baSDavid van Moolenbroek 
655*b89261baSDavid van Moolenbroek     register int min_width = 0;
656*b89261baSDavid van Moolenbroek     int precision = 0;
657*b89261baSDavid van Moolenbroek     enum {
658*b89261baSDavid van Moolenbroek 	LEFT, RIGHT
659*b89261baSDavid van Moolenbroek     } adjust;
660*b89261baSDavid van Moolenbroek     char pad_char;
661*b89261baSDavid van Moolenbroek     char prefix_char;
662*b89261baSDavid van Moolenbroek 
663*b89261baSDavid van Moolenbroek     double fp_num;
664*b89261baSDavid van Moolenbroek     widest_int i_quad = (widest_int) 0;
665*b89261baSDavid van Moolenbroek     u_widest_int ui_quad;
666*b89261baSDavid van Moolenbroek     wide_int i_num = (wide_int) 0;
667*b89261baSDavid van Moolenbroek     u_wide_int ui_num;
668*b89261baSDavid van Moolenbroek 
669*b89261baSDavid van Moolenbroek     char num_buf[NUM_BUF_SIZE];
670*b89261baSDavid van Moolenbroek     char char_buf[2];		/* for printing %% and %<unknown> */
671*b89261baSDavid van Moolenbroek 
672*b89261baSDavid van Moolenbroek     enum var_type_enum {
673*b89261baSDavid van Moolenbroek     	IS_QUAD, IS_LONG, IS_SHORT, IS_INT
674*b89261baSDavid van Moolenbroek     };
675*b89261baSDavid van Moolenbroek     enum var_type_enum var_type = IS_INT;
676*b89261baSDavid van Moolenbroek 
677*b89261baSDavid van Moolenbroek     /*
678*b89261baSDavid van Moolenbroek      * Flag variables
679*b89261baSDavid van Moolenbroek      */
680*b89261baSDavid van Moolenbroek     boolean_e alternate_form;
681*b89261baSDavid van Moolenbroek     boolean_e print_sign;
682*b89261baSDavid van Moolenbroek     boolean_e print_blank;
683*b89261baSDavid van Moolenbroek     boolean_e adjust_precision;
684*b89261baSDavid van Moolenbroek     boolean_e adjust_width;
685*b89261baSDavid van Moolenbroek     bool_int is_negative;
686*b89261baSDavid van Moolenbroek 
687*b89261baSDavid van Moolenbroek     sp = vbuff->curpos;
688*b89261baSDavid van Moolenbroek     bep = vbuff->endpos;
689*b89261baSDavid van Moolenbroek 
690*b89261baSDavid van Moolenbroek     while (*fmt) {
691*b89261baSDavid van Moolenbroek 	if (*fmt != '%') {
692*b89261baSDavid van Moolenbroek 	    INS_CHAR(*fmt, sp, bep, cc);
693*b89261baSDavid van Moolenbroek 	}
694*b89261baSDavid van Moolenbroek 	else {
695*b89261baSDavid van Moolenbroek 	    /*
696*b89261baSDavid van Moolenbroek 	     * Default variable settings
697*b89261baSDavid van Moolenbroek 	     */
698*b89261baSDavid van Moolenbroek 	    adjust = RIGHT;
699*b89261baSDavid van Moolenbroek 	    alternate_form = print_sign = print_blank = NO;
700*b89261baSDavid van Moolenbroek 	    pad_char = ' ';
701*b89261baSDavid van Moolenbroek 	    prefix_char = NUL;
702*b89261baSDavid van Moolenbroek 
703*b89261baSDavid van Moolenbroek 	    fmt++;
704*b89261baSDavid van Moolenbroek 
705*b89261baSDavid van Moolenbroek 	    /*
706*b89261baSDavid van Moolenbroek 	     * Try to avoid checking for flags, width or precision
707*b89261baSDavid van Moolenbroek 	     */
708*b89261baSDavid van Moolenbroek 	    if (!ap_islower(*fmt)) {
709*b89261baSDavid van Moolenbroek 		/*
710*b89261baSDavid van Moolenbroek 		 * Recognize flags: -, #, BLANK, +
711*b89261baSDavid van Moolenbroek 		 */
712*b89261baSDavid van Moolenbroek 		for (;; fmt++) {
713*b89261baSDavid van Moolenbroek 		    if (*fmt == '-')
714*b89261baSDavid van Moolenbroek 			adjust = LEFT;
715*b89261baSDavid van Moolenbroek 		    else if (*fmt == '+')
716*b89261baSDavid van Moolenbroek 			print_sign = YES;
717*b89261baSDavid van Moolenbroek 		    else if (*fmt == '#')
718*b89261baSDavid van Moolenbroek 			alternate_form = YES;
719*b89261baSDavid van Moolenbroek 		    else if (*fmt == ' ')
720*b89261baSDavid van Moolenbroek 			print_blank = YES;
721*b89261baSDavid van Moolenbroek 		    else if (*fmt == '0')
722*b89261baSDavid van Moolenbroek 			pad_char = '0';
723*b89261baSDavid van Moolenbroek 		    else
724*b89261baSDavid van Moolenbroek 			break;
725*b89261baSDavid van Moolenbroek 		}
726*b89261baSDavid van Moolenbroek 
727*b89261baSDavid van Moolenbroek 		/*
728*b89261baSDavid van Moolenbroek 		 * Check if a width was specified
729*b89261baSDavid van Moolenbroek 		 */
730*b89261baSDavid van Moolenbroek 		if (ap_isdigit(*fmt)) {
731*b89261baSDavid van Moolenbroek 		    STR_TO_DEC(fmt, min_width);
732*b89261baSDavid van Moolenbroek 		    adjust_width = YES;
733*b89261baSDavid van Moolenbroek 		}
734*b89261baSDavid van Moolenbroek 		else if (*fmt == '*') {
735*b89261baSDavid van Moolenbroek 		    min_width = va_arg(ap, int);
736*b89261baSDavid van Moolenbroek 		    fmt++;
737*b89261baSDavid van Moolenbroek 		    adjust_width = YES;
738*b89261baSDavid van Moolenbroek 		    if (min_width < 0) {
739*b89261baSDavid van Moolenbroek 			adjust = LEFT;
740*b89261baSDavid van Moolenbroek 			min_width = -min_width;
741*b89261baSDavid van Moolenbroek 		    }
742*b89261baSDavid van Moolenbroek 		}
743*b89261baSDavid van Moolenbroek 		else
744*b89261baSDavid van Moolenbroek 		    adjust_width = NO;
745*b89261baSDavid van Moolenbroek 
746*b89261baSDavid van Moolenbroek 		/*
747*b89261baSDavid van Moolenbroek 		 * Check if a precision was specified
748*b89261baSDavid van Moolenbroek 		 */
749*b89261baSDavid van Moolenbroek 		if (*fmt == '.') {
750*b89261baSDavid van Moolenbroek 		    adjust_precision = YES;
751*b89261baSDavid van Moolenbroek 		    fmt++;
752*b89261baSDavid van Moolenbroek 		    if (ap_isdigit(*fmt)) {
753*b89261baSDavid van Moolenbroek 			STR_TO_DEC(fmt, precision);
754*b89261baSDavid van Moolenbroek 		    }
755*b89261baSDavid van Moolenbroek 		    else if (*fmt == '*') {
756*b89261baSDavid van Moolenbroek 			precision = va_arg(ap, int);
757*b89261baSDavid van Moolenbroek 			fmt++;
758*b89261baSDavid van Moolenbroek 			if (precision < 0)
759*b89261baSDavid van Moolenbroek 			    precision = 0;
760*b89261baSDavid van Moolenbroek 		    }
761*b89261baSDavid van Moolenbroek 		    else
762*b89261baSDavid van Moolenbroek 			precision = 0;
763*b89261baSDavid van Moolenbroek 		}
764*b89261baSDavid van Moolenbroek 		else
765*b89261baSDavid van Moolenbroek 		    adjust_precision = NO;
766*b89261baSDavid van Moolenbroek 	    }
767*b89261baSDavid van Moolenbroek 	    else
768*b89261baSDavid van Moolenbroek 		adjust_precision = adjust_width = NO;
769*b89261baSDavid van Moolenbroek 
770*b89261baSDavid van Moolenbroek 	    /*
771*b89261baSDavid van Moolenbroek 	     * Modifier check
772*b89261baSDavid van Moolenbroek 	     */
773*b89261baSDavid van Moolenbroek 	    if (*fmt == 'q') {
774*b89261baSDavid van Moolenbroek 		var_type = IS_QUAD;
775*b89261baSDavid van Moolenbroek 		fmt++;
776*b89261baSDavid van Moolenbroek 	    }
777*b89261baSDavid van Moolenbroek 	    else if (*fmt == 'l') {
778*b89261baSDavid van Moolenbroek 		var_type = IS_LONG;
779*b89261baSDavid van Moolenbroek 		fmt++;
780*b89261baSDavid van Moolenbroek 	    }
781*b89261baSDavid van Moolenbroek 	    else if (*fmt == 'h') {
782*b89261baSDavid van Moolenbroek 		var_type = IS_SHORT;
783*b89261baSDavid van Moolenbroek 		fmt++;
784*b89261baSDavid van Moolenbroek 	    }
785*b89261baSDavid van Moolenbroek 	    else {
786*b89261baSDavid van Moolenbroek 		var_type = IS_INT;
787*b89261baSDavid van Moolenbroek 	    }
788*b89261baSDavid van Moolenbroek 
789*b89261baSDavid van Moolenbroek 	    /*
790*b89261baSDavid van Moolenbroek 	     * Argument extraction and printing.
791*b89261baSDavid van Moolenbroek 	     * First we determine the argument type.
792*b89261baSDavid van Moolenbroek 	     * Then, we convert the argument to a string.
793*b89261baSDavid van Moolenbroek 	     * On exit from the switch, s points to the string that
794*b89261baSDavid van Moolenbroek 	     * must be printed, s_len has the length of the string
795*b89261baSDavid van Moolenbroek 	     * The precision requirements, if any, are reflected in s_len.
796*b89261baSDavid van Moolenbroek 	     *
797*b89261baSDavid van Moolenbroek 	     * NOTE: pad_char may be set to '0' because of the 0 flag.
798*b89261baSDavid van Moolenbroek 	     *   It is reset to ' ' by non-numeric formats
799*b89261baSDavid van Moolenbroek 	     */
800*b89261baSDavid van Moolenbroek 	    switch (*fmt) {
801*b89261baSDavid van Moolenbroek 	    case 'u':
802*b89261baSDavid van Moolenbroek 	    	if (var_type == IS_QUAD) {
803*b89261baSDavid van Moolenbroek 		    i_quad = va_arg(ap, u_widest_int);
804*b89261baSDavid van Moolenbroek 		    s = conv_10_quad(i_quad, 1, &is_negative,
805*b89261baSDavid van Moolenbroek 			    &num_buf[NUM_BUF_SIZE], &s_len);
806*b89261baSDavid van Moolenbroek 		}
807*b89261baSDavid van Moolenbroek 		else {
808*b89261baSDavid van Moolenbroek 		    if (var_type == IS_LONG)
809*b89261baSDavid van Moolenbroek 			i_num = (wide_int) va_arg(ap, u_wide_int);
810*b89261baSDavid van Moolenbroek 		    else if (var_type == IS_SHORT)
811*b89261baSDavid van Moolenbroek 			i_num = (wide_int) (unsigned short) va_arg(ap, unsigned int);
812*b89261baSDavid van Moolenbroek 		    else
813*b89261baSDavid van Moolenbroek 			i_num = (wide_int) va_arg(ap, unsigned int);
814*b89261baSDavid van Moolenbroek 		    s = conv_10(i_num, 1, &is_negative,
815*b89261baSDavid van Moolenbroek 			    &num_buf[NUM_BUF_SIZE], &s_len);
816*b89261baSDavid van Moolenbroek 		}
817*b89261baSDavid van Moolenbroek 		FIX_PRECISION(adjust_precision, precision, s, s_len);
818*b89261baSDavid van Moolenbroek 		break;
819*b89261baSDavid van Moolenbroek 
820*b89261baSDavid van Moolenbroek 	    case 'd':
821*b89261baSDavid van Moolenbroek 	    case 'i':
822*b89261baSDavid van Moolenbroek 	    	if (var_type == IS_QUAD) {
823*b89261baSDavid van Moolenbroek 		    i_quad = va_arg(ap, widest_int);
824*b89261baSDavid van Moolenbroek 		    s = conv_10_quad(i_quad, 0, &is_negative,
825*b89261baSDavid van Moolenbroek 			    &num_buf[NUM_BUF_SIZE], &s_len);
826*b89261baSDavid van Moolenbroek 		}
827*b89261baSDavid van Moolenbroek 		else {
828*b89261baSDavid van Moolenbroek 		    if (var_type == IS_LONG)
829*b89261baSDavid van Moolenbroek 			i_num = (wide_int) va_arg(ap, wide_int);
830*b89261baSDavid van Moolenbroek 		    else if (var_type == IS_SHORT)
831*b89261baSDavid van Moolenbroek 			i_num = (wide_int) (short) va_arg(ap, int);
832*b89261baSDavid van Moolenbroek 		    else
833*b89261baSDavid van Moolenbroek 			i_num = (wide_int) va_arg(ap, int);
834*b89261baSDavid van Moolenbroek 		    s = conv_10(i_num, 0, &is_negative,
835*b89261baSDavid van Moolenbroek 			    &num_buf[NUM_BUF_SIZE], &s_len);
836*b89261baSDavid van Moolenbroek 		}
837*b89261baSDavid van Moolenbroek 		FIX_PRECISION(adjust_precision, precision, s, s_len);
838*b89261baSDavid van Moolenbroek 
839*b89261baSDavid van Moolenbroek 		if (is_negative)
840*b89261baSDavid van Moolenbroek 		    prefix_char = '-';
841*b89261baSDavid van Moolenbroek 		else if (print_sign)
842*b89261baSDavid van Moolenbroek 		    prefix_char = '+';
843*b89261baSDavid van Moolenbroek 		else if (print_blank)
844*b89261baSDavid van Moolenbroek 		    prefix_char = ' ';
845*b89261baSDavid van Moolenbroek 		break;
846*b89261baSDavid van Moolenbroek 
847*b89261baSDavid van Moolenbroek 
848*b89261baSDavid van Moolenbroek 	    case 'o':
849*b89261baSDavid van Moolenbroek 		if (var_type == IS_QUAD) {
850*b89261baSDavid van Moolenbroek 		    ui_quad = va_arg(ap, u_widest_int);
851*b89261baSDavid van Moolenbroek 		    s = conv_p2_quad(ui_quad, 3, *fmt,
852*b89261baSDavid van Moolenbroek 			    &num_buf[NUM_BUF_SIZE], &s_len);
853*b89261baSDavid van Moolenbroek 		}
854*b89261baSDavid van Moolenbroek 		else {
855*b89261baSDavid van Moolenbroek 		    if (var_type == IS_LONG)
856*b89261baSDavid van Moolenbroek 			ui_num = (u_wide_int) va_arg(ap, u_wide_int);
857*b89261baSDavid van Moolenbroek 		    else if (var_type == IS_SHORT)
858*b89261baSDavid van Moolenbroek 			ui_num = (u_wide_int) (unsigned short) va_arg(ap, unsigned int);
859*b89261baSDavid van Moolenbroek 		    else
860*b89261baSDavid van Moolenbroek 			ui_num = (u_wide_int) va_arg(ap, unsigned int);
861*b89261baSDavid van Moolenbroek 		    s = conv_p2(ui_num, 3, *fmt,
862*b89261baSDavid van Moolenbroek 			    &num_buf[NUM_BUF_SIZE], &s_len);
863*b89261baSDavid van Moolenbroek 		}
864*b89261baSDavid van Moolenbroek 		FIX_PRECISION(adjust_precision, precision, s, s_len);
865*b89261baSDavid van Moolenbroek 		if (alternate_form && *s != '0') {
866*b89261baSDavid van Moolenbroek 		    *--s = '0';
867*b89261baSDavid van Moolenbroek 		    s_len++;
868*b89261baSDavid van Moolenbroek 		}
869*b89261baSDavid van Moolenbroek 		break;
870*b89261baSDavid van Moolenbroek 
871*b89261baSDavid van Moolenbroek 
872*b89261baSDavid van Moolenbroek 	    case 'x':
873*b89261baSDavid van Moolenbroek 	    case 'X':
874*b89261baSDavid van Moolenbroek 		if (var_type == IS_QUAD) {
875*b89261baSDavid van Moolenbroek 		    ui_quad = va_arg(ap, u_widest_int);
876*b89261baSDavid van Moolenbroek 		    s = conv_p2_quad(ui_quad, 4, *fmt,
877*b89261baSDavid van Moolenbroek 			    &num_buf[NUM_BUF_SIZE], &s_len);
878*b89261baSDavid van Moolenbroek 		}
879*b89261baSDavid van Moolenbroek 		else {
880*b89261baSDavid van Moolenbroek 		    if (var_type == IS_LONG)
881*b89261baSDavid van Moolenbroek 			ui_num = (u_wide_int) va_arg(ap, u_wide_int);
882*b89261baSDavid van Moolenbroek 		    else if (var_type == IS_SHORT)
883*b89261baSDavid van Moolenbroek 			ui_num = (u_wide_int) (unsigned short) va_arg(ap, unsigned int);
884*b89261baSDavid van Moolenbroek 		    else
885*b89261baSDavid van Moolenbroek 			ui_num = (u_wide_int) va_arg(ap, unsigned int);
886*b89261baSDavid van Moolenbroek 		    s = conv_p2(ui_num, 4, *fmt,
887*b89261baSDavid van Moolenbroek 			    &num_buf[NUM_BUF_SIZE], &s_len);
888*b89261baSDavid van Moolenbroek 		}
889*b89261baSDavid van Moolenbroek 		FIX_PRECISION(adjust_precision, precision, s, s_len);
890*b89261baSDavid van Moolenbroek 		if (alternate_form && i_num != 0) {
891*b89261baSDavid van Moolenbroek 		    *--s = *fmt;	/* 'x' or 'X' */
892*b89261baSDavid van Moolenbroek 		    *--s = '0';
893*b89261baSDavid van Moolenbroek 		    s_len += 2;
894*b89261baSDavid van Moolenbroek 		}
895*b89261baSDavid van Moolenbroek 		break;
896*b89261baSDavid van Moolenbroek 
897*b89261baSDavid van Moolenbroek 
898*b89261baSDavid van Moolenbroek 	    case 's':
899*b89261baSDavid van Moolenbroek 		s = va_arg(ap, char *);
900*b89261baSDavid van Moolenbroek 		if (s != NULL) {
901*b89261baSDavid van Moolenbroek 		    s_len = strlen(s);
902*b89261baSDavid van Moolenbroek 		    if (adjust_precision && precision < s_len)
903*b89261baSDavid van Moolenbroek 			s_len = precision;
904*b89261baSDavid van Moolenbroek 		}
905*b89261baSDavid van Moolenbroek 		else {
906*b89261baSDavid van Moolenbroek 		    s = S_NULL;
907*b89261baSDavid van Moolenbroek 		    s_len = S_NULL_LEN;
908*b89261baSDavid van Moolenbroek 		}
909*b89261baSDavid van Moolenbroek 		pad_char = ' ';
910*b89261baSDavid van Moolenbroek 		break;
911*b89261baSDavid van Moolenbroek 
912*b89261baSDavid van Moolenbroek 
913*b89261baSDavid van Moolenbroek 	    case 'f':
914*b89261baSDavid van Moolenbroek 	    case 'e':
915*b89261baSDavid van Moolenbroek 	    case 'E':
916*b89261baSDavid van Moolenbroek 		fp_num = va_arg(ap, double);
917*b89261baSDavid van Moolenbroek 		/*
918*b89261baSDavid van Moolenbroek 		 * * We use &num_buf[ 1 ], so that we have room for the sign
919*b89261baSDavid van Moolenbroek 		 */
920*b89261baSDavid van Moolenbroek #ifdef HAVE_ISNAN
921*b89261baSDavid van Moolenbroek 		if (isnan(fp_num)) {
922*b89261baSDavid van Moolenbroek 		    s = "nan";
923*b89261baSDavid van Moolenbroek 		    s_len = 3;
924*b89261baSDavid van Moolenbroek 		}
925*b89261baSDavid van Moolenbroek 		else
926*b89261baSDavid van Moolenbroek #endif
927*b89261baSDavid van Moolenbroek #ifdef HAVE_ISINF
928*b89261baSDavid van Moolenbroek 		if (isinf(fp_num)) {
929*b89261baSDavid van Moolenbroek 		    s = "inf";
930*b89261baSDavid van Moolenbroek 		    s_len = 3;
931*b89261baSDavid van Moolenbroek 		}
932*b89261baSDavid van Moolenbroek 		else
933*b89261baSDavid van Moolenbroek #endif
934*b89261baSDavid van Moolenbroek 		{
935*b89261baSDavid van Moolenbroek 		    s = conv_fp(*fmt, fp_num, alternate_form,
936*b89261baSDavid van Moolenbroek 			    (adjust_precision == NO) ? FLOAT_DIGITS : precision,
937*b89261baSDavid van Moolenbroek 				&is_negative, &num_buf[1], &s_len);
938*b89261baSDavid van Moolenbroek 		    if (is_negative)
939*b89261baSDavid van Moolenbroek 			prefix_char = '-';
940*b89261baSDavid van Moolenbroek 		    else if (print_sign)
941*b89261baSDavid van Moolenbroek 			prefix_char = '+';
942*b89261baSDavid van Moolenbroek 		    else if (print_blank)
943*b89261baSDavid van Moolenbroek 			prefix_char = ' ';
944*b89261baSDavid van Moolenbroek 		}
945*b89261baSDavid van Moolenbroek 	        break;
946*b89261baSDavid van Moolenbroek 
947*b89261baSDavid van Moolenbroek 
948*b89261baSDavid van Moolenbroek 	    case 'g':
949*b89261baSDavid van Moolenbroek 	    case 'G':
950*b89261baSDavid van Moolenbroek 		if (adjust_precision == NO)
951*b89261baSDavid van Moolenbroek 		    precision = FLOAT_DIGITS;
952*b89261baSDavid van Moolenbroek 		else if (precision == 0)
953*b89261baSDavid van Moolenbroek 		    precision = 1;
954*b89261baSDavid van Moolenbroek 		/*
955*b89261baSDavid van Moolenbroek 		 * * We use &num_buf[ 1 ], so that we have room for the sign
956*b89261baSDavid van Moolenbroek 		 */
957*b89261baSDavid van Moolenbroek 		s = ap_gcvt(va_arg(ap, double), precision, &num_buf[1],
958*b89261baSDavid van Moolenbroek 		            alternate_form);
959*b89261baSDavid van Moolenbroek 		if (*s == '-')
960*b89261baSDavid van Moolenbroek 		    prefix_char = *s++;
961*b89261baSDavid van Moolenbroek 		else if (print_sign)
962*b89261baSDavid van Moolenbroek 		    prefix_char = '+';
963*b89261baSDavid van Moolenbroek 		else if (print_blank)
964*b89261baSDavid van Moolenbroek 		    prefix_char = ' ';
965*b89261baSDavid van Moolenbroek 
966*b89261baSDavid van Moolenbroek 		s_len = strlen(s);
967*b89261baSDavid van Moolenbroek 
968*b89261baSDavid van Moolenbroek 		if (alternate_form && (q = strchr(s, '.')) == NULL) {
969*b89261baSDavid van Moolenbroek 		    s[s_len++] = '.';
970*b89261baSDavid van Moolenbroek 		    s[s_len] = '\0'; /* delimit for following strchr() */
971*b89261baSDavid van Moolenbroek 		}
972*b89261baSDavid van Moolenbroek 		if (*fmt == 'G' && (q = strchr(s, 'e')) != NULL)
973*b89261baSDavid van Moolenbroek 		    *q = 'E';
974*b89261baSDavid van Moolenbroek 		break;
975*b89261baSDavid van Moolenbroek 
976*b89261baSDavid van Moolenbroek 
977*b89261baSDavid van Moolenbroek 	    case 'c':
978*b89261baSDavid van Moolenbroek 		char_buf[0] = (char) (va_arg(ap, int));
979*b89261baSDavid van Moolenbroek 		s = &char_buf[0];
980*b89261baSDavid van Moolenbroek 		s_len = 1;
981*b89261baSDavid van Moolenbroek 		pad_char = ' ';
982*b89261baSDavid van Moolenbroek 		break;
983*b89261baSDavid van Moolenbroek 
984*b89261baSDavid van Moolenbroek 
985*b89261baSDavid van Moolenbroek 	    case '%':
986*b89261baSDavid van Moolenbroek 		char_buf[0] = '%';
987*b89261baSDavid van Moolenbroek 		s = &char_buf[0];
988*b89261baSDavid van Moolenbroek 		s_len = 1;
989*b89261baSDavid van Moolenbroek 		pad_char = ' ';
990*b89261baSDavid van Moolenbroek 		break;
991*b89261baSDavid van Moolenbroek 
992*b89261baSDavid van Moolenbroek 
993*b89261baSDavid van Moolenbroek 	    case 'n':
994*b89261baSDavid van Moolenbroek 	    	if (var_type == IS_QUAD)
995*b89261baSDavid van Moolenbroek 		    *(va_arg(ap, widest_int *)) = cc;
996*b89261baSDavid van Moolenbroek 		else if (var_type == IS_LONG)
997*b89261baSDavid van Moolenbroek 		    *(va_arg(ap, long *)) = cc;
998*b89261baSDavid van Moolenbroek 		else if (var_type == IS_SHORT)
999*b89261baSDavid van Moolenbroek 		    *(va_arg(ap, short *)) = cc;
1000*b89261baSDavid van Moolenbroek 		else
1001*b89261baSDavid van Moolenbroek 		    *(va_arg(ap, int *)) = cc;
1002*b89261baSDavid van Moolenbroek 		break;
1003*b89261baSDavid van Moolenbroek 
1004*b89261baSDavid van Moolenbroek 		/*
1005*b89261baSDavid van Moolenbroek 		 * This is where we extend the printf format, with a second
1006*b89261baSDavid van Moolenbroek 		 * type specifier
1007*b89261baSDavid van Moolenbroek 		 */
1008*b89261baSDavid van Moolenbroek 	    case 'p':
1009*b89261baSDavid van Moolenbroek 		switch(*++fmt) {
1010*b89261baSDavid van Moolenbroek 		    /*
1011*b89261baSDavid van Moolenbroek 		     * If the pointer size is equal to or smaller than the size
1012*b89261baSDavid van Moolenbroek 		     * of the largest unsigned int, we convert the pointer to a
1013*b89261baSDavid van Moolenbroek 		     * hex number, otherwise we print "%p" to indicate that we
1014*b89261baSDavid van Moolenbroek 		     * don't handle "%p".
1015*b89261baSDavid van Moolenbroek 		     */
1016*b89261baSDavid van Moolenbroek 		case 'p':
1017*b89261baSDavid van Moolenbroek #ifdef AP_VOID_P_IS_QUAD
1018*b89261baSDavid van Moolenbroek 		    if (sizeof(void *) <= sizeof(u_widest_int)) {
1019*b89261baSDavid van Moolenbroek 		    	ui_quad = (u_widest_int) va_arg(ap, void *);
1020*b89261baSDavid van Moolenbroek 			s = conv_p2_quad(ui_quad, 4, 'x',
1021*b89261baSDavid van Moolenbroek 				&num_buf[NUM_BUF_SIZE], &s_len);
1022*b89261baSDavid van Moolenbroek 		    }
1023*b89261baSDavid van Moolenbroek #else
1024*b89261baSDavid van Moolenbroek 		    if (sizeof(void *) <= sizeof(u_wide_int)) {
1025*b89261baSDavid van Moolenbroek 		    	ui_num = (u_wide_int) va_arg(ap, void *);
1026*b89261baSDavid van Moolenbroek 			s = conv_p2(ui_num, 4, 'x',
1027*b89261baSDavid van Moolenbroek 				&num_buf[NUM_BUF_SIZE], &s_len);
1028*b89261baSDavid van Moolenbroek 		    }
1029*b89261baSDavid van Moolenbroek #endif
1030*b89261baSDavid van Moolenbroek 		    else {
1031*b89261baSDavid van Moolenbroek 			s = "%p";
1032*b89261baSDavid van Moolenbroek 			s_len = 2;
1033*b89261baSDavid van Moolenbroek 			prefix_char = NUL;
1034*b89261baSDavid van Moolenbroek 		    }
1035*b89261baSDavid van Moolenbroek 		    pad_char = ' ';
1036*b89261baSDavid van Moolenbroek 		    break;
1037*b89261baSDavid van Moolenbroek 
1038*b89261baSDavid van Moolenbroek 		    /* print a struct sockaddr_in as a.b.c.d:port */
1039*b89261baSDavid van Moolenbroek 		case 'I':
1040*b89261baSDavid van Moolenbroek 		    {
1041*b89261baSDavid van Moolenbroek 			struct sockaddr_in *si;
1042*b89261baSDavid van Moolenbroek 
1043*b89261baSDavid van Moolenbroek 			si = va_arg(ap, struct sockaddr_in *);
1044*b89261baSDavid van Moolenbroek 			if (si != NULL) {
1045*b89261baSDavid van Moolenbroek 			    s = conv_sockaddr_in(si, &num_buf[NUM_BUF_SIZE], &s_len);
1046*b89261baSDavid van Moolenbroek 			    if (adjust_precision && precision < s_len)
1047*b89261baSDavid van Moolenbroek 				s_len = precision;
1048*b89261baSDavid van Moolenbroek 			}
1049*b89261baSDavid van Moolenbroek 			else {
1050*b89261baSDavid van Moolenbroek 			    s = S_NULL;
1051*b89261baSDavid van Moolenbroek 			    s_len = S_NULL_LEN;
1052*b89261baSDavid van Moolenbroek 			}
1053*b89261baSDavid van Moolenbroek 			pad_char = ' ';
1054*b89261baSDavid van Moolenbroek 		    }
1055*b89261baSDavid van Moolenbroek 		    break;
1056*b89261baSDavid van Moolenbroek 
1057*b89261baSDavid van Moolenbroek 		    /* print a struct in_addr as a.b.c.d */
1058*b89261baSDavid van Moolenbroek 		case 'A':
1059*b89261baSDavid van Moolenbroek 		    {
1060*b89261baSDavid van Moolenbroek 			struct in_addr *ia;
1061*b89261baSDavid van Moolenbroek 
1062*b89261baSDavid van Moolenbroek 			ia = va_arg(ap, struct in_addr *);
1063*b89261baSDavid van Moolenbroek 			if (ia != NULL) {
1064*b89261baSDavid van Moolenbroek 			    s = conv_in_addr(ia, &num_buf[NUM_BUF_SIZE], &s_len);
1065*b89261baSDavid van Moolenbroek 			    if (adjust_precision && precision < s_len)
1066*b89261baSDavid van Moolenbroek 				s_len = precision;
1067*b89261baSDavid van Moolenbroek 			}
1068*b89261baSDavid van Moolenbroek 			else {
1069*b89261baSDavid van Moolenbroek 			    s = S_NULL;
1070*b89261baSDavid van Moolenbroek 			    s_len = S_NULL_LEN;
1071*b89261baSDavid van Moolenbroek 			}
1072*b89261baSDavid van Moolenbroek 			pad_char = ' ';
1073*b89261baSDavid van Moolenbroek 		    }
1074*b89261baSDavid van Moolenbroek 		    break;
1075*b89261baSDavid van Moolenbroek 
1076*b89261baSDavid van Moolenbroek 		case NUL:
1077*b89261baSDavid van Moolenbroek 		    /* if %p ends the string, oh well ignore it */
1078*b89261baSDavid van Moolenbroek 		    continue;
1079*b89261baSDavid van Moolenbroek 
1080*b89261baSDavid van Moolenbroek 		default:
1081*b89261baSDavid van Moolenbroek 		    s = "bogus %p";
1082*b89261baSDavid van Moolenbroek 		    s_len = 8;
1083*b89261baSDavid van Moolenbroek 		    prefix_char = NUL;
1084*b89261baSDavid van Moolenbroek 		    break;
1085*b89261baSDavid van Moolenbroek 		}
1086*b89261baSDavid van Moolenbroek 		break;
1087*b89261baSDavid van Moolenbroek 
1088*b89261baSDavid van Moolenbroek 	    case NUL:
1089*b89261baSDavid van Moolenbroek 		/*
1090*b89261baSDavid van Moolenbroek 		 * The last character of the format string was %.
1091*b89261baSDavid van Moolenbroek 		 * We ignore it.
1092*b89261baSDavid van Moolenbroek 		 */
1093*b89261baSDavid van Moolenbroek 		continue;
1094*b89261baSDavid van Moolenbroek 
1095*b89261baSDavid van Moolenbroek 
1096*b89261baSDavid van Moolenbroek 		/*
1097*b89261baSDavid van Moolenbroek 		 * The default case is for unrecognized %'s.
1098*b89261baSDavid van Moolenbroek 		 * We print %<char> to help the user identify what
1099*b89261baSDavid van Moolenbroek 		 * option is not understood.
1100*b89261baSDavid van Moolenbroek 		 * This is also useful in case the user wants to pass
1101*b89261baSDavid van Moolenbroek 		 * the output of format_converter to another function
1102*b89261baSDavid van Moolenbroek 		 * that understands some other %<char> (like syslog).
1103*b89261baSDavid van Moolenbroek 		 * Note that we can't point s inside fmt because the
1104*b89261baSDavid van Moolenbroek 		 * unknown <char> could be preceded by width etc.
1105*b89261baSDavid van Moolenbroek 		 */
1106*b89261baSDavid van Moolenbroek 	    default:
1107*b89261baSDavid van Moolenbroek 		char_buf[0] = '%';
1108*b89261baSDavid van Moolenbroek 		char_buf[1] = *fmt;
1109*b89261baSDavid van Moolenbroek 		s = char_buf;
1110*b89261baSDavid van Moolenbroek 		s_len = 2;
1111*b89261baSDavid van Moolenbroek 		pad_char = ' ';
1112*b89261baSDavid van Moolenbroek 		break;
1113*b89261baSDavid van Moolenbroek 	    }
1114*b89261baSDavid van Moolenbroek 
1115*b89261baSDavid van Moolenbroek 	    if (prefix_char != NUL && s != S_NULL && s != char_buf) {
1116*b89261baSDavid van Moolenbroek 		*--s = prefix_char;
1117*b89261baSDavid van Moolenbroek 		s_len++;
1118*b89261baSDavid van Moolenbroek 	    }
1119*b89261baSDavid van Moolenbroek 
1120*b89261baSDavid van Moolenbroek 	    if (adjust_width && adjust == RIGHT && min_width > s_len) {
1121*b89261baSDavid van Moolenbroek 		if (pad_char == '0' && prefix_char != NUL) {
1122*b89261baSDavid van Moolenbroek 		    INS_CHAR(*s, sp, bep, cc);
1123*b89261baSDavid van Moolenbroek 		    s++;
1124*b89261baSDavid van Moolenbroek 		    s_len--;
1125*b89261baSDavid van Moolenbroek 		    min_width--;
1126*b89261baSDavid van Moolenbroek 		}
1127*b89261baSDavid van Moolenbroek 		PAD(min_width, s_len, pad_char);
1128*b89261baSDavid van Moolenbroek 	    }
1129*b89261baSDavid van Moolenbroek 
1130*b89261baSDavid van Moolenbroek 	    /*
1131*b89261baSDavid van Moolenbroek 	     * Print the string s.
1132*b89261baSDavid van Moolenbroek 	     */
1133*b89261baSDavid van Moolenbroek 	    for (i = s_len; i != 0; i--) {
1134*b89261baSDavid van Moolenbroek 		INS_CHAR(*s, sp, bep, cc);
1135*b89261baSDavid van Moolenbroek 		s++;
1136*b89261baSDavid van Moolenbroek 	    }
1137*b89261baSDavid van Moolenbroek 
1138*b89261baSDavid van Moolenbroek 	    if (adjust_width && adjust == LEFT && min_width > s_len)
1139*b89261baSDavid van Moolenbroek 		PAD(min_width, s_len, pad_char);
1140*b89261baSDavid van Moolenbroek 	}
1141*b89261baSDavid van Moolenbroek 	fmt++;
1142*b89261baSDavid van Moolenbroek     }
1143*b89261baSDavid van Moolenbroek     vbuff->curpos = sp;
1144*b89261baSDavid van Moolenbroek 
1145*b89261baSDavid van Moolenbroek     return cc;
1146*b89261baSDavid van Moolenbroek }
1147*b89261baSDavid van Moolenbroek 
1148*b89261baSDavid van Moolenbroek 
snprintf_flush(ap_vformatter_buff * vbuff)1149*b89261baSDavid van Moolenbroek static int snprintf_flush(ap_vformatter_buff *vbuff)
1150*b89261baSDavid van Moolenbroek {
1151*b89261baSDavid van Moolenbroek     /* if the buffer fills we have to abort immediately, there is no way
1152*b89261baSDavid van Moolenbroek      * to "flush" an ap_snprintf... there's nowhere to flush it to.
1153*b89261baSDavid van Moolenbroek      */
1154*b89261baSDavid van Moolenbroek     return -1;
1155*b89261baSDavid van Moolenbroek }
1156*b89261baSDavid van Moolenbroek 
1157*b89261baSDavid van Moolenbroek 
ap_snprintf(char * buf,size_t len,const char * format,...)1158*b89261baSDavid van Moolenbroek API_EXPORT_NONSTD(int) ap_snprintf(char *buf, size_t len, const char *format,...)
1159*b89261baSDavid van Moolenbroek {
1160*b89261baSDavid van Moolenbroek     int cc;
1161*b89261baSDavid van Moolenbroek     va_list ap;
1162*b89261baSDavid van Moolenbroek     ap_vformatter_buff vbuff;
1163*b89261baSDavid van Moolenbroek 
1164*b89261baSDavid van Moolenbroek     if (len == 0)
1165*b89261baSDavid van Moolenbroek 	return 0;
1166*b89261baSDavid van Moolenbroek 
1167*b89261baSDavid van Moolenbroek     /* save one byte for nul terminator */
1168*b89261baSDavid van Moolenbroek     vbuff.curpos = buf;
1169*b89261baSDavid van Moolenbroek     vbuff.endpos = buf + len - 1;
1170*b89261baSDavid van Moolenbroek     va_start(ap, format);
1171*b89261baSDavid van Moolenbroek     cc = ap_vformatter(snprintf_flush, &vbuff, format, ap);
1172*b89261baSDavid van Moolenbroek     va_end(ap);
1173*b89261baSDavid van Moolenbroek     *vbuff.curpos = '\0';
1174*b89261baSDavid van Moolenbroek     return (cc == -1) ? len : cc;
1175*b89261baSDavid van Moolenbroek }
1176*b89261baSDavid van Moolenbroek 
1177*b89261baSDavid van Moolenbroek 
ap_vsnprintf(char * buf,size_t len,const char * format,va_list ap)1178*b89261baSDavid van Moolenbroek API_EXPORT(int) ap_vsnprintf(char *buf, size_t len, const char *format,
1179*b89261baSDavid van Moolenbroek 			     va_list ap)
1180*b89261baSDavid van Moolenbroek {
1181*b89261baSDavid van Moolenbroek     int cc;
1182*b89261baSDavid van Moolenbroek     ap_vformatter_buff vbuff;
1183*b89261baSDavid van Moolenbroek 
1184*b89261baSDavid van Moolenbroek     if (len == 0)
1185*b89261baSDavid van Moolenbroek 	return 0;
1186*b89261baSDavid van Moolenbroek 
1187*b89261baSDavid van Moolenbroek     /* save one byte for nul terminator */
1188*b89261baSDavid van Moolenbroek     vbuff.curpos = buf;
1189*b89261baSDavid van Moolenbroek     vbuff.endpos = buf + len - 1;
1190*b89261baSDavid van Moolenbroek     cc = ap_vformatter(snprintf_flush, &vbuff, format, ap);
1191*b89261baSDavid van Moolenbroek     *vbuff.curpos = '\0';
1192*b89261baSDavid van Moolenbroek     return (cc == -1) ? len : cc;
1193*b89261baSDavid van Moolenbroek }
1194