~ubuntu-branches/ubuntu/maverick/uim/maverick

« back to all changes in this revision

Viewing changes to replace/bsd-snprintf.c

  • Committer: Bazaar Package Importer
  • Author(s): Masahito Omote
  • Date: 2008-06-25 19:56:33 UTC
  • mfrom: (3.1.18 intrepid)
  • Revision ID: james.westby@ubuntu.com-20080625195633-8jljph4rfq00l8o7
Tags: 1:1.5.1-2
* uim-tcode: provide tutcode-custom.scm, tutcode-bushudic.scm
  and tutcode-rule.scm (Closes: #482659)
* Fix FTBFS: segv during compile (Closes: #483078).
  I personally think this bug is not specific for uim but is a optimization
  problem on gcc-4.3.1. (https://bugs.freedesktop.org/show_bug.cgi?id=16477)

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
 * date: 2002/12/19 19:56:31;  author: herb;  state: Exp;  lines: +2 -0
 
57
 * actually print args for %g and %e
 
58
 * 
 
59
 * date: 2002/06/03 13:37:52;  author: jmcd;  state: Exp;  lines: +8 -0
 
60
 * Since includes.h isn't included here, VA_COPY has to be defined here.  I don't
 
61
 * see any include file that is guaranteed to be here, so I'm defining it
 
62
 * locally.  Fixes AIX and Solaris builds.
 
63
 * 
 
64
 * date: 2002/06/03 03:07:24;  author: tridge;  state: Exp;  lines: +5 -13
 
65
 * put the ifdef for HAVE_VA_COPY in one place rather than in lots of
 
66
 * functions
 
67
 * 
 
68
 * date: 2002/05/17 14:51:22;  author: jmcd;  state: Exp;  lines: +21 -4
 
69
 * Fix usage of va_list passed as an arg.  Use __va_copy before using it
 
70
 * when it exists.
 
71
 * 
 
72
 * date: 2002/04/16 22:38:04;  author: idra;  state: Exp;  lines: +20 -14
 
73
 * Fix incorrect zpadlen handling in fmtfp.
 
74
 * Thanks to Ollie Oldham <ollie.oldham@metro-optix.com> for spotting it.
 
75
 * few mods to make it easier to compile the tests.
 
76
 * addedd the "Ollie" test to the floating point ones.
 
77
 *
 
78
 * Martin Pool (mbp@samba.org) April 2003
 
79
 *    Remove NO_CONFIG_H so that the test case can be built within a source
 
80
 *    tree with less trouble.
 
81
 *    Remove unnecessary SAFE_FREE() definition.
 
82
 *
 
83
 * Martin Pool (mbp@samba.org) May 2003
 
84
 *    Put in a prototype for dummy_snprintf() to quiet compiler warnings.
 
85
 *
 
86
 *    Move #endif to make sure VA_COPY, LDOUBLE, etc are defined even
 
87
 *    if the C library has some snprintf functions already.
 
88
 **************************************************************/
 
89
 
 
90
#include <config.h>
 
91
 
 
92
#if defined(BROKEN_SNPRINTF)            /* For those with broken snprintf() */
 
93
# undef HAVE_SNPRINTF
 
94
# undef HAVE_VSNPRINTF
 
95
#endif
 
96
 
 
97
#ifndef VA_COPY
 
98
# ifdef HAVE_VA_COPY
 
99
#  define VA_COPY(dest, src) va_copy(dest, src)
 
100
# else
 
101
#  ifdef HAVE___VA_COPY
 
102
#   define VA_COPY(dest, src) __va_copy(dest, src)
 
103
#  else
 
104
#   define VA_COPY(dest, src) (dest) = (src)
 
105
#  endif
 
106
# endif
 
107
#endif
 
108
 
 
109
#if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF)
 
110
 
 
111
#include <ctype.h>
 
112
#include <stdarg.h>
 
113
#include <stdlib.h>
 
114
#include <string.h>
 
115
 
 
116
#ifdef HAVE_LONG_DOUBLE
 
117
# define LDOUBLE long double
 
118
#else
 
119
# define LDOUBLE double
 
120
#endif
 
121
 
 
122
#ifdef HAVE_LONG_LONG
 
123
# define LLONG long long
 
124
#else
 
125
# define LLONG long
 
126
#endif
 
127
 
 
128
/*
 
129
 * dopr(): poor man's version of doprintf
 
130
 */
 
131
 
 
132
/* format read states */
 
133
#define DP_S_DEFAULT 0
 
134
#define DP_S_FLAGS   1
 
135
#define DP_S_MIN     2
 
136
#define DP_S_DOT     3
 
137
#define DP_S_MAX     4
 
138
#define DP_S_MOD     5
 
139
#define DP_S_CONV    6
 
140
#define DP_S_DONE    7
 
141
 
 
142
/* format flags - Bits */
 
143
#define DP_F_MINUS      (1 << 0)
 
144
#define DP_F_PLUS       (1 << 1)
 
145
#define DP_F_SPACE      (1 << 2)
 
146
#define DP_F_NUM        (1 << 3)
 
147
#define DP_F_ZERO       (1 << 4)
 
148
#define DP_F_UP         (1 << 5)
 
149
#define DP_F_UNSIGNED   (1 << 6)
 
150
 
 
151
/* Conversion Flags */
 
152
#define DP_C_SHORT   1
 
153
#define DP_C_LONG    2
 
154
#define DP_C_LDOUBLE 3
 
155
#define DP_C_LLONG   4
 
156
 
 
157
#define char_to_int(p) ((p)- '0')
 
158
#ifndef MAX
 
159
# define MAX(p,q) (((p) >= (q)) ? (p) : (q))
 
160
#endif
 
161
 
 
162
static size_t dopr(char *buffer, size_t maxlen, const char *format, 
 
163
                   va_list args_in);
 
164
static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
 
165
                    char *value, int flags, int min, int max);
 
166
static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
 
167
                    LLONG value, int base, int min, int max, int flags);
 
168
static void fmtfp(char *buffer, size_t *currlen, size_t maxlen,
 
169
                   LDOUBLE fvalue, int min, int max, int flags);
 
170
static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c);
 
171
 
 
172
static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args_in)
 
173
{
 
174
        char ch;
 
175
        LLONG value;
 
176
        LDOUBLE fvalue;
 
177
        char *strvalue;
 
178
        int min;
 
179
        int max;
 
180
        int state;
 
181
        int flags;
 
182
        int cflags;
 
183
        size_t currlen;
 
184
        va_list args;
 
185
 
 
186
        VA_COPY(args, args_in);
 
187
        
 
188
        state = DP_S_DEFAULT;
 
189
        currlen = flags = cflags = min = 0;
 
190
        max = -1;
 
191
        ch = *format++;
 
192
        
 
193
        while (state != DP_S_DONE) {
 
194
                if (ch == '\0') 
 
195
                        state = DP_S_DONE;
 
196
 
 
197
                switch(state) {
 
198
                case DP_S_DEFAULT:
 
199
                        if (ch == '%') 
 
200
                                state = DP_S_FLAGS;
 
201
                        else 
 
202
                                dopr_outch (buffer, &currlen, maxlen, ch);
 
203
                        ch = *format++;
 
204
                        break;
 
205
                case DP_S_FLAGS:
 
206
                        switch (ch) {
 
207
                        case '-':
 
208
                                flags |= DP_F_MINUS;
 
209
                                ch = *format++;
 
210
                                break;
 
211
                        case '+':
 
212
                                flags |= DP_F_PLUS;
 
213
                                ch = *format++;
 
214
                                break;
 
215
                        case ' ':
 
216
                                flags |= DP_F_SPACE;
 
217
                                ch = *format++;
 
218
                                break;
 
219
                        case '#':
 
220
                                flags |= DP_F_NUM;
 
221
                                ch = *format++;
 
222
                                break;
 
223
                        case '0':
 
224
                                flags |= DP_F_ZERO;
 
225
                                ch = *format++;
 
226
                                break;
 
227
                        default:
 
228
                                state = DP_S_MIN;
 
229
                                break;
 
230
                        }
 
231
                        break;
 
232
                case DP_S_MIN:
 
233
                        if (isdigit((unsigned char)ch)) {
 
234
                                min = 10*min + char_to_int (ch);
 
235
                                ch = *format++;
 
236
                        } else if (ch == '*') {
 
237
                                min = va_arg (args, int);
 
238
                                ch = *format++;
 
239
                                state = DP_S_DOT;
 
240
                        } else {
 
241
                                state = DP_S_DOT;
 
242
                        }
 
243
                        break;
 
244
                case DP_S_DOT:
 
245
                        if (ch == '.') {
 
246
                                state = DP_S_MAX;
 
247
                                ch = *format++;
 
248
                        } else { 
 
249
                                state = DP_S_MOD;
 
250
                        }
 
251
                        break;
 
252
                case DP_S_MAX:
 
253
                        if (isdigit((unsigned char)ch)) {
 
254
                                if (max < 0)
 
255
                                        max = 0;
 
256
                                max = 10*max + char_to_int (ch);
 
257
                                ch = *format++;
 
258
                        } else if (ch == '*') {
 
259
                                max = va_arg (args, int);
 
260
                                ch = *format++;
 
261
                                state = DP_S_MOD;
 
262
                        } else {
 
263
                                state = DP_S_MOD;
 
264
                        }
 
265
                        break;
 
266
                case DP_S_MOD:
 
267
                        switch (ch) {
 
268
                        case 'h':
 
269
                                cflags = DP_C_SHORT;
 
270
                                ch = *format++;
 
271
                                break;
 
272
                        case 'l':
 
273
                                cflags = DP_C_LONG;
 
274
                                ch = *format++;
 
275
                                if (ch == 'l') {        /* It's a long long */
 
276
                                        cflags = DP_C_LLONG;
 
277
                                        ch = *format++;
 
278
                                }
 
279
                                break;
 
280
                        case 'L':
 
281
                                cflags = DP_C_LDOUBLE;
 
282
                                ch = *format++;
 
283
                                break;
 
284
                        default:
 
285
                                break;
 
286
                        }
 
287
                        state = DP_S_CONV;
 
288
                        break;
 
289
                case DP_S_CONV:
 
290
                        switch (ch) {
 
291
                        case 'd':
 
292
                        case 'i':
 
293
                                if (cflags == DP_C_SHORT) 
 
294
                                        value = va_arg (args, int);
 
295
                                else if (cflags == DP_C_LONG)
 
296
                                        value = va_arg (args, long int);
 
297
                                else if (cflags == DP_C_LLONG)
 
298
                                        value = va_arg (args, LLONG);
 
299
                                else
 
300
                                        value = va_arg (args, int);
 
301
                                fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
 
302
                                break;
 
303
                        case 'o':
 
304
                                flags |= DP_F_UNSIGNED;
 
305
                                if (cflags == DP_C_SHORT)
 
306
                                        value = va_arg (args, unsigned int);
 
307
                                else if (cflags == DP_C_LONG)
 
308
                                        value = (long)va_arg (args, unsigned long int);
 
309
                                else if (cflags == DP_C_LLONG)
 
310
                                        value = (long)va_arg (args, unsigned LLONG);
 
311
                                else
 
312
                                        value = (long)va_arg (args, unsigned int);
 
313
                                fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags);
 
314
                                break;
 
315
                        case 'u':
 
316
                                flags |= DP_F_UNSIGNED;
 
317
                                if (cflags == DP_C_SHORT)
 
318
                                        value = va_arg (args, unsigned int);
 
319
                                else if (cflags == DP_C_LONG)
 
320
                                        value = (long)va_arg (args, unsigned long int);
 
321
                                else if (cflags == DP_C_LLONG)
 
322
                                        value = (LLONG)va_arg (args, unsigned LLONG);
 
323
                                else
 
324
                                        value = (long)va_arg (args, unsigned int);
 
325
                                fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
 
326
                                break;
 
327
                        case 'X':
 
328
                                flags |= DP_F_UP;
 
329
                        case 'x':
 
330
                                flags |= DP_F_UNSIGNED;
 
331
                                if (cflags == DP_C_SHORT)
 
332
                                        value = va_arg (args, unsigned int);
 
333
                                else if (cflags == DP_C_LONG)
 
334
                                        value = (long)va_arg (args, unsigned long int);
 
335
                                else if (cflags == DP_C_LLONG)
 
336
                                        value = (LLONG)va_arg (args, unsigned LLONG);
 
337
                                else
 
338
                                        value = (long)va_arg (args, unsigned int);
 
339
                                fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags);
 
340
                                break;
 
341
                        case 'f':
 
342
                                if (cflags == DP_C_LDOUBLE)
 
343
                                        fvalue = va_arg (args, LDOUBLE);
 
344
                                else
 
345
                                        fvalue = va_arg (args, double);
 
346
                                /* um, floating point? */
 
347
                                fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
 
348
                                break;
 
349
                        case 'E':
 
350
                                flags |= DP_F_UP;
 
351
                        case 'e':
 
352
                                if (cflags == DP_C_LDOUBLE)
 
353
                                        fvalue = va_arg (args, LDOUBLE);
 
354
                                else
 
355
                                        fvalue = va_arg (args, double);
 
356
                                fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
 
357
                                break;
 
358
                        case 'G':
 
359
                                flags |= DP_F_UP;
 
360
                        case 'g':
 
361
                                if (cflags == DP_C_LDOUBLE)
 
362
                                        fvalue = va_arg (args, LDOUBLE);
 
363
                                else
 
364
                                        fvalue = va_arg (args, double);
 
365
                                fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
 
366
                                break;
 
367
                        case 'c':
 
368
                                dopr_outch (buffer, &currlen, maxlen, va_arg (args, int));
 
369
                                break;
 
370
                        case 's':
 
371
                                strvalue = va_arg (args, char *);
 
372
                                if (!strvalue) strvalue = "(NULL)";
 
373
                                if (max == -1) {
 
374
                                        max = strlen(strvalue);
 
375
                                }
 
376
                                if (min > 0 && max >= 0 && min > max) max = min;
 
377
                                fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max);
 
378
                                break;
 
379
                        case 'p':
 
380
                                strvalue = va_arg (args, void *);
 
381
                                fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags);
 
382
                                break;
 
383
                        case 'n':
 
384
                                if (cflags == DP_C_SHORT) {
 
385
                                        short int *num;
 
386
                                        num = va_arg (args, short int *);
 
387
                                        *num = currlen;
 
388
                                } else if (cflags == DP_C_LONG) {
 
389
                                        long int *num;
 
390
                                        num = va_arg (args, long int *);
 
391
                                        *num = (long int)currlen;
 
392
                                } else if (cflags == DP_C_LLONG) {
 
393
                                        LLONG *num;
 
394
                                        num = va_arg (args, LLONG *);
 
395
                                        *num = (LLONG)currlen;
 
396
                                } else {
 
397
                                        int *num;
 
398
                                        num = va_arg (args, int *);
 
399
                                        *num = currlen;
 
400
                                }
 
401
                                break;
 
402
                        case '%':
 
403
                                dopr_outch (buffer, &currlen, maxlen, ch);
 
404
                                break;
 
405
                        case 'w':
 
406
                                /* not supported yet, treat as next char */
 
407
                                ch = *format++;
 
408
                                break;
 
409
                        default:
 
410
                                /* Unknown, skip */
 
411
                                break;
 
412
                        }
 
413
                        ch = *format++;
 
414
                        state = DP_S_DEFAULT;
 
415
                        flags = cflags = min = 0;
 
416
                        max = -1;
 
417
                        break;
 
418
                case DP_S_DONE:
 
419
                        break;
 
420
                default:
 
421
                        /* hmm? */
 
422
                        break; /* some picky compilers need this */
 
423
                }
 
424
        }
 
425
        if (maxlen != 0) {
 
426
                if (currlen < maxlen - 1) 
 
427
                        buffer[currlen] = '\0';
 
428
                else if (maxlen > 0) 
 
429
                        buffer[maxlen - 1] = '\0';
 
430
        }
 
431
        
 
432
        return currlen;
 
433
}
 
434
 
 
435
static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
 
436
                    char *value, int flags, int min, int max)
 
437
{
 
438
        int padlen, strln;     /* amount to pad */
 
439
        int cnt = 0;
 
440
 
 
441
#ifdef DEBUG_SNPRINTF
 
442
        printf("fmtstr min=%d max=%d s=[%s]\n", min, max, value);
 
443
#endif
 
444
        if (value == 0) {
 
445
                value = "<NULL>";
 
446
        }
 
447
 
 
448
        for (strln = 0; strln < max && value[strln]; ++strln); /* strlen */
 
449
        padlen = min - strln;
 
450
        if (padlen < 0) 
 
451
                padlen = 0;
 
452
        if (flags & DP_F_MINUS) 
 
453
                padlen = -padlen; /* Left Justify */
 
454
        
 
455
        while ((padlen > 0) && (cnt < max)) {
 
456
                dopr_outch (buffer, currlen, maxlen, ' ');
 
457
                --padlen;
 
458
                ++cnt;
 
459
        }
 
460
        while (*value && (cnt < max)) {
 
461
                dopr_outch (buffer, currlen, maxlen, *value++);
 
462
                ++cnt;
 
463
        }
 
464
        while ((padlen < 0) && (cnt < max)) {
 
465
                dopr_outch (buffer, currlen, maxlen, ' ');
 
466
                ++padlen;
 
467
                ++cnt;
 
468
        }
 
469
}
 
470
 
 
471
/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
 
472
 
 
473
static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
 
474
                    LLONG value, int base, int min, int max, int flags)
 
475
{
 
476
        int signvalue = 0;
 
477
        unsigned LLONG uvalue;
 
478
        char convert[20];
 
479
        int place = 0;
 
480
        int spadlen = 0; /* amount to space pad */
 
481
        int zpadlen = 0; /* amount to zero pad */
 
482
        int caps = 0;
 
483
        
 
484
        if (max < 0)
 
485
                max = 0;
 
486
        
 
487
        uvalue = value;
 
488
        
 
489
        if(!(flags & DP_F_UNSIGNED)) {
 
490
                if( value < 0 ) {
 
491
                        signvalue = '-';
 
492
                        uvalue = -value;
 
493
                } else {
 
494
                        if (flags & DP_F_PLUS)  /* Do a sign (+/i) */
 
495
                                signvalue = '+';
 
496
                        else if (flags & DP_F_SPACE)
 
497
                                signvalue = ' ';
 
498
                }
 
499
        }
 
500
  
 
501
        if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
 
502
 
 
503
        do {
 
504
                convert[place++] =
 
505
                        (caps? "0123456789ABCDEF":"0123456789abcdef")
 
506
                        [uvalue % (unsigned)base  ];
 
507
                uvalue = (uvalue / (unsigned)base );
 
508
        } while(uvalue && (place < 20));
 
509
        if (place == 20) place--;
 
510
        convert[place] = 0;
 
511
 
 
512
        zpadlen = max - place;
 
513
        spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
 
514
        if (zpadlen < 0) zpadlen = 0;
 
515
        if (spadlen < 0) spadlen = 0;
 
516
        if (flags & DP_F_ZERO) {
 
517
                zpadlen = MAX(zpadlen, spadlen);
 
518
                spadlen = 0;
 
519
        }
 
520
        if (flags & DP_F_MINUS) 
 
521
                spadlen = -spadlen; /* Left Justifty */
 
522
 
 
523
#ifdef DEBUG_SNPRINTF
 
524
        printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
 
525
               zpadlen, spadlen, min, max, place);
 
526
#endif
 
527
 
 
528
        /* Spaces */
 
529
        while (spadlen > 0) {
 
530
                dopr_outch (buffer, currlen, maxlen, ' ');
 
531
                --spadlen;
 
532
        }
 
533
 
 
534
        /* Sign */
 
535
        if (signvalue) 
 
536
                dopr_outch (buffer, currlen, maxlen, signvalue);
 
537
 
 
538
        /* Zeros */
 
539
        if (zpadlen > 0) {
 
540
                while (zpadlen > 0) {
 
541
                        dopr_outch (buffer, currlen, maxlen, '0');
 
542
                        --zpadlen;
 
543
                }
 
544
        }
 
545
 
 
546
        /* Digits */
 
547
        while (place > 0) 
 
548
                dopr_outch (buffer, currlen, maxlen, convert[--place]);
 
549
  
 
550
        /* Left Justified spaces */
 
551
        while (spadlen < 0) {
 
552
                dopr_outch (buffer, currlen, maxlen, ' ');
 
553
                ++spadlen;
 
554
        }
 
555
}
 
556
 
 
557
static LDOUBLE abs_val(LDOUBLE value)
 
558
{
 
559
        LDOUBLE result = value;
 
560
 
 
561
        if (value < 0)
 
562
                result = -value;
 
563
        
 
564
        return result;
 
565
}
 
566
 
 
567
static LDOUBLE POW10(int exp)
 
568
{
 
569
        LDOUBLE result = 1;
 
570
        
 
571
        while (exp) {
 
572
                result *= 10;
 
573
                exp--;
 
574
        }
 
575
  
 
576
        return result;
 
577
}
 
578
 
 
579
static LLONG ROUND(LDOUBLE value)
 
580
{
 
581
        LLONG intpart;
 
582
 
 
583
        intpart = (LLONG)value;
 
584
        value = value - intpart;
 
585
        if (value >= 0.5) intpart++;
 
586
        
 
587
        return intpart;
 
588
}
 
589
 
 
590
/* a replacement for modf that doesn't need the math library. Should
 
591
   be portable, but slow */
 
592
static double my_modf(double x0, double *iptr)
 
593
{
 
594
        int i;
 
595
        long l;
 
596
        double x = x0;
 
597
        double f = 1.0;
 
598
 
 
599
        for (i=0;i<100;i++) {
 
600
                l = (long)x;
 
601
                if (l <= (x+1) && l >= (x-1)) break;
 
602
                x *= 0.1;
 
603
                f *= 10.0;
 
604
        }
 
605
 
 
606
        if (i == 100) {
 
607
                /* yikes! the number is beyond what we can handle. What do we do? */
 
608
                (*iptr) = 0;
 
609
                return 0;
 
610
        }
 
611
 
 
612
        if (i != 0) {
 
613
                double i2;
 
614
                double ret;
 
615
 
 
616
                ret = my_modf(x0-l*f, &i2);
 
617
                (*iptr) = l*f + i2;
 
618
                return ret;
 
619
        } 
 
620
 
 
621
        (*iptr) = l;
 
622
        return x - (*iptr);
 
623
}
 
624
 
 
625
 
 
626
static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
 
627
                   LDOUBLE fvalue, int min, int max, int flags)
 
628
{
 
629
        int signvalue = 0;
 
630
        double ufvalue;
 
631
        char iconvert[311];
 
632
        char fconvert[311];
 
633
        int iplace = 0;
 
634
        int fplace = 0;
 
635
        int padlen = 0; /* amount to pad */
 
636
        int zpadlen = 0; 
 
637
        int caps = 0;
 
638
        int idx;
 
639
        double intpart;
 
640
        double fracpart;
 
641
        double temp;
 
642
  
 
643
        /* 
 
644
         * AIX manpage says the default is 0, but Solaris says the default
 
645
         * is 6, and sprintf on AIX defaults to 6
 
646
         */
 
647
        if (max < 0)
 
648
                max = 6;
 
649
 
 
650
        ufvalue = abs_val (fvalue);
 
651
 
 
652
        if (fvalue < 0) {
 
653
                signvalue = '-';
 
654
        } else {
 
655
                if (flags & DP_F_PLUS) { /* Do a sign (+/i) */
 
656
                        signvalue = '+';
 
657
                } else {
 
658
                        if (flags & DP_F_SPACE)
 
659
                                signvalue = ' ';
 
660
                }
 
661
        }
 
662
 
 
663
#if 0
 
664
        if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
 
665
#endif
 
666
 
 
667
#if 0
 
668
         if (max == 0) ufvalue += 0.5; /* if max = 0 we must round */
 
669
#endif
 
670
 
 
671
        /* 
 
672
         * Sorry, we only support 16 digits past the decimal because of our 
 
673
         * conversion method
 
674
         */
 
675
        if (max > 16)
 
676
                max = 16;
 
677
 
 
678
        /* We "cheat" by converting the fractional part to integer by
 
679
         * multiplying by a factor of 10
 
680
         */
 
681
 
 
682
        temp = ufvalue;
 
683
        my_modf(temp, &intpart);
 
684
 
 
685
        fracpart = ROUND((POW10(max)) * (ufvalue - intpart));
 
686
        
 
687
        if (fracpart >= POW10(max)) {
 
688
                intpart++;
 
689
                fracpart -= POW10(max);
 
690
        }
 
691
 
 
692
        /* Convert integer part */
 
693
        do {
 
694
                temp = intpart*0.1;
 
695
                my_modf(temp, &intpart);
 
696
                idx = (int) ((temp -intpart +0.05)* 10.0);
 
697
                /* idx = (int) (((double)(temp*0.1) -intpart +0.05) *10.0); */
 
698
                /* printf ("%llf, %f, %x\n", temp, intpart, idx); */
 
699
                iconvert[iplace++] =
 
700
                        (caps? "0123456789ABCDEF":"0123456789abcdef")[idx];
 
701
        } while (intpart && (iplace < 311));
 
702
        if (iplace == 311) iplace--;
 
703
        iconvert[iplace] = 0;
 
704
 
 
705
        /* Convert fractional part */
 
706
        if (fracpart)
 
707
        {
 
708
                do {
 
709
                        temp = fracpart*0.1;
 
710
                        my_modf(temp, &fracpart);
 
711
                        idx = (int) ((temp -fracpart +0.05)* 10.0);
 
712
                        /* idx = (int) ((((temp/10) -fracpart) +0.05) *10); */
 
713
                        /* printf ("%lf, %lf, %ld\n", temp, fracpart, idx ); */
 
714
                        fconvert[fplace++] =
 
715
                        (caps? "0123456789ABCDEF":"0123456789abcdef")[idx];
 
716
                } while(fracpart && (fplace < 311));
 
717
                if (fplace == 311) fplace--;
 
718
        }
 
719
        fconvert[fplace] = 0;
 
720
  
 
721
        /* -1 for decimal point, another -1 if we are printing a sign */
 
722
        padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0); 
 
723
        zpadlen = max - fplace;
 
724
        if (zpadlen < 0) zpadlen = 0;
 
725
        if (padlen < 0) 
 
726
                padlen = 0;
 
727
        if (flags & DP_F_MINUS) 
 
728
                padlen = -padlen; /* Left Justifty */
 
729
        
 
730
        if ((flags & DP_F_ZERO) && (padlen > 0)) {
 
731
                if (signvalue) {
 
732
                        dopr_outch (buffer, currlen, maxlen, signvalue);
 
733
                        --padlen;
 
734
                        signvalue = 0;
 
735
                }
 
736
                while (padlen > 0) {
 
737
                        dopr_outch (buffer, currlen, maxlen, '0');
 
738
                        --padlen;
 
739
                }
 
740
        }
 
741
        while (padlen > 0) {
 
742
                dopr_outch (buffer, currlen, maxlen, ' ');
 
743
                --padlen;
 
744
        }
 
745
        if (signvalue) 
 
746
                dopr_outch (buffer, currlen, maxlen, signvalue);
 
747
        
 
748
        while (iplace > 0) 
 
749
                dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]);
 
750
 
 
751
#ifdef DEBUG_SNPRINTF
 
752
        printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen);
 
753
#endif
 
754
 
 
755
        /*
 
756
         * Decimal point.  This should probably use locale to find the correct
 
757
         * char to print out.
 
758
         */
 
759
        if (max > 0) {
 
760
                dopr_outch (buffer, currlen, maxlen, '.');
 
761
                
 
762
                while (zpadlen > 0) {
 
763
                        dopr_outch (buffer, currlen, maxlen, '0');
 
764
                        --zpadlen;
 
765
                }
 
766
 
 
767
                while (fplace > 0) 
 
768
                        dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]);
 
769
        }
 
770
 
 
771
        while (padlen < 0) {
 
772
                dopr_outch (buffer, currlen, maxlen, ' ');
 
773
                ++padlen;
 
774
        }
 
775
}
 
776
 
 
777
static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
 
778
{
 
779
        if (*currlen < maxlen) {
 
780
                buffer[(*currlen)] = c;
 
781
        }
 
782
        (*currlen)++;
 
783
}
 
784
#endif /* !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) */
 
785
 
 
786
#if !defined(HAVE_VSNPRINTF)
 
787
int vsnprintf (char *str, size_t count, const char *fmt, va_list args)
 
788
{
 
789
        return dopr(str, count, fmt, args);
 
790
}
 
791
#endif
 
792
 
 
793
#if !defined(HAVE_SNPRINTF)
 
794
int snprintf(char *str, size_t count, SNPRINTF_CONST char *fmt, ...)
 
795
{
 
796
        size_t ret;
 
797
        va_list ap;
 
798
 
 
799
        va_start(ap, fmt);
 
800
        ret = vsnprintf(str, count, fmt, ap);
 
801
        va_end(ap);
 
802
        return ret;
 
803
}
 
804
#endif
 
805