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