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