1 /* ====================================================================
2 * Copyright (c) 1995-1998 The Apache Group. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
14 * distribution.
15 *
16 * 3. All advertising materials mentioning features or use of this
17 * software must display the following acknowledgment:
18 * "This product includes software developed by the Apache Group
19 * 4. The names "Apache Server" and "Apache Group" must not be used to
20 * endorse or promote products derived from this software without
21 * prior written permission.
22 *
23 * 5. Redistributions of any form whatsoever must retain the following
24 * acknowledgment:
25 * "This product includes software developed by the Apache Group
26 * for use in the Apache HTTP server project (http://www.apache.org/)."
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
29 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR
32 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
34 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
35 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
37 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
39 * OF THE POSSIBILITY OF SUCH DAMAGE.
40 * ====================================================================
41 *
42 * This software consists of voluntary contributions made by many
43 * individuals on behalf of the Apache Group and was originally based
44 * on public domain software written at the National Center for
45 * Supercomputing Applications, University of Illinois, Urbana-Champaign.
46 * For more information on the Apache Group and the Apache HTTP server
47 * project, please see <http://www.apache.org/>.
48 *
49 * This code is based on, and used with the permission of, the
50 * SIO stdio-replacement strx_* functions by Panos Tsirigotis
51 * <panos@alumni.cs.colorado.edu> for xinetd.
52 */
53
54 #ifdef HAVE_CONFIG_H
55 # include "config.h"
56 #endif
57
58 #if !defined(HAVE_SNPRINTF) || defined(HAVE_BROKEN_SNPRINTF) || !defined(HAVE_VSNPRINTF) || defined(HAVE_BROKEN_VSNPRINTF)
59
60 /* jabberd2 Windows DLL */
61 #ifndef JABBERD2_API
62 # ifdef _WIN32
63 # ifdef JABBERD2_EXPORTS
64 # define JABBERD2_API __declspec(dllexport)
65 # else /* JABBERD2_EXPORTS */
66 # define JABBERD2_API __declspec(dllimport)
67 # endif /* JABBERD2_EXPORTS */
68 # else /* _WIN32 */
69 # define JABBERD2_API extern
70 # endif /* _WIN32 */
71 #endif /* JABBERD2_API */
72
73 #include <stdio.h>
74 #include <ctype.h>
75 #include <sys/types.h>
76 #include <stdarg.h>
77 #include <string.h>
78 #include <stdlib.h>
79 #include <math.h>
80
81
82 #ifdef HAVE_GCVT
83
84 #define ap_ecvt ecvt
85 #define ap_fcvt fcvt
86 #define ap_gcvt gcvt
87
88 #else
89
90 /*
91 * cvt.c - IEEE floating point formatting routines for FreeBSD
92 * from GNU libc-4.6.27
93 */
94
95 /*
96 * ap_ecvt converts to decimal
97 * the number of digits is specified by ndigit
98 * decpt is set to the position of the decimal point
99 * sign is set to 0 for positive, 1 for negative
100 */
101
102 #define NDIG 80
103
104 static char *
ap_cvt(double arg,int ndigits,int * decpt,int * sign,int eflag)105 ap_cvt(double arg, int ndigits, int *decpt, int *sign, int eflag)
106 {
107 register int r2;
108 double fi, fj;
109 register char *p, *p1;
110 static char buf[NDIG];
111
112 if (ndigits >= NDIG - 1)
113 ndigits = NDIG - 2;
114 r2 = 0;
115 *sign = 0;
116 p = &buf[0];
117 if (arg < 0) {
118 *sign = 1;
119 arg = -arg;
120 }
121 arg = modf(arg, &fi);
122 p1 = &buf[NDIG];
123 /*
124 * Do integer part
125 */
126 if (fi != 0) {
127 p1 = &buf[NDIG];
128 while (fi != 0) {
129 fj = modf(fi / 10, &fi);
130 *--p1 = (int) ((fj + .03) * 10) + '0';
131 r2++;
132 }
133 while (p1 < &buf[NDIG])
134 *p++ = *p1++;
135 } else if (arg > 0) {
136 while ((fj = arg * 10) < 1) {
137 arg = fj;
138 r2--;
139 }
140 }
141 p1 = &buf[ndigits];
142 if (eflag == 0)
143 p1 += r2;
144 *decpt = r2;
145 if (p1 < &buf[0]) {
146 buf[0] = '\0';
147 return (buf);
148 }
149 while (p <= p1 && p < &buf[NDIG]) {
150 arg *= 10;
151 arg = modf(arg, &fj);
152 *p++ = (int) fj + '0';
153 }
154 if (p1 >= &buf[NDIG]) {
155 buf[NDIG - 1] = '\0';
156 return (buf);
157 }
158 p = p1;
159 *p1 += 5;
160 while (*p1 > '9') {
161 *p1 = '0';
162 if (p1 > buf)
163 ++ * --p1;
164 else {
165 *p1 = '1';
166 (*decpt)++;
167 if (eflag == 0) {
168 if (p > buf)
169 *p = '0';
170 p++;
171 }
172 }
173 }
174 *p = '\0';
175 return (buf);
176 }
177
178 static char *
ap_ecvt(double arg,int ndigits,int * decpt,int * sign)179 ap_ecvt(double arg, int ndigits, int *decpt, int *sign)
180 {
181 return (ap_cvt(arg, ndigits, decpt, sign, 1));
182 }
183
184 static char *
ap_fcvt(double arg,int ndigits,int * decpt,int * sign)185 ap_fcvt(double arg, int ndigits, int *decpt, int *sign)
186 {
187 return (ap_cvt(arg, ndigits, decpt, sign, 0));
188 }
189
190 /*
191 * ap_gcvt - Floating output conversion to
192 * minimal length string
193 */
194
195 static char *
ap_gcvt(double number,int ndigit,char * buf)196 ap_gcvt(double number, int ndigit, char *buf)
197 {
198 int sign, decpt;
199 register char *p1, *p2;
200 int i;
201
202 p1 = ap_ecvt(number, ndigit, &decpt, &sign);
203 p2 = buf;
204 if (sign)
205 *p2++ = '-';
206 for (i = ndigit - 1; i > 0 && p1[i] == '0'; i--)
207 ndigit--;
208 if ((decpt >= 0 && decpt - ndigit > 4)
209 || (decpt < 0 && decpt < -3)) { /* use E-style */
210 decpt--;
211 *p2++ = *p1++;
212 *p2++ = '.';
213 for (i = 1; i < ndigit; i++)
214 *p2++ = *p1++;
215 *p2++ = 'e';
216 if (decpt < 0) {
217 decpt = -decpt;
218 *p2++ = '-';
219 } else
220 *p2++ = '+';
221 if (decpt / 100 > 0)
222 *p2++ = decpt / 100 + '0';
223 if (decpt / 10 > 0)
224 *p2++ = (decpt % 100) / 10 + '0';
225 *p2++ = decpt % 10 + '0';
226 } else {
227 if (decpt <= 0) {
228 if (*p1 != '0')
229 *p2++ = '.';
230 while (decpt < 0) {
231 decpt++;
232 *p2++ = '0';
233 }
234 }
235 for (i = 1; i <= ndigit; i++) {
236 *p2++ = *p1++;
237 if (i == decpt)
238 *p2++ = '.';
239 }
240 if (ndigit < decpt) {
241 while (ndigit++ < decpt)
242 *p2++ = '0';
243 *p2++ = '.';
244 }
245 }
246 if (p2[-1] == '.')
247 p2--;
248 *p2 = '\0';
249 return (buf);
250 }
251
252 #endif /* HAVE_CVT */
253
254 typedef enum {
255 NO = 0, YES = 1
256 } boolean_e;
257
258 #define FALSE 0
259 #define TRUE 1
260 #define NUL '\0'
261 #define INT_NULL ((int *)0)
262 #define WIDE_INT long
263
264 typedef WIDE_INT wide_int;
265 typedef unsigned WIDE_INT u_wide_int;
266 typedef int bool_int;
267
268 #define S_NULL "(null)"
269 #define S_NULL_LEN 6
270
271 #define FLOAT_DIGITS 6
272 #define EXPONENT_LENGTH 10
273
274 /*
275 * NUM_BUF_SIZE is the size of the buffer used for arithmetic conversions
276 *
277 * XXX: this is a magic number; do not decrease it
278 */
279 #define NUM_BUF_SIZE 512
280
281
282 /*
283 * Descriptor for buffer area
284 */
285 struct buf_area {
286 char *buf_end;
287 char *nextb; /* pointer to next byte to read/write */
288 };
289
290 typedef struct buf_area buffy;
291
292 /*
293 * The INS_CHAR macro inserts a character in the buffer and writes
294 * the buffer back to disk if necessary
295 * It uses the char pointers sp and bep:
296 * sp points to the next available character in the buffer
297 * bep points to the end-of-buffer+1
298 * While using this macro, note that the nextb pointer is NOT updated.
299 *
300 * NOTE: Evaluation of the c argument should not have any side-effects
301 */
302 #define INS_CHAR( c, sp, bep, cc ) \
303 { \
304 if ( sp < bep ) \
305 { \
306 *sp++ = c ; \
307 cc++ ; \
308 } \
309 }
310
311 #define NUM( c ) ( c - '0' )
312
313 #define STR_TO_DEC( str, num ) \
314 num = NUM( *str++ ) ; \
315 while ( isdigit((int)*str ) ) \
316 { \
317 num *= 10 ; \
318 num += NUM( *str++ ) ; \
319 }
320
321 /*
322 * This macro does zero padding so that the precision
323 * requirement is satisfied. The padding is done by
324 * adding '0's to the left of the string that is going
325 * to be printed.
326 */
327 #define FIX_PRECISION( adjust, precision, s, s_len ) \
328 if ( adjust ) \
329 while ( s_len < precision ) \
330 { \
331 *--s = '0' ; \
332 s_len++ ; \
333 }
334
335 /*
336 * Macro that does padding. The padding is done by printing
337 * the character ch.
338 */
339 #define PAD( width, len, ch ) do \
340 { \
341 INS_CHAR( ch, sp, bep, cc ) ; \
342 width-- ; \
343 } \
344 while ( width > len )
345
346 /*
347 * Prefix the character ch to the string str
348 * Increase length
349 * Set the has_prefix flag
350 */
351 #define PREFIX( str, length, ch ) *--str = ch ; length++ ; has_prefix = YES
352
353
354 /*
355 * Convert num to its decimal format.
356 * Return value:
357 * - a pointer to a string containing the number (no sign)
358 * - len contains the length of the string
359 * - is_negative is set to TRUE or FALSE depending on the sign
360 * of the number (always set to FALSE if is_unsigned is TRUE)
361 *
362 * The caller provides a buffer for the string: that is the buf_end argument
363 * which is a pointer to the END of the buffer + 1 (i.e. if the buffer
364 * is declared as buf[ 100 ], buf_end should be &buf[ 100 ])
365 */
366 static char *
conv_10(register wide_int num,register bool_int is_unsigned,register bool_int * is_negative,char * buf_end,register int * len)367 conv_10(register wide_int num, register bool_int is_unsigned,
368 register bool_int * is_negative, char *buf_end, register int *len)
369 {
370 register char *p = buf_end;
371 register u_wide_int magnitude;
372
373 if (is_unsigned) {
374 magnitude = (u_wide_int) num;
375 *is_negative = FALSE;
376 } else {
377 *is_negative = (num < 0);
378
379 /*
380 * On a 2's complement machine, negating the most negative integer
381 * results in a number that cannot be represented as a signed integer.
382 * Here is what we do to obtain the number's magnitude:
383 * a. add 1 to the number
384 * b. negate it (becomes positive)
385 * c. convert it to unsigned
386 * d. add 1
387 */
388 if (*is_negative) {
389 wide_int t = num + 1;
390
391 magnitude = ((u_wide_int) - t) + 1;
392 } else
393 magnitude = (u_wide_int) num;
394 }
395
396 /*
397 * We use a do-while loop so that we write at least 1 digit
398 */
399 do {
400 register u_wide_int new_magnitude = magnitude / 10;
401
402 *--p = magnitude - new_magnitude * 10 + '0';
403 magnitude = new_magnitude;
404 }
405 while (magnitude);
406
407 *len = buf_end - p;
408 return (p);
409 }
410
411
412
413 /*
414 * Convert a floating point number to a string formats 'f', 'e' or 'E'.
415 * The result is placed in buf, and len denotes the length of the string
416 * The sign is returned in the is_negative argument (and is not placed
417 * in buf).
418 */
419 static char *
conv_fp(register char format,register double num,boolean_e add_dp,int precision,bool_int * is_negative,char * buf,int * len)420 conv_fp(register char format, register double num,
421 boolean_e add_dp, int precision, bool_int * is_negative, char *buf, int *len)
422 {
423 register char *s = buf;
424 register char *p;
425 int decimal_point;
426
427 if (format == 'f')
428 p = ap_fcvt(num, precision, &decimal_point, is_negative);
429 else /* either e or E format */
430 p = ap_ecvt(num, precision + 1, &decimal_point, is_negative);
431
432 /*
433 * Check for Infinity and NaN
434 */
435 if (isalpha((int)*p)) {
436 *len = strlen(strcpy(buf, p));
437 *is_negative = FALSE;
438 return (buf);
439 }
440 if (format == 'f') {
441 if (decimal_point <= 0) {
442 *s++ = '0';
443 if (precision > 0) {
444 *s++ = '.';
445 while (decimal_point++ < 0)
446 *s++ = '0';
447 } else if (add_dp) {
448 *s++ = '.';
449 }
450 } else {
451 while (decimal_point-- > 0) {
452 *s++ = *p++;
453 }
454 if (precision > 0 || add_dp) {
455 *s++ = '.';
456 }
457 }
458 } else {
459 *s++ = *p++;
460 if (precision > 0 || add_dp)
461 *s++ = '.';
462 }
463
464 /*
465 * copy the rest of p, the NUL is NOT copied
466 */
467 while (*p)
468 *s++ = *p++;
469
470 if (format != 'f') {
471 char temp[EXPONENT_LENGTH]; /* for exponent conversion */
472 int t_len;
473 bool_int exponent_is_negative;
474
475 *s++ = format; /* either e or E */
476 decimal_point--;
477 if (decimal_point != 0) {
478 p = conv_10((wide_int) decimal_point, FALSE, &exponent_is_negative,
479 &temp[EXPONENT_LENGTH], &t_len);
480 *s++ = exponent_is_negative ? '-' : '+';
481
482 /*
483 * Make sure the exponent has at least 2 digits
484 */
485 if (t_len == 1)
486 *s++ = '0';
487 while (t_len--)
488 *s++ = *p++;
489 } else {
490 *s++ = '+';
491 *s++ = '0';
492 *s++ = '0';
493 }
494 }
495 *len = s - buf;
496 return (buf);
497 }
498
499
500 /*
501 * Convert num to a base X number where X is a power of 2. nbits determines X.
502 * For example, if nbits is 3, we do base 8 conversion
503 * Return value:
504 * a pointer to a string containing the number
505 *
506 * The caller provides a buffer for the string: that is the buf_end argument
507 * which is a pointer to the END of the buffer + 1 (i.e. if the buffer
508 * is declared as buf[ 100 ], buf_end should be &buf[ 100 ])
509 */
510 static char *
conv_p2(register u_wide_int num,register int nbits,char format,char * buf_end,register int * len)511 conv_p2(register u_wide_int num, register int nbits,
512 char format, char *buf_end, register int *len)
513 {
514 register int mask = (1 << nbits) - 1;
515 register char *p = buf_end;
516 static char low_digits[] = "0123456789abcdef";
517 static char upper_digits[] = "0123456789ABCDEF";
518 register char *digits = (format == 'X') ? upper_digits : low_digits;
519
520 do {
521 *--p = digits[num & mask];
522 num >>= nbits;
523 }
524 while (num);
525
526 *len = buf_end - p;
527 return (p);
528 }
529
530
531 /*
532 * Do format conversion placing the output in buffer
533 */
format_converter(register buffy * odp,const char * fmt,va_list ap)534 static int format_converter(register buffy * odp, const char *fmt,
535 va_list ap)
536 {
537 register char *sp;
538 register char *bep;
539 register int cc = 0;
540 register int i;
541
542 register char *s = NULL;
543 char *q;
544 int s_len;
545
546 register int min_width = 0;
547 int precision = 0;
548 enum {
549 LEFT, RIGHT
550 } adjust;
551 char pad_char;
552 char prefix_char;
553
554 double fp_num;
555 wide_int i_num = (wide_int) 0;
556 u_wide_int ui_num;
557
558 char num_buf[NUM_BUF_SIZE];
559 char char_buf[2]; /* for printing %% and %<unknown> */
560
561 /*
562 * Flag variables
563 */
564 boolean_e is_long;
565 boolean_e alternate_form;
566 boolean_e print_sign;
567 boolean_e print_blank;
568 boolean_e adjust_precision;
569 boolean_e adjust_width;
570 bool_int is_negative;
571
572 sp = odp->nextb;
573 bep = odp->buf_end;
574
575 while (*fmt) {
576 if (*fmt != '%') {
577 INS_CHAR(*fmt, sp, bep, cc);
578 } else {
579 /*
580 * Default variable settings
581 */
582 adjust = RIGHT;
583 alternate_form = print_sign = print_blank = NO;
584 pad_char = ' ';
585 prefix_char = NUL;
586
587 fmt++;
588
589 /*
590 * Try to avoid checking for flags, width or precision
591 */
592 if (isascii((int)*fmt) && !islower((int)*fmt)) {
593 /*
594 * Recognize flags: -, #, BLANK, +
595 */
596 for (;; fmt++) {
597 if (*fmt == '-')
598 adjust = LEFT;
599 else if (*fmt == '+')
600 print_sign = YES;
601 else if (*fmt == '#')
602 alternate_form = YES;
603 else if (*fmt == ' ')
604 print_blank = YES;
605 else if (*fmt == '0')
606 pad_char = '0';
607 else
608 break;
609 }
610
611 /*
612 * Check if a width was specified
613 */
614 if (isdigit((int)*fmt)) {
615 STR_TO_DEC(fmt, min_width);
616 adjust_width = YES;
617 } else if (*fmt == '*') {
618 min_width = va_arg(ap, int);
619 fmt++;
620 adjust_width = YES;
621 if (min_width < 0) {
622 adjust = LEFT;
623 min_width = -min_width;
624 }
625 } else
626 adjust_width = NO;
627
628 /*
629 * Check if a precision was specified
630 *
631 * XXX: an unreasonable amount of precision may be specified
632 * resulting in overflow of num_buf. Currently we
633 * ignore this possibility.
634 */
635 if (*fmt == '.') {
636 adjust_precision = YES;
637 fmt++;
638 if (isdigit((int)*fmt)) {
639 STR_TO_DEC(fmt, precision);
640 } else if (*fmt == '*') {
641 precision = va_arg(ap, int);
642 fmt++;
643 if (precision < 0)
644 precision = 0;
645 } else
646 precision = 0;
647 } else
648 adjust_precision = NO;
649 } else
650 adjust_precision = adjust_width = NO;
651
652 /*
653 * Modifier check
654 */
655 if (*fmt == 'l') {
656 is_long = YES;
657 fmt++;
658 } else
659 is_long = NO;
660
661 /*
662 * Argument extraction and printing.
663 * First we determine the argument type.
664 * Then, we convert the argument to a string.
665 * On exit from the switch, s points to the string that
666 * must be printed, s_len has the length of the string
667 * The precision requirements, if any, are reflected in s_len.
668 *
669 * NOTE: pad_char may be set to '0' because of the 0 flag.
670 * It is reset to ' ' by non-numeric formats
671 */
672 switch (*fmt) {
673 case 'u':
674 if (is_long)
675 i_num = va_arg(ap, u_wide_int);
676 else
677 i_num = (wide_int) va_arg(ap, unsigned int);
678 /*
679 * The rest also applies to other integer formats, so fall
680 * into that case.
681 */
682 case 'd':
683 case 'i':
684 /*
685 * Get the arg if we haven't already.
686 */
687 if ((*fmt) != 'u') {
688 if (is_long)
689 i_num = va_arg(ap, wide_int);
690 else
691 i_num = (wide_int) va_arg(ap, int);
692 };
693 s = conv_10(i_num, (*fmt) == 'u', &is_negative,
694 &num_buf[NUM_BUF_SIZE], &s_len);
695 FIX_PRECISION(adjust_precision, precision, s, s_len);
696
697 if (*fmt != 'u') {
698 if (is_negative)
699 prefix_char = '-';
700 else if (print_sign)
701 prefix_char = '+';
702 else if (print_blank)
703 prefix_char = ' ';
704 }
705 break;
706
707
708 case 'o':
709 if (is_long)
710 ui_num = va_arg(ap, u_wide_int);
711 else
712 ui_num = (u_wide_int) va_arg(ap, unsigned int);
713 s = conv_p2(ui_num, 3, *fmt,
714 &num_buf[NUM_BUF_SIZE], &s_len);
715 FIX_PRECISION(adjust_precision, precision, s, s_len);
716 if (alternate_form && *s != '0') {
717 *--s = '0';
718 s_len++;
719 }
720 break;
721
722
723 case 'x':
724 case 'X':
725 if (is_long)
726 ui_num = (u_wide_int) va_arg(ap, u_wide_int);
727 else
728 ui_num = (u_wide_int) va_arg(ap, unsigned int);
729 s = conv_p2(ui_num, 4, *fmt,
730 &num_buf[NUM_BUF_SIZE], &s_len);
731 FIX_PRECISION(adjust_precision, precision, s, s_len);
732 if (alternate_form && i_num != 0) {
733 *--s = *fmt; /* 'x' or 'X' */
734 *--s = '0';
735 s_len += 2;
736 }
737 break;
738
739
740 case 's':
741 s = va_arg(ap, char *);
742 if (s != NULL) {
743 if (!adjust_precision) {
744 s_len = strlen(s);
745 }
746 else {
747 /* From the C library standard in section 7.9.6.1:
748 * ...if the precision is specified, no more then
749 * that many characters are written. If the
750 * precision is not specified or is greater
751 * than the size of the array, the array shall
752 * contain a null character.
753 *
754 * My reading is is precision is specified and
755 * is less then or equal to the size of the
756 * array, no null character is required. So
757 * we can't do a strlen.
758 *
759 * This figures out the length of the string
760 * up to the precision. Once it's long enough
761 * for the specified precision, we don't care
762 * anymore.
763 *
764 * NOTE: you must do the length comparison
765 * before the check for the null character.
766 * Otherwise, you'll check one beyond the
767 * last valid character.
768 */
769 const char *walk;
770
771 for (walk = s, s_len = 0;
772 (s_len < precision) && (*walk != '\0');
773 ++walk, ++s_len);
774 }
775 } else {
776 s = S_NULL;
777 s_len = S_NULL_LEN;
778 }
779 pad_char = ' ';
780 break;
781
782
783 case 'f':
784 case 'e':
785 case 'E':
786 fp_num = va_arg(ap, double);
787
788 s = conv_fp(*fmt, fp_num, alternate_form,
789 (adjust_precision == NO) ? FLOAT_DIGITS : precision,
790 &is_negative, &num_buf[1], &s_len);
791 if (is_negative)
792 prefix_char = '-';
793 else if (print_sign)
794 prefix_char = '+';
795 else if (print_blank)
796 prefix_char = ' ';
797 break;
798
799
800 case 'g':
801 case 'G':
802 if (adjust_precision == NO)
803 precision = FLOAT_DIGITS;
804 else if (precision == 0)
805 precision = 1;
806 /*
807 * * We use &num_buf[ 1 ], so that we have room for the sign
808 */
809 s = ap_gcvt(va_arg(ap, double), precision, &num_buf[1]);
810 if (*s == '-')
811 prefix_char = *s++;
812 else if (print_sign)
813 prefix_char = '+';
814 else if (print_blank)
815 prefix_char = ' ';
816
817 s_len = strlen(s);
818
819 if (alternate_form && (q = strchr(s, '.')) == NULL)
820 s[s_len++] = '.';
821 if (*fmt == 'G' && (q = strchr(s, 'e')) != NULL)
822 *q = 'E';
823 break;
824
825
826 case 'c':
827 char_buf[0] = (char) (va_arg(ap, int));
828 s = &char_buf[0];
829 s_len = 1;
830 pad_char = ' ';
831 break;
832
833
834 case '%':
835 char_buf[0] = '%';
836 s = &char_buf[0];
837 s_len = 1;
838 pad_char = ' ';
839 break;
840
841
842 case 'n':
843 *(va_arg(ap, int *)) = cc;
844 break;
845
846 /*
847 * Always extract the argument as a "char *" pointer. We
848 * should be using "void *" but there are still machines
849 * that don't understand it.
850 * If the pointer size is equal to the size of an unsigned
851 * integer we convert the pointer to a hex number, otherwise
852 * we print "%p" to indicate that we don't handle "%p".
853 */
854 case 'p':
855 ui_num = (u_wide_int) va_arg(ap, char *);
856
857 if (sizeof(char *) <= sizeof(u_wide_int))
858 s = conv_p2(ui_num, 4, 'x',
859 &num_buf[NUM_BUF_SIZE], &s_len);
860 else {
861 s = "%p";
862 s_len = 2;
863 }
864 pad_char = ' ';
865 break;
866
867
868 case NUL:
869 /*
870 * The last character of the format string was %.
871 * We ignore it.
872 */
873 continue;
874
875
876 /*
877 * The default case is for unrecognized %'s.
878 * We print %<char> to help the user identify what
879 * option is not understood.
880 * This is also useful in case the user wants to pass
881 * the output of format_converter to another function
882 * that understands some other %<char> (like syslog).
883 * Note that we can't point s inside fmt because the
884 * unknown <char> could be preceded by width etc.
885 */
886 default:
887 char_buf[0] = '%';
888 char_buf[1] = *fmt;
889 s = char_buf;
890 s_len = 2;
891 pad_char = ' ';
892 break;
893 }
894
895 if (prefix_char != NUL) {
896 *--s = prefix_char;
897 s_len++;
898 }
899 if (adjust_width && adjust == RIGHT && min_width > s_len) {
900 if (pad_char == '0' && prefix_char != NUL) {
901 INS_CHAR(*s, sp, bep, cc)
902 s++;
903 s_len--;
904 min_width--;
905 }
906 PAD(min_width, s_len, pad_char);
907 }
908 /*
909 * Print the string s.
910 */
911 for (i = s_len; i != 0; i--) {
912 INS_CHAR(*s, sp, bep, cc);
913 s++;
914 }
915
916 if (adjust_width && adjust == LEFT && min_width > s_len)
917 PAD(min_width, s_len, pad_char);
918 }
919 fmt++;
920 }
921 odp->nextb = sp;
922 return (cc);
923 }
924
925
926 /*
927 * This is the general purpose conversion function.
928 */
strx_printv(int * ccp,char * buf,size_t len,const char * format,va_list ap)929 static void strx_printv(int *ccp, char *buf, size_t len, const char *format,
930 va_list ap)
931 {
932 buffy od;
933 int cc;
934
935 /*
936 * First initialize the descriptor
937 * Notice that if no length is given, we initialize buf_end to the
938 * highest possible address.
939 */
940 od.buf_end = len ? &buf[len] : (char *) ~0;
941 od.nextb = buf;
942
943 /*
944 * Do the conversion
945 */
946 cc = format_converter(&od, format, ap);
947 if (len == 0 || od.nextb <= od.buf_end)
948 *(od.nextb) = '\0';
949 if (ccp)
950 *ccp = cc;
951 }
952
953
ap_snprintf(char * buf,size_t len,const char * format,...)954 JABBERD2_API int ap_snprintf(char *buf, size_t len, const char *format,...)
955 {
956 int cc;
957 va_list ap;
958
959 va_start(ap, format);
960 strx_printv(&cc, buf, (len - 1), format, ap);
961 va_end(ap);
962 return (cc);
963 }
964
965
ap_vsnprintf(char * buf,size_t len,const char * format,va_list ap)966 JABBERD2_API int ap_vsnprintf(char *buf, size_t len, const char *format, va_list ap)
967 {
968 int cc;
969
970 strx_printv(&cc, buf, (len - 1), format, ap);
971 return (cc);
972 }
973
974 #endif /* HAVE_SNPRINTF */
975