stropheruby 0.1.3

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