~ubuntu-branches/ubuntu/warty/syslog-ng/warty

« back to all changes in this revision

Viewing changes to src/snprintf.c

  • Committer: Bazaar Package Importer
  • Author(s): SZALAY Attila
  • Date: 2002-03-04 21:29:11 UTC
  • Revision ID: james.westby@ubuntu.com-20020304212911-zmhvv15v8dmigez1
Tags: upstream-1.5.15
ImportĀ upstreamĀ versionĀ 1.5.15

Show diffs side-by-side

added added

removed removed

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