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  * Original:
9  * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
10  * A bombproof version of doprnt (dopr) included.
11  * Sigh.  This sort of thing is always nasty do deal with.  Note that
12  * the version here does not include floating point...
13  *
14  * snprintf() is used instead of sprintf() as it does limit checks
15  * for string length.  This covers a nasty loophole.
16  *
17  * The other functions are there to prevent NULL pointers from
18  * causing nast effects.
19  *
20  * More Recently:
21  *  Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43
22  *  This was ugly.  It is still ugly.  I opted out of floating point
23  *  numbers, but the formatter understands just about everything
24  *  from the normal C string format, at least as far as I can tell from
25  *  the Solaris 2.5 printf(3S) man page.
26  *
27  *  Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1
28  *    Ok, added some minimal floating point support, which means this
29  *    probably requires libm on most operating systems.  Don't yet
30  *    support the exponent (e,E) and sigfig (g,G).  Also, fmtint()
31  *    was pretty badly broken, it just wasn't being exercised in ways
32  *    which showed it, so that's been fixed.  Also, formated the code
33  *    to mutt conventions, and removed dead code left over from the
34  *    original.  Also, there is now a builtin-test, just compile with:
35  *           gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
36  *    and run snprintf for results.
37  *
38  *  Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i
39  *    The PGP code was using unsigned hexadecimal formats.
40  *    Unfortunately, unsigned formats simply didn't work.
41  *
42  *  Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8
43  *    The original code assumed that both snprintf() and vsnprintf() were
44  *    missing.  Some systems only have snprintf() but not vsnprintf(), so
45  *    the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
46  *
47  **************************************************************/
48 
49 #include "config.h"
50 
51 #include <string.h>
52 #include <ctype.h>
53 #include <sys/types.h>
54 #ifndef _WIN32
55 #include <sys/stat.h>
56 #include <fcntl.h>
57 #endif
58 
59 #ifndef FLT_MAX
60 # include <float.h>
61 #endif
62 #include <math.h>
63 #include <stdlib.h>
64 
65 #ifdef _WIN32
66 #include <io.h>
67 #include <stdio.h>
68 #include <windows.h>
69 #else
70 #include <unistd.h>
71 #endif
72 
73 /* varargs declarations: */
74 
75 #if defined(HAVE_STDARG_H)
76 # include <stdarg.h>
77 # define HAVE_STDARGS    /* let's hope that works everywhere (mj) */
78 # define VA_LOCAL_DECL   va_list ap;
79 # define VA_START(f)     va_start(ap, f)
80 # define VA_SHIFT(v,t)  ;   /* no-op for ANSI */
81 # define VA_END          va_end(ap)
82 #else
83 # if defined(HAVE_VARARGS_H)
84 #  include <varargs.h>
85 #  undef HAVE_STDARGS
86 #  define VA_LOCAL_DECL   va_list ap;
87 #  define VA_START(f)     va_start(ap)      /* f is ignored! */
88 #  define VA_SHIFT(v,t) v = va_arg(ap,t)
89 #  define VA_END        va_end(ap)
90 # else
91 /*XX ** NO VARARGS ** XX*/
92 # error no either stdarg or varargs needed
93 # endif
94 #endif
95 
96 static void dopr (char *buffer, size_t maxlen, const char *format,
97                   va_list args);
98 static void fmtstr (char *buffer, size_t *currlen, size_t maxlen,
99                     const char *value, int flags, int min, int max);
100 static void fmtint (char *buffer, size_t *currlen, size_t maxlen,
101                     long value, int base, int min, int max, int flags);
102 static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
103                    long double fvalue, int min, int max, int flags);
104 static void fmtefp (char *buffer, size_t *currlen, size_t maxlen,
105                     long double fvalue, int min, int max, int flags);
106 static void dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c );
107 
108 /*
109  * myisdigit(): signalhandlerparanoia isdigit version independend of C-Library
110  */
111 
myisdigit(int c)112 static int myisdigit(int c)
113    {
114    switch(c)
115       {
116       case '0':
117          return 1;
118       case '1':
119          return 1;
120       case '2':
121          return 1;
122       case '3':
123          return 1;
124       case '4':
125          return 1;
126       case '5':
127          return 1;
128       case '6':
129          return 1;
130       case '7':
131          return 1;
132       case '8':
133          return 1;
134       case '9':
135          return 1;
136       default:
137          return 0;
138       }
139    }
140 
141  /*
142  * mystrlen(): signalhandlerparanoia strlen version independend of C-Library
143  */
144 
mystrlen(const char * s)145 size_t mystrlen (const char *s)
146    {
147    int strln;
148    for (strln = 0; s[strln]; ++strln);
149    return strln;
150    }
151 
152 /*
153  * mystrcpy(): signalhandlerparanoia strcpy version independend of C-Library
154  */
155 
mystrcpy(char * s1,const char * s2)156 char *mystrcpy(char *s1, const char *s2)
157    {
158    int strln;
159    for (strln = 0; s2[strln]; ++strln)
160       s1[strln]=s2[strln];
161    s1[strln]=0;
162    return s1;
163    }
164 
165 /*
166  * mystrcat(): signalhandlerparanoia strcpy version independend of C-Library
167  */
168 
mystrcat(char * s1,const char * s2)169 char *mystrcat(char *s1, const char *s2)
170    {
171    int strln;
172    int length=mystrlen(s1);
173    for (strln = 0; s2[strln]; ++strln)
174       s1[length+strln]=s2[strln];
175    s1[length+strln]=0;
176    return s1;
177    }
178 
179 
180 #ifdef HAVE_XOPEN_SOURCE_4_FPCLASSIFY
181 # define _XOPEN_SOURCE 600
182 # define HAVE_FPCLASSIFY 1
183 #endif
184 
185 #ifdef HAVE_FPCLASSIFY
186 
187 #define MAX_VALUE FLT_MAX
188 
handle_nan(int fpclass,long double fvalue)189 static long double handle_nan(int fpclass, long double fvalue)
190 {
191   const char *error = NULL;
192   long double ret = fvalue;
193   switch (fpclass) {
194     case FP_INFINITE:
195 //      error = "dune internal error: tried to write +/- INFINITE floating point value !\n";
196       ret = 0;
197       break;
198     case FP_NAN:
199 //      error = "dune internal error: tried to write NAN floating point value !\n";
200     case FP_SUBNORMAL:
201 //      error = "dune internal error: tried to write SUBNORMAL floating point value !\n";
202       ret = 0;
203       break;
204     case FP_ZERO:
205     case FP_NORMAL:
206       break;
207 //    default:
208 //      error = "dune internal error: tried to write unclassified floatingpoint !\n";
209   }
210   if (error != NULL)
211       while (write(2, error, strlen(error)) == -1);
212   return ret;
213 }
214 
check_nan(long double fvalue)215 static long double check_nan(long double fvalue)
216 {
217   return handle_nan(fpclassify(fvalue),fvalue);
218 }
219 
220 /*
221 static long double check_dnan(double fvalue)
222 {
223   return handle_nan(fpclassify(fvalue),fvalue);
224 }
225 
226 static long double check_fnan(float fvalue)
227 {
228   return handle_nan(fpclassify(fvalue),fvalue);
229 }
230 */
231 
232 #endif
233 
234 /*
235  * dopr(): poor man's version of doprintf
236  */
237 
238 /* format read states */
239 #define DP_S_DEFAULT 0
240 #define DP_S_FLAGS   1
241 #define DP_S_MIN     2
242 #define DP_S_DOT     3
243 #define DP_S_MAX     4
244 #define DP_S_MOD     5
245 #define DP_S_CONV    6
246 #define DP_S_DONE    7
247 
248 /* format flags - Bits */
249 #define DP_F_MINUS      (1 << 0)
250 #define DP_F_PLUS       (1 << 1)
251 #define DP_F_SPACE      (1 << 2)
252 #define DP_F_NUM        (1 << 3)
253 #define DP_F_ZERO       (1 << 4)
254 #define DP_F_UP         (1 << 5)
255 #define DP_F_UNSIGNED   (1 << 6)
256 
257 /* Conversion Flags */
258 #define DP_C_SHORT   1
259 #define DP_C_LONG    2
260 #define DP_C_LDOUBLE 3
261 
262 #define char_to_int(p) (p - '0')
263 #ifndef MAX
264 # define MAX(p,q) ((p >= q) ? p : q)
265 #endif
266 
dopr(char * buffer,size_t maxlen,const char * format,va_list args)267 static void dopr (char *buffer, size_t maxlen, const char *format, va_list args)
268 {
269   char ch = 0;
270   long value = 0;
271   long double fvalue = 0;
272   char *strvalue = NULL;
273   int min = 0;
274   int max = -1;
275   int state = 0;
276   int flags = 0;
277   int cflags = 0;
278   size_t currlen = 0;
279 
280   state = DP_S_DEFAULT;
281   currlen = flags = cflags = min = 0;
282   ch = *format++;
283 
284   while (state != DP_S_DONE)
285   {
286     if ((ch == '\0') || (currlen >= maxlen))
287       state = DP_S_DONE;
288 
289     switch(state)
290     {
291     case DP_S_DEFAULT:
292       if (ch == '%')
293         state = DP_S_FLAGS;
294       else
295         dopr_outch (buffer, &currlen, maxlen, ch);
296       ch = *format++;
297       break;
298     case DP_S_FLAGS:
299       switch (ch)
300       {
301       case '-':
302         flags |= DP_F_MINUS;
303         ch = *format++;
304         break;
305       case '+':
306         flags |= DP_F_PLUS;
307         ch = *format++;
308         break;
309       case ' ':
310         flags |= DP_F_SPACE;
311         ch = *format++;
312         break;
313       case '#':
314         flags |= DP_F_NUM;
315         ch = *format++;
316         break;
317       case '0':
318         flags |= DP_F_ZERO;
319         ch = *format++;
320         break;
321       default:
322         state = DP_S_MIN;
323         break;
324       }
325       break;
326     case DP_S_MIN:
327       if (myisdigit((unsigned char)ch))
328       {
329         min = 10 * min + char_to_int (ch);
330         ch = *format++;
331       }
332       else if (ch == '*')
333       {
334         min = va_arg (args, int);
335         ch = *format++;
336         state = DP_S_DOT;
337       }
338       else
339         state = DP_S_DOT;
340       break;
341     case DP_S_DOT:
342       if (ch == '.')
343       {
344         state = DP_S_MAX;
345         ch = *format++;
346       }
347       else
348         state = DP_S_MOD;
349       break;
350     case DP_S_MAX:
351       if (myisdigit((unsigned char)ch))
352       {
353         if (max < 0)
354           max = 0;
355         max = 10 * max + char_to_int (ch);
356         ch = *format++;
357       }
358       else if (ch == '*')
359       {
360         max = va_arg (args, int);
361         ch = *format++;
362         state = DP_S_MOD;
363       }
364       else
365         state = DP_S_MOD;
366       break;
367     case DP_S_MOD:
368       /* Currently, we don't support Long Long, bummer */
369       switch (ch)
370       {
371       case 'h':
372         cflags = DP_C_SHORT;
373         ch = *format++;
374         break;
375       case 'l':
376         cflags = DP_C_LONG;
377         ch = *format++;
378         break;
379       case 'L':
380         cflags = DP_C_LDOUBLE;
381         ch = *format++;
382         break;
383       default:
384         break;
385       }
386       state = DP_S_CONV;
387       break;
388     case DP_S_CONV:
389       switch (ch)
390       {
391       case 'd':
392       case 'i':
393         if (cflags == DP_C_SHORT)
394           value =(short int)  va_arg (args, int);
395         else if (cflags == DP_C_LONG)
396           value = va_arg (args, long int);
397         else
398           value = va_arg (args, int);
399         fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
400         break;
401       case 'o':
402         flags |= DP_F_UNSIGNED;
403         if (cflags == DP_C_SHORT)
404           value = (unsigned short int) va_arg (args, int);
405         else if (cflags == DP_C_LONG)
406           value = va_arg (args, unsigned long int);
407         else
408           value = va_arg (args, unsigned int);
409         fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags);
410         break;
411       case 'u':
412         flags |= DP_F_UNSIGNED;
413         if (cflags == DP_C_SHORT)
414           value = (unsigned short int) va_arg (args, int);
415         else if (cflags == DP_C_LONG)
416           value = va_arg (args, unsigned long int);
417         else
418           value = va_arg (args, unsigned int);
419         fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
420         break;
421       case 'X':
422         flags |= DP_F_UP;
423       case 'x':
424         flags |= DP_F_UNSIGNED;
425         if (cflags == DP_C_SHORT)
426           value = (unsigned short int) va_arg (args, int);
427         else if (cflags == DP_C_LONG)
428           value = va_arg (args, unsigned long int);
429         else
430           value = va_arg (args, unsigned int);
431         fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags);
432         break;
433       case 'f':
434         if (cflags == DP_C_LDOUBLE)
435           fvalue = va_arg (args, long double);
436         else
437           fvalue = va_arg (args, double);
438         /* um, floating point? */
439         fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
440         break;
441       case 'E':
442         flags |= DP_F_UP;
443       case 'e':
444         if (cflags == DP_C_LDOUBLE)
445           fvalue = va_arg (args, long double);
446         else
447           fvalue = va_arg (args, double);
448         /* um, floating point? */
449         fmtefp (buffer, &currlen, maxlen, fvalue, min, max, flags);
450         break;
451       case 'G':
452         flags |= DP_F_UP;
453       case 'g':
454         if (cflags == DP_C_LDOUBLE)
455           fvalue = va_arg (args, long double);
456         else
457           fvalue = va_arg (args, double);
458         /* um, floating point? */
459         fmtefp (buffer, &currlen, maxlen, fvalue, min, max, flags);
460         break;
461       case 'c':
462         dopr_outch (buffer, &currlen, maxlen, va_arg (args, int));
463         break;
464       case 's':
465         strvalue = va_arg (args, char *);
466         if (max < 0)
467           max = maxlen; /* ie, no max */
468         fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max);
469         break;
470       case 'p':
471         strvalue = va_arg (args, void *);
472         fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags);
473         break;
474       case 'n':
475         if (cflags == DP_C_SHORT)
476         {
477           short int *num;
478           num = va_arg (args, short int *);
479           *num = currlen;
480         }
481         else if (cflags == DP_C_LONG)
482         {
483           long int *num;
484           num = va_arg (args, long int *);
485           *num = currlen;
486         }
487         else
488         {
489           int *num;
490           num = va_arg (args, int *);
491           *num = currlen;
492         }
493         break;
494       case '%':
495         dopr_outch (buffer, &currlen, maxlen, ch);
496         break;
497       case 'w':
498         /* not supported yet, treat as next char */
499         ch = *format++;
500         break;
501       default:
502         /* Unknown, skip */
503         break;
504       }
505       ch = *format++;
506       state = DP_S_DEFAULT;
507       flags = cflags = min = 0;
508       max = -1;
509       break;
510     case DP_S_DONE:
511       break;
512     default:
513       /* hmm? */
514       break; /* some picky compilers need this */
515     }
516   }
517   if (currlen < maxlen - 1)
518     buffer[currlen] = '\0';
519   else
520     buffer[maxlen - 1] = '\0';
521 }
522 
fmtstr(char * buffer,size_t * currlen,size_t maxlen,const char * value,int flags,int min,int max)523 static void fmtstr (char *buffer, size_t *currlen, size_t maxlen,
524                     const char *value, int flags, int min, int max)
525 {
526   int padlen, strln;     /* amount to pad */
527   int cnt = 0;
528 
529   if (value == 0)
530   {
531     value = "<NULL>";
532   }
533 
534   for (strln = 0; value[strln]; ++strln); /* strlen */
535   padlen = min - strln;
536   if (padlen < 0)
537     padlen = 0;
538   if (flags & DP_F_MINUS)
539     padlen = -padlen; /* Left Justify */
540 
541   while ((padlen > 0) && (cnt < max))
542   {
543     dopr_outch (buffer, currlen, maxlen, ' ');
544     --padlen;
545     ++cnt;
546   }
547   while (*value && (cnt < max))
548   {
549     dopr_outch (buffer, currlen, maxlen, *value++);
550     ++cnt;
551   }
552   while ((padlen < 0) && (cnt < max))
553   {
554     dopr_outch (buffer, currlen, maxlen, ' ');
555     ++padlen;
556     ++cnt;
557   }
558 }
559 
560 /* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
561 
fmtint(char * buffer,size_t * currlen,size_t maxlen,long value,int base,int min,int max,int flags)562 static void fmtint (char *buffer, size_t *currlen, size_t maxlen,
563                     long value, int base, int min, int max, int flags)
564 {
565   int signvalue = 0;
566   unsigned long uvalue;
567   char convert[20];
568   int place = 0;
569   int spadlen = 0; /* amount to space pad */
570   int zpadlen = 0; /* amount to zero pad */
571   int caps = 0;
572 
573   if (max < 0)
574     max = 0;
575 
576   uvalue = value;
577 
578   if(!(flags & DP_F_UNSIGNED))
579   {
580     if( value < 0 ) {
581       signvalue = '-';
582       uvalue = -value;
583     }
584     else
585       if (flags & DP_F_PLUS)  /* Do a sign (+/i) */
586         signvalue = '+';
587     else
588       if (flags & DP_F_SPACE)
589         signvalue = ' ';
590   }
591 
592   if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
593 
594   do {
595     convert[place++] =
596       (caps ? "0123456789ABCDEF0" : "0123456789abcdef0")
597       [uvalue % (unsigned)base];
598     uvalue = (uvalue / (unsigned)base );
599   } while(uvalue && (place < 20));
600   if (place == 20) place--;
601   convert[place] = 0;
602 
603   zpadlen = max - place;
604   spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
605   if (zpadlen < 0) zpadlen = 0;
606   if (spadlen < 0) spadlen = 0;
607   if (flags & DP_F_ZERO)
608   {
609     zpadlen = MAX(zpadlen, spadlen);
610     spadlen = 0;
611   }
612   if (flags & DP_F_MINUS)
613     spadlen = -spadlen; /* Left Justifty */
614 
615 #ifdef DEBUG_SNPRINTF
616   dprint (1, (debugfile, "zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
617       zpadlen, spadlen, min, max, place));
618 #endif
619 
620   /* Spaces */
621   while (spadlen > 0)
622   {
623     dopr_outch (buffer, currlen, maxlen, ' ');
624     --spadlen;
625   }
626 
627   /* Sign */
628   if (signvalue)
629     dopr_outch (buffer, currlen, maxlen, signvalue);
630 
631   /* Zeros */
632   if (zpadlen > 0)
633   {
634     while (zpadlen > 0)
635     {
636       dopr_outch (buffer, currlen, maxlen, '0');
637       --zpadlen;
638     }
639   }
640 
641   /* Digits */
642   while (place > 0)
643     dopr_outch (buffer, currlen, maxlen, convert[--place]);
644 
645   /* Left Justified spaces */
646   while (spadlen < 0) {
647     dopr_outch (buffer, currlen, maxlen, ' ');
648     ++spadlen;
649   }
650 }
651 
abs_val(long double value)652 static long double abs_val (long double value)
653 {
654   long double result = value;
655 
656   if (value < 0)
657     result = -value;
658 
659   return result;
660 }
661 
mypow10(int exp)662 static long double mypow10 (int exp)
663 {
664   long double result = 1;
665 
666   while (exp)
667   {
668     result *= 10;
669     exp--;
670   }
671 
672   return result;
673 }
674 
675 static int default_max = 6;
676 
set_number_of_digits(int digits)677 void set_number_of_digits(int digits)
678 {
679   default_max = digits;
680 }
681 
682 static int use_Efloat_format = 1;
683 
set_Efloat_format(int flag)684 void set_Efloat_format(int flag)
685 {
686   use_Efloat_format = flag;
687 }
688 
fmtfp(char * buffer,size_t * currlen,size_t maxlen,long double value,int min,int max,int flags)689 static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
690                    long double value, int min, int max, int flags)
691 {
692   int signvalue = 0;
693   long double ufvalue = 0;
694   char iconvert[20];
695   char fconvert[20];
696   int iplace = 0;
697   int fplace = 0;
698   int padlen = 0; /* amount to pad */
699   int zpadlen = 0;
700   int caps = 0;
701   long intpart = 0;
702   long fracpart = 0;
703   long old_fracpart = 0;
704   int zeros = 0;
705   int i = 0;
706   long double fvalue = 0;
707 
708   fvalue = value;
709 
710   /*
711    * AIX manpage says the default is 0, but Solaris says the default
712    * is 6, and sprintf on AIX defaults to 6
713    */
714   if (max < 0) {
715 //     fprintf(stderr, "setting max to %d\n", default_max);
716      max = default_max;
717   }
718 
719 #ifdef HAVE_FPCLASSIFY
720    fvalue = check_nan(fvalue);
721 #endif
722 
723   ufvalue = abs_val(fvalue);
724 
725   if (fvalue < 0)
726     signvalue = '-';
727   else
728     if (flags & DP_F_PLUS)  /* Do a sign (+/i) */
729       signvalue = '+';
730     else
731       if (flags & DP_F_SPACE)
732         signvalue = ' ';
733 
734 #if 0
735   if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
736 #endif
737 
738   intpart = lrint(ufvalue);
739 
740   /*
741    * Sorry, we only support 9 digits past the decimal because of our
742    * conversion method
743    */
744   if (max > 9)
745      max = 9;
746 
747   /* We "cheat" by converting the fractional part to integer by
748    * multiplying by a factor of 10
749    */
750 
751   fracpart = rint((mypow10(max)) * (ufvalue - intpart));
752 
753   if (fracpart>0)
754      {
755      zeros=fabs(floor(log(fracpart / mypow10(max))/log(10))+1);
756      if (zeros>=20)
757        zeros=20;
758      }
759   else
760      {
761      fracpart=0;
762      zeros=0;
763      }
764   old_fracpart=fracpart;
765 
766   if (fracpart >= mypow10 (max))
767   {
768     intpart++;
769     fracpart -= mypow10 (max);
770   }
771 
772 #ifdef DEBUG_SNPRINTF
773   dprint (1, (debugfile, "fmtfp: %f =? %d.%d\n", fvalue, intpart, fracpart));
774 #endif
775 
776   /* Convert integer part */
777   do {
778     iconvert[iplace++] = intpart < 0 ? '0' :
779       (caps ? "0123456789ABCDEF0" : "0123456789abcdef0")[(intpart % 10)];
780     intpart = (intpart / 10);
781   } while(intpart && (iplace < 20));
782   if (iplace == 20) iplace--;
783   iconvert[iplace] = 0;
784 
785   /* Convert fractional part */
786   do {
787     fconvert[fplace++] =
788       (caps ? "0123456789ABCDEF0" : "0123456789abcdef0")[fracpart % 10];
789     fracpart = (fracpart / 10);
790   } while(fracpart && (fplace-zeros < 20));
791   for (i=0;(i<zeros);i++)
792      fconvert[fplace++]='0';
793   if (fplace == 20) fplace--;
794   fconvert[fplace] = 0;
795 
796   /* -1 for decimal point, another -1 if we are printing a sign */
797   padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
798   zpadlen = max - fplace;
799   if (zpadlen < 0)
800     zpadlen = 0;
801   if (padlen < 0)
802     padlen = 0;
803   if (flags & DP_F_MINUS)
804     padlen = -padlen; /* Left Justifty */
805 
806   if ((flags & DP_F_ZERO) && (padlen > 0))
807   {
808     if (signvalue)
809     {
810       dopr_outch (buffer, currlen, maxlen, signvalue);
811       --padlen;
812       signvalue = 0;
813     }
814     while (padlen > 0)
815     {
816       dopr_outch (buffer, currlen, maxlen, '0');
817       --padlen;
818     }
819   }
820   while (padlen > 0)
821   {
822     dopr_outch (buffer, currlen, maxlen, ' ');
823     --padlen;
824   }
825   if (signvalue)
826     dopr_outch (buffer, currlen, maxlen, signvalue);
827 
828   while (iplace > 0)
829     dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]);
830 
831   if (old_fracpart!=0) {
832      /*
833       * Decimal point.  This should probably use locale to find the correct
834       * char to print out.
835       */
836      dopr_outch (buffer, currlen, maxlen, '.');
837 
838      while (fplace > 0)
839        dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]);
840 
841      while (zpadlen > 0)
842      {
843        dopr_outch (buffer, currlen, maxlen, '0');
844        --zpadlen;
845      }
846 
847      while (padlen < 0)
848      {
849        dopr_outch (buffer, currlen, maxlen, ' ');
850        ++padlen;
851      }
852   }
853 }
854 
855 
dopr_outch(char * buffer,size_t * currlen,size_t maxlen,char c)856 static void dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c)
857 {
858   if (*currlen < maxlen)
859     buffer[(*currlen)++] = c;
860 }
861 
myvsnprintf(char * str,size_t count,const char * fmt,va_list args)862 int myvsnprintf (char *str, size_t count, const char *fmt, va_list args)
863 {
864   str[0] = 0;
865   dopr(str, count, fmt, args);
866   return(mystrlen(str));
867 }
868 
869 /* VARARGS3 */
870 #ifdef HAVE_STDARGS
mysnprintf(char * str,size_t count,const char * fmt,...)871 int mysnprintf (char *str,size_t count,const char *fmt,...)
872 #else
873 int mysnprintf (va_alist) va_dcl
874 #endif
875 {
876 #ifndef HAVE_STDARGS
877   char *str = NULL;
878   size_t count = 0;
879   char *fmt = NULL;
880 #endif
881   VA_LOCAL_DECL;
882 
883   VA_START (fmt);
884   VA_SHIFT (str, char *);
885   VA_SHIFT (count, size_t );
886   VA_SHIFT (fmt, char *);
887   (void) myvsnprintf(str, count, fmt, ap);
888   VA_END;
889   return(mystrlen(str));
890 }
891 
892 #ifndef HAVE_POWL
mypowl(long double ten,int exp)893 long double mypowl(long double ten,int exp)
894 {
895   // poor mans powl, only useful if second argument is a integer
896   int i;
897   long double result = 1;
898   for (i = 0; i < exp; i++)
899       result *= ten;
900   for (i = 0; i > exp; i--)
901       result /= ten;
902    return result;
903 }
904 #endif
905 
906 #ifdef _WIN32
907 /* VARARGS3 */
908 #ifdef HAVE_STDARGS
msgboxprintf(FILE * f,const char * fmt,...)909 int __cdecl msgboxprintf (FILE * f,const char *fmt,...)
910 #else
911 int __cdecl msgboxprintf (va_alist) va_dcl
912 #endif
913 {
914 #ifndef HAVE_STDARGS
915   FILE* f;
916   char *fmt;
917 #endif
918   char text[1024];
919   VA_LOCAL_DECL;
920 
921   VA_START (fmt);
922   VA_SHIFT (text, char *);
923   VA_SHIFT (1024, size_t );
924   VA_SHIFT (fmt, char *);
925   (void) myvsnprintf(text, 1024, fmt, ap);
926   VA_END;
927   MessageBox(NULL,text,"white_dune",MB_ICONINFORMATION);
928   return(mystrlen(text));
929 }
930 #endif
931 
fmtefp(char * buffer,size_t * currlen,size_t maxlen,long double evalue,int min,int max,int flags)932 static void fmtefp (char *buffer, size_t *currlen, size_t maxlen,
933                     long double evalue, int min, int max, int flags)
934 {
935   long double fvalue = 0;
936   int exp = 0;
937 
938 #ifdef HAVE_FPCLASSIFY
939    evalue = check_nan(evalue);
940 #endif
941 
942   if (evalue==0)
943      dopr_outch(buffer, currlen, maxlen, '0');
944   else
945      {
946      exp=floor(log(fabs(evalue))/log(10.0));
947      if (use_Efloat_format && ((exp>2) || (exp<-1)))
948         {
949 #ifdef HAVE_POWL
950         fvalue=evalue*powl(10.0,-(long double)exp);
951 #else
952         fvalue=evalue*mypowl(10.0,-exp);
953 #endif
954         fmtfp (buffer, currlen, maxlen, fvalue, min, max, flags);
955         dopr_outch(buffer, currlen, maxlen, 'e');
956         fmtint (buffer,currlen, maxlen,exp,10,min,max,flags);
957         }
958      else
959         fmtfp (buffer, currlen, maxlen, evalue, min, max, flags);
960      }
961 
962 }
963 
964 # define MY_MAX_BUFFER_SIZE 65536
965 
966 static char buffer[MY_MAX_BUFFER_SIZE];
967 static int buffersize = 0;
968 static int current_filedes = -1;
969 
mywrite(int filedes,const char * str,int size)970 int mywrite(int filedes,const char *str,int size)
971   {
972   int restlength=size;
973   int position_written=0;
974 
975   while (restlength>0)
976      {
977      int writereturn;
978 
979      if ( (writereturn = write(filedes,str+position_written,restlength)) < 0 )
980         return(-1);
981      restlength=restlength-writereturn;
982      position_written=position_written+writereturn;
983      }
984   return(0);
985   }
986 
myflushbuffer(void)987 static int myflushbuffer(void)
988   {
989   int ret = 0;
990   if (buffersize > 0)
991       ret=mywrite(current_filedes,buffer,buffersize);
992   buffersize=0;
993   current_filedes=-1;
994   return ret;
995   }
996 
myflushall(void)997 int myflushall(void)
998   {
999   return myflushbuffer();
1000   }
1001 
myclose(int filedes)1002 int myclose(int filedes)
1003   {
1004   int error=0;
1005   if (myflushbuffer() < 0) {
1006      error=-1;
1007   }
1008   buffersize=0;
1009   current_filedes=-1;
1010   close(filedes);
1011   return error;
1012   }
1013 
1014 #ifdef DEBUG
1015 /* write unbuffered */
1016 
mywritestr(int filedes,const char * str)1017 int mywritestr(int filedes,const char *str)
1018   {
1019   if (mywrite(filedes,str,strlen(str)) < 0)
1020      return -1;
1021   return 0;
1022   }
1023 #else
1024 /* write via a buffer to improve performance */
1025 
mywritestr(int filedes,const char * str)1026 int mywritestr(int filedes,const char *str)
1027   {
1028   int len=strlen(str);
1029   if (len==0)
1030      return 0;
1031   if (len > MY_MAX_BUFFER_SIZE)
1032      {
1033      if (myflushbuffer() < 0)
1034         return -1;
1035      if (mywrite(filedes,str,len) < 0)
1036         return -1;
1037      return 0;
1038      }
1039   if (((current_filedes != -1) && (current_filedes != filedes)) ||
1040       ((buffersize+len) >= MY_MAX_BUFFER_SIZE))
1041      {
1042      if (myflushbuffer() < 0)
1043         return -1;
1044      }
1045   current_filedes = filedes;
1046   memcpy(buffer+buffersize, str, len);
1047   buffersize+=len;
1048   return 0;
1049   }
1050 #endif
1051 
1052 
1053 /* VARARGS3 */
1054 #ifdef HAVE_STDARGS
mywritef(int filedes,const char * fmt,...)1055 int mywritef (int filedes,const char *fmt,...)
1056 #else
1057 int mywritef (va_alist) va_dcl
1058 #endif
1059 {
1060   char str[8000];
1061 #ifndef HAVE_STDARGS
1062   int filedes;
1063   char *fmt;
1064 #endif
1065   VA_LOCAL_DECL;
1066 
1067   VA_START (fmt);
1068   VA_SHIFT (filedes, int);
1069   VA_SHIFT (fmt, char *);
1070   (void) myvsnprintf(str, 8000, fmt, ap);
1071   VA_END;
1072   /* error, myvsnprintf possibly truncated data */
1073   if (mystrlen(str)>=7999)
1074      return(-2);
1075   return mywritestr(filedes,str);
1076 }
1077 
1078 /*
1079  * strncpy that copies n bytes and can write zero to n+1-th byte
1080  * use this when you want to copy exact n bytes (or less)
1081  */
mystrncpy_danger(char * str1,const char * str2,int n)1082 char* mystrncpy_danger(char* str1,const char *str2,int n)
1083    {
1084    char* ret;
1085    ret = strncpy(str1,str2,n);
1086    ret[n] = 0;
1087    return ret;
1088    }
1089 
1090 /*
1091  * strncpy that copies n bytes and then write zero to n-th byte
1092  * use this when you want to copy less than n bytes
1093  */
mystrncpy_secure(char * str1,const char * str2,int n)1094 char* mystrncpy_secure(char* str1,const char *str2,int n)
1095    {
1096    char* ret;
1097    ret = strncpy(str1,str2,n);
1098    ret[n-1] = 0;
1099    return ret;
1100    }
1101 
1102 /*
1103  * special version of strdup, that explicitly calls malloc
1104  * this is needed to allow ld -r linking of the efence library
1105  */
mystrdup(const char * s)1106 char *mystrdup(const char *s)
1107 {
1108     char *ret = NULL;
1109     if (s == NULL) {
1110         ret = malloc(1);
1111         ret[0] = 0;
1112         return ret;
1113     }
1114     ret = malloc(strlen(s) + 1);
1115     strcpy(ret, s);
1116     return ret;
1117 }
1118 
1119 #ifdef TEST_SNPRINTF
1120 #ifndef LONG_STRING
1121 #define LONG_STRING 1024
1122 #endif
1123 #include <stdio.h>
main(void)1124 int main (void)
1125 {
1126   char buf1[LONG_STRING];
1127   char buf2[LONG_STRING];
1128   char *fp_fmt[] = {
1129     "%-1.5f",
1130     "%g",
1131     "%f",
1132     "%-1.5f",
1133     "%1.5f",
1134     "%123.9f",
1135     "%10.5f",
1136     "% 10.5f",
1137     "%+22.9f",
1138     "%+4.9f",
1139     "%01.3f",
1140     "%4f",
1141     "%3.1f",
1142     "%3.2f",
1143     NULL
1144   };
1145   float test_fp_nums[] = { -1, 1, 0.5, 0102.1, 1.0032, 203.9,-1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996,
1146     0.9996, 1.996, 1.003, 4.136, 3e-2, 0};
1147   char *int_fmt[] = {
1148     "%-1.5d",
1149     "%1.5d",
1150     "%123.9d",
1151     "%5.5d",
1152     "%10.5d",
1153     "% 10.5d",
1154     "%+22.33d",
1155     "%01.3d",
1156     "%4d",
1157     NULL
1158   };
1159   long int_nums[] = { -1, 134, 91340, 341, 0203, 0};
1160   int x, y;
1161   int fail = 0;
1162   int num = 0;
1163 
1164   printf ("Testing snprintf format codes against system sprintf...\n");
1165 
1166   for (x = 0; fp_fmt[x] != NULL ; x++)
1167     {
1168     for (y = 0; test_fp_nums[y] != 0 ; y++)
1169     {
1170       mysnprintf (buf1, sizeof (buf1), fp_fmt[x], test_fp_nums[y]);
1171       sprintf (buf2, fp_fmt[x], test_fp_nums[y]);
1172       if (strcmp (buf1, buf2))
1173       {
1174         printf("snprintf %lf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf  = %s\n",
1175             test_fp_nums[y],fp_fmt[x], buf1, buf2);
1176         fail++;
1177       }
1178     }
1179    mysnprintf (buf1, sizeof (buf1), fp_fmt[x],0);
1180    sprintf (buf2, fp_fmt[x], 0);
1181    if (strcmp (buf1, buf2))
1182    {
1183       printf("snprintf %lf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf  = %s\n",
1184       test_fp_nums[y],fp_fmt[x], buf1, buf2);
1185       fail++;
1186    }
1187    num++;
1188   }
1189 
1190   for (x = 0; int_fmt[x] != NULL ; x++)
1191     for (y = 0; int_nums[y] != 0 ; y++)
1192     {
1193       mysnprintf (buf1, sizeof (buf1), int_fmt[x], int_nums[y]);
1194       sprintf (buf2, int_fmt[x], int_nums[y]);
1195       if (strcmp (buf1, buf2))
1196       {
1197         printf("snprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf  = %s\n",
1198             int_fmt[x], buf1, buf2);
1199         fail++;
1200       }
1201       num++;
1202     }
1203   printf ("%d tests failed out of %d.\n", fail, num);
1204 }
1205 #endif /* SNPRINTF_TEST */
1206 
1207