5 * by JH <jheinonen@bigfoot.com>
7 * Copyright (C) Jaakko Heinonen
54 while( ( *str = toupper( *str ) ) )
65 while( ( *str = tolower ( *str ) ) )
78 for(t = s; ISSPACE(*t); t++);
80 memmove(s, t, strlen(t)+1);
82 for (tt = t = s; *t != '\0'; t++)
96 /* varargs declarations: */
99 # define MY_VA_LOCAL_DECL va_list ap
100 # define MY_VA_START(f) va_start(ap, f)
101 # define MY_VA_SHIFT(v,t) v = va_arg(ap, t)
102 # define MY_VA_END va_end(ap)
104 # error HAVE_STDARG_H not defined
108 mkstr (const char *format, ... )
114 (char *) abook_malloc (size);
116 (char *) malloc (size);
122 n = vsnprintf (buffer, size,
126 if (n > -1 && n < size)
136 (char *) abook_realloc (buffer, size);
138 (char *) realloc (buffer, size);
145 strconcat (const char *str, ...)
154 l = 1 + strlen (str);
156 MY_VA_SHIFT(s, char*);
159 MY_VA_SHIFT(s, char*);
170 strcpy (concat, str);
172 MY_VA_SHIFT(s, char*);
175 MY_VA_SHIFT(s, char*);
184 safe_strcmp(const char *s1, const char * s2)
186 if (s1 == NULL && s2 == NULL) return 0;
187 if (s1 == NULL) return -1;
188 if (s2 == NULL) return 1;
190 return strcmp(s1, s2);
201 while( getcwd(dir, size) == NULL && errno == ERANGE )
202 dir = realloc(dir, size *=2);
207 #define INITIAL_SIZE 128
209 # define abook_malloc(X) malloc(X)
210 # define abook_realloc(X, XX) realloc(X, XX)
216 char *buf; /* buffer for line */
217 size_t size; /* size of buffer */
218 size_t inc; /* how much to enlarge buffer */
219 size_t len; /* # of chars stored into buf before '\0' */
221 const size_t thres = 128; /* initial buffer size (most lines should
222 fit into this size, so think of this as
223 the "long line threshold"). */
224 const size_t mucho = 128; /* if there is at least this much wasted
225 space when the whole buffer has been
226 read, try to reclaim it. Don't make
227 this too small, else there is too much
228 time wasted trying to reclaim a couple
230 const size_t mininc = 64; /* minimum number of bytes by which
231 to increase the allocated memory */
235 buf = abook_malloc(size);
237 while (fgets(buf+len, size-len, f) != NULL) {
238 len += strlen(buf+len);
239 if (len > 0 && buf[len-1] == '\n')
240 break; /* the whole line has been read */
242 for (inc = size, p = NULL; inc > mininc; inc /= 2)
243 if ((p = abook_realloc(buf, size + inc)) != NULL)
252 return NULL; /* nothing read (eof or error) */
255 if (buf[len-1] == '\n') /* remove newline, if there */
258 if (size - len > mucho) { /* a plenitude of unused memory? */
259 p = abook_realloc(buf, len+1);
269 /**************************************************************
271 * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
272 * A bombproof version of doprnt (dopr) included.
273 * Sigh. This sort of thing is always nasty do deal with. Note that
274 * the version here does not include floating point...
276 * snprintf() is used instead of sprintf() as it does limit checks
277 * for string length. This covers a nasty loophole.
279 * The other functions are there to prevent NULL pointers from
280 * causing nast effects.
283 * Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43
284 * This was ugly. It is still ugly. I opted out of floating point
285 * numbers, but the formatter understands just about everything
286 * from the normal C string format, at least as far as I can tell from
287 * the Solaris 2.5 printf(3S) man page.
289 * Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1
290 * Ok, added some minimal floating point support, which means this
291 * probably requires libm on most operating systems. Don't yet
292 * support the exponent (e,E) and sigfig (g,G). Also, fmtint()
293 * was pretty badly broken, it just wasn't being exercised in ways
294 * which showed it, so that's been fixed. Also, formated the code
295 * to mutt conventions, and removed dead code left over from the
296 * original. Also, there is now a builtin-test, just compile with:
297 * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
298 * and run snprintf for results.
300 * Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i
301 * The PGP code was using unsigned hexadecimal formats.
302 * Unfortunately, unsigned formats simply didn't work.
304 * Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8
305 * The original code assumed that both snprintf() and vsnprintf() were
306 * missing. Some systems only have snprintf() but not vsnprintf(), so
307 * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
309 **************************************************************/
313 #if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF)
317 #include <sys/types.h>
319 /* Define this as a fall through, HAVE_STDARG_H is probably already set */
321 #if !defined(HAVE_STDARG_H) && !defined(HAVE_VARARGS_H)
322 # define HAVE_VARARGS_H 1
325 /* varargs declarations: */
327 #if defined(HAVE_STDARG_H)
328 /*# include <stdarg.h>*/
329 # define HAVE_STDARGS /* let's hope that works everywhere (mj) */
330 # define VA_LOCAL_DECL va_list ap
331 # define VA_START(f) va_start(ap, f)
332 # define VA_SHIFT(v,t) ; /* no-op for ANSI */
333 # define VA_END va_end(ap)
335 # if defined(HAVE_VARARGS_H)
336 # include <varargs.h>
338 # define VA_LOCAL_DECL va_list ap
339 # define VA_START(f) va_start(ap) /* f is ignored! */
340 # define VA_SHIFT(v,t) v = va_arg(ap,t)
341 # define VA_END va_end(ap)
343 /*XX ** NO VARARGS ** XX*/
347 /*int snprintf (char *str, size_t count, const char *fmt, ...);*/
348 /*int vsnprintf (char *str, size_t count, const char *fmt, va_list arg);*/
350 static void dopr (char *buffer, size_t maxlen, const char *format,
352 static void fmtstr (char *buffer, size_t *currlen, size_t maxlen,
353 char *value, int flags, int min, int max);
354 static void fmtint (char *buffer, size_t *currlen, size_t maxlen,
355 long value, int base, int min, int max, int flags);
356 static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
357 long double fvalue, int min, int max, int flags);
358 static void dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c );
361 * dopr(): poor man's version of doprintf
364 /* format read states */
365 #define DP_S_DEFAULT 0
374 /* format flags - Bits */
375 #define DP_F_MINUS (1 << 0)
376 #define DP_F_PLUS (1 << 1)
377 #define DP_F_SPACE (1 << 2)
378 #define DP_F_NUM (1 << 3)
379 #define DP_F_ZERO (1 << 4)
380 #define DP_F_UP (1 << 5)
381 #define DP_F_UNSIGNED (1 << 6)
383 /* Conversion Flags */
386 #define DP_C_LDOUBLE 3
388 #define char_to_int(p) (p - '0')
389 #define MAX(p,q) ((p >= q) ? p : q)
391 static void dopr (char *buffer, size_t maxlen, const char *format, va_list args)
404 state = DP_S_DEFAULT;
405 currlen = flags = cflags = min = 0;
409 while (state != DP_S_DONE)
411 if ((ch == '\0') || (currlen >= maxlen))
420 dopr_outch (buffer, &currlen, maxlen, ch);
452 if (isdigit((unsigned char)ch))
454 min = 10*min + char_to_int (ch);
459 min = va_arg (args, int);
476 if (isdigit((unsigned char)ch))
480 max = 10*max + char_to_int (ch);
485 max = va_arg (args, int);
493 /* Currently, we don't support Long Long, bummer */
505 cflags = DP_C_LDOUBLE;
518 if (cflags == DP_C_SHORT)
519 value = va_arg (args, short int);
520 else if (cflags == DP_C_LONG)
521 value = va_arg (args, long int);
523 value = va_arg (args, int);
524 fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
527 flags |= DP_F_UNSIGNED;
528 if (cflags == DP_C_SHORT)
529 value = va_arg (args, unsigned short int);
530 else if (cflags == DP_C_LONG)
531 value = va_arg (args, unsigned long int);
533 value = va_arg (args, unsigned int);
534 fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags);
537 flags |= DP_F_UNSIGNED;
538 if (cflags == DP_C_SHORT)
539 value = va_arg (args, unsigned short int);
540 else if (cflags == DP_C_LONG)
541 value = va_arg (args, unsigned long int);
543 value = va_arg (args, unsigned int);
544 fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
549 flags |= DP_F_UNSIGNED;
550 if (cflags == DP_C_SHORT)
551 value = va_arg (args, unsigned short int);
552 else if (cflags == DP_C_LONG)
553 value = va_arg (args, unsigned long int);
555 value = va_arg (args, unsigned int);
556 fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags);
559 if (cflags == DP_C_LDOUBLE)
560 fvalue = va_arg (args, long double);
562 fvalue = va_arg (args, double);
563 /* um, floating point? */
564 fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
569 if (cflags == DP_C_LDOUBLE)
570 fvalue = va_arg (args, long double);
572 fvalue = va_arg (args, double);
577 if (cflags == DP_C_LDOUBLE)
578 fvalue = va_arg (args, long double);
580 fvalue = va_arg (args, double);
583 dopr_outch (buffer, &currlen, maxlen, va_arg (args, int));
586 strvalue = va_arg (args, char *);
588 max = maxlen; /* ie, no max */
589 fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max);
592 strvalue = va_arg (args, void *);
593 fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags);
596 if (cflags == DP_C_SHORT)
599 num = va_arg (args, short int *);
602 else if (cflags == DP_C_LONG)
605 num = va_arg (args, long int *);
611 num = va_arg (args, int *);
616 dopr_outch (buffer, &currlen, maxlen, ch);
619 /* not supported yet, treat as next char */
627 state = DP_S_DEFAULT;
628 flags = cflags = min = 0;
635 break; /* some picky compilers need this */
638 if (currlen < maxlen - 1)
639 buffer[currlen] = '\0';
641 buffer[maxlen - 1] = '\0';
644 static void fmtstr (char *buffer, size_t *currlen, size_t maxlen,
645 char *value, int flags, int min, int max)
647 int padlen, strln; /* amount to pad */
655 for (strln = 0; value[strln]; ++strln); /* strlen */
656 padlen = min - strln;
659 if (flags & DP_F_MINUS)
660 padlen = -padlen; /* Left Justify */
662 while ((padlen > 0) && (cnt < max))
664 dopr_outch (buffer, currlen, maxlen, ' ');
668 while (*value && (cnt < max))
670 dopr_outch (buffer, currlen, maxlen, *value++);
673 while ((padlen < 0) && (cnt < max))
675 dopr_outch (buffer, currlen, maxlen, ' ');
681 /* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
683 static void fmtint (char *buffer, size_t *currlen, size_t maxlen,
684 long value, int base, int min, int max, int flags)
687 unsigned long uvalue;
690 int spadlen = 0; /* amount to space pad */
691 int zpadlen = 0; /* amount to zero pad */
699 if(!(flags & DP_F_UNSIGNED))
706 if (flags & DP_F_PLUS) /* Do a sign (+/i) */
709 if (flags & DP_F_SPACE)
713 if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
717 (caps? "0123456789ABCDEF":"0123456789abcdef")
718 [uvalue % (unsigned)base ];
719 uvalue = (uvalue / (unsigned)base );
720 } while(uvalue && (place < 20));
721 if (place == 20) place--;
724 zpadlen = max - place;
725 spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
726 if (zpadlen < 0) zpadlen = 0;
727 if (spadlen < 0) spadlen = 0;
728 if (flags & DP_F_ZERO)
730 zpadlen = MAX(zpadlen, spadlen);
733 if (flags & DP_F_MINUS)
734 spadlen = -spadlen; /* Left Justifty */
736 #ifdef DEBUG_SNPRINTF
737 dprint (1, (debugfile, "zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
738 zpadlen, spadlen, min, max, place));
744 dopr_outch (buffer, currlen, maxlen, ' ');
750 dopr_outch (buffer, currlen, maxlen, signvalue);
757 dopr_outch (buffer, currlen, maxlen, '0');
764 dopr_outch (buffer, currlen, maxlen, convert[--place]);
766 /* Left Justified spaces */
767 while (spadlen < 0) {
768 dopr_outch (buffer, currlen, maxlen, ' ');
773 static long double abs_val (long double value)
775 long double result = value;
783 static long double pow10 (int exp)
785 long double result = 1;
796 static long round (long double value)
801 value = value - intpart;
808 static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
809 long double fvalue, int min, int max, int flags)
817 int padlen = 0; /* amount to pad */
824 * AIX manpage says the default is 0, but Solaris says the default
825 * is 6, and sprintf on AIX defaults to 6
830 ufvalue = abs_val (fvalue);
835 if (flags & DP_F_PLUS) /* Do a sign (+/i) */
838 if (flags & DP_F_SPACE)
842 if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
848 * Sorry, we only support 9 digits past the decimal because of our
854 /* We "cheat" by converting the fractional part to integer by
855 * multiplying by a factor of 10
857 fracpart = round ((pow10 (max)) * (ufvalue - intpart));
859 if (fracpart >= pow10 (max))
862 fracpart -= pow10 (max);
865 #ifdef DEBUG_SNPRINTF
866 dprint (1, (debugfile, "fmtfp: %f =? %d.%d\n", fvalue, intpart, fracpart));
869 /* Convert integer part */
872 (caps? "0123456789ABCDEF":"0123456789abcdef")[intpart % 10];
873 intpart = (intpart / 10);
874 } while(intpart && (iplace < 20));
875 if (iplace == 20) iplace--;
876 iconvert[iplace] = 0;
878 /* Convert fractional part */
881 (caps? "0123456789ABCDEF":"0123456789abcdef")[fracpart % 10];
882 fracpart = (fracpart / 10);
883 } while(fracpart && (fplace < 20));
884 if (fplace == 20) fplace--;
885 fconvert[fplace] = 0;
887 /* -1 for decimal point, another -1 if we are printing a sign */
888 padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
889 zpadlen = max - fplace;
894 if (flags & DP_F_MINUS)
895 padlen = -padlen; /* Left Justifty */
897 if ((flags & DP_F_ZERO) && (padlen > 0))
901 dopr_outch (buffer, currlen, maxlen, signvalue);
907 dopr_outch (buffer, currlen, maxlen, '0');
913 dopr_outch (buffer, currlen, maxlen, ' ');
917 dopr_outch (buffer, currlen, maxlen, signvalue);
920 dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]);
923 * Decimal point. This should probably use locale to find the correct
926 dopr_outch (buffer, currlen, maxlen, '.');
929 dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]);
933 dopr_outch (buffer, currlen, maxlen, '0');
939 dopr_outch (buffer, currlen, maxlen, ' ');
944 static void dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c)
946 if (*currlen < maxlen)
947 buffer[(*currlen)++] = c;
949 #endif /* !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) */
951 #ifndef HAVE_VSNPRINTF
952 int vsnprintf (char *str, size_t count, const char *fmt, va_list args)
955 dopr(str, count, fmt, args);
958 #endif /* !HAVE_VSNPRINTF */
960 #ifndef HAVE_SNPRINTF
963 int snprintf (char *str,size_t count,const char *fmt,...)
965 int snprintf (va_alist) va_dcl
976 VA_SHIFT (str, char *);
977 VA_SHIFT (count, size_t );
978 VA_SHIFT (fmt, char *);
979 (void) vsnprintf(str, count, fmt, ap);
986 #define LONG_STRING 1024
990 char buf1[LONG_STRING];
991 char buf2[LONG_STRING];
1006 double fp_nums[] = { -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996,
1007 0.9996, 1.996, 4.136, 0};
1020 long int_nums[] = { -1, 134, 91340, 341, 0203, 0};
1025 printf ("Testing snprintf format codes against system sprintf...\n");
1027 for (x = 0; fp_fmt[x] != NULL ; x++)
1028 for (y = 0; fp_nums[y] != 0 ; y++)
1030 snprintf (buf1, sizeof (buf1), fp_fmt[x], fp_nums[y]);
1031 sprintf (buf2, fp_fmt[x], fp_nums[y]);
1032 if (strcmp (buf1, buf2))
1034 printf("snprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
1035 fp_fmt[x], buf1, buf2);
1041 for (x = 0; int_fmt[x] != NULL ; x++)
1042 for (y = 0; int_nums[y] != 0 ; y++)
1044 snprintf (buf1, sizeof (buf1), int_fmt[x], int_nums[y]);
1045 sprintf (buf2, int_fmt[x], int_nums[y]);
1046 if (strcmp (buf1, buf2))
1048 printf("snprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
1049 int_fmt[x], buf1, buf2);
1054 printf ("%d tests failed out of %d.\n", fail, num);
1056 #endif /* SNPRINTF_TEST */
1058 #endif /* !HAVE_SNPRINTF */