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