~ubuntu-branches/ubuntu/precise/nagios-plugins/precise-proposed

« back to all changes in this revision

Viewing changes to plugins/snprintf.c

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