~ubuntu-branches/ubuntu/gutsy/net-snmp/gutsy-security

« back to all changes in this revision

Viewing changes to snmplib/snprintf.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2004-09-13 12:06:21 UTC
  • Revision ID: james.westby@ubuntu.com-20040913120621-g952ntonlleihcvm
Tags: upstream-5.1.1
ImportĀ upstreamĀ versionĀ 5.1.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright Patrick Powell 1995
 
3
 * This code is based on code written by Patrick Powell (papowell@astart.com)
 
4
 * It may be used for any purpose as long as this notice remains intact
 
5
 * on all source code distributions
 
6
 */
 
7
 
 
8
/**************************************************************
 
9
 * Original:
 
10
 * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
 
11
 * A bombproof version of doprnt (dopr) included.
 
12
 * Sigh.  This sort of thing is always nasty do deal with.  Note that
 
13
 * the version here does not include floating point...
 
14
 *
 
15
 * snprintf() is used instead of sprintf() as it does limit checks
 
16
 * for string length.  This covers a nasty loophole.
 
17
 *
 
18
 * The other functions are there to prevent NULL pointers from
 
19
 * causing nast effects.
 
20
 *
 
21
 * More Recently:
 
22
 *  Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43
 
23
 *  This was ugly.  It is still ugly.  I opted out of floating point
 
24
 *  numbers, but the formatter understands just about everything
 
25
 *  from the normal C string format, at least as far as I can tell from
 
26
 *  the Solaris 2.5 printf(3S) man page.
 
27
 *
 
28
 *  Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1
 
29
 *    Ok, added some minimal floating point support, which means this
 
30
 *    probably requires libm on most operating systems.  Don't yet
 
31
 *    support the exponent (e,E) and sigfig (g,G).  Also, fmtint()
 
32
 *    was pretty badly broken, it just wasn't being exercised in ways
 
33
 *    which showed it, so that's been fixed.  Also, formated the code
 
34
 *    to mutt conventions, and removed dead code left over from the
 
35
 *    original.  Also, there is now a builtin-test, just compile with:
 
36
 *           gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
 
37
 *    and run snprintf for results.
 
38
 * 
 
39
 *  Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i
 
40
 *    The PGP code was using unsigned hexadecimal formats. 
 
41
 *    Unfortunately, unsigned formats simply didn't work.
 
42
 *
 
43
 *  Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8
 
44
 *    The original code assumed that both snprintf() and vsnprintf() were
 
45
 *    missing.  Some systems only have snprintf() but not vsnprintf(), so
 
46
 *    the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
 
47
 *
 
48
 *  Andrew Tridgell (tridge@samba.org) Oct 1998
 
49
 *    fixed handling of %.0f
 
50
 *    added test for HAVE_LONG_DOUBLE
 
51
 *
 
52
 **************************************************************/
 
53
 
 
54
#include <net-snmp/net-snmp-config.h>
 
55
 
 
56
#if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF)
 
57
 
 
58
#if HAVE_STRING_H
 
59
#include <string.h>
 
60
#else
 
61
#include <strings.h>
 
62
#endif
 
63
#include <ctype.h>
 
64
#include <sys/types.h>
 
65
 
 
66
#if HAVE_STDARG_H
 
67
# include <stdarg.h>
 
68
# define HAVE_STDARGS           /* let's hope that works everywhere (mj) */
 
69
# define VA_LOCAL_DECL   va_list ap
 
70
# define VA_START(f)     va_start(ap, f)
 
71
# define VA_SHIFT(v,t)  ;       /* no-op for ANSI */
 
72
# define VA_END          va_end(ap)
 
73
#elif HAVE_VARARGS_H
 
74
#  include <varargs.h>
 
75
#  undef HAVE_STDARGS
 
76
#  define VA_LOCAL_DECL   va_list ap
 
77
#  define VA_START(f)     va_start(ap)  /* f is ignored! */
 
78
#  define VA_SHIFT(v,t) v = va_arg(ap,t)
 
79
#  define VA_END        va_end(ap)
 
80
#else
 
81
/*
 
82
 * XX ** NO VARARGS ** XX
 
83
 */
 
84
#endif
 
85
 
 
86
#ifdef HAVE_LONG_DOUBLE
 
87
#define LDOUBLE long double
 
88
#else
 
89
#define LDOUBLE double
 
90
#endif
 
91
 
 
92
int             snprintf(char *str, size_t count, const char *fmt, ...);
 
93
int             vsnprintf(char *str, size_t count, const char *fmt,
 
94
                          va_list arg);
 
95
 
 
96
static void     dopr(char *buffer, size_t maxlen, const char *format,
 
97
                     va_list args);
 
98
static void     fmtstr(char *buffer, size_t * currlen, size_t maxlen,
 
99
                       char *value, int flags, int min, int max);
 
100
static void     fmtint(char *buffer, size_t * currlen, size_t maxlen,
 
101
                       long value, int base, int min, int max, int flags);
 
102
static void     fmtfp(char *buffer, size_t * currlen, size_t maxlen,
 
103
                      LDOUBLE fvalue, int min, int max, int flags);
 
104
static void     dopr_outch(char *buffer, size_t * currlen, size_t maxlen,
 
105
                           char c);
 
106
 
 
107
/*
 
108
 * dopr(): poor man's version of doprintf
 
109
 */
 
110
 
 
111
/*
 
112
 * format read states 
 
113
 */
 
114
#define DP_S_DEFAULT 0
 
115
#define DP_S_FLAGS   1
 
116
#define DP_S_MIN     2
 
117
#define DP_S_DOT     3
 
118
#define DP_S_MAX     4
 
119
#define DP_S_MOD     5
 
120
#define DP_S_CONV    6
 
121
#define DP_S_DONE    7
 
122
 
 
123
/*
 
124
 * format flags - Bits 
 
125
 */
 
126
#define DP_F_MINUS      (1 << 0)
 
127
#define DP_F_PLUS       (1 << 1)
 
128
#define DP_F_SPACE      (1 << 2)
 
129
#define DP_F_NUM        (1 << 3)
 
130
#define DP_F_ZERO       (1 << 4)
 
131
#define DP_F_UP         (1 << 5)
 
132
#define DP_F_UNSIGNED   (1 << 6)
 
133
 
 
134
/*
 
135
 * Conversion Flags 
 
136
 */
 
137
#define DP_C_SHORT   1
 
138
#define DP_C_LONG    2
 
139
#define DP_C_LDOUBLE 3
 
140
 
 
141
#define char_to_int(p) (p - '0')
 
142
#define MAX(p,q) ((p >= q) ? p : q)
 
143
 
 
144
static void
 
145
dopr(char *buffer, size_t maxlen, const char *format, va_list args)
 
146
{
 
147
    char            ch;
 
148
    long            value;
 
149
    LDOUBLE         fvalue;
 
150
    char           *strvalue;
 
151
    int             min;
 
152
    int             max;
 
153
    int             state;
 
154
    int             flags;
 
155
    int             cflags;
 
156
    size_t          currlen;
 
157
 
 
158
    state = DP_S_DEFAULT;
 
159
    currlen = flags = cflags = min = 0;
 
160
    max = -1;
 
161
    ch = *format++;
 
162
 
 
163
    while (state != DP_S_DONE) {
 
164
        if ((ch == '\0') || (currlen >= maxlen))
 
165
            state = DP_S_DONE;
 
166
 
 
167
        switch (state) {
 
168
        case DP_S_DEFAULT:
 
169
            if (ch == '%')
 
170
                state = DP_S_FLAGS;
 
171
            else
 
172
                dopr_outch(buffer, &currlen, maxlen, ch);
 
173
            ch = *format++;
 
174
            break;
 
175
        case DP_S_FLAGS:
 
176
            switch (ch) {
 
177
            case '-':
 
178
                flags |= DP_F_MINUS;
 
179
                ch = *format++;
 
180
                break;
 
181
            case '+':
 
182
                flags |= DP_F_PLUS;
 
183
                ch = *format++;
 
184
                break;
 
185
            case ' ':
 
186
                flags |= DP_F_SPACE;
 
187
                ch = *format++;
 
188
                break;
 
189
            case '#':
 
190
                flags |= DP_F_NUM;
 
191
                ch = *format++;
 
192
                break;
 
193
            case '0':
 
194
                flags |= DP_F_ZERO;
 
195
                ch = *format++;
 
196
                break;
 
197
            default:
 
198
                state = DP_S_MIN;
 
199
                break;
 
200
            }
 
201
            break;
 
202
        case DP_S_MIN:
 
203
            if (isdigit(ch)) {
 
204
                min = 10 * min + char_to_int(ch);
 
205
                ch = *format++;
 
206
            } else if (ch == '*') {
 
207
                min = va_arg(args, int);
 
208
                ch = *format++;
 
209
                state = DP_S_DOT;
 
210
            } else
 
211
                state = DP_S_DOT;
 
212
            break;
 
213
        case DP_S_DOT:
 
214
            if (ch == '.') {
 
215
                state = DP_S_MAX;
 
216
                ch = *format++;
 
217
            } else
 
218
                state = DP_S_MOD;
 
219
            break;
 
220
        case DP_S_MAX:
 
221
            if (isdigit(ch)) {
 
222
                if (max < 0)
 
223
                    max = 0;
 
224
                max = 10 * max + char_to_int(ch);
 
225
                ch = *format++;
 
226
            } else if (ch == '*') {
 
227
                max = va_arg(args, int);
 
228
                ch = *format++;
 
229
                state = DP_S_MOD;
 
230
            } else
 
231
                state = DP_S_MOD;
 
232
            break;
 
233
        case DP_S_MOD:
 
234
            /*
 
235
             * Currently, we don't support Long Long, bummer 
 
236
             */
 
237
            switch (ch) {
 
238
            case 'h':
 
239
                cflags = DP_C_SHORT;
 
240
                ch = *format++;
 
241
                break;
 
242
            case 'l':
 
243
                cflags = DP_C_LONG;
 
244
                ch = *format++;
 
245
                break;
 
246
            case 'L':
 
247
                cflags = DP_C_LDOUBLE;
 
248
                ch = *format++;
 
249
                break;
 
250
            default:
 
251
                break;
 
252
            }
 
253
            state = DP_S_CONV;
 
254
            break;
 
255
        case DP_S_CONV:
 
256
            switch (ch) {
 
257
            case 'd':
 
258
            case 'i':
 
259
                if (cflags == DP_C_SHORT)
 
260
                    value = va_arg(args, short int);
 
261
                else if (cflags == DP_C_LONG)
 
262
                    value = va_arg(args, long int);
 
263
                else
 
264
                    value = va_arg(args, int);
 
265
                fmtint(buffer, &currlen, maxlen, value, 10, min, max,
 
266
                       flags);
 
267
                break;
 
268
            case 'o':
 
269
                flags |= DP_F_UNSIGNED;
 
270
                if (cflags == DP_C_SHORT)
 
271
                    value = va_arg(args, unsigned short int);
 
272
                else if (cflags == DP_C_LONG)
 
273
                    value = va_arg(args, unsigned long int);
 
274
                else
 
275
                    value = va_arg(args, unsigned int);
 
276
                fmtint(buffer, &currlen, maxlen, value, 8, min, max,
 
277
                       flags);
 
278
                break;
 
279
            case 'u':
 
280
                flags |= DP_F_UNSIGNED;
 
281
                if (cflags == DP_C_SHORT)
 
282
                    value = va_arg(args, unsigned short int);
 
283
                else if (cflags == DP_C_LONG)
 
284
                    value = va_arg(args, unsigned long int);
 
285
                else
 
286
                    value = va_arg(args, unsigned int);
 
287
                fmtint(buffer, &currlen, maxlen, value, 10, min, max,
 
288
                       flags);
 
289
                break;
 
290
            case 'X':
 
291
                flags |= DP_F_UP;
 
292
            case 'x':
 
293
                flags |= DP_F_UNSIGNED;
 
294
                if (cflags == DP_C_SHORT)
 
295
                    value = va_arg(args, unsigned short int);
 
296
                else if (cflags == DP_C_LONG)
 
297
                    value = va_arg(args, unsigned long int);
 
298
                else
 
299
                    value = va_arg(args, unsigned int);
 
300
                fmtint(buffer, &currlen, maxlen, value, 16, min, max,
 
301
                       flags);
 
302
                break;
 
303
            case 'f':
 
304
                if (cflags == DP_C_LDOUBLE)
 
305
                    fvalue = va_arg(args, LDOUBLE);
 
306
                else
 
307
                    fvalue = va_arg(args, double);
 
308
                /*
 
309
                 * um, floating point? 
 
310
                 */
 
311
                fmtfp(buffer, &currlen, maxlen, fvalue, min, max, flags);
 
312
                break;
 
313
            case 'E':
 
314
                flags |= DP_F_UP;
 
315
            case 'e':
 
316
                if (cflags == DP_C_LDOUBLE)
 
317
                    fvalue = va_arg(args, LDOUBLE);
 
318
                else
 
319
                    fvalue = va_arg(args, double);
 
320
                break;
 
321
            case 'G':
 
322
                flags |= DP_F_UP;
 
323
            case 'g':
 
324
                if (cflags == DP_C_LDOUBLE)
 
325
                    fvalue = va_arg(args, LDOUBLE);
 
326
                else
 
327
                    fvalue = va_arg(args, double);
 
328
                break;
 
329
            case 'c':
 
330
                dopr_outch(buffer, &currlen, maxlen, va_arg(args, int));
 
331
                break;
 
332
            case 's':
 
333
                strvalue = va_arg(args, char *);
 
334
                if (max < 0)
 
335
                    max = maxlen;       /* ie, no max */
 
336
                fmtstr(buffer, &currlen, maxlen, strvalue, flags, min,
 
337
                       max);
 
338
                break;
 
339
            case 'p':
 
340
                strvalue = (char *) va_arg(args, void *);
 
341
                fmtint(buffer, &currlen, maxlen, (long) strvalue, 16, min,
 
342
                       max, flags);
 
343
                break;
 
344
            case 'n':
 
345
                if (cflags == DP_C_SHORT) {
 
346
                    short int      *num;
 
347
                    num = va_arg(args, short int *);
 
348
                    *num = currlen;
 
349
                } else if (cflags == DP_C_LONG) {
 
350
                    long int       *num;
 
351
                    num = va_arg(args, long int *);
 
352
                    *num = currlen;
 
353
                } else {
 
354
                    int            *num;
 
355
                    num = va_arg(args, int *);
 
356
                    *num = currlen;
 
357
                }
 
358
                break;
 
359
            case '%':
 
360
                dopr_outch(buffer, &currlen, maxlen, ch);
 
361
                break;
 
362
            case 'w':
 
363
                /*
 
364
                 * not supported yet, treat as next char 
 
365
                 */
 
366
                ch = *format++;
 
367
                break;
 
368
            default:
 
369
                /*
 
370
                 * Unknown, skip 
 
371
                 */
 
372
                break;
 
373
            }
 
374
            ch = *format++;
 
375
            state = DP_S_DEFAULT;
 
376
            flags = cflags = min = 0;
 
377
            max = -1;
 
378
            break;
 
379
        case DP_S_DONE:
 
380
            break;
 
381
        default:
 
382
            /*
 
383
             * hmm? 
 
384
             */
 
385
            break;              /* some picky compilers need this */
 
386
        }
 
387
    }
 
388
    if (currlen < maxlen - 1)
 
389
        buffer[currlen] = '\0';
 
390
    else
 
391
        buffer[maxlen - 1] = '\0';
 
392
}
 
393
 
 
394
static void
 
395
fmtstr(char *buffer, size_t * currlen, size_t maxlen,
 
396
       char *value, int flags, int min, int max)
 
397
{
 
398
    int             padlen, strln;      /* amount to pad */
 
399
    int             cnt = 0;
 
400
 
 
401
    if (value == 0) {
 
402
        value = "<NULL>";
 
403
    }
 
404
 
 
405
    for (strln = 0; value[strln]; ++strln);     /* strlen */
 
406
    padlen = min - strln;
 
407
    if (padlen < 0)
 
408
        padlen = 0;
 
409
    if (flags & DP_F_MINUS)
 
410
        padlen = -padlen;       /* Left Justify */
 
411
 
 
412
    while ((padlen > 0) && (cnt < max)) {
 
413
        dopr_outch(buffer, currlen, maxlen, ' ');
 
414
        --padlen;
 
415
        ++cnt;
 
416
    }
 
417
    while (*value && (cnt < max)) {
 
418
        dopr_outch(buffer, currlen, maxlen, *value++);
 
419
        ++cnt;
 
420
    }
 
421
    while ((padlen < 0) && (cnt < max)) {
 
422
        dopr_outch(buffer, currlen, maxlen, ' ');
 
423
        ++padlen;
 
424
        ++cnt;
 
425
    }
 
426
}
 
427
 
 
428
/*
 
429
 * Have to handle DP_F_NUM (ie 0x and 0 alternates) 
 
430
 */
 
431
 
 
432
static void
 
433
fmtint(char *buffer, size_t * currlen, size_t maxlen,
 
434
       long value, int base, int min, int max, int flags)
 
435
{
 
436
    int             signvalue = 0;
 
437
    unsigned long   uvalue;
 
438
    char            convert[20];
 
439
    int             place = 0;
 
440
    int             spadlen = 0;        /* amount to space pad */
 
441
    int             zpadlen = 0;        /* amount to zero pad */
 
442
    int             caps = 0;
 
443
 
 
444
    if (max < 0)
 
445
        max = 0;
 
446
 
 
447
    uvalue = value;
 
448
 
 
449
    if (!(flags & DP_F_UNSIGNED)) {
 
450
        if (value < 0) {
 
451
            signvalue = '-';
 
452
            uvalue = -value;
 
453
        } else if (flags & DP_F_PLUS)   /* Do a sign (+/i) */
 
454
            signvalue = '+';
 
455
        else if (flags & DP_F_SPACE)
 
456
            signvalue = ' ';
 
457
    }
 
458
 
 
459
    if (flags & DP_F_UP)
 
460
        caps = 1;               /* Should characters be upper case? */
 
461
 
 
462
    do {
 
463
        convert[place++] = (caps ? "0123456789ABCDEF" : "0123456789abcdef")
 
464
            [uvalue % (unsigned) base];
 
465
        uvalue = (uvalue / (unsigned) base);
 
466
    } while (uvalue && (place < 20));
 
467
    if (place == 20)
 
468
        place--;
 
469
    convert[place] = 0;
 
470
 
 
471
    zpadlen = max - place;
 
472
    spadlen = min - MAX(max, place) - (signvalue ? 1 : 0);
 
473
    if (zpadlen < 0)
 
474
        zpadlen = 0;
 
475
    if (spadlen < 0)
 
476
        spadlen = 0;
 
477
    if (flags & DP_F_ZERO) {
 
478
        zpadlen = MAX(zpadlen, spadlen);
 
479
        spadlen = 0;
 
480
    }
 
481
    if (flags & DP_F_MINUS)
 
482
        spadlen = -spadlen;     /* Left Justifty */
 
483
 
 
484
#ifdef DEBUG_SNPRINTF
 
485
    dprint(1,
 
486
           (debugfile, "zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
 
487
            zpadlen, spadlen, min, max, place));
 
488
#endif
 
489
 
 
490
    /*
 
491
     * Spaces 
 
492
     */
 
493
    while (spadlen > 0) {
 
494
        dopr_outch(buffer, currlen, maxlen, ' ');
 
495
        --spadlen;
 
496
    }
 
497
 
 
498
    /*
 
499
     * Sign 
 
500
     */
 
501
    if (signvalue)
 
502
        dopr_outch(buffer, currlen, maxlen, signvalue);
 
503
 
 
504
    /*
 
505
     * Zeros 
 
506
     */
 
507
    if (zpadlen > 0) {
 
508
        while (zpadlen > 0) {
 
509
            dopr_outch(buffer, currlen, maxlen, '0');
 
510
            --zpadlen;
 
511
        }
 
512
    }
 
513
 
 
514
    /*
 
515
     * Digits 
 
516
     */
 
517
    while (place > 0)
 
518
        dopr_outch(buffer, currlen, maxlen, convert[--place]);
 
519
 
 
520
    /*
 
521
     * Left Justified spaces 
 
522
     */
 
523
    while (spadlen < 0) {
 
524
        dopr_outch(buffer, currlen, maxlen, ' ');
 
525
        ++spadlen;
 
526
    }
 
527
}
 
528
 
 
529
static          LDOUBLE
 
530
abs_val(LDOUBLE value)
 
531
{
 
532
    LDOUBLE         result = value;
 
533
 
 
534
    if (value < 0)
 
535
        result = -value;
 
536
 
 
537
    return result;
 
538
}
 
539
 
 
540
static          LDOUBLE
 
541
pow10(int exp)
 
542
{
 
543
    LDOUBLE         result = 1;
 
544
 
 
545
    while (exp) {
 
546
        result *= 10;
 
547
        exp--;
 
548
    }
 
549
 
 
550
    return result;
 
551
}
 
552
 
 
553
static long
 
554
round(LDOUBLE value)
 
555
{
 
556
    long            intpart;
 
557
 
 
558
    intpart = value;
 
559
    value = value - intpart;
 
560
    if (value >= 0.5)
 
561
        intpart++;
 
562
 
 
563
    return intpart;
 
564
}
 
565
 
 
566
static void
 
567
fmtfp(char *buffer, size_t * currlen, size_t maxlen,
 
568
      LDOUBLE fvalue, int min, int max, int flags)
 
569
{
 
570
    int             signvalue = 0;
 
571
    LDOUBLE         ufvalue;
 
572
    char            iconvert[20];
 
573
    char            fconvert[20];
 
574
    int             iplace = 0;
 
575
    int             fplace = 0;
 
576
    int             padlen = 0; /* amount to pad */
 
577
    int             zpadlen = 0;
 
578
    int             caps = 0;
 
579
    long            intpart;
 
580
    long            fracpart;
 
581
 
 
582
    /*
 
583
     * AIX manpage says the default is 0, but Solaris says the default
 
584
     * is 6, and sprintf on AIX defaults to 6
 
585
     */
 
586
    if (max < 0)
 
587
        max = 6;
 
588
 
 
589
    ufvalue = abs_val(fvalue);
 
590
 
 
591
    if (fvalue < 0)
 
592
        signvalue = '-';
 
593
    else if (flags & DP_F_PLUS) /* Do a sign (+/i) */
 
594
        signvalue = '+';
 
595
    else if (flags & DP_F_SPACE)
 
596
        signvalue = ' ';
 
597
 
 
598
#if 0
 
599
    if (flags & DP_F_UP)
 
600
        caps = 1;               /* Should characters be upper case? */
 
601
#endif
 
602
 
 
603
    intpart = ufvalue;
 
604
 
 
605
    /*
 
606
     * Sorry, we only support 9 digits past the decimal because of our 
 
607
     * conversion method
 
608
     */
 
609
    if (max > 9)
 
610
        max = 9;
 
611
 
 
612
    /*
 
613
     * We "cheat" by converting the fractional part to integer by
 
614
     * * multiplying by a factor of 10
 
615
     */
 
616
    fracpart = round((pow10(max)) * (ufvalue - intpart));
 
617
 
 
618
    if (fracpart >= pow10(max)) {
 
619
        intpart++;
 
620
        fracpart -= pow10(max);
 
621
    }
 
622
#ifdef DEBUG_SNPRINTF
 
623
    dprint(1,
 
624
           (debugfile, "fmtfp: %f =? %d.%d\n", fvalue, intpart, fracpart));
 
625
#endif
 
626
 
 
627
    /*
 
628
     * Convert integer part 
 
629
     */
 
630
    do {
 
631
        iconvert[iplace++] =
 
632
            (caps ? "0123456789ABCDEF" : "0123456789abcdef")[intpart % 10];
 
633
        intpart = (intpart / 10);
 
634
    } while (intpart && (iplace < 20));
 
635
    if (iplace == 20)
 
636
        iplace--;
 
637
    iconvert[iplace] = 0;
 
638
 
 
639
    /*
 
640
     * Convert fractional part 
 
641
     */
 
642
    do {
 
643
        fconvert[fplace++] =
 
644
            (caps ? "0123456789ABCDEF" : "0123456789abcdef")[fracpart %
 
645
                                                             10];
 
646
        fracpart = (fracpart / 10);
 
647
    } while (fracpart && (fplace < 20));
 
648
    if (fplace == 20)
 
649
        fplace--;
 
650
    fconvert[fplace] = 0;
 
651
 
 
652
    /*
 
653
     * -1 for decimal point, another -1 if we are printing a sign 
 
654
     */
 
655
    padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
 
656
    zpadlen = max - fplace;
 
657
    if (zpadlen < 0)
 
658
        zpadlen = 0;
 
659
    if (padlen < 0)
 
660
        padlen = 0;
 
661
    if (flags & DP_F_MINUS)
 
662
        padlen = -padlen;       /* Left Justifty */
 
663
 
 
664
    if ((flags & DP_F_ZERO) && (padlen > 0)) {
 
665
        if (signvalue) {
 
666
            dopr_outch(buffer, currlen, maxlen, signvalue);
 
667
            --padlen;
 
668
            signvalue = 0;
 
669
        }
 
670
        while (padlen > 0) {
 
671
            dopr_outch(buffer, currlen, maxlen, '0');
 
672
            --padlen;
 
673
        }
 
674
    }
 
675
    while (padlen > 0) {
 
676
        dopr_outch(buffer, currlen, maxlen, ' ');
 
677
        --padlen;
 
678
    }
 
679
    if (signvalue)
 
680
        dopr_outch(buffer, currlen, maxlen, signvalue);
 
681
 
 
682
    while (iplace > 0)
 
683
        dopr_outch(buffer, currlen, maxlen, iconvert[--iplace]);
 
684
 
 
685
    /*
 
686
     * Decimal point.  This should probably use locale to find the correct
 
687
     * char to print out.
 
688
     */
 
689
    if (max > 0) {
 
690
        dopr_outch(buffer, currlen, maxlen, '.');
 
691
 
 
692
        while (fplace > 0)
 
693
            dopr_outch(buffer, currlen, maxlen, fconvert[--fplace]);
 
694
    }
 
695
 
 
696
    while (zpadlen > 0) {
 
697
        dopr_outch(buffer, currlen, maxlen, '0');
 
698
        --zpadlen;
 
699
    }
 
700
 
 
701
    while (padlen < 0) {
 
702
        dopr_outch(buffer, currlen, maxlen, ' ');
 
703
        ++padlen;
 
704
    }
 
705
}
 
706
 
 
707
static void
 
708
dopr_outch(char *buffer, size_t * currlen, size_t maxlen, char c)
 
709
{
 
710
    if (*currlen < maxlen)
 
711
        buffer[(*currlen)++] = c;
 
712
}
 
713
 
 
714
#ifndef HAVE_VSNPRINTF
 
715
int
 
716
vsnprintf(char *str, size_t count, const char *fmt, va_list args)
 
717
{
 
718
    str[0] = 0;
 
719
    dopr(str, count, fmt, args);
 
720
    return (strlen(str));
 
721
}
 
722
#endif                          /* !HAVE_VSNPRINTF */
 
723
 
 
724
#ifndef HAVE_SNPRINTF
 
725
/*
 
726
 * VARARGS3 
 
727
 */
 
728
#ifdef HAVE_STDARGS
 
729
int
 
730
snprintf(char *str, size_t count, const char *fmt, ...)
 
731
#else
 
732
int
 
733
snprintf(va_alist)
 
734
     va_dcl
 
735
#endif
 
736
{
 
737
#ifndef HAVE_STDARGS
 
738
    char           *str;
 
739
    size_t          count;
 
740
    char           *fmt;
 
741
#endif
 
742
    VA_LOCAL_DECL;
 
743
 
 
744
    VA_START(fmt);
 
745
    VA_SHIFT(str, char *);
 
746
    VA_SHIFT(count, size_t);
 
747
    VA_SHIFT(fmt, char *);
 
748
    (void) vsnprintf(str, count, fmt, ap);
 
749
    VA_END;
 
750
    return (strlen(str));
 
751
}
 
752
#endif                          /* !HAVE_SNPRINTF */
 
753
 
 
754
#ifdef TEST_SNPRINTF
 
755
#ifndef LONG_STRING
 
756
#define LONG_STRING 1024
 
757
#endif
 
758
int
 
759
main(void)
 
760
{
 
761
    char            buf1[LONG_STRING];
 
762
    char            buf2[LONG_STRING];
 
763
    char           *fp_fmt[] = {
 
764
        "%-1.5f",
 
765
        "%1.5f",
 
766
        "%123.9f",
 
767
        "%10.5f",
 
768
        "% 10.5f",
 
769
        "%+22.9f",
 
770
        "%+4.9f",
 
771
        "%01.3f",
 
772
        "%4f",
 
773
        "%3.1f",
 
774
        "%3.2f",
 
775
        "%.0f",
 
776
        "%.1f",
 
777
        NULL
 
778
    };
 
779
    double          fp_nums[] =
 
780
        { -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996,
 
781
        0.9996, 1.996, 4.136, 0
 
782
    };
 
783
    char           *int_fmt[] = {
 
784
        "%-1.5d",
 
785
        "%1.5d",
 
786
        "%123.9d",
 
787
        "%5.5d",
 
788
        "%10.5d",
 
789
        "% 10.5d",
 
790
        "%+22.33d",
 
791
        "%01.3d",
 
792
        "%4d",
 
793
        NULL
 
794
    };
 
795
    long            int_nums[] = { -1, 134, 91340, 341, 0203, 0 };
 
796
    int             x, y;
 
797
    int             fail = 0;
 
798
    int             num = 0;
 
799
 
 
800
    printf("Testing snprintf format codes against system sprintf...\n");
 
801
 
 
802
    for (x = 0; fp_fmt[x] != NULL; x++)
 
803
        for (y = 0; fp_nums[y] != 0; y++) {
 
804
            snprintf(buf1, sizeof(buf1), fp_fmt[x], fp_nums[y]);
 
805
            sprintf(buf2, fp_fmt[x], fp_nums[y]);
 
806
            if (strcmp(buf1, buf2)) {
 
807
                printf
 
808
                    ("snprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf  = %s\n",
 
809
                     fp_fmt[x], buf1, buf2);
 
810
                fail++;
 
811
            }
 
812
            num++;
 
813
        }
 
814
 
 
815
    for (x = 0; int_fmt[x] != NULL; x++)
 
816
        for (y = 0; int_nums[y] != 0; y++) {
 
817
            snprintf(buf1, sizeof(buf1), int_fmt[x], int_nums[y]);
 
818
            sprintf(buf2, int_fmt[x], int_nums[y]);
 
819
            if (strcmp(buf1, buf2)) {
 
820
                printf
 
821
                    ("snprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf  = %s\n",
 
822
                     int_fmt[x], buf1, buf2);
 
823
                fail++;
 
824
            }
 
825
            num++;
 
826
        }
 
827
    printf("%d tests failed out of %d.\n", fail, num);
 
828
}
 
829
#endif                          /* SNPRINTF_TEST */
 
830
 
 
831
#endif                          /* !HAVE_SNPRINTF */