5 * by JH <jheinonen@users.sourceforge.net>
7 * Copyright (C) Jaakko Heinonen
57 while( ( *str = toupper( *str ) ) )
68 while( ( *str = tolower ( *str ) ) )
81 for(t = s; ISSPACE(*t); t++);
83 memmove(s, t, strlen(t)+1);
85 for (tt = t = s; *t != '\0'; t++)
99 /* varargs declarations: */
102 # define MY_VA_LOCAL_DECL va_list ap
103 # define MY_VA_START(f) va_start(ap, f)
104 # define MY_VA_SHIFT(v,t) v = va_arg(ap, t)
105 # define MY_VA_END va_end(ap)
107 # error HAVE_STDARG_H not defined
111 mkstr (const char *format, ... )
117 (char *) abook_malloc (size);
119 (char *) malloc (size);
125 n = vsnprintf (buffer, size,
129 if (n > -1 && n < size)
139 (char *) abook_realloc (buffer, size);
141 (char *) realloc (buffer, size);
148 strconcat (const char *str, ...)
157 l = 1 + strlen (str);
159 MY_VA_SHIFT(s, char*);
162 MY_VA_SHIFT(s, char*);
173 strcpy (concat, str);
175 MY_VA_SHIFT(s, char*);
178 MY_VA_SHIFT(s, char*);
187 safe_strcmp(const char *s1, const char *s2)
189 if (s1 == NULL && s2 == NULL) return 0;
190 if (s1 == NULL) return -1;
191 if (s2 == NULL) return 1;
193 return strcmp(s1, s2);
197 safe_strcoll(const char *s1, const char *s2)
200 if (s1 == NULL && s2 == NULL) return 0;
201 if (s1 == NULL) return -1;
202 if (s2 == NULL) return 1;
204 return strcoll(s1, s2);
205 #else /* fall back to strcmp */
206 return safe_strcmp(s1, s2);
218 while( getcwd(dir, size) == NULL && errno == ERANGE )
219 dir = realloc(dir, size *=2);
224 #define INITIAL_SIZE 128
226 # define abook_malloc(X) malloc(X)
227 # define abook_realloc(X, XX) realloc(X, XX)
233 char *buf; /* buffer for line */
234 size_t size; /* size of buffer */
235 size_t inc; /* how much to enlarge buffer */
236 size_t len; /* # of chars stored into buf before '\0' */
238 const size_t thres = 128; /* initial buffer size (most lines should
239 fit into this size, so think of this as
240 the "long line threshold"). */
241 const size_t mucho = 128; /* if there is at least this much wasted
242 space when the whole buffer has been
243 read, try to reclaim it. Don't make
244 this too small, else there is too much
245 time wasted trying to reclaim a couple
247 const size_t mininc = 64; /* minimum number of bytes by which
248 to increase the allocated memory */
252 buf = (char *)abook_malloc(size);
254 while (fgets(buf+len, size-len, f) != NULL) {
255 len += strlen(buf+len);
256 if (len > 0 && buf[len-1] == '\n')
257 break; /* the whole line has been read */
259 for (inc = size, p = NULL; inc > mininc; inc /= 2)
260 if ((p = abook_realloc(buf, size + inc)) != NULL)
269 return NULL; /* nothing read (eof or error) */
272 if (buf[len-1] == '\n') /* remove newline, if there */
275 if (size - len > mucho) { /* a plenitude of unused memory? */
276 p = abook_realloc(buf, len+1);
286 /**************************************************************
288 * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
289 * A bombproof version of doprnt (dopr) included.
290 * Sigh. This sort of thing is always nasty do deal with. Note that
291 * the version here does not include floating point...
293 * snprintf() is used instead of sprintf() as it does limit checks
294 * for string length. This covers a nasty loophole.
296 * The other functions are there to prevent NULL pointers from
297 * causing nast effects.
300 * Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43
301 * This was ugly. It is still ugly. I opted out of floating point
302 * numbers, but the formatter understands just about everything
303 * from the normal C string format, at least as far as I can tell from
304 * the Solaris 2.5 printf(3S) man page.
306 * Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1
307 * Ok, added some minimal floating point support, which means this
308 * probably requires libm on most operating systems. Don't yet
309 * support the exponent (e,E) and sigfig (g,G). Also, fmtint()
310 * was pretty badly broken, it just wasn't being exercised in ways
311 * which showed it, so that's been fixed. Also, formated the code
312 * to mutt conventions, and removed dead code left over from the
313 * original. Also, there is now a builtin-test, just compile with:
314 * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
315 * and run snprintf for results.
317 * Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i
318 * The PGP code was using unsigned hexadecimal formats.
319 * Unfortunately, unsigned formats simply didn't work.
321 * Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8
322 * The original code assumed that both snprintf() and vsnprintf() were
323 * missing. Some systems only have snprintf() but not vsnprintf(), so
324 * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
326 **************************************************************/
330 #if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF)
334 #include <sys/types.h>
336 /* Define this as a fall through, HAVE_STDARG_H is probably already set */
338 #if !defined(HAVE_STDARG_H) && !defined(HAVE_VARARGS_H)
339 # define HAVE_VARARGS_H 1
342 /* varargs declarations: */
344 #if defined(HAVE_STDARG_H)
345 /*# include <stdarg.h>*/
346 # define HAVE_STDARGS /* let's hope that works everywhere (mj) */
347 # define VA_LOCAL_DECL va_list ap
348 # define VA_START(f) va_start(ap, f)
349 # define VA_SHIFT(v,t) ; /* no-op for ANSI */
350 # define VA_END va_end(ap)
352 # if defined(HAVE_VARARGS_H)
353 # include <varargs.h>
355 # define VA_LOCAL_DECL va_list ap
356 # define VA_START(f) va_start(ap) /* f is ignored! */
357 # define VA_SHIFT(v,t) v = va_arg(ap,t)
358 # define VA_END va_end(ap)
360 /*XX ** NO VARARGS ** XX*/
364 /*int snprintf (char *str, size_t count, const char *fmt, ...);*/
365 /*int vsnprintf (char *str, size_t count, const char *fmt, va_list arg);*/
367 static void dopr (char *buffer, size_t maxlen, const char *format,
369 static void fmtstr (char *buffer, size_t *currlen, size_t maxlen,
370 char *value, int flags, int min, int max);
371 static void fmtint (char *buffer, size_t *currlen, size_t maxlen,
372 long value, int base, int min, int max, int flags);
373 static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
374 long double fvalue, int min, int max, int flags);
375 static void dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c );
378 * dopr(): poor man's version of doprintf
381 /* format read states */
382 #define DP_S_DEFAULT 0
391 /* format flags - Bits */
392 #define DP_F_MINUS (1 << 0)
393 #define DP_F_PLUS (1 << 1)
394 #define DP_F_SPACE (1 << 2)
395 #define DP_F_NUM (1 << 3)
396 #define DP_F_ZERO (1 << 4)
397 #define DP_F_UP (1 << 5)
398 #define DP_F_UNSIGNED (1 << 6)
400 /* Conversion Flags */
403 #define DP_C_LDOUBLE 3
405 #define char_to_int(p) (p - '0')
406 #define MAX(p,q) ((p >= q) ? p : q)
408 static void dopr (char *buffer, size_t maxlen, const char *format, va_list args)
421 state = DP_S_DEFAULT;
422 currlen = flags = cflags = min = 0;
426 while (state != DP_S_DONE)
428 if ((ch == '\0') || (currlen >= maxlen))
437 dopr_outch (buffer, &currlen, maxlen, ch);
469 if (isdigit((unsigned char)ch))
471 min = 10*min + char_to_int (ch);
476 min = va_arg (args, int);
493 if (isdigit((unsigned char)ch))
497 max = 10*max + char_to_int (ch);
502 max = va_arg (args, int);
510 /* Currently, we don't support Long Long, bummer */
522 cflags = DP_C_LDOUBLE;
535 if (cflags == DP_C_SHORT)
536 value = va_arg (args, short int);
537 else if (cflags == DP_C_LONG)
538 value = va_arg (args, long int);
540 value = va_arg (args, int);
541 fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
544 flags |= DP_F_UNSIGNED;
545 if (cflags == DP_C_SHORT)
546 value = va_arg (args, unsigned short int);
547 else if (cflags == DP_C_LONG)
548 value = va_arg (args, unsigned long int);
550 value = va_arg (args, unsigned int);
551 fmtint (buffer, &currlen, maxlen, value, 8, 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, 10, min, max, flags);
566 flags |= DP_F_UNSIGNED;
567 if (cflags == DP_C_SHORT)
568 value = va_arg (args, unsigned short int);
569 else if (cflags == DP_C_LONG)
570 value = va_arg (args, unsigned long int);
572 value = va_arg (args, unsigned int);
573 fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags);
576 if (cflags == DP_C_LDOUBLE)
577 fvalue = va_arg (args, long double);
579 fvalue = va_arg (args, double);
580 /* um, floating point? */
581 fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
586 if (cflags == DP_C_LDOUBLE)
587 fvalue = va_arg (args, long double);
589 fvalue = va_arg (args, double);
594 if (cflags == DP_C_LDOUBLE)
595 fvalue = va_arg (args, long double);
597 fvalue = va_arg (args, double);
600 dopr_outch (buffer, &currlen, maxlen, va_arg (args, int));
603 strvalue = va_arg (args, char *);
605 max = maxlen; /* ie, no max */
606 fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max);
609 strvalue = va_arg (args, void *);
610 fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags);
613 if (cflags == DP_C_SHORT)
616 num = va_arg (args, short int *);
619 else if (cflags == DP_C_LONG)
622 num = va_arg (args, long int *);
628 num = va_arg (args, int *);
633 dopr_outch (buffer, &currlen, maxlen, ch);
636 /* not supported yet, treat as next char */
644 state = DP_S_DEFAULT;
645 flags = cflags = min = 0;
652 break; /* some picky compilers need this */
655 if (currlen < maxlen - 1)
656 buffer[currlen] = '\0';
658 buffer[maxlen - 1] = '\0';
661 static void fmtstr (char *buffer, size_t *currlen, size_t maxlen,
662 char *value, int flags, int min, int max)
664 int padlen, strln; /* amount to pad */
672 for (strln = 0; value[strln]; ++strln); /* strlen */
673 padlen = min - strln;
676 if (flags & DP_F_MINUS)
677 padlen = -padlen; /* Left Justify */
679 while ((padlen > 0) && (cnt < max))
681 dopr_outch (buffer, currlen, maxlen, ' ');
685 while (*value && (cnt < max))
687 dopr_outch (buffer, currlen, maxlen, *value++);
690 while ((padlen < 0) && (cnt < max))
692 dopr_outch (buffer, currlen, maxlen, ' ');
698 /* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
700 static void fmtint (char *buffer, size_t *currlen, size_t maxlen,
701 long value, int base, int min, int max, int flags)
704 unsigned long uvalue;
707 int spadlen = 0; /* amount to space pad */
708 int zpadlen = 0; /* amount to zero pad */
716 if(!(flags & DP_F_UNSIGNED))
723 if (flags & DP_F_PLUS) /* Do a sign (+/i) */
726 if (flags & DP_F_SPACE)
730 if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
734 (caps? "0123456789ABCDEF":"0123456789abcdef")
735 [uvalue % (unsigned)base ];
736 uvalue = (uvalue / (unsigned)base );
737 } while(uvalue && (place < 20));
738 if (place == 20) place--;
741 zpadlen = max - place;
742 spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
743 if (zpadlen < 0) zpadlen = 0;
744 if (spadlen < 0) spadlen = 0;
745 if (flags & DP_F_ZERO)
747 zpadlen = MAX(zpadlen, spadlen);
750 if (flags & DP_F_MINUS)
751 spadlen = -spadlen; /* Left Justifty */
753 #ifdef DEBUG_SNPRINTF
754 dprint (1, (debugfile, "zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
755 zpadlen, spadlen, min, max, place));
761 dopr_outch (buffer, currlen, maxlen, ' ');
767 dopr_outch (buffer, currlen, maxlen, signvalue);
774 dopr_outch (buffer, currlen, maxlen, '0');
781 dopr_outch (buffer, currlen, maxlen, convert[--place]);
783 /* Left Justified spaces */
784 while (spadlen < 0) {
785 dopr_outch (buffer, currlen, maxlen, ' ');
790 static long double abs_val (long double value)
792 long double result = value;
800 static long double pow10 (int exp)
802 long double result = 1;
813 static long round (long double value)
818 value = value - intpart;
825 static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
826 long double fvalue, int min, int max, int flags)
834 int padlen = 0; /* amount to pad */
841 * AIX manpage says the default is 0, but Solaris says the default
842 * is 6, and sprintf on AIX defaults to 6
847 ufvalue = abs_val (fvalue);
852 if (flags & DP_F_PLUS) /* Do a sign (+/i) */
855 if (flags & DP_F_SPACE)
859 if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
865 * Sorry, we only support 9 digits past the decimal because of our
871 /* We "cheat" by converting the fractional part to integer by
872 * multiplying by a factor of 10
874 fracpart = round ((pow10 (max)) * (ufvalue - intpart));
876 if (fracpart >= pow10 (max))
879 fracpart -= pow10 (max);
882 #ifdef DEBUG_SNPRINTF
883 dprint (1, (debugfile, "fmtfp: %f =? %d.%d\n", fvalue, intpart, fracpart));
886 /* Convert integer part */
889 (caps? "0123456789ABCDEF":"0123456789abcdef")[intpart % 10];
890 intpart = (intpart / 10);
891 } while(intpart && (iplace < 20));
892 if (iplace == 20) iplace--;
893 iconvert[iplace] = 0;
895 /* Convert fractional part */
898 (caps? "0123456789ABCDEF":"0123456789abcdef")[fracpart % 10];
899 fracpart = (fracpart / 10);
900 } while(fracpart && (fplace < 20));
901 if (fplace == 20) fplace--;
902 fconvert[fplace] = 0;
904 /* -1 for decimal point, another -1 if we are printing a sign */
905 padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
906 zpadlen = max - fplace;
911 if (flags & DP_F_MINUS)
912 padlen = -padlen; /* Left Justifty */
914 if ((flags & DP_F_ZERO) && (padlen > 0))
918 dopr_outch (buffer, currlen, maxlen, signvalue);
924 dopr_outch (buffer, currlen, maxlen, '0');
930 dopr_outch (buffer, currlen, maxlen, ' ');
934 dopr_outch (buffer, currlen, maxlen, signvalue);
937 dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]);
940 * Decimal point. This should probably use locale to find the correct
943 dopr_outch (buffer, currlen, maxlen, '.');
946 dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]);
950 dopr_outch (buffer, currlen, maxlen, '0');
956 dopr_outch (buffer, currlen, maxlen, ' ');
961 static void dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c)
963 if (*currlen < maxlen)
964 buffer[(*currlen)++] = c;
966 #endif /* !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) */
968 #ifndef HAVE_VSNPRINTF
969 int vsnprintf (char *str, size_t count, const char *fmt, va_list args)
972 dopr(str, count, fmt, args);
975 #endif /* !HAVE_VSNPRINTF */
977 #ifndef HAVE_SNPRINTF
980 int snprintf (char *str,size_t count,const char *fmt,...)
982 int snprintf (va_alist) va_dcl
993 VA_SHIFT (str, char *);
994 VA_SHIFT (count, size_t );
995 VA_SHIFT (fmt, char *);
996 (void) vsnprintf(str, count, fmt, ap);
1001 #ifdef TEST_SNPRINTF
1003 #define LONG_STRING 1024
1007 char buf1[LONG_STRING];
1008 char buf2[LONG_STRING];
1023 double fp_nums[] = { -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996,
1024 0.9996, 1.996, 4.136, 0};
1037 long int_nums[] = { -1, 134, 91340, 341, 0203, 0};
1042 printf ("Testing snprintf format codes against system sprintf...\n");
1044 for (x = 0; fp_fmt[x] != NULL ; x++)
1045 for (y = 0; fp_nums[y] != 0 ; y++)
1047 snprintf (buf1, sizeof (buf1), fp_fmt[x], fp_nums[y]);
1048 sprintf (buf2, fp_fmt[x], fp_nums[y]);
1049 if (strcmp (buf1, buf2))
1051 printf("snprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
1052 fp_fmt[x], buf1, buf2);
1058 for (x = 0; int_fmt[x] != NULL ; x++)
1059 for (y = 0; int_nums[y] != 0 ; y++)
1061 snprintf (buf1, sizeof (buf1), int_fmt[x], int_nums[y]);
1062 sprintf (buf2, int_fmt[x], int_nums[y]);
1063 if (strcmp (buf1, buf2))
1065 printf("snprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
1066 int_fmt[x], buf1, buf2);
1071 printf ("%d tests failed out of %d.\n", fail, num);
1073 #endif /* SNPRINTF_TEST */
1075 #endif /* !HAVE_SNPRINTF */