5 * by JH <jheinonen@users.sourceforge.net>
7 * Copyright (C) Jaakko Heinonen
19 #ifdef HANDLE_MULTIBYTE
20 # include <mbswidth.h>
40 while( ( *str = tolower ( *str ) ) )
53 for(t = s; isspace(*t); t++);
55 memmove(s, t, strlen(t)+1);
57 for (tt = t = s; *t != '\0'; t++)
71 /* varargs declarations: */
74 # define MY_VA_LOCAL_DECL va_list ap
75 # define MY_VA_START(f) va_start(ap, f)
76 # define MY_VA_SHIFT(v,t) v = va_arg(ap, t)
77 # define MY_VA_END va_end(ap)
79 # error HAVE_STDARG_H not defined
83 mkstr (const char *format, ... )
87 char *buffer = xmalloc (size);
89 assert(format != NULL);
94 n = vsnprintf (buffer, size,
98 if (n > -1 && n < size)
106 buffer = xrealloc(buffer, size);
112 strconcat (const char *str, ...)
120 l = 1 + strlen (str);
122 MY_VA_SHIFT(s, char*);
125 MY_VA_SHIFT(s, char*);
131 strcpy (concat, str);
133 MY_VA_SHIFT(s, char*);
136 MY_VA_SHIFT(s, char*);
145 safe_strcmp(const char *s1, const char *s2)
147 if (s1 == NULL && s2 == NULL) return 0;
148 if (s1 == NULL) return -1;
149 if (s2 == NULL) return 1;
151 return strcmp(s1, s2);
155 safe_strcoll(const char *s1, const char *s2)
158 if (s1 == NULL && s2 == NULL) return 0;
159 if (s1 == NULL) return -1;
160 if (s2 == NULL) return 1;
162 return strcoll(s1, s2);
163 #else /* fall back to strcmp */
164 return safe_strcmp(s1, s2);
174 if( (dir = xmalloc(size)) == NULL)
179 while( getcwd(dir, size) == NULL && errno == ERANGE )
180 if( (dir = xrealloc(dir, size *=2)) == NULL)
186 #define INITIAL_SIZE 128
191 char *buf; /* buffer for line */
192 size_t size; /* size of buffer */
193 size_t inc; /* how much to enlarge buffer */
194 size_t len; /* # of chars stored into buf before '\0' */
196 const size_t thres = 128; /* initial buffer size (most lines should
197 fit into this size, so think of this as
198 the "long line threshold"). */
199 const size_t mucho = 128; /* if there is at least this much wasted
200 space when the whole buffer has been
201 read, try to reclaim it. Don't make
202 this too small, else there is too much
203 time wasted trying to reclaim a couple
205 const size_t mininc = 64; /* minimum number of bytes by which
206 to increase the allocated memory */
212 while (fgets(buf+len, size-len, f) != NULL) {
213 len += strlen(buf+len);
214 if (len > 0 && buf[len-1] == '\n')
215 break; /* the whole line has been read */
217 for (inc = size, p = NULL; inc > mininc; inc /= 2)
218 if ((p = xrealloc_inc(buf, size, inc)) !=
228 return NULL; /* nothing read (eof or error) */
231 if (buf[len-1] == '\n') /* remove newline, if there */
234 if (size - len > mucho) { /* a plenitude of unused memory? */
235 p = xrealloc_inc(buf, len, 1);
246 strwidth(const char *s)
249 #ifdef HANDLE_MULTIBYTE
250 return (int)mbswidth(s, 0);
257 bytes2width(const char *s, int width)
260 #ifdef HANDLE_MULTIBYTE
261 return mbsnbytes(s, strlen(s), width, 0);
267 /**************************************************************
269 * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
270 * A bombproof version of doprnt (dopr) included.
271 * Sigh. This sort of thing is always nasty do deal with. Note that
272 * the version here does not include floating point...
274 * snprintf() is used instead of sprintf() as it does limit checks
275 * for string length. This covers a nasty loophole.
277 * The other functions are there to prevent NULL pointers from
278 * causing nast effects.
281 * Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43
282 * This was ugly. It is still ugly. I opted out of floating point
283 * numbers, but the formatter understands just about everything
284 * from the normal C string format, at least as far as I can tell from
285 * the Solaris 2.5 printf(3S) man page.
287 * Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1
288 * Ok, added some minimal floating point support, which means this
289 * probably requires libm on most operating systems. Don't yet
290 * support the exponent (e,E) and sigfig (g,G). Also, fmtint()
291 * was pretty badly broken, it just wasn't being exercised in ways
292 * which showed it, so that's been fixed. Also, formated the code
293 * to mutt conventions, and removed dead code left over from the
294 * original. Also, there is now a builtin-test, just compile with:
295 * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
296 * and run snprintf for results.
298 * Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i
299 * The PGP code was using unsigned hexadecimal formats.
300 * Unfortunately, unsigned formats simply didn't work.
302 * Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8
303 * The original code assumed that both snprintf() and vsnprintf() were
304 * missing. Some systems only have snprintf() but not vsnprintf(), so
305 * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
307 **************************************************************/
311 #if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF)
315 #include <sys/types.h>
317 /* Define this as a fall through, HAVE_STDARG_H is probably already set */
319 #if !defined(HAVE_STDARG_H) && !defined(HAVE_VARARGS_H)
320 # define HAVE_VARARGS_H 1
323 /* varargs declarations: */
325 #if defined(HAVE_STDARG_H)
326 /*# include <stdarg.h>*/
327 # define HAVE_STDARGS /* let's hope that works everywhere (mj) */
328 # define VA_LOCAL_DECL va_list ap
329 # define VA_START(f) va_start(ap, f)
330 # define VA_SHIFT(v,t) ; /* no-op for ANSI */
331 # define VA_END va_end(ap)
333 # if defined(HAVE_VARARGS_H)
334 # include <varargs.h>
336 # define VA_LOCAL_DECL va_list ap
337 # define VA_START(f) va_start(ap) /* f is ignored! */
338 # define VA_SHIFT(v,t) v = va_arg(ap,t)
339 # define VA_END va_end(ap)
341 /*XX ** NO VARARGS ** XX*/
345 /*int snprintf (char *str, size_t count, const char *fmt, ...);*/
346 /*int vsnprintf (char *str, size_t count, const char *fmt, va_list arg);*/
348 static void dopr (char *buffer, size_t maxlen, const char *format,
350 static void fmtstr (char *buffer, size_t *currlen, size_t maxlen,
351 char *value, int flags, int min, int max);
352 static void fmtint (char *buffer, size_t *currlen, size_t maxlen,
353 long value, int base, int min, int max, int flags);
354 static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
355 long double fvalue, int min, int max, int flags);
356 static void dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c );
359 * dopr(): poor man's version of doprintf
362 /* format read states */
363 #define DP_S_DEFAULT 0
372 /* format flags - Bits */
373 #define DP_F_MINUS (1 << 0)
374 #define DP_F_PLUS (1 << 1)
375 #define DP_F_SPACE (1 << 2)
376 #define DP_F_NUM (1 << 3)
377 #define DP_F_ZERO (1 << 4)
378 #define DP_F_UP (1 << 5)
379 #define DP_F_UNSIGNED (1 << 6)
381 /* Conversion Flags */
384 #define DP_C_LDOUBLE 3
386 #define char_to_int(p) (p - '0')
387 #define MAX(p,q) ((p >= q) ? p : q)
389 static void dopr (char *buffer, size_t maxlen, const char *format, va_list args)
402 state = DP_S_DEFAULT;
403 currlen = flags = cflags = min = 0;
407 while (state != DP_S_DONE)
409 if ((ch == '\0') || (currlen >= maxlen))
418 dopr_outch (buffer, &currlen, maxlen, ch);
450 if (isdigit((unsigned char)ch))
452 min = 10*min + char_to_int (ch);
457 min = va_arg (args, int);
474 if (isdigit((unsigned char)ch))
478 max = 10*max + char_to_int (ch);
483 max = va_arg (args, int);
491 /* Currently, we don't support Long Long, bummer */
503 cflags = DP_C_LDOUBLE;
516 if (cflags == DP_C_SHORT)
517 value = va_arg (args, short int);
518 else if (cflags == DP_C_LONG)
519 value = va_arg (args, long int);
521 value = va_arg (args, int);
522 fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
525 flags |= DP_F_UNSIGNED;
526 if (cflags == DP_C_SHORT)
527 value = va_arg (args, unsigned short int);
528 else if (cflags == DP_C_LONG)
529 value = va_arg (args, unsigned long int);
531 value = va_arg (args, unsigned int);
532 fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags);
535 flags |= DP_F_UNSIGNED;
536 if (cflags == DP_C_SHORT)
537 value = va_arg (args, unsigned short int);
538 else if (cflags == DP_C_LONG)
539 value = va_arg (args, unsigned long int);
541 value = va_arg (args, unsigned int);
542 fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
547 flags |= DP_F_UNSIGNED;
548 if (cflags == DP_C_SHORT)
549 value = va_arg (args, unsigned short int);
550 else if (cflags == DP_C_LONG)
551 value = va_arg (args, unsigned long int);
553 value = va_arg (args, unsigned int);
554 fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags);
557 if (cflags == DP_C_LDOUBLE)
558 fvalue = va_arg (args, long double);
560 fvalue = va_arg (args, double);
561 /* um, floating point? */
562 fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
567 if (cflags == DP_C_LDOUBLE)
568 fvalue = va_arg (args, long double);
570 fvalue = va_arg (args, double);
575 if (cflags == DP_C_LDOUBLE)
576 fvalue = va_arg (args, long double);
578 fvalue = va_arg (args, double);
581 dopr_outch (buffer, &currlen, maxlen, va_arg (args, int));
584 strvalue = va_arg (args, char *);
586 max = maxlen; /* ie, no max */
587 fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max);
590 strvalue = va_arg (args, void *);
591 fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags);
594 if (cflags == DP_C_SHORT)
597 num = va_arg (args, short int *);
600 else if (cflags == DP_C_LONG)
603 num = va_arg (args, long int *);
609 num = va_arg (args, int *);
614 dopr_outch (buffer, &currlen, maxlen, ch);
617 /* not supported yet, treat as next char */
625 state = DP_S_DEFAULT;
626 flags = cflags = min = 0;
633 break; /* some picky compilers need this */
636 if (currlen < maxlen - 1)
637 buffer[currlen] = '\0';
639 buffer[maxlen - 1] = '\0';
642 static void fmtstr (char *buffer, size_t *currlen, size_t maxlen,
643 char *value, int flags, int min, int max)
645 int padlen, strln; /* amount to pad */
653 for (strln = 0; value[strln]; ++strln); /* strlen */
654 padlen = min - strln;
657 if (flags & DP_F_MINUS)
658 padlen = -padlen; /* Left Justify */
660 while ((padlen > 0) && (cnt < max))
662 dopr_outch (buffer, currlen, maxlen, ' ');
666 while (*value && (cnt < max))
668 dopr_outch (buffer, currlen, maxlen, *value++);
671 while ((padlen < 0) && (cnt < max))
673 dopr_outch (buffer, currlen, maxlen, ' ');
679 /* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
681 static void fmtint (char *buffer, size_t *currlen, size_t maxlen,
682 long value, int base, int min, int max, int flags)
685 unsigned long uvalue;
688 int spadlen = 0; /* amount to space pad */
689 int zpadlen = 0; /* amount to zero pad */
697 if(!(flags & DP_F_UNSIGNED))
704 if (flags & DP_F_PLUS) /* Do a sign (+/i) */
707 if (flags & DP_F_SPACE)
711 if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
715 (caps? "0123456789ABCDEF":"0123456789abcdef")
716 [uvalue % (unsigned)base ];
717 uvalue = (uvalue / (unsigned)base );
718 } while(uvalue && (place < 20));
719 if (place == 20) place--;
722 zpadlen = max - place;
723 spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
724 if (zpadlen < 0) zpadlen = 0;
725 if (spadlen < 0) spadlen = 0;
726 if (flags & DP_F_ZERO)
728 zpadlen = MAX(zpadlen, spadlen);
731 if (flags & DP_F_MINUS)
732 spadlen = -spadlen; /* Left Justifty */
734 #ifdef DEBUG_SNPRINTF
735 dprint (1, (debugfile, "zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
736 zpadlen, spadlen, min, max, place));
742 dopr_outch (buffer, currlen, maxlen, ' ');
748 dopr_outch (buffer, currlen, maxlen, signvalue);
755 dopr_outch (buffer, currlen, maxlen, '0');
762 dopr_outch (buffer, currlen, maxlen, convert[--place]);
764 /* Left Justified spaces */
765 while (spadlen < 0) {
766 dopr_outch (buffer, currlen, maxlen, ' ');
771 static long double abs_val (long double value)
773 long double result = value;
781 static long double pow10 (int exp)
783 long double result = 1;
794 static long round (long double value)
799 value = value - intpart;
806 static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
807 long double fvalue, int min, int max, int flags)
815 int padlen = 0; /* amount to pad */
822 * AIX manpage says the default is 0, but Solaris says the default
823 * is 6, and sprintf on AIX defaults to 6
828 ufvalue = abs_val (fvalue);
833 if (flags & DP_F_PLUS) /* Do a sign (+/i) */
836 if (flags & DP_F_SPACE)
840 if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
846 * Sorry, we only support 9 digits past the decimal because of our
852 /* We "cheat" by converting the fractional part to integer by
853 * multiplying by a factor of 10
855 fracpart = round ((pow10 (max)) * (ufvalue - intpart));
857 if (fracpart >= pow10 (max))
860 fracpart -= pow10 (max);
863 #ifdef DEBUG_SNPRINTF
864 dprint (1, (debugfile, "fmtfp: %f =? %d.%d\n", fvalue, intpart, fracpart));
867 /* Convert integer part */
870 (caps? "0123456789ABCDEF":"0123456789abcdef")[intpart % 10];
871 intpart = (intpart / 10);
872 } while(intpart && (iplace < 20));
873 if (iplace == 20) iplace--;
874 iconvert[iplace] = 0;
876 /* Convert fractional part */
879 (caps? "0123456789ABCDEF":"0123456789abcdef")[fracpart % 10];
880 fracpart = (fracpart / 10);
881 } while(fracpart && (fplace < 20));
882 if (fplace == 20) fplace--;
883 fconvert[fplace] = 0;
885 /* -1 for decimal point, another -1 if we are printing a sign */
886 padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
887 zpadlen = max - fplace;
892 if (flags & DP_F_MINUS)
893 padlen = -padlen; /* Left Justifty */
895 if ((flags & DP_F_ZERO) && (padlen > 0))
899 dopr_outch (buffer, currlen, maxlen, signvalue);
905 dopr_outch (buffer, currlen, maxlen, '0');
911 dopr_outch (buffer, currlen, maxlen, ' ');
915 dopr_outch (buffer, currlen, maxlen, signvalue);
918 dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]);
921 * Decimal point. This should probably use locale to find the correct
924 dopr_outch (buffer, currlen, maxlen, '.');
927 dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]);
931 dopr_outch (buffer, currlen, maxlen, '0');
937 dopr_outch (buffer, currlen, maxlen, ' ');
942 static void dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c)
944 if (*currlen < maxlen)
945 buffer[(*currlen)++] = c;
947 #endif /* !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) */
949 #ifndef HAVE_VSNPRINTF
950 int vsnprintf (char *str, size_t count, const char *fmt, va_list args)
953 dopr(str, count, fmt, args);
956 #endif /* !HAVE_VSNPRINTF */
958 #ifndef HAVE_SNPRINTF
961 int snprintf (char *str,size_t count,const char *fmt,...)
963 int snprintf (va_alist) va_dcl
974 VA_SHIFT (str, char *);
975 VA_SHIFT (count, size_t );
976 VA_SHIFT (fmt, char *);
977 (void) vsnprintf(str, count, fmt, ap);
984 #define LONG_STRING 1024
988 char buf1[LONG_STRING];
989 char buf2[LONG_STRING];
1004 double fp_nums[] = { -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996,
1005 0.9996, 1.996, 4.136, 0};
1018 long int_nums[] = { -1, 134, 91340, 341, 0203, 0};
1023 printf ("Testing snprintf format codes against system sprintf...\n");
1025 for (x = 0; fp_fmt[x] != NULL ; x++)
1026 for (y = 0; fp_nums[y] != 0 ; y++)
1028 snprintf (buf1, sizeof (buf1), fp_fmt[x], fp_nums[y]);
1029 sprintf (buf2, fp_fmt[x], fp_nums[y]);
1030 if (strcmp (buf1, buf2))
1032 printf("snprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
1033 fp_fmt[x], buf1, buf2);
1039 for (x = 0; int_fmt[x] != NULL ; x++)
1040 for (y = 0; int_nums[y] != 0 ; y++)
1042 snprintf (buf1, sizeof (buf1), int_fmt[x], int_nums[y]);
1043 sprintf (buf2, int_fmt[x], int_nums[y]);
1044 if (strcmp (buf1, buf2))
1046 printf("snprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
1047 int_fmt[x], buf1, buf2);
1052 printf ("%d tests failed out of %d.\n", fail, num);
1054 #endif /* SNPRINTF_TEST */
1056 #endif /* !HAVE_SNPRINTF */