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 = malloc(size)) == NULL)
226 while( getcwd(dir, size) == NULL && errno == ERANGE )
227 if( (dir = 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 = abook_realloc(buf, size + inc)) != NULL)
278 return NULL; /* nothing read (eof or error) */
281 if (buf[len-1] == '\n') /* remove newline, if there */
284 if (size - len > mucho) { /* a plenitude of unused memory? */
285 p = abook_realloc(buf, len+1);
295 /**************************************************************
297 * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
298 * A bombproof version of doprnt (dopr) included.
299 * Sigh. This sort of thing is always nasty do deal with. Note that
300 * the version here does not include floating point...
302 * snprintf() is used instead of sprintf() as it does limit checks
303 * for string length. This covers a nasty loophole.
305 * The other functions are there to prevent NULL pointers from
306 * causing nast effects.
309 * Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43
310 * This was ugly. It is still ugly. I opted out of floating point
311 * numbers, but the formatter understands just about everything
312 * from the normal C string format, at least as far as I can tell from
313 * the Solaris 2.5 printf(3S) man page.
315 * Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1
316 * Ok, added some minimal floating point support, which means this
317 * probably requires libm on most operating systems. Don't yet
318 * support the exponent (e,E) and sigfig (g,G). Also, fmtint()
319 * was pretty badly broken, it just wasn't being exercised in ways
320 * which showed it, so that's been fixed. Also, formated the code
321 * to mutt conventions, and removed dead code left over from the
322 * original. Also, there is now a builtin-test, just compile with:
323 * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
324 * and run snprintf for results.
326 * Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i
327 * The PGP code was using unsigned hexadecimal formats.
328 * Unfortunately, unsigned formats simply didn't work.
330 * Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8
331 * The original code assumed that both snprintf() and vsnprintf() were
332 * missing. Some systems only have snprintf() but not vsnprintf(), so
333 * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
335 **************************************************************/
339 #if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF)
343 #include <sys/types.h>
345 /* Define this as a fall through, HAVE_STDARG_H is probably already set */
347 #if !defined(HAVE_STDARG_H) && !defined(HAVE_VARARGS_H)
348 # define HAVE_VARARGS_H 1
351 /* varargs declarations: */
353 #if defined(HAVE_STDARG_H)
354 /*# include <stdarg.h>*/
355 # define HAVE_STDARGS /* let's hope that works everywhere (mj) */
356 # define VA_LOCAL_DECL va_list ap
357 # define VA_START(f) va_start(ap, f)
358 # define VA_SHIFT(v,t) ; /* no-op for ANSI */
359 # define VA_END va_end(ap)
361 # if defined(HAVE_VARARGS_H)
362 # include <varargs.h>
364 # define VA_LOCAL_DECL va_list ap
365 # define VA_START(f) va_start(ap) /* f is ignored! */
366 # define VA_SHIFT(v,t) v = va_arg(ap,t)
367 # define VA_END va_end(ap)
369 /*XX ** NO VARARGS ** XX*/
373 /*int snprintf (char *str, size_t count, const char *fmt, ...);*/
374 /*int vsnprintf (char *str, size_t count, const char *fmt, va_list arg);*/
376 static void dopr (char *buffer, size_t maxlen, const char *format,
378 static void fmtstr (char *buffer, size_t *currlen, size_t maxlen,
379 char *value, int flags, int min, int max);
380 static void fmtint (char *buffer, size_t *currlen, size_t maxlen,
381 long value, int base, int min, int max, int flags);
382 static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
383 long double fvalue, int min, int max, int flags);
384 static void dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c );
387 * dopr(): poor man's version of doprintf
390 /* format read states */
391 #define DP_S_DEFAULT 0
400 /* format flags - Bits */
401 #define DP_F_MINUS (1 << 0)
402 #define DP_F_PLUS (1 << 1)
403 #define DP_F_SPACE (1 << 2)
404 #define DP_F_NUM (1 << 3)
405 #define DP_F_ZERO (1 << 4)
406 #define DP_F_UP (1 << 5)
407 #define DP_F_UNSIGNED (1 << 6)
409 /* Conversion Flags */
412 #define DP_C_LDOUBLE 3
414 #define char_to_int(p) (p - '0')
415 #define MAX(p,q) ((p >= q) ? p : q)
417 static void dopr (char *buffer, size_t maxlen, const char *format, va_list args)
430 state = DP_S_DEFAULT;
431 currlen = flags = cflags = min = 0;
435 while (state != DP_S_DONE)
437 if ((ch == '\0') || (currlen >= maxlen))
446 dopr_outch (buffer, &currlen, maxlen, ch);
478 if (isdigit((unsigned char)ch))
480 min = 10*min + char_to_int (ch);
485 min = va_arg (args, int);
502 if (isdigit((unsigned char)ch))
506 max = 10*max + char_to_int (ch);
511 max = va_arg (args, int);
519 /* Currently, we don't support Long Long, bummer */
531 cflags = DP_C_LDOUBLE;
544 if (cflags == DP_C_SHORT)
545 value = va_arg (args, short int);
546 else if (cflags == DP_C_LONG)
547 value = va_arg (args, long int);
549 value = va_arg (args, int);
550 fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
553 flags |= DP_F_UNSIGNED;
554 if (cflags == DP_C_SHORT)
555 value = va_arg (args, unsigned short int);
556 else if (cflags == DP_C_LONG)
557 value = va_arg (args, unsigned long int);
559 value = va_arg (args, unsigned int);
560 fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags);
563 flags |= DP_F_UNSIGNED;
564 if (cflags == DP_C_SHORT)
565 value = va_arg (args, unsigned short int);
566 else if (cflags == DP_C_LONG)
567 value = va_arg (args, unsigned long int);
569 value = va_arg (args, unsigned int);
570 fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
575 flags |= DP_F_UNSIGNED;
576 if (cflags == DP_C_SHORT)
577 value = va_arg (args, unsigned short int);
578 else if (cflags == DP_C_LONG)
579 value = va_arg (args, unsigned long int);
581 value = va_arg (args, unsigned int);
582 fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags);
585 if (cflags == DP_C_LDOUBLE)
586 fvalue = va_arg (args, long double);
588 fvalue = va_arg (args, double);
589 /* um, floating point? */
590 fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
595 if (cflags == DP_C_LDOUBLE)
596 fvalue = va_arg (args, long double);
598 fvalue = va_arg (args, double);
603 if (cflags == DP_C_LDOUBLE)
604 fvalue = va_arg (args, long double);
606 fvalue = va_arg (args, double);
609 dopr_outch (buffer, &currlen, maxlen, va_arg (args, int));
612 strvalue = va_arg (args, char *);
614 max = maxlen; /* ie, no max */
615 fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max);
618 strvalue = va_arg (args, void *);
619 fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags);
622 if (cflags == DP_C_SHORT)
625 num = va_arg (args, short int *);
628 else if (cflags == DP_C_LONG)
631 num = va_arg (args, long int *);
637 num = va_arg (args, int *);
642 dopr_outch (buffer, &currlen, maxlen, ch);
645 /* not supported yet, treat as next char */
653 state = DP_S_DEFAULT;
654 flags = cflags = min = 0;
661 break; /* some picky compilers need this */
664 if (currlen < maxlen - 1)
665 buffer[currlen] = '\0';
667 buffer[maxlen - 1] = '\0';
670 static void fmtstr (char *buffer, size_t *currlen, size_t maxlen,
671 char *value, int flags, int min, int max)
673 int padlen, strln; /* amount to pad */
681 for (strln = 0; value[strln]; ++strln); /* strlen */
682 padlen = min - strln;
685 if (flags & DP_F_MINUS)
686 padlen = -padlen; /* Left Justify */
688 while ((padlen > 0) && (cnt < max))
690 dopr_outch (buffer, currlen, maxlen, ' ');
694 while (*value && (cnt < max))
696 dopr_outch (buffer, currlen, maxlen, *value++);
699 while ((padlen < 0) && (cnt < max))
701 dopr_outch (buffer, currlen, maxlen, ' ');
707 /* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
709 static void fmtint (char *buffer, size_t *currlen, size_t maxlen,
710 long value, int base, int min, int max, int flags)
713 unsigned long uvalue;
716 int spadlen = 0; /* amount to space pad */
717 int zpadlen = 0; /* amount to zero pad */
725 if(!(flags & DP_F_UNSIGNED))
732 if (flags & DP_F_PLUS) /* Do a sign (+/i) */
735 if (flags & DP_F_SPACE)
739 if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
743 (caps? "0123456789ABCDEF":"0123456789abcdef")
744 [uvalue % (unsigned)base ];
745 uvalue = (uvalue / (unsigned)base );
746 } while(uvalue && (place < 20));
747 if (place == 20) place--;
750 zpadlen = max - place;
751 spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
752 if (zpadlen < 0) zpadlen = 0;
753 if (spadlen < 0) spadlen = 0;
754 if (flags & DP_F_ZERO)
756 zpadlen = MAX(zpadlen, spadlen);
759 if (flags & DP_F_MINUS)
760 spadlen = -spadlen; /* Left Justifty */
762 #ifdef DEBUG_SNPRINTF
763 dprint (1, (debugfile, "zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
764 zpadlen, spadlen, min, max, place));
770 dopr_outch (buffer, currlen, maxlen, ' ');
776 dopr_outch (buffer, currlen, maxlen, signvalue);
783 dopr_outch (buffer, currlen, maxlen, '0');
790 dopr_outch (buffer, currlen, maxlen, convert[--place]);
792 /* Left Justified spaces */
793 while (spadlen < 0) {
794 dopr_outch (buffer, currlen, maxlen, ' ');
799 static long double abs_val (long double value)
801 long double result = value;
809 static long double pow10 (int exp)
811 long double result = 1;
822 static long round (long double value)
827 value = value - intpart;
834 static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
835 long double fvalue, int min, int max, int flags)
843 int padlen = 0; /* amount to pad */
850 * AIX manpage says the default is 0, but Solaris says the default
851 * is 6, and sprintf on AIX defaults to 6
856 ufvalue = abs_val (fvalue);
861 if (flags & DP_F_PLUS) /* Do a sign (+/i) */
864 if (flags & DP_F_SPACE)
868 if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
874 * Sorry, we only support 9 digits past the decimal because of our
880 /* We "cheat" by converting the fractional part to integer by
881 * multiplying by a factor of 10
883 fracpart = round ((pow10 (max)) * (ufvalue - intpart));
885 if (fracpart >= pow10 (max))
888 fracpart -= pow10 (max);
891 #ifdef DEBUG_SNPRINTF
892 dprint (1, (debugfile, "fmtfp: %f =? %d.%d\n", fvalue, intpart, fracpart));
895 /* Convert integer part */
898 (caps? "0123456789ABCDEF":"0123456789abcdef")[intpart % 10];
899 intpart = (intpart / 10);
900 } while(intpart && (iplace < 20));
901 if (iplace == 20) iplace--;
902 iconvert[iplace] = 0;
904 /* Convert fractional part */
907 (caps? "0123456789ABCDEF":"0123456789abcdef")[fracpart % 10];
908 fracpart = (fracpart / 10);
909 } while(fracpart && (fplace < 20));
910 if (fplace == 20) fplace--;
911 fconvert[fplace] = 0;
913 /* -1 for decimal point, another -1 if we are printing a sign */
914 padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
915 zpadlen = max - fplace;
920 if (flags & DP_F_MINUS)
921 padlen = -padlen; /* Left Justifty */
923 if ((flags & DP_F_ZERO) && (padlen > 0))
927 dopr_outch (buffer, currlen, maxlen, signvalue);
933 dopr_outch (buffer, currlen, maxlen, '0');
939 dopr_outch (buffer, currlen, maxlen, ' ');
943 dopr_outch (buffer, currlen, maxlen, signvalue);
946 dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]);
949 * Decimal point. This should probably use locale to find the correct
952 dopr_outch (buffer, currlen, maxlen, '.');
955 dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]);
959 dopr_outch (buffer, currlen, maxlen, '0');
965 dopr_outch (buffer, currlen, maxlen, ' ');
970 static void dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c)
972 if (*currlen < maxlen)
973 buffer[(*currlen)++] = c;
975 #endif /* !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) */
977 #ifndef HAVE_VSNPRINTF
978 int vsnprintf (char *str, size_t count, const char *fmt, va_list args)
981 dopr(str, count, fmt, args);
984 #endif /* !HAVE_VSNPRINTF */
986 #ifndef HAVE_SNPRINTF
989 int snprintf (char *str,size_t count,const char *fmt,...)
991 int snprintf (va_alist) va_dcl
1002 VA_SHIFT (str, char *);
1003 VA_SHIFT (count, size_t );
1004 VA_SHIFT (fmt, char *);
1005 (void) vsnprintf(str, count, fmt, ap);
1007 return(strlen(str));
1010 #ifdef TEST_SNPRINTF
1012 #define LONG_STRING 1024
1016 char buf1[LONG_STRING];
1017 char buf2[LONG_STRING];
1032 double fp_nums[] = { -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996,
1033 0.9996, 1.996, 4.136, 0};
1046 long int_nums[] = { -1, 134, 91340, 341, 0203, 0};
1051 printf ("Testing snprintf format codes against system sprintf...\n");
1053 for (x = 0; fp_fmt[x] != NULL ; x++)
1054 for (y = 0; fp_nums[y] != 0 ; y++)
1056 snprintf (buf1, sizeof (buf1), fp_fmt[x], fp_nums[y]);
1057 sprintf (buf2, fp_fmt[x], fp_nums[y]);
1058 if (strcmp (buf1, buf2))
1060 printf("snprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
1061 fp_fmt[x], buf1, buf2);
1067 for (x = 0; int_fmt[x] != NULL ; x++)
1068 for (y = 0; int_nums[y] != 0 ; y++)
1070 snprintf (buf1, sizeof (buf1), int_fmt[x], int_nums[y]);
1071 sprintf (buf2, int_fmt[x], int_nums[y]);
1072 if (strcmp (buf1, buf2))
1074 printf("snprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
1075 int_fmt[x], buf1, buf2);
1080 printf ("%d tests failed out of %d.\n", fail, num);
1082 #endif /* SNPRINTF_TEST */
1084 #endif /* !HAVE_SNPRINTF */