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++)
72 /* varargs declarations: */
75 # define MY_VA_LOCAL_DECL va_list ap
76 # define MY_VA_START(f) va_start(ap, f)
77 # define MY_VA_SHIFT(v,t) v = va_arg(ap, t)
78 # define MY_VA_END va_end(ap)
80 # error HAVE_STDARG_H not defined
84 strdup_printf (const char *format, ... )
88 char *buffer = xmalloc (size);
90 assert(format != NULL);
95 n = vsnprintf (buffer, size,
99 if (n > -1 && n < size)
107 buffer = xrealloc(buffer, size);
113 strconcat (const char *str, ...)
121 l = 1 + strlen (str);
123 MY_VA_SHIFT(s, char*);
126 MY_VA_SHIFT(s, char*);
132 strcpy (concat, str);
134 MY_VA_SHIFT(s, char*);
137 MY_VA_SHIFT(s, char*);
146 safe_strcmp(const char *s1, const char *s2)
148 if (s1 == NULL && s2 == NULL) return 0;
149 if (s1 == NULL) return -1;
150 if (s2 == NULL) return 1;
152 return strcmp(s1, s2);
156 safe_strcoll(const char *s1, const char *s2)
159 if (s1 == NULL && s2 == NULL) return 0;
160 if (s1 == NULL) return -1;
161 if (s2 == NULL) return 1;
163 return strcoll(s1, s2);
164 #else /* fall back to strcmp */
165 return safe_strcmp(s1, s2);
175 if( (dir = xmalloc(size)) == NULL)
180 while( getcwd(dir, size) == NULL && errno == ERANGE )
181 if( (dir = xrealloc(dir, size *=2)) == NULL)
190 * Copyright (c) 1994 Lars Wirzenius
191 * All rights reserved.
193 * Redistribution and use in source and binary forms, with or without
194 * modification, are permitted provided that the following conditions
196 * 1. Redistributions of source code must retain the above copyright
197 * notice, this list of conditions and the following disclaimer
198 * in this position and unchanged.
199 * 2. Redistributions in binary form must reproduce the above copyright
200 * notice, this list of conditions and the following disclaimer in the
201 * documentation and/or other materials provided with the distribution.
203 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
204 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
205 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
206 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
207 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
208 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
209 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
210 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
211 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
212 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
218 char *buf; /* buffer for line */
219 size_t size; /* size of buffer */
220 size_t inc; /* how much to enlarge buffer */
221 size_t len; /* # of chars stored into buf before '\0' */
223 const size_t thres = 128; /* initial buffer size (most lines should
224 fit into this size, so think of this as
225 the "long line threshold"). */
226 const size_t mucho = 128; /* if there is at least this much wasted
227 space when the whole buffer has been
228 read, try to reclaim it. Don't make
229 this too small, else there is too much
230 time wasted trying to reclaim a couple
232 const size_t mininc = 64; /* minimum number of bytes by which
233 to increase the allocated memory */
239 while (fgets(buf+len, size-len, f) != NULL) {
240 len += strlen(buf+len);
241 if (len > 0 && buf[len-1] == '\n')
242 break; /* the whole line has been read */
244 for (inc = size, p = NULL; inc > mininc; inc /= 2)
245 if ((p = xrealloc_inc(buf, size, inc)) !=
255 return NULL; /* nothing read (eof or error) */
258 if (buf[len-1] == '\n') /* remove newline, if there */
261 if (size - len > mucho) { /* a plenitude of unused memory? */
262 p = xrealloc_inc(buf, len, 1);
273 strwidth(const char *s)
276 return mbswidth(s, 0);
280 bytes2width(const char *s, int width)
283 #ifdef HANDLE_MULTIBYTE
284 return mbsnbytes(s, strlen(s), width, 0);
290 /**************************************************************
292 * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
293 * A bombproof version of doprnt (dopr) included.
294 * Sigh. This sort of thing is always nasty do deal with. Note that
295 * the version here does not include floating point...
297 * snprintf() is used instead of sprintf() as it does limit checks
298 * for string length. This covers a nasty loophole.
300 * The other functions are there to prevent NULL pointers from
301 * causing nast effects.
304 * Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43
305 * This was ugly. It is still ugly. I opted out of floating point
306 * numbers, but the formatter understands just about everything
307 * from the normal C string format, at least as far as I can tell from
308 * the Solaris 2.5 printf(3S) man page.
310 * Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1
311 * Ok, added some minimal floating point support, which means this
312 * probably requires libm on most operating systems. Don't yet
313 * support the exponent (e,E) and sigfig (g,G). Also, fmtint()
314 * was pretty badly broken, it just wasn't being exercised in ways
315 * which showed it, so that's been fixed. Also, formated the code
316 * to mutt conventions, and removed dead code left over from the
317 * original. Also, there is now a builtin-test, just compile with:
318 * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
319 * and run snprintf for results.
321 * Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i
322 * The PGP code was using unsigned hexadecimal formats.
323 * Unfortunately, unsigned formats simply didn't work.
325 * Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8
326 * The original code assumed that both snprintf() and vsnprintf() were
327 * missing. Some systems only have snprintf() but not vsnprintf(), so
328 * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
330 **************************************************************/
334 #if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF)
338 #include <sys/types.h>
340 /* Define this as a fall through, HAVE_STDARG_H is probably already set */
342 #if !defined(HAVE_STDARG_H) && !defined(HAVE_VARARGS_H)
343 # define HAVE_VARARGS_H 1
346 /* varargs declarations: */
348 #if defined(HAVE_STDARG_H)
349 /*# include <stdarg.h>*/
350 # define HAVE_STDARGS /* let's hope that works everywhere (mj) */
351 # define VA_LOCAL_DECL va_list ap
352 # define VA_START(f) va_start(ap, f)
353 # define VA_SHIFT(v,t) ; /* no-op for ANSI */
354 # define VA_END va_end(ap)
356 # if defined(HAVE_VARARGS_H)
357 # include <varargs.h>
359 # define VA_LOCAL_DECL va_list ap
360 # define VA_START(f) va_start(ap) /* f is ignored! */
361 # define VA_SHIFT(v,t) v = va_arg(ap,t)
362 # define VA_END va_end(ap)
364 /*XX ** NO VARARGS ** XX*/
368 /*int snprintf (char *str, size_t count, const char *fmt, ...);*/
369 /*int vsnprintf (char *str, size_t count, const char *fmt, va_list arg);*/
371 static void dopr (char *buffer, size_t maxlen, const char *format,
373 static void fmtstr (char *buffer, size_t *currlen, size_t maxlen,
374 char *value, int flags, int min, int max);
375 static void fmtint (char *buffer, size_t *currlen, size_t maxlen,
376 long value, int base, int min, int max, int flags);
377 static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
378 long double fvalue, int min, int max, int flags);
379 static void dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c );
382 * dopr(): poor man's version of doprintf
385 /* format read states */
386 #define DP_S_DEFAULT 0
395 /* format flags - Bits */
396 #define DP_F_MINUS (1 << 0)
397 #define DP_F_PLUS (1 << 1)
398 #define DP_F_SPACE (1 << 2)
399 #define DP_F_NUM (1 << 3)
400 #define DP_F_ZERO (1 << 4)
401 #define DP_F_UP (1 << 5)
402 #define DP_F_UNSIGNED (1 << 6)
404 /* Conversion Flags */
407 #define DP_C_LDOUBLE 3
409 #define char_to_int(p) (p - '0')
410 #define MAX(p,q) ((p >= q) ? p : q)
412 static void dopr (char *buffer, size_t maxlen, const char *format, va_list args)
425 state = DP_S_DEFAULT;
426 currlen = flags = cflags = min = 0;
430 while (state != DP_S_DONE)
432 if ((ch == '\0') || (currlen >= maxlen))
441 dopr_outch (buffer, &currlen, maxlen, ch);
473 if (isdigit((unsigned char)ch))
475 min = 10*min + char_to_int (ch);
480 min = va_arg (args, int);
497 if (isdigit((unsigned char)ch))
501 max = 10*max + char_to_int (ch);
506 max = va_arg (args, int);
514 /* Currently, we don't support Long Long, bummer */
526 cflags = DP_C_LDOUBLE;
539 if (cflags == DP_C_SHORT)
540 value = va_arg (args, short int);
541 else if (cflags == DP_C_LONG)
542 value = va_arg (args, long int);
544 value = va_arg (args, int);
545 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, 8, min, max, flags);
558 flags |= DP_F_UNSIGNED;
559 if (cflags == DP_C_SHORT)
560 value = va_arg (args, unsigned short int);
561 else if (cflags == DP_C_LONG)
562 value = va_arg (args, unsigned long int);
564 value = va_arg (args, unsigned int);
565 fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
570 flags |= DP_F_UNSIGNED;
571 if (cflags == DP_C_SHORT)
572 value = va_arg (args, unsigned short int);
573 else if (cflags == DP_C_LONG)
574 value = va_arg (args, unsigned long int);
576 value = va_arg (args, unsigned int);
577 fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags);
580 if (cflags == DP_C_LDOUBLE)
581 fvalue = va_arg (args, long double);
583 fvalue = va_arg (args, double);
584 /* um, floating point? */
585 fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
590 if (cflags == DP_C_LDOUBLE)
591 fvalue = va_arg (args, long double);
593 fvalue = va_arg (args, double);
598 if (cflags == DP_C_LDOUBLE)
599 fvalue = va_arg (args, long double);
601 fvalue = va_arg (args, double);
604 dopr_outch (buffer, &currlen, maxlen, va_arg (args, int));
607 strvalue = va_arg (args, char *);
609 max = maxlen; /* ie, no max */
610 fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max);
613 strvalue = va_arg (args, void *);
614 fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags);
617 if (cflags == DP_C_SHORT)
620 num = va_arg (args, short int *);
623 else if (cflags == DP_C_LONG)
626 num = va_arg (args, long int *);
632 num = va_arg (args, int *);
637 dopr_outch (buffer, &currlen, maxlen, ch);
640 /* not supported yet, treat as next char */
648 state = DP_S_DEFAULT;
649 flags = cflags = min = 0;
656 break; /* some picky compilers need this */
659 if (currlen < maxlen - 1)
660 buffer[currlen] = '\0';
662 buffer[maxlen - 1] = '\0';
665 static void fmtstr (char *buffer, size_t *currlen, size_t maxlen,
666 char *value, int flags, int min, int max)
668 int padlen, strln; /* amount to pad */
676 for (strln = 0; value[strln]; ++strln); /* strlen */
677 padlen = min - strln;
680 if (flags & DP_F_MINUS)
681 padlen = -padlen; /* Left Justify */
683 while ((padlen > 0) && (cnt < max))
685 dopr_outch (buffer, currlen, maxlen, ' ');
689 while (*value && (cnt < max))
691 dopr_outch (buffer, currlen, maxlen, *value++);
694 while ((padlen < 0) && (cnt < max))
696 dopr_outch (buffer, currlen, maxlen, ' ');
702 /* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
704 static void fmtint (char *buffer, size_t *currlen, size_t maxlen,
705 long value, int base, int min, int max, int flags)
708 unsigned long uvalue;
711 int spadlen = 0; /* amount to space pad */
712 int zpadlen = 0; /* amount to zero pad */
720 if(!(flags & DP_F_UNSIGNED))
727 if (flags & DP_F_PLUS) /* Do a sign (+/i) */
730 if (flags & DP_F_SPACE)
734 if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
738 (caps? "0123456789ABCDEF":"0123456789abcdef")
739 [uvalue % (unsigned)base ];
740 uvalue = (uvalue / (unsigned)base );
741 } while(uvalue && (place < 20));
742 if (place == 20) place--;
745 zpadlen = max - place;
746 spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
747 if (zpadlen < 0) zpadlen = 0;
748 if (spadlen < 0) spadlen = 0;
749 if (flags & DP_F_ZERO)
751 zpadlen = MAX(zpadlen, spadlen);
754 if (flags & DP_F_MINUS)
755 spadlen = -spadlen; /* Left Justifty */
757 #ifdef DEBUG_SNPRINTF
758 dprint (1, (debugfile, "zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
759 zpadlen, spadlen, min, max, place));
765 dopr_outch (buffer, currlen, maxlen, ' ');
771 dopr_outch (buffer, currlen, maxlen, signvalue);
778 dopr_outch (buffer, currlen, maxlen, '0');
785 dopr_outch (buffer, currlen, maxlen, convert[--place]);
787 /* Left Justified spaces */
788 while (spadlen < 0) {
789 dopr_outch (buffer, currlen, maxlen, ' ');
794 static long double abs_val (long double value)
796 long double result = value;
804 static long double pow10 (int exp)
806 long double result = 1;
817 static long round (long double value)
822 value = value - intpart;
829 static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
830 long double fvalue, int min, int max, int flags)
838 int padlen = 0; /* amount to pad */
845 * AIX manpage says the default is 0, but Solaris says the default
846 * is 6, and sprintf on AIX defaults to 6
851 ufvalue = abs_val (fvalue);
856 if (flags & DP_F_PLUS) /* Do a sign (+/i) */
859 if (flags & DP_F_SPACE)
863 if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
869 * Sorry, we only support 9 digits past the decimal because of our
875 /* We "cheat" by converting the fractional part to integer by
876 * multiplying by a factor of 10
878 fracpart = round ((pow10 (max)) * (ufvalue - intpart));
880 if (fracpart >= pow10 (max))
883 fracpart -= pow10 (max);
886 #ifdef DEBUG_SNPRINTF
887 dprint (1, (debugfile, "fmtfp: %f =? %d.%d\n", fvalue, intpart, fracpart));
890 /* Convert integer part */
893 (caps? "0123456789ABCDEF":"0123456789abcdef")[intpart % 10];
894 intpart = (intpart / 10);
895 } while(intpart && (iplace < 20));
896 if (iplace == 20) iplace--;
897 iconvert[iplace] = 0;
899 /* Convert fractional part */
902 (caps? "0123456789ABCDEF":"0123456789abcdef")[fracpart % 10];
903 fracpart = (fracpart / 10);
904 } while(fracpart && (fplace < 20));
905 if (fplace == 20) fplace--;
906 fconvert[fplace] = 0;
908 /* -1 for decimal point, another -1 if we are printing a sign */
909 padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
910 zpadlen = max - fplace;
915 if (flags & DP_F_MINUS)
916 padlen = -padlen; /* Left Justifty */
918 if ((flags & DP_F_ZERO) && (padlen > 0))
922 dopr_outch (buffer, currlen, maxlen, signvalue);
928 dopr_outch (buffer, currlen, maxlen, '0');
934 dopr_outch (buffer, currlen, maxlen, ' ');
938 dopr_outch (buffer, currlen, maxlen, signvalue);
941 dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]);
944 * Decimal point. This should probably use locale to find the correct
947 dopr_outch (buffer, currlen, maxlen, '.');
950 dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]);
954 dopr_outch (buffer, currlen, maxlen, '0');
960 dopr_outch (buffer, currlen, maxlen, ' ');
965 static void dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c)
967 if (*currlen < maxlen)
968 buffer[(*currlen)++] = c;
970 #endif /* !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) */
972 #ifndef HAVE_VSNPRINTF
973 int vsnprintf (char *str, size_t count, const char *fmt, va_list args)
976 dopr(str, count, fmt, args);
979 #endif /* !HAVE_VSNPRINTF */
981 #ifndef HAVE_SNPRINTF
984 int snprintf (char *str,size_t count,const char *fmt,...)
986 int snprintf (va_alist) va_dcl
997 VA_SHIFT (str, char *);
998 VA_SHIFT (count, size_t );
999 VA_SHIFT (fmt, char *);
1000 (void) vsnprintf(str, count, fmt, ap);
1002 return(strlen(str));
1005 #ifdef TEST_SNPRINTF
1007 #define LONG_STRING 1024
1011 char buf1[LONG_STRING];
1012 char buf2[LONG_STRING];
1027 double fp_nums[] = { -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996,
1028 0.9996, 1.996, 4.136, 0};
1041 long int_nums[] = { -1, 134, 91340, 341, 0203, 0};
1046 printf ("Testing snprintf format codes against system sprintf...\n");
1048 for (x = 0; fp_fmt[x] != NULL ; x++)
1049 for (y = 0; fp_nums[y] != 0 ; y++)
1051 snprintf (buf1, sizeof (buf1), fp_fmt[x], fp_nums[y]);
1052 sprintf (buf2, fp_fmt[x], fp_nums[y]);
1053 if (strcmp (buf1, buf2))
1055 printf("snprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
1056 fp_fmt[x], buf1, buf2);
1062 for (x = 0; int_fmt[x] != NULL ; x++)
1063 for (y = 0; int_nums[y] != 0 ; y++)
1065 snprintf (buf1, sizeof (buf1), int_fmt[x], int_nums[y]);
1066 sprintf (buf2, int_fmt[x], int_nums[y]);
1067 if (strcmp (buf1, buf2))
1069 printf("snprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
1070 int_fmt[x], buf1, buf2);
1075 printf ("%d tests failed out of %d.\n", fail, num);
1077 #endif /* SNPRINTF_TEST */
1079 #endif /* !HAVE_SNPRINTF */
1085 * List handling functions
1089 abook_list_append(abook_list **list, char *str)
1096 for(tmp = *list; tmp && tmp->next; tmp = tmp->next)
1100 tmp->next = xmalloc(sizeof(abook_list));
1103 tmp = *list = xmalloc(sizeof(abook_list));
1105 tmp->data = xstrdup(str);
1110 abook_list_free(abook_list **list)
1112 abook_list *prev = NULL, *tmp = *list;
1128 csv_to_abook_list(char *str)
1130 char *start, *p = str, *end;
1131 abook_list *list = NULL;
1140 if(!strchr(", ", *p)) {
1145 if((*p == ',') && (end - start)) {
1146 abook_list_append(&list, xstrndup(start, end - start));
1156 abook_list_append(&list, xstrndup(start, end - start));
1162 abook_list_to_csv(abook_list *list)
1167 for(tmp = list; tmp; tmp = tmp->next) {
1169 res = xstrdup(tmp->data);
1171 res = xrealloc(res, strlen(res)+strlen(tmp->data)+2);
1173 strcat(res, tmp->data);
1181 abook_list_rotate(abook_list **list, enum rotate_dir dir)
1183 abook_list *tmp = *list;
1185 if(!tmp || !tmp->next)
1190 for(; tmp && tmp->next; tmp = tmp->next)
1195 *list = (*list)->next;
1199 for(; tmp && tmp->next && tmp->next->next;
1203 tmp->next->next = *list;
1212 /* if str == NULL, deleting the list element */
1214 abook_list_replace(abook_list **list, int index, char *str)
1216 abook_list *cur, *prev;
1221 if((index == 0) && !str) {
1242 cur->data = xstrdup(str);
1244 prev->next = cur->next;
1251 abook_list_get(abook_list *list, int index)