3 * $Id: misc.c,v 1.21 2005/10/05 11:03:36 jheinonen 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
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 strdup_printf (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)
189 * Copyright (c) 1994 Lars Wirzenius
190 * All rights reserved.
192 * Redistribution and use in source and binary forms, with or without
193 * modification, are permitted provided that the following conditions
195 * 1. Redistributions of source code must retain the above copyright
196 * notice, this list of conditions and the following disclaimer
197 * in this position and unchanged.
198 * 2. Redistributions in binary form must reproduce the above copyright
199 * notice, this list of conditions and the following disclaimer in the
200 * documentation and/or other materials provided with the distribution.
202 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
203 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
204 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
205 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
206 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
207 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
208 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
209 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
210 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
211 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
217 char *buf; /* buffer for line */
218 size_t size; /* size of buffer */
219 size_t inc; /* how much to enlarge buffer */
220 size_t len; /* # of chars stored into buf before '\0' */
222 const size_t thres = 128; /* initial buffer size (most lines should
223 fit into this size, so think of this as
224 the "long line threshold"). */
225 const size_t mucho = 128; /* if there is at least this much wasted
226 space when the whole buffer has been
227 read, try to reclaim it. Don't make
228 this too small, else there is too much
229 time wasted trying to reclaim a couple
231 const size_t mininc = 64; /* minimum number of bytes by which
232 to increase the allocated memory */
238 while (fgets(buf+len, size-len, f) != NULL) {
239 len += strlen(buf+len);
240 if (len > 0 && buf[len-1] == '\n')
241 break; /* the whole line has been read */
243 for (inc = size, p = NULL; inc > mininc; inc /= 2)
244 if ((p = xrealloc_inc(buf, size, inc)) !=
254 return NULL; /* nothing read (eof or error) */
257 if (buf[len-1] == '\n') /* remove newline, if there */
260 if (size - len > mucho) { /* a plenitude of unused memory? */
261 p = xrealloc_inc(buf, len, 1);
272 strwidth(const char *s)
275 return mbswidth(s, 0);
279 bytes2width(const char *s, int width)
282 #ifdef HANDLE_MULTIBYTE
283 return mbsnbytes(s, strlen(s), width, 0);
289 /**************************************************************
291 * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
292 * A bombproof version of doprnt (dopr) included.
293 * Sigh. This sort of thing is always nasty do deal with. Note that
294 * the version here does not include floating point...
296 * snprintf() is used instead of sprintf() as it does limit checks
297 * for string length. This covers a nasty loophole.
299 * The other functions are there to prevent NULL pointers from
300 * causing nast effects.
303 * Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43
304 * This was ugly. It is still ugly. I opted out of floating point
305 * numbers, but the formatter understands just about everything
306 * from the normal C string format, at least as far as I can tell from
307 * the Solaris 2.5 printf(3S) man page.
309 * Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1
310 * Ok, added some minimal floating point support, which means this
311 * probably requires libm on most operating systems. Don't yet
312 * support the exponent (e,E) and sigfig (g,G). Also, fmtint()
313 * was pretty badly broken, it just wasn't being exercised in ways
314 * which showed it, so that's been fixed. Also, formated the code
315 * to mutt conventions, and removed dead code left over from the
316 * original. Also, there is now a builtin-test, just compile with:
317 * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
318 * and run snprintf for results.
320 * Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i
321 * The PGP code was using unsigned hexadecimal formats.
322 * Unfortunately, unsigned formats simply didn't work.
324 * Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8
325 * The original code assumed that both snprintf() and vsnprintf() were
326 * missing. Some systems only have snprintf() but not vsnprintf(), so
327 * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
329 **************************************************************/
333 #if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF)
337 #include <sys/types.h>
339 /* Define this as a fall through, HAVE_STDARG_H is probably already set */
341 #if !defined(HAVE_STDARG_H) && !defined(HAVE_VARARGS_H)
342 # define HAVE_VARARGS_H 1
345 /* varargs declarations: */
347 #if defined(HAVE_STDARG_H)
348 /*# include <stdarg.h>*/
349 # define HAVE_STDARGS /* let's hope that works everywhere (mj) */
350 # define VA_LOCAL_DECL va_list ap
351 # define VA_START(f) va_start(ap, f)
352 # define VA_SHIFT(v,t) ; /* no-op for ANSI */
353 # define VA_END va_end(ap)
355 # if defined(HAVE_VARARGS_H)
356 # include <varargs.h>
358 # define VA_LOCAL_DECL va_list ap
359 # define VA_START(f) va_start(ap) /* f is ignored! */
360 # define VA_SHIFT(v,t) v = va_arg(ap,t)
361 # define VA_END va_end(ap)
363 /*XX ** NO VARARGS ** XX*/
367 /*int snprintf (char *str, size_t count, const char *fmt, ...);*/
368 /*int vsnprintf (char *str, size_t count, const char *fmt, va_list arg);*/
370 static void dopr (char *buffer, size_t maxlen, const char *format,
372 static void fmtstr (char *buffer, size_t *currlen, size_t maxlen,
373 char *value, int flags, int min, int max);
374 static void fmtint (char *buffer, size_t *currlen, size_t maxlen,
375 long value, int base, int min, int max, int flags);
376 static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
377 long double fvalue, int min, int max, int flags);
378 static void dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c );
381 * dopr(): poor man's version of doprintf
384 /* format read states */
385 #define DP_S_DEFAULT 0
394 /* format flags - Bits */
395 #define DP_F_MINUS (1 << 0)
396 #define DP_F_PLUS (1 << 1)
397 #define DP_F_SPACE (1 << 2)
398 #define DP_F_NUM (1 << 3)
399 #define DP_F_ZERO (1 << 4)
400 #define DP_F_UP (1 << 5)
401 #define DP_F_UNSIGNED (1 << 6)
403 /* Conversion Flags */
406 #define DP_C_LDOUBLE 3
408 #define char_to_int(p) (p - '0')
409 #define MAX(p,q) ((p >= q) ? p : q)
411 static void dopr (char *buffer, size_t maxlen, const char *format, va_list args)
424 state = DP_S_DEFAULT;
425 currlen = flags = cflags = min = 0;
429 while (state != DP_S_DONE)
431 if ((ch == '\0') || (currlen >= maxlen))
440 dopr_outch (buffer, &currlen, maxlen, ch);
472 if (isdigit((unsigned char)ch))
474 min = 10*min + char_to_int (ch);
479 min = va_arg (args, int);
496 if (isdigit((unsigned char)ch))
500 max = 10*max + char_to_int (ch);
505 max = va_arg (args, int);
513 /* Currently, we don't support Long Long, bummer */
525 cflags = DP_C_LDOUBLE;
538 if (cflags == DP_C_SHORT)
539 value = va_arg (args, short int);
540 else if (cflags == DP_C_LONG)
541 value = va_arg (args, long int);
543 value = va_arg (args, int);
544 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, 8, min, max, flags);
557 flags |= DP_F_UNSIGNED;
558 if (cflags == DP_C_SHORT)
559 value = va_arg (args, unsigned short int);
560 else if (cflags == DP_C_LONG)
561 value = va_arg (args, unsigned long int);
563 value = va_arg (args, unsigned int);
564 fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
569 flags |= DP_F_UNSIGNED;
570 if (cflags == DP_C_SHORT)
571 value = va_arg (args, unsigned short int);
572 else if (cflags == DP_C_LONG)
573 value = va_arg (args, unsigned long int);
575 value = va_arg (args, unsigned int);
576 fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags);
579 if (cflags == DP_C_LDOUBLE)
580 fvalue = va_arg (args, long double);
582 fvalue = va_arg (args, double);
583 /* um, floating point? */
584 fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
589 if (cflags == DP_C_LDOUBLE)
590 fvalue = va_arg (args, long double);
592 fvalue = va_arg (args, double);
597 if (cflags == DP_C_LDOUBLE)
598 fvalue = va_arg (args, long double);
600 fvalue = va_arg (args, double);
603 dopr_outch (buffer, &currlen, maxlen, va_arg (args, int));
606 strvalue = va_arg (args, char *);
608 max = maxlen; /* ie, no max */
609 fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max);
612 strvalue = va_arg (args, void *);
613 fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags);
616 if (cflags == DP_C_SHORT)
619 num = va_arg (args, short int *);
622 else if (cflags == DP_C_LONG)
625 num = va_arg (args, long int *);
631 num = va_arg (args, int *);
636 dopr_outch (buffer, &currlen, maxlen, ch);
639 /* not supported yet, treat as next char */
647 state = DP_S_DEFAULT;
648 flags = cflags = min = 0;
655 break; /* some picky compilers need this */
658 if (currlen < maxlen - 1)
659 buffer[currlen] = '\0';
661 buffer[maxlen - 1] = '\0';
664 static void fmtstr (char *buffer, size_t *currlen, size_t maxlen,
665 char *value, int flags, int min, int max)
667 int padlen, strln; /* amount to pad */
675 for (strln = 0; value[strln]; ++strln); /* strlen */
676 padlen = min - strln;
679 if (flags & DP_F_MINUS)
680 padlen = -padlen; /* Left Justify */
682 while ((padlen > 0) && (cnt < max))
684 dopr_outch (buffer, currlen, maxlen, ' ');
688 while (*value && (cnt < max))
690 dopr_outch (buffer, currlen, maxlen, *value++);
693 while ((padlen < 0) && (cnt < max))
695 dopr_outch (buffer, currlen, maxlen, ' ');
701 /* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
703 static void fmtint (char *buffer, size_t *currlen, size_t maxlen,
704 long value, int base, int min, int max, int flags)
707 unsigned long uvalue;
710 int spadlen = 0; /* amount to space pad */
711 int zpadlen = 0; /* amount to zero pad */
719 if(!(flags & DP_F_UNSIGNED))
726 if (flags & DP_F_PLUS) /* Do a sign (+/i) */
729 if (flags & DP_F_SPACE)
733 if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
737 (caps? "0123456789ABCDEF":"0123456789abcdef")
738 [uvalue % (unsigned)base ];
739 uvalue = (uvalue / (unsigned)base );
740 } while(uvalue && (place < 20));
741 if (place == 20) place--;
744 zpadlen = max - place;
745 spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
746 if (zpadlen < 0) zpadlen = 0;
747 if (spadlen < 0) spadlen = 0;
748 if (flags & DP_F_ZERO)
750 zpadlen = MAX(zpadlen, spadlen);
753 if (flags & DP_F_MINUS)
754 spadlen = -spadlen; /* Left Justifty */
756 #ifdef DEBUG_SNPRINTF
757 dprint (1, (debugfile, "zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
758 zpadlen, spadlen, min, max, place));
764 dopr_outch (buffer, currlen, maxlen, ' ');
770 dopr_outch (buffer, currlen, maxlen, signvalue);
777 dopr_outch (buffer, currlen, maxlen, '0');
784 dopr_outch (buffer, currlen, maxlen, convert[--place]);
786 /* Left Justified spaces */
787 while (spadlen < 0) {
788 dopr_outch (buffer, currlen, maxlen, ' ');
793 static long double abs_val (long double value)
795 long double result = value;
803 static long double pow10 (int exp)
805 long double result = 1;
816 static long round (long double value)
821 value = value - intpart;
828 static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
829 long double fvalue, int min, int max, int flags)
837 int padlen = 0; /* amount to pad */
844 * AIX manpage says the default is 0, but Solaris says the default
845 * is 6, and sprintf on AIX defaults to 6
850 ufvalue = abs_val (fvalue);
855 if (flags & DP_F_PLUS) /* Do a sign (+/i) */
858 if (flags & DP_F_SPACE)
862 if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
868 * Sorry, we only support 9 digits past the decimal because of our
874 /* We "cheat" by converting the fractional part to integer by
875 * multiplying by a factor of 10
877 fracpart = round ((pow10 (max)) * (ufvalue - intpart));
879 if (fracpart >= pow10 (max))
882 fracpart -= pow10 (max);
885 #ifdef DEBUG_SNPRINTF
886 dprint (1, (debugfile, "fmtfp: %f =? %d.%d\n", fvalue, intpart, fracpart));
889 /* Convert integer part */
892 (caps? "0123456789ABCDEF":"0123456789abcdef")[intpart % 10];
893 intpart = (intpart / 10);
894 } while(intpart && (iplace < 20));
895 if (iplace == 20) iplace--;
896 iconvert[iplace] = 0;
898 /* Convert fractional part */
901 (caps? "0123456789ABCDEF":"0123456789abcdef")[fracpart % 10];
902 fracpart = (fracpart / 10);
903 } while(fracpart && (fplace < 20));
904 if (fplace == 20) fplace--;
905 fconvert[fplace] = 0;
907 /* -1 for decimal point, another -1 if we are printing a sign */
908 padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
909 zpadlen = max - fplace;
914 if (flags & DP_F_MINUS)
915 padlen = -padlen; /* Left Justifty */
917 if ((flags & DP_F_ZERO) && (padlen > 0))
921 dopr_outch (buffer, currlen, maxlen, signvalue);
927 dopr_outch (buffer, currlen, maxlen, '0');
933 dopr_outch (buffer, currlen, maxlen, ' ');
937 dopr_outch (buffer, currlen, maxlen, signvalue);
940 dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]);
943 * Decimal point. This should probably use locale to find the correct
946 dopr_outch (buffer, currlen, maxlen, '.');
949 dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]);
953 dopr_outch (buffer, currlen, maxlen, '0');
959 dopr_outch (buffer, currlen, maxlen, ' ');
964 static void dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c)
966 if (*currlen < maxlen)
967 buffer[(*currlen)++] = c;
969 #endif /* !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) */
971 #ifndef HAVE_VSNPRINTF
972 int vsnprintf (char *str, size_t count, const char *fmt, va_list args)
975 dopr(str, count, fmt, args);
978 #endif /* !HAVE_VSNPRINTF */
980 #ifndef HAVE_SNPRINTF
983 int snprintf (char *str,size_t count,const char *fmt,...)
985 int snprintf (va_alist) va_dcl
996 VA_SHIFT (str, char *);
997 VA_SHIFT (count, size_t );
998 VA_SHIFT (fmt, char *);
999 (void) vsnprintf(str, count, fmt, ap);
1001 return(strlen(str));
1004 #ifdef TEST_SNPRINTF
1006 #define LONG_STRING 1024
1010 char buf1[LONG_STRING];
1011 char buf2[LONG_STRING];
1026 double fp_nums[] = { -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996,
1027 0.9996, 1.996, 4.136, 0};
1040 long int_nums[] = { -1, 134, 91340, 341, 0203, 0};
1045 printf ("Testing snprintf format codes against system sprintf...\n");
1047 for (x = 0; fp_fmt[x] != NULL ; x++)
1048 for (y = 0; fp_nums[y] != 0 ; y++)
1050 snprintf (buf1, sizeof (buf1), fp_fmt[x], fp_nums[y]);
1051 sprintf (buf2, fp_fmt[x], fp_nums[y]);
1052 if (strcmp (buf1, buf2))
1054 printf("snprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
1055 fp_fmt[x], buf1, buf2);
1061 for (x = 0; int_fmt[x] != NULL ; x++)
1062 for (y = 0; int_nums[y] != 0 ; y++)
1064 snprintf (buf1, sizeof (buf1), int_fmt[x], int_nums[y]);
1065 sprintf (buf2, int_fmt[x], int_nums[y]);
1066 if (strcmp (buf1, buf2))
1068 printf("snprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
1069 int_fmt[x], buf1, buf2);
1074 printf ("%d tests failed out of %d.\n", fail, num);
1076 #endif /* SNPRINTF_TEST */
1078 #endif /* !HAVE_SNPRINTF */