~profzoom/ubuntu/quantal/wmaker/bug-1079925

« back to all changes in this revision

Viewing changes to WINGs/snprintf.c

  • Committer: Bazaar Package Importer
  • Author(s): Marcelo E. Magallon
  • Date: 2004-11-10 14:05:30 UTC
  • Revision ID: james.westby@ubuntu.com-20041110140530-qpd66b5lm38x7apk
Tags: upstream-0.91.0
ImportĀ upstreamĀ versionĀ 0.91.0

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
 * tridge@samba.org, idra@samba.org, April 2001
 
53
 *    got rid of fcvt code (twas buggy and made testing harder)
 
54
 *    added C99 semantics
 
55
 *
 
56
 **************************************************************/
 
57
 
 
58
#ifndef NO_CONFIG_H /* for some tests */
 
59
#include "config.h"
 
60
#endif
 
61
 
 
62
#ifdef HAVE_STRING_H
 
63
#include <string.h>
 
64
#endif
 
65
 
 
66
#ifdef HAVE_STRINGS_H
 
67
#include <strings.h>
 
68
#endif
 
69
#ifdef HAVE_CTYPE_H
 
70
#include <ctype.h>
 
71
#endif
 
72
#include <sys/types.h>
 
73
#include <stdarg.h>
 
74
#ifdef HAVE_STDLIB_H
 
75
#include <stdlib.h>
 
76
#endif
 
77
 
 
78
#if defined(HAVE_SNPRINTF) && defined(HAVE_VSNPRINTF) && defined(HAVE_C99_VSNPRINTF)
 
79
/* only include stdio.h if we are not re-defining snprintf or vsnprintf */
 
80
#include <stdio.h>
 
81
/* make the compiler happy with an empty file */
 
82
void dummy_snprintf(void) {}
 
83
#else
 
84
 
 
85
#ifdef HAVE_LONG_DOUBLE
 
86
#define LDOUBLE long double
 
87
#else
 
88
#define LDOUBLE double
 
89
#endif
 
90
 
 
91
#ifdef HAVE_LONG_LONG
 
92
#define LLONG long long
 
93
#else
 
94
#define LLONG long
 
95
#endif
 
96
 
 
97
static size_t dopr(char *buffer, size_t maxlen, const char *format,
 
98
                   va_list args);
 
99
static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
 
100
                   char *value, int flags, int min, int max);
 
101
static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
 
102
                   long value, int base, int min, int max, int flags);
 
103
static void fmtfp(char *buffer, size_t *currlen, size_t maxlen,
 
104
                  LDOUBLE fvalue, int min, int max, int flags);
 
105
static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c);
 
106
 
 
107
/*
 
108
 * dopr(): poor man's version of doprintf
 
109
 */
 
110
 
 
111
/* format read states */
 
112
#define DP_S_DEFAULT 0
 
113
#define DP_S_FLAGS   1
 
114
#define DP_S_MIN     2
 
115
#define DP_S_DOT     3
 
116
#define DP_S_MAX     4
 
117
#define DP_S_MOD     5
 
118
#define DP_S_CONV    6
 
119
#define DP_S_DONE    7
 
120
 
 
121
/* format flags - Bits */
 
122
#define DP_F_MINUS      (1 << 0)
 
123
#define DP_F_PLUS       (1 << 1)
 
124
#define DP_F_SPACE      (1 << 2)
 
125
#define DP_F_NUM        (1 << 3)
 
126
#define DP_F_ZERO       (1 << 4)
 
127
#define DP_F_UP         (1 << 5)
 
128
#define DP_F_UNSIGNED   (1 << 6)
 
129
 
 
130
/* Conversion Flags */
 
131
#define DP_C_SHORT   1
 
132
#define DP_C_LONG    2
 
133
#define DP_C_LDOUBLE 3
 
134
#define DP_C_LLONG   4
 
135
 
 
136
#define char_to_int(p) ((p)- '0')
 
137
#ifndef MAX
 
138
#define MAX(p,q) (((p) >= (q)) ? (p) : (q))
 
139
#endif
 
140
 
 
141
static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args)
 
142
{
 
143
    char ch;
 
144
    LLONG value;
 
145
    LDOUBLE fvalue;
 
146
    char *strvalue;
 
147
    int min;
 
148
    int max;
 
149
    int state;
 
150
    int flags;
 
151
    int cflags;
 
152
    size_t currlen;
 
153
 
 
154
    state = DP_S_DEFAULT;
 
155
    currlen = flags = cflags = min = 0;
 
156
    max = -1;
 
157
    ch = *format++;
 
158
 
 
159
    while (state != DP_S_DONE) {
 
160
        if (ch == '\0')
 
161
            state = DP_S_DONE;
 
162
 
 
163
        switch(state) {
 
164
        case DP_S_DEFAULT:
 
165
            if (ch == '%')
 
166
                state = DP_S_FLAGS;
 
167
            else
 
168
                dopr_outch (buffer, &currlen, maxlen, ch);
 
169
            ch = *format++;
 
170
            break;
 
171
        case DP_S_FLAGS:
 
172
            switch (ch) {
 
173
            case '-':
 
174
                flags |= DP_F_MINUS;
 
175
                ch = *format++;
 
176
                break;
 
177
            case '+':
 
178
                flags |= DP_F_PLUS;
 
179
                ch = *format++;
 
180
                break;
 
181
            case ' ':
 
182
                flags |= DP_F_SPACE;
 
183
                ch = *format++;
 
184
                break;
 
185
            case '#':
 
186
                flags |= DP_F_NUM;
 
187
                ch = *format++;
 
188
                break;
 
189
            case '0':
 
190
                flags |= DP_F_ZERO;
 
191
                ch = *format++;
 
192
                break;
 
193
            default:
 
194
                state = DP_S_MIN;
 
195
                break;
 
196
            }
 
197
            break;
 
198
        case DP_S_MIN:
 
199
            if (isdigit((unsigned char)ch)) {
 
200
                min = 10*min + char_to_int (ch);
 
201
                ch = *format++;
 
202
            } else if (ch == '*') {
 
203
                min = va_arg (args, int);
 
204
                ch = *format++;
 
205
                state = DP_S_DOT;
 
206
            } else {
 
207
                state = DP_S_DOT;
 
208
            }
 
209
            break;
 
210
        case DP_S_DOT:
 
211
            if (ch == '.') {
 
212
                state = DP_S_MAX;
 
213
                ch = *format++;
 
214
            } else {
 
215
                state = DP_S_MOD;
 
216
            }
 
217
            break;
 
218
        case DP_S_MAX:
 
219
            if (isdigit((unsigned char)ch)) {
 
220
                if (max < 0)
 
221
                    max = 0;
 
222
                max = 10*max + char_to_int (ch);
 
223
                ch = *format++;
 
224
            } else if (ch == '*') {
 
225
                max = va_arg (args, int);
 
226
                ch = *format++;
 
227
                state = DP_S_MOD;
 
228
            } else {
 
229
                state = DP_S_MOD;
 
230
            }
 
231
            break;
 
232
        case DP_S_MOD:
 
233
            switch (ch) {
 
234
            case 'h':
 
235
                cflags = DP_C_SHORT;
 
236
                ch = *format++;
 
237
                break;
 
238
            case 'l':
 
239
                cflags = DP_C_LONG;
 
240
                ch = *format++;
 
241
                if (ch == 'l') {        /* It's a long long */
 
242
                    cflags = DP_C_LLONG;
 
243
                    ch = *format++;
 
244
                }
 
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, int);
 
261
                else if (cflags == DP_C_LONG)
 
262
                    value = va_arg (args, long int);
 
263
                else if (cflags == DP_C_LLONG)
 
264
                    value = va_arg (args, LLONG);
 
265
                else
 
266
                    value = va_arg (args, int);
 
267
                fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
 
268
                break;
 
269
            case 'o':
 
270
                flags |= DP_F_UNSIGNED;
 
271
                if (cflags == DP_C_SHORT)
 
272
                    value = va_arg (args, unsigned int);
 
273
                else if (cflags == DP_C_LONG)
 
274
                    value = (long)va_arg (args, unsigned long int);
 
275
                else if (cflags == DP_C_LLONG)
 
276
                    value = (long)va_arg (args, unsigned LLONG);
 
277
                else
 
278
                    value = (long)va_arg (args, unsigned int);
 
279
                fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags);
 
280
                break;
 
281
            case 'u':
 
282
                flags |= DP_F_UNSIGNED;
 
283
                if (cflags == DP_C_SHORT)
 
284
                    value = va_arg (args, unsigned int);
 
285
                else if (cflags == DP_C_LONG)
 
286
                    value = (long)va_arg (args, unsigned long int);
 
287
                else if (cflags == DP_C_LLONG)
 
288
                    value = (LLONG)va_arg (args, unsigned LLONG);
 
289
                else
 
290
                    value = (long)va_arg (args, unsigned int);
 
291
                fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
 
292
                break;
 
293
            case 'X':
 
294
                flags |= DP_F_UP;
 
295
            case 'x':
 
296
                flags |= DP_F_UNSIGNED;
 
297
                if (cflags == DP_C_SHORT)
 
298
                    value = va_arg (args, unsigned int);
 
299
                else if (cflags == DP_C_LONG)
 
300
                    value = (long)va_arg (args, unsigned long int);
 
301
                else if (cflags == DP_C_LLONG)
 
302
                    value = (LLONG)va_arg (args, unsigned LLONG);
 
303
                else
 
304
                    value = (long)va_arg (args, unsigned int);
 
305
                fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags);
 
306
                break;
 
307
            case 'f':
 
308
                if (cflags == DP_C_LDOUBLE)
 
309
                    fvalue = va_arg (args, LDOUBLE);
 
310
                else
 
311
                    fvalue = va_arg (args, double);
 
312
                /* um, floating point? */
 
313
                fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
 
314
                break;
 
315
            case 'E':
 
316
                flags |= DP_F_UP;
 
317
            case 'e':
 
318
                if (cflags == DP_C_LDOUBLE)
 
319
                    fvalue = va_arg (args, LDOUBLE);
 
320
                else
 
321
                    fvalue = va_arg (args, double);
 
322
                break;
 
323
            case 'G':
 
324
                flags |= DP_F_UP;
 
325
            case 'g':
 
326
                if (cflags == DP_C_LDOUBLE)
 
327
                    fvalue = va_arg (args, LDOUBLE);
 
328
                else
 
329
                    fvalue = va_arg (args, double);
 
330
                break;
 
331
            case 'c':
 
332
                dopr_outch (buffer, &currlen, maxlen, va_arg (args, int));
 
333
                break;
 
334
            case 's':
 
335
                strvalue = va_arg (args, char *);
 
336
                if (max == -1) {
 
337
                    max = strlen(strvalue);
 
338
                }
 
339
                if (min > 0 && max >= 0 && min > max) max = min;
 
340
                fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max);
 
341
                break;
 
342
            case 'p':
 
343
                strvalue = va_arg (args, void *);
 
344
                fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags);
 
345
                break;
 
346
            case 'n':
 
347
                if (cflags == DP_C_SHORT) {
 
348
                    short int *num;
 
349
                    num = va_arg (args, short int *);
 
350
                    *num = currlen;
 
351
                } else if (cflags == DP_C_LONG) {
 
352
                    long int *num;
 
353
                    num = va_arg (args, long int *);
 
354
                    *num = (long int)currlen;
 
355
                } else if (cflags == DP_C_LLONG) {
 
356
                    LLONG *num;
 
357
                    num = va_arg (args, LLONG *);
 
358
                    *num = (LLONG)currlen;
 
359
                } else {
 
360
                    int *num;
 
361
                    num = va_arg (args, int *);
 
362
                    *num = currlen;
 
363
                }
 
364
                break;
 
365
            case '%':
 
366
                dopr_outch (buffer, &currlen, maxlen, ch);
 
367
                break;
 
368
            case 'w':
 
369
                /* not supported yet, treat as next char */
 
370
                ch = *format++;
 
371
                break;
 
372
            default:
 
373
                /* Unknown, skip */
 
374
                break;
 
375
            }
 
376
            ch = *format++;
 
377
            state = DP_S_DEFAULT;
 
378
            flags = cflags = min = 0;
 
379
            max = -1;
 
380
            break;
 
381
        case DP_S_DONE:
 
382
            break;
 
383
        default:
 
384
            /* hmm? */
 
385
            break; /* some picky compilers need this */
 
386
        }
 
387
    }
 
388
    if (maxlen != 0) {
 
389
        if (currlen < maxlen - 1)
 
390
            buffer[currlen] = '\0';
 
391
        else if (maxlen > 0)
 
392
            buffer[maxlen - 1] = '\0';
 
393
    }
 
394
 
 
395
    return currlen;
 
396
}
 
397
 
 
398
static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
 
399
                   char *value, int flags, int min, int max)
 
400
{
 
401
    int padlen, strln;     /* amount to pad */
 
402
    int cnt = 0;
 
403
 
 
404
#ifdef DEBUG_SNPRINTF
 
405
    printf("fmtstr min=%d max=%d s=[%s]\n", min, max, value);
 
406
#endif
 
407
    if (value == 0) {
 
408
        value = "<NULL>";
 
409
    }
 
410
 
 
411
    for (strln = 0; value[strln]; ++strln); /* strlen */
 
412
    padlen = min - strln;
 
413
    if (padlen < 0)
 
414
        padlen = 0;
 
415
    if (flags & DP_F_MINUS)
 
416
        padlen = -padlen; /* Left Justify */
 
417
 
 
418
    while ((padlen > 0) && (cnt < max)) {
 
419
        dopr_outch (buffer, currlen, maxlen, ' ');
 
420
        --padlen;
 
421
        ++cnt;
 
422
    }
 
423
    while (*value && (cnt < max)) {
 
424
        dopr_outch (buffer, currlen, maxlen, *value++);
 
425
        ++cnt;
 
426
    }
 
427
    while ((padlen < 0) && (cnt < max)) {
 
428
        dopr_outch (buffer, currlen, maxlen, ' ');
 
429
        ++padlen;
 
430
        ++cnt;
 
431
    }
 
432
}
 
433
 
 
434
/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
 
435
 
 
436
static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
 
437
                   long value, int base, int min, int max, int flags)
 
438
{
 
439
    int signvalue = 0;
 
440
    unsigned long uvalue;
 
441
    char convert[20];
 
442
    int place = 0;
 
443
    int spadlen = 0; /* amount to space pad */
 
444
    int zpadlen = 0; /* amount to zero pad */
 
445
    int caps = 0;
 
446
 
 
447
    if (max < 0)
 
448
        max = 0;
 
449
 
 
450
    uvalue = value;
 
451
 
 
452
    if(!(flags & DP_F_UNSIGNED)) {
 
453
        if( value < 0 ) {
 
454
            signvalue = '-';
 
455
            uvalue = -value;
 
456
        } else {
 
457
            if (flags & DP_F_PLUS)  /* Do a sign (+/i) */
 
458
                signvalue = '+';
 
459
            else if (flags & DP_F_SPACE)
 
460
                signvalue = ' ';
 
461
        }
 
462
    }
 
463
 
 
464
    if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
 
465
 
 
466
    do {
 
467
        convert[place++] =
 
468
            (caps? "0123456789ABCDEF":"0123456789abcdef")
 
469
            [uvalue % (unsigned)base  ];
 
470
        uvalue = (uvalue / (unsigned)base );
 
471
    } while(uvalue && (place < 20));
 
472
    if (place == 20) place--;
 
473
    convert[place] = 0;
 
474
 
 
475
    zpadlen = max - place;
 
476
    spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
 
477
    if (zpadlen < 0) zpadlen = 0;
 
478
    if (spadlen < 0) spadlen = 0;
 
479
    if (flags & DP_F_ZERO) {
 
480
        zpadlen = MAX(zpadlen, spadlen);
 
481
        spadlen = 0;
 
482
    }
 
483
    if (flags & DP_F_MINUS)
 
484
        spadlen = -spadlen; /* Left Justifty */
 
485
 
 
486
#ifdef DEBUG_SNPRINTF
 
487
    printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
 
488
           zpadlen, spadlen, min, max, place);
 
489
#endif
 
490
 
 
491
    /* Spaces */
 
492
    while (spadlen > 0) {
 
493
        dopr_outch (buffer, currlen, maxlen, ' ');
 
494
        --spadlen;
 
495
    }
 
496
 
 
497
    /* Sign */
 
498
    if (signvalue)
 
499
        dopr_outch (buffer, currlen, maxlen, signvalue);
 
500
 
 
501
    /* Zeros */
 
502
    if (zpadlen > 0) {
 
503
        while (zpadlen > 0) {
 
504
            dopr_outch (buffer, currlen, maxlen, '0');
 
505
            --zpadlen;
 
506
        }
 
507
    }
 
508
 
 
509
    /* Digits */
 
510
    while (place > 0)
 
511
        dopr_outch (buffer, currlen, maxlen, convert[--place]);
 
512
 
 
513
    /* Left Justified spaces */
 
514
    while (spadlen < 0) {
 
515
        dopr_outch (buffer, currlen, maxlen, ' ');
 
516
        ++spadlen;
 
517
    }
 
518
}
 
519
 
 
520
static LDOUBLE abs_val(LDOUBLE value)
 
521
{
 
522
    LDOUBLE result = value;
 
523
 
 
524
    if (value < 0)
 
525
        result = -value;
 
526
 
 
527
    return result;
 
528
}
 
529
 
 
530
static LDOUBLE POW10(int exp)
 
531
{
 
532
    LDOUBLE result = 1;
 
533
 
 
534
    while (exp) {
 
535
        result *= 10;
 
536
        exp--;
 
537
    }
 
538
 
 
539
    return result;
 
540
}
 
541
 
 
542
static LLONG ROUND(LDOUBLE value)
 
543
{
 
544
    LLONG intpart;
 
545
 
 
546
    intpart = (LLONG)value;
 
547
    value = value - intpart;
 
548
    if (value >= 0.5) intpart++;
 
549
 
 
550
    return intpart;
 
551
}
 
552
 
 
553
/* a replacement for modf that doesn't need the math library. Should
 
554
 be portable, but slow */
 
555
static double my_modf(double x0, double *iptr)
 
556
{
 
557
    int i;
 
558
    long l;
 
559
    double x = x0;
 
560
    double f = 1.0;
 
561
 
 
562
    for (i=0;i<100;i++) {
 
563
        l = (long)x;
 
564
        if (l <= (x+1) && l >= (x-1)) break;
 
565
        x *= 0.1;
 
566
        f *= 10.0;
 
567
    }
 
568
 
 
569
    if (i == 100) {
 
570
        /* yikes! the number is beyond what we can handle. What do we do? */
 
571
        (*iptr) = 0;
 
572
        return 0;
 
573
    }
 
574
 
 
575
    if (i != 0) {
 
576
        double i2;
 
577
        double ret;
 
578
 
 
579
        ret = my_modf(x0-l*f, &i2);
 
580
        (*iptr) = l*f + i2;
 
581
        return ret;
 
582
    }
 
583
 
 
584
    (*iptr) = l;
 
585
    return x - (*iptr);
 
586
}
 
587
 
 
588
 
 
589
static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
 
590
                   LDOUBLE fvalue, int min, int max, int flags)
 
591
{
 
592
    int signvalue = 0;
 
593
    double ufvalue;
 
594
    char iconvert[311];
 
595
    char fconvert[311];
 
596
    int iplace = 0;
 
597
    int fplace = 0;
 
598
    int padlen = 0; /* amount to pad */
 
599
    int zpadlen = 0;
 
600
    int caps = 0;
 
601
    int index;
 
602
    double intpart;
 
603
    double fracpart;
 
604
    double temp;
 
605
 
 
606
    /*
 
607
     * AIX manpage says the default is 0, but Solaris says the default
 
608
     * is 6, and sprintf on AIX defaults to 6
 
609
     */
 
610
    if (max < 0)
 
611
        max = 6;
 
612
 
 
613
    ufvalue = abs_val (fvalue);
 
614
 
 
615
    if (fvalue < 0) {
 
616
        signvalue = '-';
 
617
    } else {
 
618
        if (flags & DP_F_PLUS) { /* Do a sign (+/i) */
 
619
            signvalue = '+';
 
620
        } else {
 
621
            if (flags & DP_F_SPACE)
 
622
                signvalue = ' ';
 
623
        }
 
624
    }
 
625
 
 
626
#if 0
 
627
    if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
 
628
#endif
 
629
 
 
630
#if 0
 
631
    if (max == 0) ufvalue += 0.5; /* if max = 0 we must round */
 
632
#endif
 
633
 
 
634
    /*
 
635
     * Sorry, we only support 16 digits past the decimal because of our
 
636
     * conversion method
 
637
     */
 
638
    if (max > 16)
 
639
        max = 16;
 
640
 
 
641
    /* We "cheat" by converting the fractional part to integer by
 
642
     * multiplying by a factor of 10
 
643
     */
 
644
 
 
645
    temp = ufvalue;
 
646
    my_modf(temp, &intpart);
 
647
 
 
648
    fracpart = ROUND((POW10(max)) * (ufvalue - intpart));
 
649
 
 
650
    if (fracpart >= POW10(max)) {
 
651
        intpart++;
 
652
        fracpart -= POW10(max);
 
653
    }
 
654
 
 
655
 
 
656
    /* Convert integer part */
 
657
    do {
 
658
        temp = intpart;
 
659
        my_modf(intpart*0.1, &intpart);
 
660
        temp = temp*0.1;
 
661
        index = (int) ((temp -intpart +0.05)* 10.0);
 
662
        /* index = (int) (((double)(temp*0.1) -intpart +0.05) *10.0); */
 
663
        /* printf ("%llf, %f, %x\n", temp, intpart, index); */
 
664
        iconvert[iplace++] =
 
665
            (caps? "0123456789ABCDEF":"0123456789abcdef")[index];
 
666
    } while (intpart && (iplace < 311));
 
667
    if (iplace == 311) iplace--;
 
668
    iconvert[iplace] = 0;
 
669
 
 
670
    /* Convert fractional part */
 
671
    if (fracpart)
 
672
    {
 
673
        do {
 
674
            temp = fracpart;
 
675
            my_modf(fracpart*0.1, &fracpart);
 
676
            temp = temp*0.1;
 
677
            index = (int) ((temp -fracpart +0.05)* 10.0);
 
678
            /* index = (int) ((((temp/10) -fracpart) +0.05) *10); */
 
679
            /* printf ("%lf, %lf, %ld\n", temp, fracpart, index); */
 
680
            fconvert[fplace++] =
 
681
                (caps? "0123456789ABCDEF":"0123456789abcdef")[index];
 
682
        } while(fracpart && (fplace < 311));
 
683
        if (fplace == 311) fplace--;
 
684
    }
 
685
    fconvert[fplace] = 0;
 
686
 
 
687
    /* -1 for decimal point, another -1 if we are printing a sign */
 
688
    padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
 
689
    zpadlen = max - fplace;
 
690
    if (zpadlen < 0) zpadlen = 0;
 
691
    if (padlen < 0)
 
692
        padlen = 0;
 
693
    if (flags & DP_F_MINUS)
 
694
        padlen = -padlen; /* Left Justifty */
 
695
 
 
696
    if ((flags & DP_F_ZERO) && (padlen > 0)) {
 
697
        if (signvalue) {
 
698
            dopr_outch (buffer, currlen, maxlen, signvalue);
 
699
            --padlen;
 
700
            signvalue = 0;
 
701
        }
 
702
        while (padlen > 0) {
 
703
            dopr_outch (buffer, currlen, maxlen, '0');
 
704
            --padlen;
 
705
        }
 
706
    }
 
707
    while (padlen > 0) {
 
708
        dopr_outch (buffer, currlen, maxlen, ' ');
 
709
        --padlen;
 
710
    }
 
711
    if (signvalue)
 
712
        dopr_outch (buffer, currlen, maxlen, signvalue);
 
713
 
 
714
    while (iplace > 0)
 
715
        dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]);
 
716
 
 
717
#ifdef DEBUG_SNPRINTF
 
718
    printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen);
 
719
#endif
 
720
 
 
721
    /*
 
722
     * Decimal point.  This should probably use locale to find the correct
 
723
     * char to print out.
 
724
     */
 
725
    if (max > 0) {
 
726
        dopr_outch (buffer, currlen, maxlen, '.');
 
727
 
 
728
        while (fplace > 0)
 
729
            dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]);
 
730
    }
 
731
 
 
732
    while (zpadlen > 0) {
 
733
        dopr_outch (buffer, currlen, maxlen, '0');
 
734
        --zpadlen;
 
735
    }
 
736
 
 
737
    while (padlen < 0) {
 
738
        dopr_outch (buffer, currlen, maxlen, ' ');
 
739
        ++padlen;
 
740
    }
 
741
}
 
742
 
 
743
static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
 
744
{
 
745
    if (*currlen < maxlen) {
 
746
        buffer[(*currlen)] = c;
 
747
    }
 
748
    (*currlen)++;
 
749
}
 
750
 
 
751
#if !defined(HAVE_VSNPRINTF) || !defined(HAVE_C99_VSNPRINTF)
 
752
int vsnprintf (char *str, size_t count, const char *fmt, va_list args)
 
753
{
 
754
    return dopr(str, count, fmt, args);
 
755
}
 
756
#endif
 
757
 
 
758
#if !defined(HAVE_SNPRINTF) || !defined(HAVE_C99_VSNPRINTF)
 
759
int snprintf(char *str,size_t count,const char *fmt,...)
 
760
{
 
761
    size_t ret;
 
762
    va_list ap;
 
763
 
 
764
    va_start(ap, fmt);
 
765
    ret = vsnprintf(str, count, fmt, ap);
 
766
    va_end(ap);
 
767
    return ret;
 
768
}
 
769
#endif
 
770
 
 
771
#endif
 
772
 
 
773
#ifndef HAVE_VASPRINTF
 
774
int vasprintf(char **ptr, const char *format, va_list ap)
 
775
{
 
776
    int ret;
 
777
 
 
778
    ret = vsnprintf(NULL, 0, format, ap);
 
779
    if (ret <= 0) return ret;
 
780
 
 
781
    (*ptr) = (char *)malloc(ret+1);
 
782
    if (!*ptr) return -1;
 
783
    ret = vsnprintf(*ptr, ret+1, format, ap);
 
784
 
 
785
    return ret;
 
786
}
 
787
#endif
 
788
 
 
789
 
 
790
#ifndef HAVE_ASPRINTF
 
791
int asprintf(char **ptr, const char *format, ...)
 
792
{
 
793
    va_list ap;
 
794
    int ret;
 
795
 
 
796
    va_start(ap, format);
 
797
    ret = vasprintf(ptr, format, ap);
 
798
    va_end(ap);
 
799
 
 
800
    return ret;
 
801
}
 
802
#endif
 
803
 
 
804
#ifdef TEST_SNPRINTF
 
805
 
 
806
int sprintf(char *str,const char *fmt,...);
 
807
 
 
808
int main (void)
 
809
{
 
810
    char buf1[1024];
 
811
    char buf2[1024];
 
812
    char *fp_fmt[] = {
 
813
        "%1.1f",
 
814
        "%-1.5f",
 
815
        "%1.5f",
 
816
        "%123.9f",
 
817
        "%10.5f",
 
818
        "% 10.5f",
 
819
        "%+22.9f",
 
820
        "%+4.9f",
 
821
        "%01.3f",
 
822
        "%4f",
 
823
        "%3.1f",
 
824
        "%3.2f",
 
825
        "%.0f",
 
826
        "%f",
 
827
        "-16.16f",
 
828
        NULL
 
829
    };
 
830
    double fp_nums[] = { 6442452944.1234, -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996,
 
831
    0.9996, 1.996, 4.136,  0};
 
832
    char *int_fmt[] = {
 
833
        "%-1.5d",
 
834
        "%1.5d",
 
835
        "%123.9d",
 
836
        "%5.5d",
 
837
        "%10.5d",
 
838
        "% 10.5d",
 
839
        "%+22.33d",
 
840
        "%01.3d",
 
841
        "%4d",
 
842
        "%d",
 
843
        NULL
 
844
    };
 
845
    long int_nums[] = { -1, 134, 91340, 341, 0203, 0};
 
846
    char *str_fmt[] = {
 
847
        "10.5s",
 
848
        "5.10s",
 
849
        "10.1s",
 
850
        "0.10s",
 
851
        "10.0s",
 
852
        "1.10s",
 
853
        "%s",
 
854
        "%.1s",
 
855
        "%.10s",
 
856
        "%10s",
 
857
        NULL
 
858
    };
 
859
    char *str_vals[] = {"hello", "a", "", "a longer string", NULL};
 
860
    int x, y;
 
861
    int fail = 0;
 
862
    int num = 0;
 
863
 
 
864
    printf ("Testing snprintf format codes against system sprintf...\n");
 
865
 
 
866
    for (x = 0; fp_fmt[x] ; x++) {
 
867
        for (y = 0; fp_nums[y] != 0 ; y++) {
 
868
            int l1 = snprintf(NULL, 0, fp_fmt[x], fp_nums[y]);
 
869
            int l2 = snprintf(buf1, sizeof(buf1), fp_fmt[x], fp_nums[y]);
 
870
            sprintf (buf2, fp_fmt[x], fp_nums[y]);
 
871
            if (strcmp (buf1, buf2)) {
 
872
                printf("snprintf doesn't match Format: %s\n\tsnprintf = [%s]\n\t sprintf = [%s]\n",
 
873
                       fp_fmt[x], buf1, buf2);
 
874
                fail++;
 
875
            }
 
876
            if (l1 != l2) {
 
877
                printf("snprintf l1 != l2 (%d %d) %s\n", l1, l2, fp_fmt[x]);
 
878
                fail++;
 
879
            }
 
880
            num++;
 
881
        }
 
882
    }
 
883
 
 
884
    for (x = 0; int_fmt[x] ; x++) {
 
885
        for (y = 0; int_nums[y] != 0 ; y++) {
 
886
            int l1 = snprintf(NULL, 0, int_fmt[x], int_nums[y]);
 
887
            int l2 = snprintf(buf1, sizeof(buf1), int_fmt[x], int_nums[y]);
 
888
            sprintf (buf2, int_fmt[x], int_nums[y]);
 
889
            if (strcmp (buf1, buf2)) {
 
890
                printf("snprintf doesn't match Format: %s\n\tsnprintf = [%s]\n\t sprintf = [%s]\n",
 
891
                       int_fmt[x], buf1, buf2);
 
892
                fail++;
 
893
            }
 
894
            if (l1 != l2) {
 
895
                printf("snprintf l1 != l2 (%d %d) %s\n", l1, l2, int_fmt[x]);
 
896
                fail++;
 
897
            }
 
898
            num++;
 
899
        }
 
900
    }
 
901
 
 
902
    for (x = 0; str_fmt[x] ; x++) {
 
903
        for (y = 0; str_vals[y] != 0 ; y++) {
 
904
            int l1 = snprintf(NULL, 0, str_fmt[x], str_vals[y]);
 
905
            int l2 = snprintf(buf1, sizeof(buf1), str_fmt[x], str_vals[y]);
 
906
            sprintf (buf2, str_fmt[x], str_vals[y]);
 
907
            if (strcmp (buf1, buf2)) {
 
908
                printf("snprintf doesn't match Format: %s\n\tsnprintf = [%s]\n\t sprintf = [%s]\n",
 
909
                       str_fmt[x], buf1, buf2);
 
910
                fail++;
 
911
            }
 
912
            if (l1 != l2) {
 
913
                printf("snprintf l1 != l2 (%d %d) %s\n", l1, l2, str_fmt[x]);
 
914
                fail++;
 
915
            }
 
916
            num++;
 
917
        }
 
918
    }
 
919
 
 
920
    printf ("%d tests failed out of %d.\n", fail, num);
 
921
 
 
922
    printf("seeing how many digits we support\n");
 
923
    {
 
924
        double v0 = 0.12345678901234567890123456789012345678901;
 
925
        for (x=0; x<100; x++) {
 
926
            snprintf(buf1, sizeof(buf1), "%1.1f", v0*pow(10, x));
 
927
            sprintf(buf2,                "%1.1f", v0*pow(10, x));
 
928
            if (strcmp(buf1, buf2)) {
 
929
                printf("we seem to support %d digits\n", x-1);
 
930
                break;
 
931
            }
 
932
        }
 
933
    }
 
934
 
 
935
    return 0;
 
936
}
 
937
#endif /* SNPRINTF_TEST */
 
938