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