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