~ubuntu-branches/ubuntu/trusty/advancecomp/trusty

« back to all changes in this revision

Viewing changes to snprintf.c

  • Committer: Bazaar Package Importer
  • Author(s): Piotr Ozarowski
  • Date: 2006-05-13 21:15:49 UTC
  • Revision ID: james.westby@ubuntu.com-20060513211549-2vu7peis643ojcm5
Tags: upstream-1.15
ImportĀ upstreamĀ versionĀ 1.15

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