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