5 * by JH <jheinonen@users.sourceforge.net>
7 * Copyright (C) Jaakko Heinonen
8 * getaline() Copyright (C) Lars Wirzenius
9 * sprintf and snprintf copyright is owned by various people
41 while( ( *str = tolower ( *str ) ) )
54 for(t = s; isspace(*t); t++);
56 memmove(s, t, strlen(t)+1);
58 for (tt = t = s; *t != '\0'; t++)
70 if(!p || !*p || (*p == '-' && !*++p))
80 #ifndef HAVE_STRCASESTR
82 strcasestr(const char *haystack, const char *needle)
87 assert(haystack != NULL);
88 assert(needle != NULL);
90 for(i=0; i<strlen(haystack)-strlen(needle)+1; i++) {
91 for(k=0; k<strlen(needle); k++, i++) {
92 if (tolower(haystack[i]) != tolower(needle[k]))
94 else if ((k+1) == strlen(needle))
107 /* varargs declarations: */
110 # define MY_VA_LOCAL_DECL va_list ap
111 # define MY_VA_START(f) va_start(ap, f)
112 # define MY_VA_SHIFT(v,t) v = va_arg(ap, t)
113 # define MY_VA_END va_end(ap)
115 # error HAVE_STDARG_H not defined
119 strdup_printf (const char *format, ... )
123 char *buffer = xmalloc (size);
125 assert(format != NULL);
130 n = vsnprintf (buffer, size,
134 if (n > -1 && n < size)
142 buffer = xrealloc(buffer, size);
148 strconcat (const char *str, ...)
156 l = 1 + strlen (str);
158 MY_VA_SHIFT(s, char*);
161 MY_VA_SHIFT(s, char*);
167 strcpy (concat, str);
169 MY_VA_SHIFT(s, char*);
172 MY_VA_SHIFT(s, char*);
181 safe_strcmp(const char *s1, const char *s2)
183 if (s1 == NULL && s2 == NULL) return 0;
184 if (s1 == NULL) return -1;
185 if (s2 == NULL) return 1;
187 return strcmp(s1, s2);
191 safe_strcoll(const char *s1, const char *s2)
194 if (s1 == NULL && s2 == NULL) return 0;
195 if (s1 == NULL) return -1;
196 if (s2 == NULL) return 1;
198 return strcoll(s1, s2);
199 #else /* fall back to strcmp */
200 return safe_strcmp(s1, s2);
210 if( (dir = xmalloc(size)) == NULL)
215 while( getcwd(dir, size) == NULL && errno == ERANGE )
216 if( (dir = xrealloc(dir, size *=2)) == NULL)
225 * Copyright (c) 1994 Lars Wirzenius
226 * All rights reserved.
228 * Redistribution and use in source and binary forms, with or without
229 * modification, are permitted provided that the following conditions
231 * 1. Redistributions of source code must retain the above copyright
232 * notice, this list of conditions and the following disclaimer
233 * in this position and unchanged.
234 * 2. Redistributions in binary form must reproduce the above copyright
235 * notice, this list of conditions and the following disclaimer in the
236 * documentation and/or other materials provided with the distribution.
238 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
239 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
240 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
241 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
242 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
243 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
244 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
245 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
246 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
247 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
253 char *buf; /* buffer for line */
254 size_t size; /* size of buffer */
255 size_t inc; /* how much to enlarge buffer */
256 size_t len; /* # of chars stored into buf before '\0' */
258 const size_t thres = 128; /* initial buffer size (most lines should
259 fit into this size, so think of this as
260 the "long line threshold"). */
261 const size_t mucho = 128; /* if there is at least this much wasted
262 space when the whole buffer has been
263 read, try to reclaim it. Don't make
264 this too small, else there is too much
265 time wasted trying to reclaim a couple
267 const size_t mininc = 64; /* minimum number of bytes by which
268 to increase the allocated memory */
274 while (fgets(buf+len, size-len, f) != NULL) {
275 len += strlen(buf+len);
276 if (len > 0 && buf[len-1] == '\n')
277 break; /* the whole line has been read */
279 for (inc = size, p = NULL; inc > mininc; inc /= 2)
280 if ((p = xrealloc_inc(buf, size, inc)) !=
290 return NULL; /* nothing read (eof or error) */
293 if (buf[len-1] == '\n') /* remove newline, if there */
296 if (size - len > mucho) { /* a plenitude of unused memory? */
297 p = xrealloc_inc(buf, len, 1);
308 strwidth(const char *s)
311 return mbswidth(s, 0);
315 bytes2width(const char *s, int width)
318 #ifdef HANDLE_MULTIBYTE
319 return mbsnbytes(s, strlen(s), width, 0);
325 /**************************************************************
327 * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
328 * A bombproof version of doprnt (dopr) included.
329 * Sigh. This sort of thing is always nasty do deal with. Note that
330 * the version here does not include floating point...
332 * snprintf() is used instead of sprintf() as it does limit checks
333 * for string length. This covers a nasty loophole.
335 * The other functions are there to prevent NULL pointers from
336 * causing nast effects.
339 * Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43
340 * This was ugly. It is still ugly. I opted out of floating point
341 * numbers, but the formatter understands just about everything
342 * from the normal C string format, at least as far as I can tell from
343 * the Solaris 2.5 printf(3S) man page.
345 * Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1
346 * Ok, added some minimal floating point support, which means this
347 * probably requires libm on most operating systems. Don't yet
348 * support the exponent (e,E) and sigfig (g,G). Also, fmtint()
349 * was pretty badly broken, it just wasn't being exercised in ways
350 * which showed it, so that's been fixed. Also, formated the code
351 * to mutt conventions, and removed dead code left over from the
352 * original. Also, there is now a builtin-test, just compile with:
353 * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
354 * and run snprintf for results.
356 * Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i
357 * The PGP code was using unsigned hexadecimal formats.
358 * Unfortunately, unsigned formats simply didn't work.
360 * Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8
361 * The original code assumed that both snprintf() and vsnprintf() were
362 * missing. Some systems only have snprintf() but not vsnprintf(), so
363 * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
365 **************************************************************/
369 #if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF)
373 #include <sys/types.h>
375 /* Define this as a fall through, HAVE_STDARG_H is probably already set */
377 #if !defined(HAVE_STDARG_H) && !defined(HAVE_VARARGS_H)
378 # define HAVE_VARARGS_H 1
381 /* varargs declarations: */
383 #if defined(HAVE_STDARG_H)
384 /*# include <stdarg.h>*/
385 # define HAVE_STDARGS /* let's hope that works everywhere (mj) */
386 # define VA_LOCAL_DECL va_list ap
387 # define VA_START(f) va_start(ap, f)
388 # define VA_SHIFT(v,t) ; /* no-op for ANSI */
389 # define VA_END va_end(ap)
391 # if defined(HAVE_VARARGS_H)
392 # include <varargs.h>
394 # define VA_LOCAL_DECL va_list ap
395 # define VA_START(f) va_start(ap) /* f is ignored! */
396 # define VA_SHIFT(v,t) v = va_arg(ap,t)
397 # define VA_END va_end(ap)
399 /*XX ** NO VARARGS ** XX*/
403 /*int snprintf (char *str, size_t count, const char *fmt, ...);*/
404 /*int vsnprintf (char *str, size_t count, const char *fmt, va_list arg);*/
406 static void dopr (char *buffer, size_t maxlen, const char *format,
408 static void fmtstr (char *buffer, size_t *currlen, size_t maxlen,
409 char *value, int flags, int min, int max);
410 static void fmtint (char *buffer, size_t *currlen, size_t maxlen,
411 long value, int base, int min, int max, int flags);
412 static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
413 long double fvalue, int min, int max, int flags);
414 static void dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c );
417 * dopr(): poor man's version of doprintf
420 /* format read states */
421 #define DP_S_DEFAULT 0
430 /* format flags - Bits */
431 #define DP_F_MINUS (1 << 0)
432 #define DP_F_PLUS (1 << 1)
433 #define DP_F_SPACE (1 << 2)
434 #define DP_F_NUM (1 << 3)
435 #define DP_F_ZERO (1 << 4)
436 #define DP_F_UP (1 << 5)
437 #define DP_F_UNSIGNED (1 << 6)
439 /* Conversion Flags */
442 #define DP_C_LDOUBLE 3
444 #define char_to_int(p) (p - '0')
445 #define MAX(p,q) ((p >= q) ? p : q)
447 static void dopr (char *buffer, size_t maxlen, const char *format, va_list args)
460 state = DP_S_DEFAULT;
461 currlen = flags = cflags = min = 0;
465 while (state != DP_S_DONE)
467 if ((ch == '\0') || (currlen >= maxlen))
476 dopr_outch (buffer, &currlen, maxlen, ch);
508 if (isdigit((unsigned char)ch))
510 min = 10*min + char_to_int (ch);
515 min = va_arg (args, int);
532 if (isdigit((unsigned char)ch))
536 max = 10*max + char_to_int (ch);
541 max = va_arg (args, int);
549 /* Currently, we don't support Long Long, bummer */
561 cflags = DP_C_LDOUBLE;
574 if (cflags == DP_C_SHORT)
575 value = va_arg (args, short int);
576 else if (cflags == DP_C_LONG)
577 value = va_arg (args, long int);
579 value = va_arg (args, int);
580 fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
583 flags |= DP_F_UNSIGNED;
584 if (cflags == DP_C_SHORT)
585 value = va_arg (args, unsigned short int);
586 else if (cflags == DP_C_LONG)
587 value = va_arg (args, unsigned long int);
589 value = va_arg (args, unsigned int);
590 fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags);
593 flags |= DP_F_UNSIGNED;
594 if (cflags == DP_C_SHORT)
595 value = va_arg (args, unsigned short int);
596 else if (cflags == DP_C_LONG)
597 value = va_arg (args, unsigned long int);
599 value = va_arg (args, unsigned int);
600 fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
605 flags |= DP_F_UNSIGNED;
606 if (cflags == DP_C_SHORT)
607 value = va_arg (args, unsigned short int);
608 else if (cflags == DP_C_LONG)
609 value = va_arg (args, unsigned long int);
611 value = va_arg (args, unsigned int);
612 fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags);
615 if (cflags == DP_C_LDOUBLE)
616 fvalue = va_arg (args, long double);
618 fvalue = va_arg (args, double);
619 /* um, floating point? */
620 fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
625 if (cflags == DP_C_LDOUBLE)
626 fvalue = va_arg (args, long double);
628 fvalue = va_arg (args, double);
633 if (cflags == DP_C_LDOUBLE)
634 fvalue = va_arg (args, long double);
636 fvalue = va_arg (args, double);
639 dopr_outch (buffer, &currlen, maxlen, va_arg (args, int));
642 strvalue = va_arg (args, char *);
644 max = maxlen; /* ie, no max */
645 fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max);
648 strvalue = va_arg (args, void *);
649 fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags);
652 if (cflags == DP_C_SHORT)
655 num = va_arg (args, short int *);
658 else if (cflags == DP_C_LONG)
661 num = va_arg (args, long int *);
667 num = va_arg (args, int *);
672 dopr_outch (buffer, &currlen, maxlen, ch);
675 /* not supported yet, treat as next char */
683 state = DP_S_DEFAULT;
684 flags = cflags = min = 0;
691 break; /* some picky compilers need this */
694 if (currlen < maxlen - 1)
695 buffer[currlen] = '\0';
697 buffer[maxlen - 1] = '\0';
700 static void fmtstr (char *buffer, size_t *currlen, size_t maxlen,
701 char *value, int flags, int min, int max)
703 int padlen, strln; /* amount to pad */
711 for (strln = 0; value[strln]; ++strln); /* strlen */
712 padlen = min - strln;
715 if (flags & DP_F_MINUS)
716 padlen = -padlen; /* Left Justify */
718 while ((padlen > 0) && (cnt < max))
720 dopr_outch (buffer, currlen, maxlen, ' ');
724 while (*value && (cnt < max))
726 dopr_outch (buffer, currlen, maxlen, *value++);
729 while ((padlen < 0) && (cnt < max))
731 dopr_outch (buffer, currlen, maxlen, ' ');
737 /* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
739 static void fmtint (char *buffer, size_t *currlen, size_t maxlen,
740 long value, int base, int min, int max, int flags)
743 unsigned long uvalue;
746 int spadlen = 0; /* amount to space pad */
747 int zpadlen = 0; /* amount to zero pad */
755 if(!(flags & DP_F_UNSIGNED))
762 if (flags & DP_F_PLUS) /* Do a sign (+/i) */
765 if (flags & DP_F_SPACE)
769 if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
773 (caps? "0123456789ABCDEF":"0123456789abcdef")
774 [uvalue % (unsigned)base ];
775 uvalue = (uvalue / (unsigned)base );
776 } while(uvalue && (place < 20));
777 if (place == 20) place--;
780 zpadlen = max - place;
781 spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
782 if (zpadlen < 0) zpadlen = 0;
783 if (spadlen < 0) spadlen = 0;
784 if (flags & DP_F_ZERO)
786 zpadlen = MAX(zpadlen, spadlen);
789 if (flags & DP_F_MINUS)
790 spadlen = -spadlen; /* Left Justifty */
792 #ifdef DEBUG_SNPRINTF
793 dprint (1, (debugfile, "zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
794 zpadlen, spadlen, min, max, place));
800 dopr_outch (buffer, currlen, maxlen, ' ');
806 dopr_outch (buffer, currlen, maxlen, signvalue);
813 dopr_outch (buffer, currlen, maxlen, '0');
820 dopr_outch (buffer, currlen, maxlen, convert[--place]);
822 /* Left Justified spaces */
823 while (spadlen < 0) {
824 dopr_outch (buffer, currlen, maxlen, ' ');
829 static long double abs_val (long double value)
831 long double result = value;
839 static long double pow10 (int exp)
841 long double result = 1;
852 static long round (long double value)
857 value = value - intpart;
864 static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
865 long double fvalue, int min, int max, int flags)
873 int padlen = 0; /* amount to pad */
880 * AIX manpage says the default is 0, but Solaris says the default
881 * is 6, and sprintf on AIX defaults to 6
886 ufvalue = abs_val (fvalue);
891 if (flags & DP_F_PLUS) /* Do a sign (+/i) */
894 if (flags & DP_F_SPACE)
898 if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
904 * Sorry, we only support 9 digits past the decimal because of our
910 /* We "cheat" by converting the fractional part to integer by
911 * multiplying by a factor of 10
913 fracpart = round ((pow10 (max)) * (ufvalue - intpart));
915 if (fracpart >= pow10 (max))
918 fracpart -= pow10 (max);
921 #ifdef DEBUG_SNPRINTF
922 dprint (1, (debugfile, "fmtfp: %f =? %d.%d\n", fvalue, intpart, fracpart));
925 /* Convert integer part */
928 (caps? "0123456789ABCDEF":"0123456789abcdef")[intpart % 10];
929 intpart = (intpart / 10);
930 } while(intpart && (iplace < 20));
931 if (iplace == 20) iplace--;
932 iconvert[iplace] = 0;
934 /* Convert fractional part */
937 (caps? "0123456789ABCDEF":"0123456789abcdef")[fracpart % 10];
938 fracpart = (fracpart / 10);
939 } while(fracpart && (fplace < 20));
940 if (fplace == 20) fplace--;
941 fconvert[fplace] = 0;
943 /* -1 for decimal point, another -1 if we are printing a sign */
944 padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
945 zpadlen = max - fplace;
950 if (flags & DP_F_MINUS)
951 padlen = -padlen; /* Left Justifty */
953 if ((flags & DP_F_ZERO) && (padlen > 0))
957 dopr_outch (buffer, currlen, maxlen, signvalue);
963 dopr_outch (buffer, currlen, maxlen, '0');
969 dopr_outch (buffer, currlen, maxlen, ' ');
973 dopr_outch (buffer, currlen, maxlen, signvalue);
976 dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]);
979 * Decimal point. This should probably use locale to find the correct
982 dopr_outch (buffer, currlen, maxlen, '.');
985 dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]);
989 dopr_outch (buffer, currlen, maxlen, '0');
995 dopr_outch (buffer, currlen, maxlen, ' ');
1000 static void dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c)
1002 if (*currlen < maxlen)
1003 buffer[(*currlen)++] = c;
1005 #endif /* !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) */
1007 #ifndef HAVE_VSNPRINTF
1008 int vsnprintf (char *str, size_t count, const char *fmt, va_list args)
1011 dopr(str, count, fmt, args);
1012 return(strlen(str));
1014 #endif /* !HAVE_VSNPRINTF */
1016 #ifndef HAVE_SNPRINTF
1019 int snprintf (char *str,size_t count,const char *fmt,...)
1021 int snprintf (va_alist) va_dcl
1024 #ifndef HAVE_STDARGS
1032 VA_SHIFT (str, char *);
1033 VA_SHIFT (count, size_t );
1034 VA_SHIFT (fmt, char *);
1035 (void) vsnprintf(str, count, fmt, ap);
1037 return(strlen(str));
1040 #ifdef TEST_SNPRINTF
1042 #define LONG_STRING 1024
1046 char buf1[LONG_STRING];
1047 char buf2[LONG_STRING];
1062 double fp_nums[] = { -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996,
1063 0.9996, 1.996, 4.136, 0};
1076 long int_nums[] = { -1, 134, 91340, 341, 0203, 0};
1081 printf ("Testing snprintf format codes against system sprintf...\n");
1083 for (x = 0; fp_fmt[x] != NULL ; x++)
1084 for (y = 0; fp_nums[y] != 0 ; y++)
1086 snprintf (buf1, sizeof (buf1), fp_fmt[x], fp_nums[y]);
1087 sprintf (buf2, fp_fmt[x], fp_nums[y]);
1088 if (strcmp (buf1, buf2))
1090 printf("snprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
1091 fp_fmt[x], buf1, buf2);
1097 for (x = 0; int_fmt[x] != NULL ; x++)
1098 for (y = 0; int_nums[y] != 0 ; y++)
1100 snprintf (buf1, sizeof (buf1), int_fmt[x], int_nums[y]);
1101 sprintf (buf2, int_fmt[x], int_nums[y]);
1102 if (strcmp (buf1, buf2))
1104 printf("snprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
1105 int_fmt[x], buf1, buf2);
1110 printf ("%d tests failed out of %d.\n", fail, num);
1112 #endif /* SNPRINTF_TEST */
1114 #endif /* !HAVE_SNPRINTF */
1120 * List handling functions
1124 abook_list_append(abook_list **list, char *str)
1131 for(tmp = *list; tmp && tmp->next; tmp = tmp->next)
1135 tmp->next = xmalloc(sizeof(abook_list));
1138 tmp = *list = xmalloc(sizeof(abook_list));
1140 tmp->data = xstrdup(str);
1145 abook_list_free(abook_list **list)
1147 abook_list *prev = NULL, *tmp = *list;
1163 csv_to_abook_list(char *str)
1165 char *start, *p = str, *end;
1166 abook_list *list = NULL;
1175 if(!strchr(", ", *p)) {
1180 if((*p == ',') && (end - start)) {
1181 abook_list_append(&list, xstrndup(start, end - start));
1191 abook_list_append(&list, xstrndup(start, end - start));
1197 abook_list_to_csv(abook_list *list)
1202 for(tmp = list; tmp; tmp = tmp->next) {
1204 res = xstrdup(tmp->data);
1206 res = xrealloc(res, strlen(res)+strlen(tmp->data)+2);
1208 strcat(res, tmp->data);
1216 abook_list_rotate(abook_list **list, enum rotate_dir dir)
1218 abook_list *tmp = *list;
1220 if(!tmp || !tmp->next)
1225 for(; tmp && tmp->next; tmp = tmp->next)
1230 *list = (*list)->next;
1234 for(; tmp && tmp->next && tmp->next->next;
1238 tmp->next->next = *list;
1247 /* if str == NULL, deleting the list element */
1249 abook_list_replace(abook_list **list, int index, char *str)
1251 abook_list *cur, *prev;
1256 if((index == 0) && !str) {
1277 cur->data = xstrdup(str);
1279 prev->next = cur->next;
1286 abook_list_get(abook_list *list, int index)