3 * $Id: misc.c,v 1.19 2005/08/11 07:32:35 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
21 #ifdef HANDLE_MULTIBYTE
22 # include <mbswidth.h>
42 while( ( *str = tolower ( *str ) ) )
55 for(t = s; isspace(*t); t++);
57 memmove(s, t, strlen(t)+1);
59 for (tt = t = s; *t != '\0'; t++)
73 /* varargs declarations: */
76 # define MY_VA_LOCAL_DECL va_list ap
77 # define MY_VA_START(f) va_start(ap, f)
78 # define MY_VA_SHIFT(v,t) v = va_arg(ap, t)
79 # define MY_VA_END va_end(ap)
81 # error HAVE_STDARG_H not defined
85 mkstr (const char *format, ... )
89 char *buffer = xmalloc (size);
91 assert(format != NULL);
96 n = vsnprintf (buffer, size,
100 if (n > -1 && n < size)
108 buffer = xrealloc(buffer, size);
114 strconcat (const char *str, ...)
122 l = 1 + strlen (str);
124 MY_VA_SHIFT(s, char*);
127 MY_VA_SHIFT(s, char*);
133 strcpy (concat, str);
135 MY_VA_SHIFT(s, char*);
138 MY_VA_SHIFT(s, char*);
147 safe_strcmp(const char *s1, const char *s2)
149 if (s1 == NULL && s2 == NULL) return 0;
150 if (s1 == NULL) return -1;
151 if (s2 == NULL) return 1;
153 return strcmp(s1, s2);
157 safe_strcoll(const char *s1, const char *s2)
160 if (s1 == NULL && s2 == NULL) return 0;
161 if (s1 == NULL) return -1;
162 if (s2 == NULL) return 1;
164 return strcoll(s1, s2);
165 #else /* fall back to strcmp */
166 return safe_strcmp(s1, s2);
176 if( (dir = xmalloc(size)) == NULL)
181 while( getcwd(dir, size) == NULL && errno == ERANGE )
182 if( (dir = xrealloc(dir, size *=2)) == NULL)
191 * Copyright (c) 1994 Lars Wirzenius
192 * All rights reserved.
194 * Redistribution and use in source and binary forms, with or without
195 * modification, are permitted provided that the following conditions
197 * 1. Redistributions of source code must retain the above copyright
198 * notice, this list of conditions and the following disclaimer
199 * in this position and unchanged.
200 * 2. Redistributions in binary form must reproduce the above copyright
201 * notice, this list of conditions and the following disclaimer in the
202 * documentation and/or other materials provided with the distribution.
204 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
205 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
206 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
207 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
208 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
209 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
210 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
211 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
212 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
213 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
219 char *buf; /* buffer for line */
220 size_t size; /* size of buffer */
221 size_t inc; /* how much to enlarge buffer */
222 size_t len; /* # of chars stored into buf before '\0' */
224 const size_t thres = 128; /* initial buffer size (most lines should
225 fit into this size, so think of this as
226 the "long line threshold"). */
227 const size_t mucho = 128; /* if there is at least this much wasted
228 space when the whole buffer has been
229 read, try to reclaim it. Don't make
230 this too small, else there is too much
231 time wasted trying to reclaim a couple
233 const size_t mininc = 64; /* minimum number of bytes by which
234 to increase the allocated memory */
240 while (fgets(buf+len, size-len, f) != NULL) {
241 len += strlen(buf+len);
242 if (len > 0 && buf[len-1] == '\n')
243 break; /* the whole line has been read */
245 for (inc = size, p = NULL; inc > mininc; inc /= 2)
246 if ((p = xrealloc_inc(buf, size, inc)) !=
256 return NULL; /* nothing read (eof or error) */
259 if (buf[len-1] == '\n') /* remove newline, if there */
262 if (size - len > mucho) { /* a plenitude of unused memory? */
263 p = xrealloc_inc(buf, len, 1);
274 strwidth(const char *s)
277 #ifdef HANDLE_MULTIBYTE
278 return (int)mbswidth(s, 0);
285 bytes2width(const char *s, int width)
288 #ifdef HANDLE_MULTIBYTE
289 return mbsnbytes(s, strlen(s), width, 0);
295 /**************************************************************
297 * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
298 * A bombproof version of doprnt (dopr) included.
299 * Sigh. This sort of thing is always nasty do deal with. Note that
300 * the version here does not include floating point...
302 * snprintf() is used instead of sprintf() as it does limit checks
303 * for string length. This covers a nasty loophole.
305 * The other functions are there to prevent NULL pointers from
306 * causing nast effects.
309 * Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43
310 * This was ugly. It is still ugly. I opted out of floating point
311 * numbers, but the formatter understands just about everything
312 * from the normal C string format, at least as far as I can tell from
313 * the Solaris 2.5 printf(3S) man page.
315 * Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1
316 * Ok, added some minimal floating point support, which means this
317 * probably requires libm on most operating systems. Don't yet
318 * support the exponent (e,E) and sigfig (g,G). Also, fmtint()
319 * was pretty badly broken, it just wasn't being exercised in ways
320 * which showed it, so that's been fixed. Also, formated the code
321 * to mutt conventions, and removed dead code left over from the
322 * original. Also, there is now a builtin-test, just compile with:
323 * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
324 * and run snprintf for results.
326 * Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i
327 * The PGP code was using unsigned hexadecimal formats.
328 * Unfortunately, unsigned formats simply didn't work.
330 * Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8
331 * The original code assumed that both snprintf() and vsnprintf() were
332 * missing. Some systems only have snprintf() but not vsnprintf(), so
333 * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
335 **************************************************************/
339 #if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF)
343 #include <sys/types.h>
345 /* Define this as a fall through, HAVE_STDARG_H is probably already set */
347 #if !defined(HAVE_STDARG_H) && !defined(HAVE_VARARGS_H)
348 # define HAVE_VARARGS_H 1
351 /* varargs declarations: */
353 #if defined(HAVE_STDARG_H)
354 /*# include <stdarg.h>*/
355 # define HAVE_STDARGS /* let's hope that works everywhere (mj) */
356 # define VA_LOCAL_DECL va_list ap
357 # define VA_START(f) va_start(ap, f)
358 # define VA_SHIFT(v,t) ; /* no-op for ANSI */
359 # define VA_END va_end(ap)
361 # if defined(HAVE_VARARGS_H)
362 # include <varargs.h>
364 # define VA_LOCAL_DECL va_list ap
365 # define VA_START(f) va_start(ap) /* f is ignored! */
366 # define VA_SHIFT(v,t) v = va_arg(ap,t)
367 # define VA_END va_end(ap)
369 /*XX ** NO VARARGS ** XX*/
373 /*int snprintf (char *str, size_t count, const char *fmt, ...);*/
374 /*int vsnprintf (char *str, size_t count, const char *fmt, va_list arg);*/
376 static void dopr (char *buffer, size_t maxlen, const char *format,
378 static void fmtstr (char *buffer, size_t *currlen, size_t maxlen,
379 char *value, int flags, int min, int max);
380 static void fmtint (char *buffer, size_t *currlen, size_t maxlen,
381 long value, int base, int min, int max, int flags);
382 static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
383 long double fvalue, int min, int max, int flags);
384 static void dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c );
387 * dopr(): poor man's version of doprintf
390 /* format read states */
391 #define DP_S_DEFAULT 0
400 /* format flags - Bits */
401 #define DP_F_MINUS (1 << 0)
402 #define DP_F_PLUS (1 << 1)
403 #define DP_F_SPACE (1 << 2)
404 #define DP_F_NUM (1 << 3)
405 #define DP_F_ZERO (1 << 4)
406 #define DP_F_UP (1 << 5)
407 #define DP_F_UNSIGNED (1 << 6)
409 /* Conversion Flags */
412 #define DP_C_LDOUBLE 3
414 #define char_to_int(p) (p - '0')
415 #define MAX(p,q) ((p >= q) ? p : q)
417 static void dopr (char *buffer, size_t maxlen, const char *format, va_list args)
430 state = DP_S_DEFAULT;
431 currlen = flags = cflags = min = 0;
435 while (state != DP_S_DONE)
437 if ((ch == '\0') || (currlen >= maxlen))
446 dopr_outch (buffer, &currlen, maxlen, ch);
478 if (isdigit((unsigned char)ch))
480 min = 10*min + char_to_int (ch);
485 min = va_arg (args, int);
502 if (isdigit((unsigned char)ch))
506 max = 10*max + char_to_int (ch);
511 max = va_arg (args, int);
519 /* Currently, we don't support Long Long, bummer */
531 cflags = DP_C_LDOUBLE;
544 if (cflags == DP_C_SHORT)
545 value = va_arg (args, short int);
546 else if (cflags == DP_C_LONG)
547 value = va_arg (args, long int);
549 value = va_arg (args, int);
550 fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
553 flags |= DP_F_UNSIGNED;
554 if (cflags == DP_C_SHORT)
555 value = va_arg (args, unsigned short int);
556 else if (cflags == DP_C_LONG)
557 value = va_arg (args, unsigned long int);
559 value = va_arg (args, unsigned int);
560 fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags);
563 flags |= DP_F_UNSIGNED;
564 if (cflags == DP_C_SHORT)
565 value = va_arg (args, unsigned short int);
566 else if (cflags == DP_C_LONG)
567 value = va_arg (args, unsigned long int);
569 value = va_arg (args, unsigned int);
570 fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
575 flags |= DP_F_UNSIGNED;
576 if (cflags == DP_C_SHORT)
577 value = va_arg (args, unsigned short int);
578 else if (cflags == DP_C_LONG)
579 value = va_arg (args, unsigned long int);
581 value = va_arg (args, unsigned int);
582 fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags);
585 if (cflags == DP_C_LDOUBLE)
586 fvalue = va_arg (args, long double);
588 fvalue = va_arg (args, double);
589 /* um, floating point? */
590 fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
595 if (cflags == DP_C_LDOUBLE)
596 fvalue = va_arg (args, long double);
598 fvalue = va_arg (args, double);
603 if (cflags == DP_C_LDOUBLE)
604 fvalue = va_arg (args, long double);
606 fvalue = va_arg (args, double);
609 dopr_outch (buffer, &currlen, maxlen, va_arg (args, int));
612 strvalue = va_arg (args, char *);
614 max = maxlen; /* ie, no max */
615 fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max);
618 strvalue = va_arg (args, void *);
619 fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags);
622 if (cflags == DP_C_SHORT)
625 num = va_arg (args, short int *);
628 else if (cflags == DP_C_LONG)
631 num = va_arg (args, long int *);
637 num = va_arg (args, int *);
642 dopr_outch (buffer, &currlen, maxlen, ch);
645 /* not supported yet, treat as next char */
653 state = DP_S_DEFAULT;
654 flags = cflags = min = 0;
661 break; /* some picky compilers need this */
664 if (currlen < maxlen - 1)
665 buffer[currlen] = '\0';
667 buffer[maxlen - 1] = '\0';
670 static void fmtstr (char *buffer, size_t *currlen, size_t maxlen,
671 char *value, int flags, int min, int max)
673 int padlen, strln; /* amount to pad */
681 for (strln = 0; value[strln]; ++strln); /* strlen */
682 padlen = min - strln;
685 if (flags & DP_F_MINUS)
686 padlen = -padlen; /* Left Justify */
688 while ((padlen > 0) && (cnt < max))
690 dopr_outch (buffer, currlen, maxlen, ' ');
694 while (*value && (cnt < max))
696 dopr_outch (buffer, currlen, maxlen, *value++);
699 while ((padlen < 0) && (cnt < max))
701 dopr_outch (buffer, currlen, maxlen, ' ');
707 /* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
709 static void fmtint (char *buffer, size_t *currlen, size_t maxlen,
710 long value, int base, int min, int max, int flags)
713 unsigned long uvalue;
716 int spadlen = 0; /* amount to space pad */
717 int zpadlen = 0; /* amount to zero pad */
725 if(!(flags & DP_F_UNSIGNED))
732 if (flags & DP_F_PLUS) /* Do a sign (+/i) */
735 if (flags & DP_F_SPACE)
739 if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
743 (caps? "0123456789ABCDEF":"0123456789abcdef")
744 [uvalue % (unsigned)base ];
745 uvalue = (uvalue / (unsigned)base );
746 } while(uvalue && (place < 20));
747 if (place == 20) place--;
750 zpadlen = max - place;
751 spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
752 if (zpadlen < 0) zpadlen = 0;
753 if (spadlen < 0) spadlen = 0;
754 if (flags & DP_F_ZERO)
756 zpadlen = MAX(zpadlen, spadlen);
759 if (flags & DP_F_MINUS)
760 spadlen = -spadlen; /* Left Justifty */
762 #ifdef DEBUG_SNPRINTF
763 dprint (1, (debugfile, "zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
764 zpadlen, spadlen, min, max, place));
770 dopr_outch (buffer, currlen, maxlen, ' ');
776 dopr_outch (buffer, currlen, maxlen, signvalue);
783 dopr_outch (buffer, currlen, maxlen, '0');
790 dopr_outch (buffer, currlen, maxlen, convert[--place]);
792 /* Left Justified spaces */
793 while (spadlen < 0) {
794 dopr_outch (buffer, currlen, maxlen, ' ');
799 static long double abs_val (long double value)
801 long double result = value;
809 static long double pow10 (int exp)
811 long double result = 1;
822 static long round (long double value)
827 value = value - intpart;
834 static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
835 long double fvalue, int min, int max, int flags)
843 int padlen = 0; /* amount to pad */
850 * AIX manpage says the default is 0, but Solaris says the default
851 * is 6, and sprintf on AIX defaults to 6
856 ufvalue = abs_val (fvalue);
861 if (flags & DP_F_PLUS) /* Do a sign (+/i) */
864 if (flags & DP_F_SPACE)
868 if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
874 * Sorry, we only support 9 digits past the decimal because of our
880 /* We "cheat" by converting the fractional part to integer by
881 * multiplying by a factor of 10
883 fracpart = round ((pow10 (max)) * (ufvalue - intpart));
885 if (fracpart >= pow10 (max))
888 fracpart -= pow10 (max);
891 #ifdef DEBUG_SNPRINTF
892 dprint (1, (debugfile, "fmtfp: %f =? %d.%d\n", fvalue, intpart, fracpart));
895 /* Convert integer part */
898 (caps? "0123456789ABCDEF":"0123456789abcdef")[intpart % 10];
899 intpart = (intpart / 10);
900 } while(intpart && (iplace < 20));
901 if (iplace == 20) iplace--;
902 iconvert[iplace] = 0;
904 /* Convert fractional part */
907 (caps? "0123456789ABCDEF":"0123456789abcdef")[fracpart % 10];
908 fracpart = (fracpart / 10);
909 } while(fracpart && (fplace < 20));
910 if (fplace == 20) fplace--;
911 fconvert[fplace] = 0;
913 /* -1 for decimal point, another -1 if we are printing a sign */
914 padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
915 zpadlen = max - fplace;
920 if (flags & DP_F_MINUS)
921 padlen = -padlen; /* Left Justifty */
923 if ((flags & DP_F_ZERO) && (padlen > 0))
927 dopr_outch (buffer, currlen, maxlen, signvalue);
933 dopr_outch (buffer, currlen, maxlen, '0');
939 dopr_outch (buffer, currlen, maxlen, ' ');
943 dopr_outch (buffer, currlen, maxlen, signvalue);
946 dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]);
949 * Decimal point. This should probably use locale to find the correct
952 dopr_outch (buffer, currlen, maxlen, '.');
955 dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]);
959 dopr_outch (buffer, currlen, maxlen, '0');
965 dopr_outch (buffer, currlen, maxlen, ' ');
970 static void dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c)
972 if (*currlen < maxlen)
973 buffer[(*currlen)++] = c;
975 #endif /* !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) */
977 #ifndef HAVE_VSNPRINTF
978 int vsnprintf (char *str, size_t count, const char *fmt, va_list args)
981 dopr(str, count, fmt, args);
984 #endif /* !HAVE_VSNPRINTF */
986 #ifndef HAVE_SNPRINTF
989 int snprintf (char *str,size_t count,const char *fmt,...)
991 int snprintf (va_alist) va_dcl
1002 VA_SHIFT (str, char *);
1003 VA_SHIFT (count, size_t );
1004 VA_SHIFT (fmt, char *);
1005 (void) vsnprintf(str, count, fmt, ap);
1007 return(strlen(str));
1010 #ifdef TEST_SNPRINTF
1012 #define LONG_STRING 1024
1016 char buf1[LONG_STRING];
1017 char buf2[LONG_STRING];
1032 double fp_nums[] = { -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996,
1033 0.9996, 1.996, 4.136, 0};
1046 long int_nums[] = { -1, 134, 91340, 341, 0203, 0};
1051 printf ("Testing snprintf format codes against system sprintf...\n");
1053 for (x = 0; fp_fmt[x] != NULL ; x++)
1054 for (y = 0; fp_nums[y] != 0 ; y++)
1056 snprintf (buf1, sizeof (buf1), fp_fmt[x], fp_nums[y]);
1057 sprintf (buf2, fp_fmt[x], fp_nums[y]);
1058 if (strcmp (buf1, buf2))
1060 printf("snprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
1061 fp_fmt[x], buf1, buf2);
1067 for (x = 0; int_fmt[x] != NULL ; x++)
1068 for (y = 0; int_nums[y] != 0 ; y++)
1070 snprintf (buf1, sizeof (buf1), int_fmt[x], int_nums[y]);
1071 sprintf (buf2, int_fmt[x], int_nums[y]);
1072 if (strcmp (buf1, buf2))
1074 printf("snprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
1075 int_fmt[x], buf1, buf2);
1080 printf ("%d tests failed out of %d.\n", fail, num);
1082 #endif /* SNPRINTF_TEST */
1084 #endif /* !HAVE_SNPRINTF */