5 * by JH <jheinonen@users.sourceforge.net>
7 * Copyright (C) Jaakko Heinonen
42 while( ( *str = tolower ( *str ) ) )
55 for(t = s; ISSPACE(*t); t++);
57 memmove(s, t, strlen(t)+1);
59 for (tt = t = s; *t != '\0'; t++)
73 /* varargs declarations: */
76 # define MY_VA_LOCAL_DECL va_list ap
77 # define MY_VA_START(f) va_start(ap, f)
78 # define MY_VA_SHIFT(v,t) v = va_arg(ap, t)
79 # define MY_VA_END va_end(ap)
81 # error HAVE_STDARG_H not defined
85 mkstr (const char *format, ... )
91 (char *) abook_malloc (size);
93 (char *) malloc (size);
96 assert(format != NULL);
101 n = vsnprintf (buffer, size,
105 if (n > -1 && n < size)
115 (char *) abook_realloc (buffer, size);
117 (char *) realloc (buffer, size);
124 strconcat (const char *str, ...)
132 l = 1 + strlen (str);
134 MY_VA_SHIFT(s, char*);
137 MY_VA_SHIFT(s, char*);
150 strcpy (concat, str);
152 MY_VA_SHIFT(s, char*);
155 MY_VA_SHIFT(s, char*);
164 safe_strcmp(const char *s1, const char *s2)
166 if (s1 == NULL && s2 == NULL) return 0;
167 if (s1 == NULL) return -1;
168 if (s2 == NULL) return 1;
170 return strcmp(s1, s2);
174 safe_strcoll(const char *s1, const char *s2)
177 if (s1 == NULL && s2 == NULL) return 0;
178 if (s1 == NULL) return -1;
179 if (s2 == NULL) return 1;
181 return strcoll(s1, s2);
182 #else /* fall back to strcmp */
183 return safe_strcmp(s1, s2);
193 if( (dir = (char *)malloc(size)) == NULL)
198 while( getcwd(dir, size) == NULL && errno == ERANGE )
199 if( (dir = (char *)realloc(dir, size *=2)) == NULL)
205 #define INITIAL_SIZE 128
207 # define abook_malloc(X) malloc(X)
208 # define abook_realloc(X, XX) realloc(X, XX)
214 char *buf; /* buffer for line */
215 size_t size; /* size of buffer */
216 size_t inc; /* how much to enlarge buffer */
217 size_t len; /* # of chars stored into buf before '\0' */
219 const size_t thres = 128; /* initial buffer size (most lines should
220 fit into this size, so think of this as
221 the "long line threshold"). */
222 const size_t mucho = 128; /* if there is at least this much wasted
223 space when the whole buffer has been
224 read, try to reclaim it. Don't make
225 this too small, else there is too much
226 time wasted trying to reclaim a couple
228 const size_t mininc = 64; /* minimum number of bytes by which
229 to increase the allocated memory */
233 buf = (char *)abook_malloc(size);
235 while (fgets(buf+len, size-len, f) != NULL) {
236 len += strlen(buf+len);
237 if (len > 0 && buf[len-1] == '\n')
238 break; /* the whole line has been read */
240 for (inc = size, p = NULL; inc > mininc; inc /= 2)
241 if ((p = (char *)abook_realloc(buf, size + inc)) !=
251 return NULL; /* nothing read (eof or error) */
254 if (buf[len-1] == '\n') /* remove newline, if there */
257 if (size - len > mucho) { /* a plenitude of unused memory? */
258 p = (char *)abook_realloc(buf, len+1);
268 /**************************************************************
270 * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
271 * A bombproof version of doprnt (dopr) included.
272 * Sigh. This sort of thing is always nasty do deal with. Note that
273 * the version here does not include floating point...
275 * snprintf() is used instead of sprintf() as it does limit checks
276 * for string length. This covers a nasty loophole.
278 * The other functions are there to prevent NULL pointers from
279 * causing nast effects.
282 * Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43
283 * This was ugly. It is still ugly. I opted out of floating point
284 * numbers, but the formatter understands just about everything
285 * from the normal C string format, at least as far as I can tell from
286 * the Solaris 2.5 printf(3S) man page.
288 * Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1
289 * Ok, added some minimal floating point support, which means this
290 * probably requires libm on most operating systems. Don't yet
291 * support the exponent (e,E) and sigfig (g,G). Also, fmtint()
292 * was pretty badly broken, it just wasn't being exercised in ways
293 * which showed it, so that's been fixed. Also, formated the code
294 * to mutt conventions, and removed dead code left over from the
295 * original. Also, there is now a builtin-test, just compile with:
296 * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
297 * and run snprintf for results.
299 * Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i
300 * The PGP code was using unsigned hexadecimal formats.
301 * Unfortunately, unsigned formats simply didn't work.
303 * Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8
304 * The original code assumed that both snprintf() and vsnprintf() were
305 * missing. Some systems only have snprintf() but not vsnprintf(), so
306 * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
308 **************************************************************/
312 #if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF)
316 #include <sys/types.h>
318 /* Define this as a fall through, HAVE_STDARG_H is probably already set */
320 #if !defined(HAVE_STDARG_H) && !defined(HAVE_VARARGS_H)
321 # define HAVE_VARARGS_H 1
324 /* varargs declarations: */
326 #if defined(HAVE_STDARG_H)
327 /*# include <stdarg.h>*/
328 # define HAVE_STDARGS /* let's hope that works everywhere (mj) */
329 # define VA_LOCAL_DECL va_list ap
330 # define VA_START(f) va_start(ap, f)
331 # define VA_SHIFT(v,t) ; /* no-op for ANSI */
332 # define VA_END va_end(ap)
334 # if defined(HAVE_VARARGS_H)
335 # include <varargs.h>
337 # define VA_LOCAL_DECL va_list ap
338 # define VA_START(f) va_start(ap) /* f is ignored! */
339 # define VA_SHIFT(v,t) v = va_arg(ap,t)
340 # define VA_END va_end(ap)
342 /*XX ** NO VARARGS ** XX*/
346 /*int snprintf (char *str, size_t count, const char *fmt, ...);*/
347 /*int vsnprintf (char *str, size_t count, const char *fmt, va_list arg);*/
349 static void dopr (char *buffer, size_t maxlen, const char *format,
351 static void fmtstr (char *buffer, size_t *currlen, size_t maxlen,
352 char *value, int flags, int min, int max);
353 static void fmtint (char *buffer, size_t *currlen, size_t maxlen,
354 long value, int base, int min, int max, int flags);
355 static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
356 long double fvalue, int min, int max, int flags);
357 static void dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c );
360 * dopr(): poor man's version of doprintf
363 /* format read states */
364 #define DP_S_DEFAULT 0
373 /* format flags - Bits */
374 #define DP_F_MINUS (1 << 0)
375 #define DP_F_PLUS (1 << 1)
376 #define DP_F_SPACE (1 << 2)
377 #define DP_F_NUM (1 << 3)
378 #define DP_F_ZERO (1 << 4)
379 #define DP_F_UP (1 << 5)
380 #define DP_F_UNSIGNED (1 << 6)
382 /* Conversion Flags */
385 #define DP_C_LDOUBLE 3
387 #define char_to_int(p) (p - '0')
388 #define MAX(p,q) ((p >= q) ? p : q)
390 static void dopr (char *buffer, size_t maxlen, const char *format, va_list args)
403 state = DP_S_DEFAULT;
404 currlen = flags = cflags = min = 0;
408 while (state != DP_S_DONE)
410 if ((ch == '\0') || (currlen >= maxlen))
419 dopr_outch (buffer, &currlen, maxlen, ch);
451 if (isdigit((unsigned char)ch))
453 min = 10*min + char_to_int (ch);
458 min = va_arg (args, int);
475 if (isdigit((unsigned char)ch))
479 max = 10*max + char_to_int (ch);
484 max = va_arg (args, int);
492 /* Currently, we don't support Long Long, bummer */
504 cflags = DP_C_LDOUBLE;
517 if (cflags == DP_C_SHORT)
518 value = va_arg (args, short int);
519 else if (cflags == DP_C_LONG)
520 value = va_arg (args, long int);
522 value = va_arg (args, int);
523 fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
526 flags |= DP_F_UNSIGNED;
527 if (cflags == DP_C_SHORT)
528 value = va_arg (args, unsigned short int);
529 else if (cflags == DP_C_LONG)
530 value = va_arg (args, unsigned long int);
532 value = va_arg (args, unsigned int);
533 fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags);
536 flags |= DP_F_UNSIGNED;
537 if (cflags == DP_C_SHORT)
538 value = va_arg (args, unsigned short int);
539 else if (cflags == DP_C_LONG)
540 value = va_arg (args, unsigned long int);
542 value = va_arg (args, unsigned int);
543 fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
548 flags |= DP_F_UNSIGNED;
549 if (cflags == DP_C_SHORT)
550 value = va_arg (args, unsigned short int);
551 else if (cflags == DP_C_LONG)
552 value = va_arg (args, unsigned long int);
554 value = va_arg (args, unsigned int);
555 fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags);
558 if (cflags == DP_C_LDOUBLE)
559 fvalue = va_arg (args, long double);
561 fvalue = va_arg (args, double);
562 /* um, floating point? */
563 fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
568 if (cflags == DP_C_LDOUBLE)
569 fvalue = va_arg (args, long double);
571 fvalue = va_arg (args, double);
576 if (cflags == DP_C_LDOUBLE)
577 fvalue = va_arg (args, long double);
579 fvalue = va_arg (args, double);
582 dopr_outch (buffer, &currlen, maxlen, va_arg (args, int));
585 strvalue = va_arg (args, char *);
587 max = maxlen; /* ie, no max */
588 fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max);
591 strvalue = va_arg (args, void *);
592 fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags);
595 if (cflags == DP_C_SHORT)
598 num = va_arg (args, short int *);
601 else if (cflags == DP_C_LONG)
604 num = va_arg (args, long int *);
610 num = va_arg (args, int *);
615 dopr_outch (buffer, &currlen, maxlen, ch);
618 /* not supported yet, treat as next char */
626 state = DP_S_DEFAULT;
627 flags = cflags = min = 0;
634 break; /* some picky compilers need this */
637 if (currlen < maxlen - 1)
638 buffer[currlen] = '\0';
640 buffer[maxlen - 1] = '\0';
643 static void fmtstr (char *buffer, size_t *currlen, size_t maxlen,
644 char *value, int flags, int min, int max)
646 int padlen, strln; /* amount to pad */
654 for (strln = 0; value[strln]; ++strln); /* strlen */
655 padlen = min - strln;
658 if (flags & DP_F_MINUS)
659 padlen = -padlen; /* Left Justify */
661 while ((padlen > 0) && (cnt < max))
663 dopr_outch (buffer, currlen, maxlen, ' ');
667 while (*value && (cnt < max))
669 dopr_outch (buffer, currlen, maxlen, *value++);
672 while ((padlen < 0) && (cnt < max))
674 dopr_outch (buffer, currlen, maxlen, ' ');
680 /* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
682 static void fmtint (char *buffer, size_t *currlen, size_t maxlen,
683 long value, int base, int min, int max, int flags)
686 unsigned long uvalue;
689 int spadlen = 0; /* amount to space pad */
690 int zpadlen = 0; /* amount to zero pad */
698 if(!(flags & DP_F_UNSIGNED))
705 if (flags & DP_F_PLUS) /* Do a sign (+/i) */
708 if (flags & DP_F_SPACE)
712 if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
716 (caps? "0123456789ABCDEF":"0123456789abcdef")
717 [uvalue % (unsigned)base ];
718 uvalue = (uvalue / (unsigned)base );
719 } while(uvalue && (place < 20));
720 if (place == 20) place--;
723 zpadlen = max - place;
724 spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
725 if (zpadlen < 0) zpadlen = 0;
726 if (spadlen < 0) spadlen = 0;
727 if (flags & DP_F_ZERO)
729 zpadlen = MAX(zpadlen, spadlen);
732 if (flags & DP_F_MINUS)
733 spadlen = -spadlen; /* Left Justifty */
735 #ifdef DEBUG_SNPRINTF
736 dprint (1, (debugfile, "zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
737 zpadlen, spadlen, min, max, place));
743 dopr_outch (buffer, currlen, maxlen, ' ');
749 dopr_outch (buffer, currlen, maxlen, signvalue);
756 dopr_outch (buffer, currlen, maxlen, '0');
763 dopr_outch (buffer, currlen, maxlen, convert[--place]);
765 /* Left Justified spaces */
766 while (spadlen < 0) {
767 dopr_outch (buffer, currlen, maxlen, ' ');
772 static long double abs_val (long double value)
774 long double result = value;
782 static long double pow10 (int exp)
784 long double result = 1;
795 static long round (long double value)
800 value = value - intpart;
807 static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
808 long double fvalue, int min, int max, int flags)
816 int padlen = 0; /* amount to pad */
823 * AIX manpage says the default is 0, but Solaris says the default
824 * is 6, and sprintf on AIX defaults to 6
829 ufvalue = abs_val (fvalue);
834 if (flags & DP_F_PLUS) /* Do a sign (+/i) */
837 if (flags & DP_F_SPACE)
841 if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
847 * Sorry, we only support 9 digits past the decimal because of our
853 /* We "cheat" by converting the fractional part to integer by
854 * multiplying by a factor of 10
856 fracpart = round ((pow10 (max)) * (ufvalue - intpart));
858 if (fracpart >= pow10 (max))
861 fracpart -= pow10 (max);
864 #ifdef DEBUG_SNPRINTF
865 dprint (1, (debugfile, "fmtfp: %f =? %d.%d\n", fvalue, intpart, fracpart));
868 /* Convert integer part */
871 (caps? "0123456789ABCDEF":"0123456789abcdef")[intpart % 10];
872 intpart = (intpart / 10);
873 } while(intpart && (iplace < 20));
874 if (iplace == 20) iplace--;
875 iconvert[iplace] = 0;
877 /* Convert fractional part */
880 (caps? "0123456789ABCDEF":"0123456789abcdef")[fracpart % 10];
881 fracpart = (fracpart / 10);
882 } while(fracpart && (fplace < 20));
883 if (fplace == 20) fplace--;
884 fconvert[fplace] = 0;
886 /* -1 for decimal point, another -1 if we are printing a sign */
887 padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
888 zpadlen = max - fplace;
893 if (flags & DP_F_MINUS)
894 padlen = -padlen; /* Left Justifty */
896 if ((flags & DP_F_ZERO) && (padlen > 0))
900 dopr_outch (buffer, currlen, maxlen, signvalue);
906 dopr_outch (buffer, currlen, maxlen, '0');
912 dopr_outch (buffer, currlen, maxlen, ' ');
916 dopr_outch (buffer, currlen, maxlen, signvalue);
919 dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]);
922 * Decimal point. This should probably use locale to find the correct
925 dopr_outch (buffer, currlen, maxlen, '.');
928 dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]);
932 dopr_outch (buffer, currlen, maxlen, '0');
938 dopr_outch (buffer, currlen, maxlen, ' ');
943 static void dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c)
945 if (*currlen < maxlen)
946 buffer[(*currlen)++] = c;
948 #endif /* !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) */
950 #ifndef HAVE_VSNPRINTF
951 int vsnprintf (char *str, size_t count, const char *fmt, va_list args)
954 dopr(str, count, fmt, args);
957 #endif /* !HAVE_VSNPRINTF */
959 #ifndef HAVE_SNPRINTF
962 int snprintf (char *str,size_t count,const char *fmt,...)
964 int snprintf (va_alist) va_dcl
975 VA_SHIFT (str, char *);
976 VA_SHIFT (count, size_t );
977 VA_SHIFT (fmt, char *);
978 (void) vsnprintf(str, count, fmt, ap);
985 #define LONG_STRING 1024
989 char buf1[LONG_STRING];
990 char buf2[LONG_STRING];
1005 double fp_nums[] = { -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996,
1006 0.9996, 1.996, 4.136, 0};
1019 long int_nums[] = { -1, 134, 91340, 341, 0203, 0};
1024 printf ("Testing snprintf format codes against system sprintf...\n");
1026 for (x = 0; fp_fmt[x] != NULL ; x++)
1027 for (y = 0; fp_nums[y] != 0 ; y++)
1029 snprintf (buf1, sizeof (buf1), fp_fmt[x], fp_nums[y]);
1030 sprintf (buf2, fp_fmt[x], fp_nums[y]);
1031 if (strcmp (buf1, buf2))
1033 printf("snprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
1034 fp_fmt[x], buf1, buf2);
1040 for (x = 0; int_fmt[x] != NULL ; x++)
1041 for (y = 0; int_nums[y] != 0 ; y++)
1043 snprintf (buf1, sizeof (buf1), int_fmt[x], int_nums[y]);
1044 sprintf (buf2, int_fmt[x], int_nums[y]);
1045 if (strcmp (buf1, buf2))
1047 printf("snprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
1048 int_fmt[x], buf1, buf2);
1053 printf ("%d tests failed out of %d.\n", fail, num);
1055 #endif /* SNPRINTF_TEST */
1057 #endif /* !HAVE_SNPRINTF */