source: trunk/third/jwgc/lib/libxode/snprintf.c @ 22406

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