5 * by JH <jheinonen@users.sourceforge.net>
7 * Copyright (C) Jaakko Heinonen
61 while( ( *str = toupper( *str ) ) )
74 while( ( *str = tolower ( *str ) ) )
87 for(t = s; ISSPACE(*t); t++);
89 memmove(s, t, strlen(t)+1);
91 for (tt = t = s; *t != '\0'; t++)
105 /* varargs declarations: */
108 # define MY_VA_LOCAL_DECL va_list ap
109 # define MY_VA_START(f) va_start(ap, f)
110 # define MY_VA_SHIFT(v,t) v = va_arg(ap, t)
111 # define MY_VA_END va_end(ap)
113 # error HAVE_STDARG_H not defined
117 mkstr (const char *format, ... )
123 (char *) abook_malloc (size);
125 (char *) malloc (size);
128 assert(format != NULL);
133 n = vsnprintf (buffer, size,
137 if (n > -1 && n < size)
147 (char *) abook_realloc (buffer, size);
149 (char *) realloc (buffer, size);
156 strconcat (const char *str, ...)
164 l = 1 + strlen (str);
166 MY_VA_SHIFT(s, char*);
169 MY_VA_SHIFT(s, char*);
180 strcpy (concat, str);
182 MY_VA_SHIFT(s, char*);
185 MY_VA_SHIFT(s, char*);
194 safe_strcmp(const char *s1, const char *s2)
196 if (s1 == NULL && s2 == NULL) return 0;
197 if (s1 == NULL) return -1;
198 if (s2 == NULL) return 1;
200 return strcmp(s1, s2);
204 safe_strcoll(const char *s1, const char *s2)
207 if (s1 == NULL && s2 == NULL) return 0;
208 if (s1 == NULL) return -1;
209 if (s2 == NULL) return 1;
211 return strcoll(s1, s2);
212 #else /* fall back to strcmp */
213 return safe_strcmp(s1, s2);
223 if( (dir = (char *)malloc(size)) == NULL)
226 while( getcwd(dir, size) == NULL && errno == ERANGE )
227 if( (dir = (char *)realloc(dir, size *=2)) == NULL)
233 #define INITIAL_SIZE 128
235 # define abook_malloc(X) malloc(X)
236 # define abook_realloc(X, XX) realloc(X, XX)
242 char *buf; /* buffer for line */
243 size_t size; /* size of buffer */
244 size_t inc; /* how much to enlarge buffer */
245 size_t len; /* # of chars stored into buf before '\0' */
247 const size_t thres = 128; /* initial buffer size (most lines should
248 fit into this size, so think of this as
249 the "long line threshold"). */
250 const size_t mucho = 128; /* if there is at least this much wasted
251 space when the whole buffer has been
252 read, try to reclaim it. Don't make
253 this too small, else there is too much
254 time wasted trying to reclaim a couple
256 const size_t mininc = 64; /* minimum number of bytes by which
257 to increase the allocated memory */
261 buf = (char *)abook_malloc(size);
263 while (fgets(buf+len, size-len, f) != NULL) {
264 len += strlen(buf+len);
265 if (len > 0 && buf[len-1] == '\n')
266 break; /* the whole line has been read */
268 for (inc = size, p = NULL; inc > mininc; inc /= 2)
269 if ((p = (char *)abook_realloc(buf, size + inc)) !=
279 return NULL; /* nothing read (eof or error) */
282 if (buf[len-1] == '\n') /* remove newline, if there */
285 if (size - len > mucho) { /* a plenitude of unused memory? */
286 p = (char *)abook_realloc(buf, len+1);
296 /**************************************************************
298 * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
299 * A bombproof version of doprnt (dopr) included.
300 * Sigh. This sort of thing is always nasty do deal with. Note that
301 * the version here does not include floating point...
303 * snprintf() is used instead of sprintf() as it does limit checks
304 * for string length. This covers a nasty loophole.
306 * The other functions are there to prevent NULL pointers from
307 * causing nast effects.
310 * Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43
311 * This was ugly. It is still ugly. I opted out of floating point
312 * numbers, but the formatter understands just about everything
313 * from the normal C string format, at least as far as I can tell from
314 * the Solaris 2.5 printf(3S) man page.
316 * Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1
317 * Ok, added some minimal floating point support, which means this
318 * probably requires libm on most operating systems. Don't yet
319 * support the exponent (e,E) and sigfig (g,G). Also, fmtint()
320 * was pretty badly broken, it just wasn't being exercised in ways
321 * which showed it, so that's been fixed. Also, formated the code
322 * to mutt conventions, and removed dead code left over from the
323 * original. Also, there is now a builtin-test, just compile with:
324 * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
325 * and run snprintf for results.
327 * Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i
328 * The PGP code was using unsigned hexadecimal formats.
329 * Unfortunately, unsigned formats simply didn't work.
331 * Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8
332 * The original code assumed that both snprintf() and vsnprintf() were
333 * missing. Some systems only have snprintf() but not vsnprintf(), so
334 * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
336 **************************************************************/
340 #if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF)
344 #include <sys/types.h>
346 /* Define this as a fall through, HAVE_STDARG_H is probably already set */
348 #if !defined(HAVE_STDARG_H) && !defined(HAVE_VARARGS_H)
349 # define HAVE_VARARGS_H 1
352 /* varargs declarations: */
354 #if defined(HAVE_STDARG_H)
355 /*# include <stdarg.h>*/
356 # define HAVE_STDARGS /* let's hope that works everywhere (mj) */
357 # define VA_LOCAL_DECL va_list ap
358 # define VA_START(f) va_start(ap, f)
359 # define VA_SHIFT(v,t) ; /* no-op for ANSI */
360 # define VA_END va_end(ap)
362 # if defined(HAVE_VARARGS_H)
363 # include <varargs.h>
365 # define VA_LOCAL_DECL va_list ap
366 # define VA_START(f) va_start(ap) /* f is ignored! */
367 # define VA_SHIFT(v,t) v = va_arg(ap,t)
368 # define VA_END va_end(ap)
370 /*XX ** NO VARARGS ** XX*/
374 /*int snprintf (char *str, size_t count, const char *fmt, ...);*/
375 /*int vsnprintf (char *str, size_t count, const char *fmt, va_list arg);*/
377 static void dopr (char *buffer, size_t maxlen, const char *format,
379 static void fmtstr (char *buffer, size_t *currlen, size_t maxlen,
380 char *value, int flags, int min, int max);
381 static void fmtint (char *buffer, size_t *currlen, size_t maxlen,
382 long value, int base, int min, int max, int flags);
383 static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
384 long double fvalue, int min, int max, int flags);
385 static void dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c );
388 * dopr(): poor man's version of doprintf
391 /* format read states */
392 #define DP_S_DEFAULT 0
401 /* format flags - Bits */
402 #define DP_F_MINUS (1 << 0)
403 #define DP_F_PLUS (1 << 1)
404 #define DP_F_SPACE (1 << 2)
405 #define DP_F_NUM (1 << 3)
406 #define DP_F_ZERO (1 << 4)
407 #define DP_F_UP (1 << 5)
408 #define DP_F_UNSIGNED (1 << 6)
410 /* Conversion Flags */
413 #define DP_C_LDOUBLE 3
415 #define char_to_int(p) (p - '0')
416 #define MAX(p,q) ((p >= q) ? p : q)
418 static void dopr (char *buffer, size_t maxlen, const char *format, va_list args)
431 state = DP_S_DEFAULT;
432 currlen = flags = cflags = min = 0;
436 while (state != DP_S_DONE)
438 if ((ch == '\0') || (currlen >= maxlen))
447 dopr_outch (buffer, &currlen, maxlen, ch);
479 if (isdigit((unsigned char)ch))
481 min = 10*min + char_to_int (ch);
486 min = va_arg (args, int);
503 if (isdigit((unsigned char)ch))
507 max = 10*max + char_to_int (ch);
512 max = va_arg (args, int);
520 /* Currently, we don't support Long Long, bummer */
532 cflags = DP_C_LDOUBLE;
545 if (cflags == DP_C_SHORT)
546 value = va_arg (args, short int);
547 else if (cflags == DP_C_LONG)
548 value = va_arg (args, long int);
550 value = va_arg (args, int);
551 fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
554 flags |= DP_F_UNSIGNED;
555 if (cflags == DP_C_SHORT)
556 value = va_arg (args, unsigned short int);
557 else if (cflags == DP_C_LONG)
558 value = va_arg (args, unsigned long int);
560 value = va_arg (args, unsigned int);
561 fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags);
564 flags |= DP_F_UNSIGNED;
565 if (cflags == DP_C_SHORT)
566 value = va_arg (args, unsigned short int);
567 else if (cflags == DP_C_LONG)
568 value = va_arg (args, unsigned long int);
570 value = va_arg (args, unsigned int);
571 fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
576 flags |= DP_F_UNSIGNED;
577 if (cflags == DP_C_SHORT)
578 value = va_arg (args, unsigned short int);
579 else if (cflags == DP_C_LONG)
580 value = va_arg (args, unsigned long int);
582 value = va_arg (args, unsigned int);
583 fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags);
586 if (cflags == DP_C_LDOUBLE)
587 fvalue = va_arg (args, long double);
589 fvalue = va_arg (args, double);
590 /* um, floating point? */
591 fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
596 if (cflags == DP_C_LDOUBLE)
597 fvalue = va_arg (args, long double);
599 fvalue = va_arg (args, double);
604 if (cflags == DP_C_LDOUBLE)
605 fvalue = va_arg (args, long double);
607 fvalue = va_arg (args, double);
610 dopr_outch (buffer, &currlen, maxlen, va_arg (args, int));
613 strvalue = va_arg (args, char *);
615 max = maxlen; /* ie, no max */
616 fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max);
619 strvalue = va_arg (args, void *);
620 fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags);
623 if (cflags == DP_C_SHORT)
626 num = va_arg (args, short int *);
629 else if (cflags == DP_C_LONG)
632 num = va_arg (args, long int *);
638 num = va_arg (args, int *);
643 dopr_outch (buffer, &currlen, maxlen, ch);
646 /* not supported yet, treat as next char */
654 state = DP_S_DEFAULT;
655 flags = cflags = min = 0;
662 break; /* some picky compilers need this */
665 if (currlen < maxlen - 1)
666 buffer[currlen] = '\0';
668 buffer[maxlen - 1] = '\0';
671 static void fmtstr (char *buffer, size_t *currlen, size_t maxlen,
672 char *value, int flags, int min, int max)
674 int padlen, strln; /* amount to pad */
682 for (strln = 0; value[strln]; ++strln); /* strlen */
683 padlen = min - strln;
686 if (flags & DP_F_MINUS)
687 padlen = -padlen; /* Left Justify */
689 while ((padlen > 0) && (cnt < max))
691 dopr_outch (buffer, currlen, maxlen, ' ');
695 while (*value && (cnt < max))
697 dopr_outch (buffer, currlen, maxlen, *value++);
700 while ((padlen < 0) && (cnt < max))
702 dopr_outch (buffer, currlen, maxlen, ' ');
708 /* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
710 static void fmtint (char *buffer, size_t *currlen, size_t maxlen,
711 long value, int base, int min, int max, int flags)
714 unsigned long uvalue;
717 int spadlen = 0; /* amount to space pad */
718 int zpadlen = 0; /* amount to zero pad */
726 if(!(flags & DP_F_UNSIGNED))
733 if (flags & DP_F_PLUS) /* Do a sign (+/i) */
736 if (flags & DP_F_SPACE)
740 if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
744 (caps? "0123456789ABCDEF":"0123456789abcdef")
745 [uvalue % (unsigned)base ];
746 uvalue = (uvalue / (unsigned)base );
747 } while(uvalue && (place < 20));
748 if (place == 20) place--;
751 zpadlen = max - place;
752 spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
753 if (zpadlen < 0) zpadlen = 0;
754 if (spadlen < 0) spadlen = 0;
755 if (flags & DP_F_ZERO)
757 zpadlen = MAX(zpadlen, spadlen);
760 if (flags & DP_F_MINUS)
761 spadlen = -spadlen; /* Left Justifty */
763 #ifdef DEBUG_SNPRINTF
764 dprint (1, (debugfile, "zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
765 zpadlen, spadlen, min, max, place));
771 dopr_outch (buffer, currlen, maxlen, ' ');
777 dopr_outch (buffer, currlen, maxlen, signvalue);
784 dopr_outch (buffer, currlen, maxlen, '0');
791 dopr_outch (buffer, currlen, maxlen, convert[--place]);
793 /* Left Justified spaces */
794 while (spadlen < 0) {
795 dopr_outch (buffer, currlen, maxlen, ' ');
800 static long double abs_val (long double value)
802 long double result = value;
810 static long double pow10 (int exp)
812 long double result = 1;
823 static long round (long double value)
828 value = value - intpart;
835 static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
836 long double fvalue, int min, int max, int flags)
844 int padlen = 0; /* amount to pad */
851 * AIX manpage says the default is 0, but Solaris says the default
852 * is 6, and sprintf on AIX defaults to 6
857 ufvalue = abs_val (fvalue);
862 if (flags & DP_F_PLUS) /* Do a sign (+/i) */
865 if (flags & DP_F_SPACE)
869 if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
875 * Sorry, we only support 9 digits past the decimal because of our
881 /* We "cheat" by converting the fractional part to integer by
882 * multiplying by a factor of 10
884 fracpart = round ((pow10 (max)) * (ufvalue - intpart));
886 if (fracpart >= pow10 (max))
889 fracpart -= pow10 (max);
892 #ifdef DEBUG_SNPRINTF
893 dprint (1, (debugfile, "fmtfp: %f =? %d.%d\n", fvalue, intpart, fracpart));
896 /* Convert integer part */
899 (caps? "0123456789ABCDEF":"0123456789abcdef")[intpart % 10];
900 intpart = (intpart / 10);
901 } while(intpart && (iplace < 20));
902 if (iplace == 20) iplace--;
903 iconvert[iplace] = 0;
905 /* Convert fractional part */
908 (caps? "0123456789ABCDEF":"0123456789abcdef")[fracpart % 10];
909 fracpart = (fracpart / 10);
910 } while(fracpart && (fplace < 20));
911 if (fplace == 20) fplace--;
912 fconvert[fplace] = 0;
914 /* -1 for decimal point, another -1 if we are printing a sign */
915 padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
916 zpadlen = max - fplace;
921 if (flags & DP_F_MINUS)
922 padlen = -padlen; /* Left Justifty */
924 if ((flags & DP_F_ZERO) && (padlen > 0))
928 dopr_outch (buffer, currlen, maxlen, signvalue);
934 dopr_outch (buffer, currlen, maxlen, '0');
940 dopr_outch (buffer, currlen, maxlen, ' ');
944 dopr_outch (buffer, currlen, maxlen, signvalue);
947 dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]);
950 * Decimal point. This should probably use locale to find the correct
953 dopr_outch (buffer, currlen, maxlen, '.');
956 dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]);
960 dopr_outch (buffer, currlen, maxlen, '0');
966 dopr_outch (buffer, currlen, maxlen, ' ');
971 static void dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c)
973 if (*currlen < maxlen)
974 buffer[(*currlen)++] = c;
976 #endif /* !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) */
978 #ifndef HAVE_VSNPRINTF
979 int vsnprintf (char *str, size_t count, const char *fmt, va_list args)
982 dopr(str, count, fmt, args);
985 #endif /* !HAVE_VSNPRINTF */
987 #ifndef HAVE_SNPRINTF
990 int snprintf (char *str,size_t count,const char *fmt,...)
992 int snprintf (va_alist) va_dcl
1003 VA_SHIFT (str, char *);
1004 VA_SHIFT (count, size_t );
1005 VA_SHIFT (fmt, char *);
1006 (void) vsnprintf(str, count, fmt, ap);
1008 return(strlen(str));
1011 #ifdef TEST_SNPRINTF
1013 #define LONG_STRING 1024
1017 char buf1[LONG_STRING];
1018 char buf2[LONG_STRING];
1033 double fp_nums[] = { -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996,
1034 0.9996, 1.996, 4.136, 0};
1047 long int_nums[] = { -1, 134, 91340, 341, 0203, 0};
1052 printf ("Testing snprintf format codes against system sprintf...\n");
1054 for (x = 0; fp_fmt[x] != NULL ; x++)
1055 for (y = 0; fp_nums[y] != 0 ; y++)
1057 snprintf (buf1, sizeof (buf1), fp_fmt[x], fp_nums[y]);
1058 sprintf (buf2, fp_fmt[x], fp_nums[y]);
1059 if (strcmp (buf1, buf2))
1061 printf("snprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
1062 fp_fmt[x], buf1, buf2);
1068 for (x = 0; int_fmt[x] != NULL ; x++)
1069 for (y = 0; int_nums[y] != 0 ; y++)
1071 snprintf (buf1, sizeof (buf1), int_fmt[x], int_nums[y]);
1072 sprintf (buf2, int_fmt[x], int_nums[y]);
1073 if (strcmp (buf1, buf2))
1075 printf("snprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
1076 int_fmt[x], buf1, buf2);
1081 printf ("%d tests failed out of %d.\n", fail, num);
1083 #endif /* SNPRINTF_TEST */
1085 #endif /* !HAVE_SNPRINTF */