~ubuntu-branches/ubuntu/gutsy/vnc4/gutsy

« back to all changes in this revision

Viewing changes to unix/xc/lib/misc/snprintf.c

  • Committer: Bazaar Package Importer
  • Author(s): Ola Lundqvist
  • Date: 2006-05-15 20:35:17 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20060515203517-l4lre1ku942mn26k
Tags: 4.1.1+X4.3.0-10
* Correction of critical security issue. Thanks to Martin Kogler
  <e9925248@student.tuwien.ac.at> that informed me about the issue,
  and provided the patch.
  This flaw was originally found by Steve Wiseman of intelliadmin.com.
* Applied patch from Javier Kohen <jkohen@users.sourceforge.net> that
  inform the user that only 8 first characters of the password will
  actually be used when typing more than 8 characters, closes:
  #355619.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * This version of snprintf() and vsnprintf() is based on Sprint from
 
3
 * SIO by Panagiotis Tsirigotis, as included with xidentd-2.2.1.
 
4
 *
 
5
 * The modifications were made by The XFree86 Project, Inc and are
 
6
 * Copyright 1999 by The XFree86 Project, Inc.  These modifications
 
7
 * consist of removing the support for writing to file streams,
 
8
 * renaming some functions, ansification, and making some adjustments
 
9
 * to achieve the semantics for snprintf and vsnprintf() as described
 
10
 * in the relevant man page for FreeBSD 2.2.8.
 
11
 *
 
12
 *
 
13
 * The original version carries the following notice:
 
14
 *
 
15
 * (c) Copyright 1992, 1993 by Panagiotis Tsirigotis
 
16
 *
 
17
 * The author (Panagiotis Tsirigotis) grants permission to use, copy,
 
18
 * and distribute this software and its documentation for any purpose
 
19
 * and without fee, provided that a) the above copyright notice extant in
 
20
 * files in this distribution is not removed from files included in any
 
21
 * redistribution, and b) this file is also included in any redistribution.
 
22
 *
 
23
 * Modifications to this software may be distributed, either by distributing
 
24
 * the modified software or by distributing patches to the original software,
 
25
 * under the following additional terms:
 
26
 *
 
27
 * 1. The version number will be modified as follows:
 
28
 *      a. The first 3 components of the version number
 
29
 *         (i.e. <number>.<number>.<number>) will remain unchanged.
 
30
 *      b. A new component will be appended to the version number to indicate
 
31
 *         the modification level. The form of this component is up to the
 
32
 *         author of the modifications.
 
33
 *
 
34
 * 2. The author of the modifications will include his/her name by appending
 
35
 *    it along with the new version number to this file and will be
 
36
 *    responsible for any wrong behavior of the modified software.
 
37
 *
 
38
 * The author makes no representations about the suitability of this
 
39
 * software for any purpose.  It is provided "as is" without any express
 
40
 * or implied warranty.
 
41
 *
 
42
 * Changes and modifications for: 
 
43
 *
 
44
 * xinetd Version 2.1.4-bsdi
 
45
 * xinetd Version 2.1.4-freebsd
 
46
 * xinetd Version 2.1.4-linux
 
47
 *
 
48
 * are      
 
49
 *
 
50
 * (c) Copyright 1995 by Charles Murcko
 
51
 * All Rights Reserved
 
52
 */
 
53
 
 
54
/* $XFree86: xc/lib/misc/snprintf.c,v 3.1 1999/04/28 15:04:51 dawes Exp $ */
 
55
 
 
56
 
 
57
/*
 
58
 * Assumption: systems that don't have snprintf and vsnprintf do have
 
59
 * ecvt, fcvt and gcvt.
 
60
 */
 
61
 
 
62
/* From: Id: sprint.c,v 1.5 1995/09/10 18:35:09 chuck Exp */
 
63
 
 
64
#include <ctype.h>
 
65
#include <stdlib.h>
 
66
#include <stdarg.h>
 
67
#include <string.h>
 
68
#include <sys/types.h>
 
69
 
 
70
#ifndef SCOPE
 
71
#define SCOPE                                   /**/
 
72
#endif
 
73
 
 
74
#ifndef WIDE_INT
 
75
#define WIDE_INT                                long
 
76
#endif
 
77
 
 
78
typedef WIDE_INT wide_int;
 
79
typedef unsigned WIDE_INT u_wide_int;
 
80
typedef int bool_int;
 
81
 
 
82
#ifndef FALSE
 
83
#define FALSE                                   0
 
84
#define TRUE                                    1
 
85
#endif
 
86
 
 
87
#define NUL                                     '\0'
 
88
 
 
89
#define S_NULL                                  "(null)"
 
90
#define S_NULL_LEN                              6
 
91
 
 
92
#define FLOAT_DIGITS                            6
 
93
#define EXPONENT_LENGTH                         10
 
94
 
 
95
typedef enum { NO = 0, YES = 1 } boolean_e ;
 
96
 
 
97
/*
 
98
 * NUM_BUF_SIZE is the size of the buffer used for arithmetic conversions
 
99
 *
 
100
 * XXX: this is a magic number; do not decrease it
 
101
 */
 
102
#define NUM_BUF_SIZE                            512
 
103
 
 
104
/*
 
105
 * The INS_CHAR macro inserts a character in the buffer.
 
106
 * It uses the char pointers sp and bep:
 
107
 *      sp points to the next available character in the buffer
 
108
 *      bep points to the end-of-buffer
 
109
 * While using this macro, note that the nextb pointer is NOT updated.
 
110
 *
 
111
 * Excess characters are discarded if the string overflows.
 
112
 *
 
113
 * NOTE: Evaluation of the c argument should not have any side-effects
 
114
 */
 
115
#define INS_CHAR( c, sp, bep, cc )                                      \
 
116
        {                                                               \
 
117
            if ( sp < bep )                                             \
 
118
                *sp++ = c ;                                             \
 
119
            cc++ ;                                                      \
 
120
        }
 
121
 
 
122
#define NUM( c )                        ( c - '0' )
 
123
 
 
124
#define STR_TO_DEC( str, num )                                          \
 
125
        num = NUM( *str++ ) ;                                           \
 
126
        while ( isdigit( *str ) ) {                                     \
 
127
                num *= 10 ;                                             \
 
128
                num += NUM( *str++ ) ;                                  \
 
129
        }
 
130
 
 
131
/*
 
132
 * This macro does zero padding so that the precision
 
133
 * requirement is satisfied. The padding is done by
 
134
 * adding '0's to the left of the string that is going
 
135
 * to be printed.
 
136
 */
 
137
#define FIX_PRECISION( adjust, precision, s, s_len )                    \
 
138
        if ( adjust )                                                   \
 
139
                while ( s_len < precision ) {                           \
 
140
                        *--s = '0' ;                                    \
 
141
                        s_len++ ;                                       \
 
142
        }
 
143
 
 
144
/*
 
145
 * Macro that does padding. The padding is done by printing
 
146
 * the character ch.
 
147
 */
 
148
#define PAD( width, len, ch )                                           \
 
149
        do {                                                            \
 
150
                INS_CHAR( ch, sp, bep, cc ) ;                           \
 
151
                width-- ;                                               \
 
152
        } while ( width > len )
 
153
 
 
154
/*
 
155
 * Prefix the character ch to the string str
 
156
 * Increase length
 
157
 * Set the has_prefix flag
 
158
 */
 
159
#define PREFIX( str, length, ch )                                       \
 
160
        *--str = ch ; length++ ; has_prefix = YES
 
161
 
 
162
static char *conv_10(wide_int num, bool_int is_unsigned,
 
163
                        bool_int * is_negative, char *buf_end, int *len);
 
164
SCOPE int vsnprintf(char *str, size_t size, const char *fmt, va_list ap);
 
165
 
 
166
/*
 
167
 * snprintf is based on SIO's Sprint.
 
168
 *
 
169
 * Sprint is the equivalent of printf for SIO.
 
170
 * It returns the # of chars written
 
171
 * Assumptions:
 
172
 *     - all floating point arguments are passed as doubles
 
173
 */
 
174
SCOPE int 
 
175
snprintf(char *str, size_t size, const char *fmt, ...)
 
176
{
 
177
    int cc;
 
178
    va_list ap;
 
179
 
 
180
    va_start(ap, fmt);
 
181
    cc = vsnprintf(str, size, fmt, ap);
 
182
    va_end(ap);
 
183
    return cc;
 
184
}
 
185
 
 
186
/*
 
187
 * Convert a floating point number to a string formats 'f', 'e' or 'E'.
 
188
 * The result is placed in buf, and len denotes the length of the string
 
189
 * The sign is returned in the is_negative argument (and is not placed
 
190
 * in buf).  Always add decimal point if add_dp is YES.
 
191
 */
 
192
static char *
 
193
conv_fp(char format, double num, boolean_e add_dp, int precision,
 
194
        bool_int *is_negative, char buf[], int *len)
 
195
{
 
196
    char *s = buf;
 
197
    char *p;
 
198
    int decimal_point;
 
199
 
 
200
    if (format == 'f')
 
201
        p = fcvt(num, precision, &decimal_point, is_negative);
 
202
    else                               /* either e or E format */
 
203
        p = ecvt(num, precision + 1, &decimal_point, is_negative);
 
204
 
 
205
    /*
 
206
     * Check for Infinity and NaN
 
207
     */
 
208
    if (isalpha(*p)) {
 
209
        *len = strlen(strcpy(buf, p));
 
210
        *is_negative = FALSE;
 
211
        return (buf);
 
212
    }
 
213
    if (format == 'f')
 
214
        if (decimal_point <= 0) {
 
215
            *s++ = '0';
 
216
            if (precision > 0) {
 
217
                *s++ = '.';
 
218
                while (decimal_point++ < 0)
 
219
                    *s++ = '0';
 
220
            } else if (add_dp)
 
221
                *s++ = '.';
 
222
        } else {
 
223
            while (decimal_point-- > 0)
 
224
                *s++ = *p++;
 
225
            if (precision > 0 || add_dp)
 
226
                *s++ = '.';
 
227
    } else {
 
228
        *s++ = *p++;
 
229
        if (precision > 0 || add_dp)
 
230
            *s++ = '.';
 
231
    }
 
232
 
 
233
    /*
 
234
     * copy the rest of p, the NUL is NOT copied
 
235
     */
 
236
    while (*p)
 
237
        *s++ = *p++;
 
238
 
 
239
    if (format != 'f') {
 
240
        char temp[EXPONENT_LENGTH];    /* for exponent conversion */
 
241
        int t_len;
 
242
        bool_int exponent_is_negative;
 
243
 
 
244
        *s++ = format;                 /* either e or E */
 
245
        decimal_point--;
 
246
        if (decimal_point != 0) {
 
247
            p = conv_10((wide_int) decimal_point, FALSE, &exponent_is_negative,
 
248
                &temp[EXPONENT_LENGTH], &t_len);
 
249
            *s++ = exponent_is_negative ? '-' : '+';
 
250
 
 
251
            /*
 
252
             * Make sure the exponent has at least 2 digits
 
253
             */
 
254
            if (t_len == 1)
 
255
                *s++ = '0';
 
256
            while (t_len--)
 
257
                *s++ = *p++;
 
258
        } else {
 
259
            *s++ = '+';
 
260
            *s++ = '0';
 
261
            *s++ = '0';
 
262
        }
 
263
    }
 
264
    *len = s - buf;
 
265
    return (buf);
 
266
}
 
267
 
 
268
/*
 
269
 * Convert num to a base X number where X is a power of 2. nbits determines X.
 
270
 * For example, if nbits is 3, we do base 8 conversion
 
271
 * Return value:
 
272
 *           a pointer to a string containing the number
 
273
 *
 
274
 * The caller provides a buffer for the string: that is the buf_end argument
 
275
 * which is a pointer to the END of the buffer + 1 (i.e. if the buffer
 
276
 * is declared as buf[ 100 ], buf_end should be &buf[ 100 ])
 
277
 */
 
278
static char *
 
279
conv_p2(u_wide_int num, int nbits, char format, char *buf_end, int *len)
 
280
{
 
281
    int mask = (1 << nbits) - 1;
 
282
    char *p = buf_end;
 
283
    static char low_digits[] = "0123456789abcdef";
 
284
    static char upper_digits[] = "0123456789ABCDEF";
 
285
    char *digits = (format == 'X') ? upper_digits : low_digits;
 
286
 
 
287
    do {
 
288
        *--p = digits[num & mask];
 
289
        num >>= nbits;
 
290
    }
 
291
    while (num);
 
292
 
 
293
    *len = buf_end - p;
 
294
    return (p);
 
295
}
 
296
 
 
297
/*
 
298
 * Convert num to its decimal format.
 
299
 * Return value:
 
300
 *       - a pointer to a string containing the number (no sign)
 
301
 *             - len contains the length of the string
 
302
 *             - is_negative is set to TRUE or FALSE depending on the sign
 
303
 *               of the number (always set to FALSE if is_unsigned is TRUE)
 
304
 *
 
305
 * The caller provides a buffer for the string: that is the buf_end argument
 
306
 * which is a pointer to the END of the buffer + 1 (i.e. if the buffer
 
307
 * is declared as buf[ 100 ], buf_end should be &buf[ 100 ])
 
308
 */
 
309
static char *
 
310
conv_10(wide_int num, bool_int is_unsigned, bool_int *is_negative,
 
311
        char *buf_end, int *len)
 
312
{
 
313
    char *p = buf_end;
 
314
    u_wide_int magnitude;
 
315
 
 
316
    if (is_unsigned) {
 
317
        magnitude = (u_wide_int) num;
 
318
        *is_negative = FALSE;
 
319
    } else {
 
320
        *is_negative = (num < 0);
 
321
 
 
322
        /*
 
323
         * On a 2's complement machine, negating the most negative integer 
 
324
         * results in a number that cannot be represented as a signed integer.
 
325
         * Here is what we do to obtain the number's magnitude:
 
326
         *              a. add 1 to the number
 
327
         *              b. negate it (becomes positive)
 
328
         *              c. convert it to unsigned
 
329
         *              d. add 1
 
330
         */
 
331
        if (*is_negative) {
 
332
            wide_int t = num + 1;
 
333
 
 
334
            magnitude = ((u_wide_int) - t) + 1;
 
335
        } else
 
336
            magnitude = (u_wide_int) num;
 
337
    }
 
338
 
 
339
    /*
 
340
     * We use a do-while loop so that we write at least 1 digit 
 
341
     */
 
342
    do {
 
343
        register u_wide_int new_magnitude = magnitude / 10;
 
344
 
 
345
        *--p = magnitude - new_magnitude * 10 + '0';
 
346
        magnitude = new_magnitude;
 
347
    }
 
348
    while (magnitude);
 
349
 
 
350
    *len = buf_end - p;
 
351
    return (p);
 
352
}
 
353
 
 
354
/*
 
355
 * Do format conversion.
 
356
 */
 
357
SCOPE int 
 
358
vsnprintf(char *str, size_t size, const char *fmt, va_list ap)
 
359
{
 
360
    char *sp;
 
361
    char *bep;
 
362
    int cc = 0;
 
363
    int i;
 
364
 
 
365
    char *s;
 
366
    char *q;
 
367
    int s_len;
 
368
 
 
369
    int min_width;
 
370
    int precision;
 
371
    enum {
 
372
        LEFT, RIGHT
 
373
    } adjust;
 
374
    char pad_char;
 
375
    char prefix_char;
 
376
 
 
377
    double fp_num;
 
378
    wide_int i_num;
 
379
    u_wide_int ui_num;
 
380
 
 
381
    char num_buf[NUM_BUF_SIZE];
 
382
    char char_buf[2];                  /* for printing %% and %<unknown> */
 
383
 
 
384
    /*
 
385
     * Flag variables
 
386
     */
 
387
    boolean_e is_long;
 
388
    boolean_e alternate_form;
 
389
    boolean_e print_sign;
 
390
    boolean_e print_blank;
 
391
    boolean_e adjust_precision;
 
392
    boolean_e adjust_width;
 
393
    bool_int is_negative;
 
394
 
 
395
    if (size == 0)
 
396
        return 0;
 
397
 
 
398
    sp = str;
 
399
    bep = str + size - 1;
 
400
 
 
401
    while (*fmt) {
 
402
        if (*fmt != '%') {
 
403
            INS_CHAR(*fmt, sp, bep, cc);
 
404
        } else {
 
405
            /*
 
406
             * Default variable settings
 
407
             */
 
408
            adjust = RIGHT;
 
409
            alternate_form = print_sign = print_blank = NO;
 
410
            pad_char = ' ';
 
411
            prefix_char = NUL;
 
412
 
 
413
            fmt++;
 
414
 
 
415
            /*
 
416
             * Try to avoid checking for flags, width or precision
 
417
             */
 
418
            if (isascii(*fmt) && !islower(*fmt)) {
 
419
                /*
 
420
                 * Recognize flags: -, #, BLANK, +
 
421
                 */
 
422
                for (;; fmt++) {
 
423
                    if (*fmt == '-')
 
424
                        adjust = LEFT;
 
425
                    else if (*fmt == '+')
 
426
                        print_sign = YES;
 
427
                    else if (*fmt == '#')
 
428
                        alternate_form = YES;
 
429
                    else if (*fmt == ' ')
 
430
                        print_blank = YES;
 
431
                    else if (*fmt == '0')
 
432
                        pad_char = '0';
 
433
                    else
 
434
                        break;
 
435
                }
 
436
 
 
437
                /*
 
438
                 * Check if a width was specified
 
439
                 */
 
440
                if (isdigit(*fmt)) {
 
441
                    STR_TO_DEC(fmt, min_width);
 
442
                    adjust_width = YES;
 
443
                } else if (*fmt == '*') {
 
444
                    min_width = va_arg(ap, int);
 
445
 
 
446
                    fmt++;
 
447
                    adjust_width = YES;
 
448
                    if (min_width < 0) {
 
449
                        adjust = LEFT;
 
450
                        min_width = -min_width;
 
451
                    }
 
452
                } else
 
453
                    adjust_width = NO;
 
454
 
 
455
                /*
 
456
                 * Check if a precision was specified
 
457
                 *
 
458
                 * XXX: an unreasonable amount of precision may be specified
 
459
                 *      resulting in overflow of num_buf. Currently we
 
460
                 *      ignore this possibility.
 
461
                 */
 
462
                if (*fmt == '.') {
 
463
                    adjust_precision = YES;
 
464
                    fmt++;
 
465
                    if (isdigit(*fmt)) {
 
466
                        STR_TO_DEC(fmt, precision);
 
467
                    } else if (*fmt == '*') {
 
468
                        precision = va_arg(ap, int);
 
469
 
 
470
                        fmt++;
 
471
                        if (precision < 0)
 
472
                            precision = 0;
 
473
                    } else
 
474
                        precision = 0;
 
475
                } else
 
476
                    adjust_precision = NO;
 
477
            } else
 
478
                adjust_precision = adjust_width = NO;
 
479
 
 
480
            /*
 
481
             * Modifier check
 
482
             */
 
483
            if (*fmt == 'l') {
 
484
                is_long = YES;
 
485
                fmt++;
 
486
            } else
 
487
                is_long = NO;
 
488
 
 
489
            /*
 
490
             * Argument extraction and printing.
 
491
             * First we determine the argument type.
 
492
             * Then, we convert the argument to a string.
 
493
             * On exit from the switch, s points to the string that
 
494
             * must be printed, s_len has the length of the string
 
495
             * The precision requirements, if any, are reflected in s_len.
 
496
             *
 
497
             * NOTE: pad_char may be set to '0' because of the 0 flag.
 
498
             *                      It is reset to ' ' by non-numeric formats
 
499
             */
 
500
            switch (*fmt) {
 
501
            case 'd':
 
502
            case 'i':
 
503
            case 'u':
 
504
                if (is_long)
 
505
                    i_num = va_arg(ap, wide_int);
 
506
                else
 
507
                    i_num = (wide_int) va_arg(ap, int);
 
508
 
 
509
                s = conv_10(i_num, (*fmt) == 'u', &is_negative,
 
510
                    &num_buf[NUM_BUF_SIZE], &s_len);
 
511
                FIX_PRECISION(adjust_precision, precision, s, s_len);
 
512
 
 
513
                if (*fmt != 'u') {
 
514
                    if (is_negative)
 
515
                        prefix_char = '-';
 
516
                    else if (print_sign)
 
517
                        prefix_char = '+';
 
518
                    else if (print_blank)
 
519
                        prefix_char = ' ';
 
520
                }
 
521
                break;
 
522
 
 
523
            case 'o':
 
524
                if (is_long)
 
525
                    ui_num = va_arg(ap, u_wide_int);
 
526
                else
 
527
                    ui_num = (u_wide_int) va_arg(ap, unsigned int);
 
528
 
 
529
                s = conv_p2(ui_num, 3, *fmt,
 
530
                    &num_buf[NUM_BUF_SIZE], &s_len);
 
531
                FIX_PRECISION(adjust_precision, precision, s, s_len);
 
532
                if (alternate_form && *s != '0') {
 
533
                    *--s = '0';
 
534
                    s_len++;
 
535
                }
 
536
                break;
 
537
 
 
538
            case 'x':
 
539
            case 'X':
 
540
                if (is_long)
 
541
                    ui_num = (u_wide_int) va_arg(ap, u_wide_int);
 
542
                else
 
543
                    ui_num = (u_wide_int) va_arg(ap, unsigned int);
 
544
 
 
545
                s = conv_p2(ui_num, 4, *fmt,
 
546
                    &num_buf[NUM_BUF_SIZE], &s_len);
 
547
                FIX_PRECISION(adjust_precision, precision, s, s_len);
 
548
                if (alternate_form && i_num != 0) {
 
549
                    *--s = *fmt;       /* 'x' or 'X' */
 
550
                    *--s = '0';
 
551
                    s_len += 2;
 
552
                }
 
553
                break;
 
554
 
 
555
            case 's':
 
556
                s = va_arg(ap, char *);
 
557
 
 
558
                if (s != NULL) {
 
559
                    s_len = strlen(s);
 
560
                    if (adjust_precision && precision < s_len)
 
561
                        s_len = precision;
 
562
                } else {
 
563
                    s = S_NULL;
 
564
                    s_len = S_NULL_LEN;
 
565
                }
 
566
                pad_char = ' ';
 
567
                break;
 
568
 
 
569
            case 'f':
 
570
            case 'e':
 
571
            case 'E':
 
572
                fp_num = va_arg(ap, double);
 
573
 
 
574
                s = conv_fp(*fmt, fp_num, alternate_form,
 
575
                    (adjust_precision == NO) ? FLOAT_DIGITS : precision,
 
576
                    &is_negative, &num_buf[1], &s_len);
 
577
                if (is_negative)
 
578
                    prefix_char = '-';
 
579
                else if (print_sign)
 
580
                    prefix_char = '+';
 
581
                else if (print_blank)
 
582
                    prefix_char = ' ';
 
583
                break;
 
584
 
 
585
            case 'g':
 
586
            case 'G':
 
587
                if (adjust_precision == NO)
 
588
                    precision = FLOAT_DIGITS;
 
589
                else if (precision == 0)
 
590
                    precision = 1;
 
591
                /*
 
592
                 * We use &num_buf[ 1 ], so that we have room for the sign
 
593
                 */
 
594
                s = gcvt(va_arg(ap, double), precision, &num_buf[1]);
 
595
 
 
596
                if (*s == '-')
 
597
                    prefix_char = *s++;
 
598
                else if (print_sign)
 
599
                    prefix_char = '+';
 
600
                else if (print_blank)
 
601
                    prefix_char = ' ';
 
602
 
 
603
                s_len = strlen(s);
 
604
 
 
605
                if (alternate_form && (q = strchr(s, '.')) == NULL)
 
606
                    s[s_len++] = '.';
 
607
                if (*fmt == 'G' && (q = strchr(s, 'e')) != NULL)
 
608
                    *q = 'E';
 
609
                break;
 
610
 
 
611
            case 'c':
 
612
                char_buf[0] = (char)(va_arg(ap, int));
 
613
 
 
614
                s = &char_buf[0];
 
615
                s_len = 1;
 
616
                pad_char = ' ';
 
617
                break;
 
618
 
 
619
            case '%':
 
620
                char_buf[0] = '%';
 
621
                s = &char_buf[0];
 
622
                s_len = 1;
 
623
                pad_char = ' ';
 
624
                break;
 
625
 
 
626
            case 'n':
 
627
                *(va_arg(ap, int *)) = cc;
 
628
 
 
629
                break;
 
630
 
 
631
                /*
 
632
                 * If the pointer size is equal to the size of an unsigned
 
633
                 * integer we convert the pointer to a hex number, otherwise 
 
634
                 * we print "%p" to indicate that we don't handle "%p".
 
635
                 */
 
636
            case 'p':
 
637
                ui_num = (u_wide_int) va_arg(ap, void *);
 
638
 
 
639
                if (sizeof(void *) <= sizeof(u_wide_int))
 
640
                        s = conv_p2(ui_num, 4, 'x',
 
641
                        &num_buf[NUM_BUF_SIZE], &s_len);
 
642
 
 
643
                else {
 
644
                    s = "%p";
 
645
                    s_len = 2;
 
646
                }
 
647
                pad_char = ' ';
 
648
                break;
 
649
 
 
650
            case NUL:
 
651
                /*
 
652
                 * The last character of the format string was %.
 
653
                 * We ignore it.
 
654
                 */
 
655
                continue;
 
656
 
 
657
                /*
 
658
                 * The default case is for unrecognized %'s.
 
659
                 * We print %<char> to help the user identify what
 
660
                 * option is not understood.
 
661
                 * This is also useful in case the user wants to pass
 
662
                 * the output of __sio_converter to another function
 
663
                 * that understands some other %<char> (like syslog).
 
664
                 * Note that we can't point s inside fmt because the
 
665
                 * unknown <char> could be preceded by width etc.
 
666
                 */
 
667
            default:
 
668
                char_buf[0] = '%';
 
669
                char_buf[1] = *fmt;
 
670
                s = char_buf;
 
671
                s_len = 2;
 
672
                pad_char = ' ';
 
673
                break;
 
674
            }
 
675
 
 
676
            if (prefix_char != NUL) {
 
677
                *--s = prefix_char;
 
678
                s_len++;
 
679
            }
 
680
            if (adjust_width && adjust == RIGHT && min_width > s_len) {
 
681
                if (pad_char == '0' && prefix_char != NUL) {
 
682
                    INS_CHAR(*s, sp, bep, cc)
 
683
                        s++;
 
684
                    s_len--;
 
685
                    min_width--;
 
686
                }
 
687
                PAD(min_width, s_len, pad_char);
 
688
            }
 
689
            /*
 
690
             * Print the string s. 
 
691
             */
 
692
            for (i = s_len; i != 0; i--) {
 
693
                INS_CHAR(*s, sp, bep, cc);
 
694
                s++;
 
695
            }
 
696
 
 
697
            if (adjust_width && adjust == LEFT && min_width > s_len)
 
698
                PAD(min_width, s_len, pad_char);
 
699
        }
 
700
        fmt++;
 
701
    }
 
702
    if (cc < size)
 
703
        str[cc] = NUL;
 
704
    else
 
705
        str[size - 1] = NUL;
 
706
    return cc;
 
707
}
 
708