~ubuntu-branches/ubuntu/utopic/libesmtp/utopic

« back to all changes in this revision

Viewing changes to snprintf.c

  • Committer: Bazaar Package Importer
  • Author(s): Jeremy T. Bouse
  • Date: 2002-03-06 08:37:48 UTC
  • Revision ID: james.westby@ubuntu.com-20020306083748-ihmt32mddsslvg5i
Tags: upstream-0.8.11
ImportĀ upstreamĀ versionĀ 0.8.11

Show diffs side-by-side

added added

removed removed

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