3 * $Id: misc.c,v 1.23 2006/09/04 18:29:25 cduval Exp $
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))
85 /* varargs declarations: */
88 # define MY_VA_LOCAL_DECL va_list ap
89 # define MY_VA_START(f) va_start(ap, f)
90 # define MY_VA_SHIFT(v,t) v = va_arg(ap, t)
91 # define MY_VA_END va_end(ap)
93 # error HAVE_STDARG_H not defined
97 strdup_printf (const char *format, ... )
101 char *buffer = xmalloc (size);
103 assert(format != NULL);
108 n = vsnprintf (buffer, size,
112 if (n > -1 && n < size)
120 buffer = xrealloc(buffer, size);
126 strconcat (const char *str, ...)
134 l = 1 + strlen (str);
136 MY_VA_SHIFT(s, char*);
139 MY_VA_SHIFT(s, char*);
145 strcpy (concat, str);
147 MY_VA_SHIFT(s, char*);
150 MY_VA_SHIFT(s, char*);
159 safe_strcmp(const char *s1, const char *s2)
161 if (s1 == NULL && s2 == NULL) return 0;
162 if (s1 == NULL) return -1;
163 if (s2 == NULL) return 1;
165 return strcmp(s1, s2);
169 safe_strcoll(const char *s1, const char *s2)
172 if (s1 == NULL && s2 == NULL) return 0;
173 if (s1 == NULL) return -1;
174 if (s2 == NULL) return 1;
176 return strcoll(s1, s2);
177 #else /* fall back to strcmp */
178 return safe_strcmp(s1, s2);
188 if( (dir = xmalloc(size)) == NULL)
193 while( getcwd(dir, size) == NULL && errno == ERANGE )
194 if( (dir = xrealloc(dir, size *=2)) == NULL)
203 * Copyright (c) 1994 Lars Wirzenius
204 * All rights reserved.
206 * Redistribution and use in source and binary forms, with or without
207 * modification, are permitted provided that the following conditions
209 * 1. Redistributions of source code must retain the above copyright
210 * notice, this list of conditions and the following disclaimer
211 * in this position and unchanged.
212 * 2. Redistributions in binary form must reproduce the above copyright
213 * notice, this list of conditions and the following disclaimer in the
214 * documentation and/or other materials provided with the distribution.
216 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
217 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
218 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
219 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
220 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
221 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
222 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
223 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
224 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
225 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
231 char *buf; /* buffer for line */
232 size_t size; /* size of buffer */
233 size_t inc; /* how much to enlarge buffer */
234 size_t len; /* # of chars stored into buf before '\0' */
236 const size_t thres = 128; /* initial buffer size (most lines should
237 fit into this size, so think of this as
238 the "long line threshold"). */
239 const size_t mucho = 128; /* if there is at least this much wasted
240 space when the whole buffer has been
241 read, try to reclaim it. Don't make
242 this too small, else there is too much
243 time wasted trying to reclaim a couple
245 const size_t mininc = 64; /* minimum number of bytes by which
246 to increase the allocated memory */
252 while (fgets(buf+len, size-len, f) != NULL) {
253 len += strlen(buf+len);
254 if (len > 0 && buf[len-1] == '\n')
255 break; /* the whole line has been read */
257 for (inc = size, p = NULL; inc > mininc; inc /= 2)
258 if ((p = xrealloc_inc(buf, size, inc)) !=
268 return NULL; /* nothing read (eof or error) */
271 if (buf[len-1] == '\n') /* remove newline, if there */
274 if (size - len > mucho) { /* a plenitude of unused memory? */
275 p = xrealloc_inc(buf, len, 1);
286 strwidth(const char *s)
289 return mbswidth(s, 0);
293 bytes2width(const char *s, int width)
296 #ifdef HANDLE_MULTIBYTE
297 return mbsnbytes(s, strlen(s), width, 0);
303 /**************************************************************
305 * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
306 * A bombproof version of doprnt (dopr) included.
307 * Sigh. This sort of thing is always nasty do deal with. Note that
308 * the version here does not include floating point...
310 * snprintf() is used instead of sprintf() as it does limit checks
311 * for string length. This covers a nasty loophole.
313 * The other functions are there to prevent NULL pointers from
314 * causing nast effects.
317 * Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43
318 * This was ugly. It is still ugly. I opted out of floating point
319 * numbers, but the formatter understands just about everything
320 * from the normal C string format, at least as far as I can tell from
321 * the Solaris 2.5 printf(3S) man page.
323 * Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1
324 * Ok, added some minimal floating point support, which means this
325 * probably requires libm on most operating systems. Don't yet
326 * support the exponent (e,E) and sigfig (g,G). Also, fmtint()
327 * was pretty badly broken, it just wasn't being exercised in ways
328 * which showed it, so that's been fixed. Also, formated the code
329 * to mutt conventions, and removed dead code left over from the
330 * original. Also, there is now a builtin-test, just compile with:
331 * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
332 * and run snprintf for results.
334 * Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i
335 * The PGP code was using unsigned hexadecimal formats.
336 * Unfortunately, unsigned formats simply didn't work.
338 * Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8
339 * The original code assumed that both snprintf() and vsnprintf() were
340 * missing. Some systems only have snprintf() but not vsnprintf(), so
341 * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
343 **************************************************************/
347 #if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF)
351 #include <sys/types.h>
353 /* Define this as a fall through, HAVE_STDARG_H is probably already set */
355 #if !defined(HAVE_STDARG_H) && !defined(HAVE_VARARGS_H)
356 # define HAVE_VARARGS_H 1
359 /* varargs declarations: */
361 #if defined(HAVE_STDARG_H)
362 /*# include <stdarg.h>*/
363 # define HAVE_STDARGS /* let's hope that works everywhere (mj) */
364 # define VA_LOCAL_DECL va_list ap
365 # define VA_START(f) va_start(ap, f)
366 # define VA_SHIFT(v,t) ; /* no-op for ANSI */
367 # define VA_END va_end(ap)
369 # if defined(HAVE_VARARGS_H)
370 # include <varargs.h>
372 # define VA_LOCAL_DECL va_list ap
373 # define VA_START(f) va_start(ap) /* f is ignored! */
374 # define VA_SHIFT(v,t) v = va_arg(ap,t)
375 # define VA_END va_end(ap)
377 /*XX ** NO VARARGS ** XX*/
381 /*int snprintf (char *str, size_t count, const char *fmt, ...);*/
382 /*int vsnprintf (char *str, size_t count, const char *fmt, va_list arg);*/
384 static void dopr (char *buffer, size_t maxlen, const char *format,
386 static void fmtstr (char *buffer, size_t *currlen, size_t maxlen,
387 char *value, int flags, int min, int max);
388 static void fmtint (char *buffer, size_t *currlen, size_t maxlen,
389 long value, int base, int min, int max, int flags);
390 static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
391 long double fvalue, int min, int max, int flags);
392 static void dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c );
395 * dopr(): poor man's version of doprintf
398 /* format read states */
399 #define DP_S_DEFAULT 0
408 /* format flags - Bits */
409 #define DP_F_MINUS (1 << 0)
410 #define DP_F_PLUS (1 << 1)
411 #define DP_F_SPACE (1 << 2)
412 #define DP_F_NUM (1 << 3)
413 #define DP_F_ZERO (1 << 4)
414 #define DP_F_UP (1 << 5)
415 #define DP_F_UNSIGNED (1 << 6)
417 /* Conversion Flags */
420 #define DP_C_LDOUBLE 3
422 #define char_to_int(p) (p - '0')
423 #define MAX(p,q) ((p >= q) ? p : q)
425 static void dopr (char *buffer, size_t maxlen, const char *format, va_list args)
438 state = DP_S_DEFAULT;
439 currlen = flags = cflags = min = 0;
443 while (state != DP_S_DONE)
445 if ((ch == '\0') || (currlen >= maxlen))
454 dopr_outch (buffer, &currlen, maxlen, ch);
486 if (isdigit((unsigned char)ch))
488 min = 10*min + char_to_int (ch);
493 min = va_arg (args, int);
510 if (isdigit((unsigned char)ch))
514 max = 10*max + char_to_int (ch);
519 max = va_arg (args, int);
527 /* Currently, we don't support Long Long, bummer */
539 cflags = DP_C_LDOUBLE;
552 if (cflags == DP_C_SHORT)
553 value = va_arg (args, short int);
554 else if (cflags == DP_C_LONG)
555 value = va_arg (args, long int);
557 value = va_arg (args, int);
558 fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
561 flags |= DP_F_UNSIGNED;
562 if (cflags == DP_C_SHORT)
563 value = va_arg (args, unsigned short int);
564 else if (cflags == DP_C_LONG)
565 value = va_arg (args, unsigned long int);
567 value = va_arg (args, unsigned int);
568 fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags);
571 flags |= DP_F_UNSIGNED;
572 if (cflags == DP_C_SHORT)
573 value = va_arg (args, unsigned short int);
574 else if (cflags == DP_C_LONG)
575 value = va_arg (args, unsigned long int);
577 value = va_arg (args, unsigned int);
578 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, 16, min, max, flags);
593 if (cflags == DP_C_LDOUBLE)
594 fvalue = va_arg (args, long double);
596 fvalue = va_arg (args, double);
597 /* um, floating point? */
598 fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
603 if (cflags == DP_C_LDOUBLE)
604 fvalue = va_arg (args, long double);
606 fvalue = va_arg (args, double);
611 if (cflags == DP_C_LDOUBLE)
612 fvalue = va_arg (args, long double);
614 fvalue = va_arg (args, double);
617 dopr_outch (buffer, &currlen, maxlen, va_arg (args, int));
620 strvalue = va_arg (args, char *);
622 max = maxlen; /* ie, no max */
623 fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max);
626 strvalue = va_arg (args, void *);
627 fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags);
630 if (cflags == DP_C_SHORT)
633 num = va_arg (args, short int *);
636 else if (cflags == DP_C_LONG)
639 num = va_arg (args, long int *);
645 num = va_arg (args, int *);
650 dopr_outch (buffer, &currlen, maxlen, ch);
653 /* not supported yet, treat as next char */
661 state = DP_S_DEFAULT;
662 flags = cflags = min = 0;
669 break; /* some picky compilers need this */
672 if (currlen < maxlen - 1)
673 buffer[currlen] = '\0';
675 buffer[maxlen - 1] = '\0';
678 static void fmtstr (char *buffer, size_t *currlen, size_t maxlen,
679 char *value, int flags, int min, int max)
681 int padlen, strln; /* amount to pad */
689 for (strln = 0; value[strln]; ++strln); /* strlen */
690 padlen = min - strln;
693 if (flags & DP_F_MINUS)
694 padlen = -padlen; /* Left Justify */
696 while ((padlen > 0) && (cnt < max))
698 dopr_outch (buffer, currlen, maxlen, ' ');
702 while (*value && (cnt < max))
704 dopr_outch (buffer, currlen, maxlen, *value++);
707 while ((padlen < 0) && (cnt < max))
709 dopr_outch (buffer, currlen, maxlen, ' ');
715 /* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
717 static void fmtint (char *buffer, size_t *currlen, size_t maxlen,
718 long value, int base, int min, int max, int flags)
721 unsigned long uvalue;
724 int spadlen = 0; /* amount to space pad */
725 int zpadlen = 0; /* amount to zero pad */
733 if(!(flags & DP_F_UNSIGNED))
740 if (flags & DP_F_PLUS) /* Do a sign (+/i) */
743 if (flags & DP_F_SPACE)
747 if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
751 (caps? "0123456789ABCDEF":"0123456789abcdef")
752 [uvalue % (unsigned)base ];
753 uvalue = (uvalue / (unsigned)base );
754 } while(uvalue && (place < 20));
755 if (place == 20) place--;
758 zpadlen = max - place;
759 spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
760 if (zpadlen < 0) zpadlen = 0;
761 if (spadlen < 0) spadlen = 0;
762 if (flags & DP_F_ZERO)
764 zpadlen = MAX(zpadlen, spadlen);
767 if (flags & DP_F_MINUS)
768 spadlen = -spadlen; /* Left Justifty */
770 #ifdef DEBUG_SNPRINTF
771 dprint (1, (debugfile, "zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
772 zpadlen, spadlen, min, max, place));
778 dopr_outch (buffer, currlen, maxlen, ' ');
784 dopr_outch (buffer, currlen, maxlen, signvalue);
791 dopr_outch (buffer, currlen, maxlen, '0');
798 dopr_outch (buffer, currlen, maxlen, convert[--place]);
800 /* Left Justified spaces */
801 while (spadlen < 0) {
802 dopr_outch (buffer, currlen, maxlen, ' ');
807 static long double abs_val (long double value)
809 long double result = value;
817 static long double pow10 (int exp)
819 long double result = 1;
830 static long round (long double value)
835 value = value - intpart;
842 static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
843 long double fvalue, int min, int max, int flags)
851 int padlen = 0; /* amount to pad */
858 * AIX manpage says the default is 0, but Solaris says the default
859 * is 6, and sprintf on AIX defaults to 6
864 ufvalue = abs_val (fvalue);
869 if (flags & DP_F_PLUS) /* Do a sign (+/i) */
872 if (flags & DP_F_SPACE)
876 if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
882 * Sorry, we only support 9 digits past the decimal because of our
888 /* We "cheat" by converting the fractional part to integer by
889 * multiplying by a factor of 10
891 fracpart = round ((pow10 (max)) * (ufvalue - intpart));
893 if (fracpart >= pow10 (max))
896 fracpart -= pow10 (max);
899 #ifdef DEBUG_SNPRINTF
900 dprint (1, (debugfile, "fmtfp: %f =? %d.%d\n", fvalue, intpart, fracpart));
903 /* Convert integer part */
906 (caps? "0123456789ABCDEF":"0123456789abcdef")[intpart % 10];
907 intpart = (intpart / 10);
908 } while(intpart && (iplace < 20));
909 if (iplace == 20) iplace--;
910 iconvert[iplace] = 0;
912 /* Convert fractional part */
915 (caps? "0123456789ABCDEF":"0123456789abcdef")[fracpart % 10];
916 fracpart = (fracpart / 10);
917 } while(fracpart && (fplace < 20));
918 if (fplace == 20) fplace--;
919 fconvert[fplace] = 0;
921 /* -1 for decimal point, another -1 if we are printing a sign */
922 padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
923 zpadlen = max - fplace;
928 if (flags & DP_F_MINUS)
929 padlen = -padlen; /* Left Justifty */
931 if ((flags & DP_F_ZERO) && (padlen > 0))
935 dopr_outch (buffer, currlen, maxlen, signvalue);
941 dopr_outch (buffer, currlen, maxlen, '0');
947 dopr_outch (buffer, currlen, maxlen, ' ');
951 dopr_outch (buffer, currlen, maxlen, signvalue);
954 dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]);
957 * Decimal point. This should probably use locale to find the correct
960 dopr_outch (buffer, currlen, maxlen, '.');
963 dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]);
967 dopr_outch (buffer, currlen, maxlen, '0');
973 dopr_outch (buffer, currlen, maxlen, ' ');
978 static void dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c)
980 if (*currlen < maxlen)
981 buffer[(*currlen)++] = c;
983 #endif /* !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) */
985 #ifndef HAVE_VSNPRINTF
986 int vsnprintf (char *str, size_t count, const char *fmt, va_list args)
989 dopr(str, count, fmt, args);
992 #endif /* !HAVE_VSNPRINTF */
994 #ifndef HAVE_SNPRINTF
997 int snprintf (char *str,size_t count,const char *fmt,...)
999 int snprintf (va_alist) va_dcl
1002 #ifndef HAVE_STDARGS
1010 VA_SHIFT (str, char *);
1011 VA_SHIFT (count, size_t );
1012 VA_SHIFT (fmt, char *);
1013 (void) vsnprintf(str, count, fmt, ap);
1015 return(strlen(str));
1018 #ifdef TEST_SNPRINTF
1020 #define LONG_STRING 1024
1024 char buf1[LONG_STRING];
1025 char buf2[LONG_STRING];
1040 double fp_nums[] = { -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996,
1041 0.9996, 1.996, 4.136, 0};
1054 long int_nums[] = { -1, 134, 91340, 341, 0203, 0};
1059 printf ("Testing snprintf format codes against system sprintf...\n");
1061 for (x = 0; fp_fmt[x] != NULL ; x++)
1062 for (y = 0; fp_nums[y] != 0 ; y++)
1064 snprintf (buf1, sizeof (buf1), fp_fmt[x], fp_nums[y]);
1065 sprintf (buf2, fp_fmt[x], fp_nums[y]);
1066 if (strcmp (buf1, buf2))
1068 printf("snprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
1069 fp_fmt[x], buf1, buf2);
1075 for (x = 0; int_fmt[x] != NULL ; x++)
1076 for (y = 0; int_nums[y] != 0 ; y++)
1078 snprintf (buf1, sizeof (buf1), int_fmt[x], int_nums[y]);
1079 sprintf (buf2, int_fmt[x], int_nums[y]);
1080 if (strcmp (buf1, buf2))
1082 printf("snprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
1083 int_fmt[x], buf1, buf2);
1088 printf ("%d tests failed out of %d.\n", fail, num);
1090 #endif /* SNPRINTF_TEST */
1092 #endif /* !HAVE_SNPRINTF */
1098 * List handling functions
1102 abook_list_append(abook_list **list, char *str)
1109 for(tmp = *list; tmp && tmp->next; tmp = tmp->next)
1113 tmp->next = xmalloc(sizeof(abook_list));
1116 tmp = *list = xmalloc(sizeof(abook_list));
1118 tmp->data = xstrdup(str);
1123 abook_list_free(abook_list **list)
1125 abook_list *prev = NULL, *tmp = *list;
1141 csv_to_abook_list(char *str)
1143 char *start, *p = str, *end;
1144 abook_list *list = NULL;
1153 if(!strchr(", ", *p)) {
1158 if((*p == ',') && (end - start)) {
1159 abook_list_append(&list, xstrndup(start, end - start));
1169 abook_list_append(&list, xstrndup(start, end - start));
1175 abook_list_to_csv(abook_list *list)
1180 for(tmp = list; tmp; tmp = tmp->next) {
1182 res = xstrdup(tmp->data);
1184 res = xrealloc(res, strlen(res)+strlen(tmp->data)+2);
1186 strcat(res, tmp->data);
1194 abook_list_rotate(abook_list **list, enum rotate_dir dir)
1196 abook_list *tmp = *list;
1198 if(!tmp || !tmp->next)
1203 for(; tmp && tmp->next; tmp = tmp->next)
1208 *list = (*list)->next;
1212 for(; tmp && tmp->next && tmp->next->next;
1216 tmp->next->next = *list;
1225 /* if str == NULL, deleting the list element */
1227 abook_list_replace(abook_list **list, int index, char *str)
1229 abook_list *cur, *prev;
1234 if((index == 0) && !str) {
1255 cur->data = xstrdup(str);
1257 prev->next = cur->next;
1264 abook_list_get(abook_list *list, int index)