use automake 1.11, autoconf 2.65
[abook.git] / misc.c
blob9e39d0fd5b2c7573e0f28e898d601855e415f341
2 /*
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
12 #include <stdio.h>
13 #include <string.h>
14 #include <stdlib.h>
15 #include <ctype.h>
16 #include <unistd.h>
17 #include <errno.h>
18 #ifdef HAVE_CONFIG_H
19 # include "config.h"
20 #endif
21 #include <mbswidth.h>
22 #include "abook.h"
23 #include "misc.h"
24 #include "xmalloc.h"
26 #ifndef DEBUG
27 # define NDEBUG 1
28 #else
29 # undef NDEBUG
30 #endif
32 #include <assert.h>
34 char *
35 strlower(char *str)
37 char *tmp = str;
39 assert(str != NULL);
41 while( ( *str = tolower ( *str ) ) )
42 str++;
44 return tmp;
47 char *
48 strtrim(char *s)
50 char *t, *tt;
52 assert(s != NULL);
54 for(t = s; isspace(*t); t++);
56 memmove(s, t, strlen(t)+1);
58 for (tt = t = s; *t != '\0'; t++)
59 if(!isspace(*t))
60 tt = t+1;
62 *tt = '\0';
64 return s;
67 int
68 is_number(char *p)
70 if(!p || !*p || (*p == '-' && !*++p))
71 return 0;
73 for(; *p; p++)
74 if(!isdigit(*p))
75 return 0;
77 return 1;
80 char *
81 strcasestr(char *haystack, char *needle)
83 int i;
84 int k;
86 assert(haystack != NULL);
87 assert(needle != NULL);
89 for(i=0; i<strlen(haystack)-strlen(needle)+1; i++) {
90 for(k=0; k<strlen(needle); k++, i++) {
91 if (tolower(haystack[i]) != tolower(needle[k]))
92 break;
93 else if ((k+1) == strlen(needle))
94 return &haystack[i];
98 return NULL;
102 #ifdef HAVE_CONFIG_H
103 # include "config.h"
104 #endif
106 /* varargs declarations: */
108 #ifdef HAVE_STDARG_H
109 # define MY_VA_LOCAL_DECL va_list ap
110 # define MY_VA_START(f) va_start(ap, f)
111 # define MY_VA_SHIFT(v,t) v = va_arg(ap, t)
112 # define MY_VA_END va_end(ap)
113 #else
114 # error HAVE_STDARG_H not defined
115 #endif
117 char *
118 strdup_printf (const char *format, ... )
120 MY_VA_LOCAL_DECL;
121 size_t size = 100;
122 char *buffer = xmalloc (size);
124 assert(format != NULL);
126 for(;;) {
127 int n;
128 MY_VA_START(format);
129 n = vsnprintf (buffer, size,
130 format, ap);
131 MY_VA_END;
133 if (n > -1 && n < size)
134 return buffer;
136 if (n > -1)
137 size = n + 1;
138 else
139 size *= 2;
141 buffer = xrealloc(buffer, size);
146 char*
147 strconcat (const char *str, ...)
149 unsigned long l;
150 MY_VA_LOCAL_DECL;
151 char *s, *concat;
153 assert(str != NULL);
155 l = 1 + strlen (str);
156 MY_VA_START(str);
157 MY_VA_SHIFT(s, char*);
158 while (s) {
159 l += strlen (s);
160 MY_VA_SHIFT(s, char*);
162 MY_VA_END;
164 concat = xmalloc(l);
166 strcpy (concat, str);
167 MY_VA_START(str);
168 MY_VA_SHIFT(s, char*);
169 while (s) {
170 strcat (concat, s);
171 MY_VA_SHIFT(s, char*);
173 MY_VA_END;
175 return concat;
180 safe_strcmp(const char *s1, const char *s2)
182 if (s1 == NULL && s2 == NULL) return 0;
183 if (s1 == NULL) return -1;
184 if (s2 == NULL) return 1;
186 return strcmp(s1, s2);
190 safe_strcoll(const char *s1, const char *s2)
192 #ifdef HAVE_STRCOLL
193 if (s1 == NULL && s2 == NULL) return 0;
194 if (s1 == NULL) return -1;
195 if (s2 == NULL) return 1;
197 return strcoll(s1, s2);
198 #else /* fall back to strcmp */
199 return safe_strcmp(s1, s2);
200 #endif
203 char *
204 my_getcwd()
206 char *dir = NULL;
207 size_t size = 100;
209 if( (dir = xmalloc(size)) == NULL)
210 return NULL;
212 *dir = 0;
214 while( getcwd(dir, size) == NULL && errno == ERANGE )
215 if( (dir = xrealloc(dir, size *=2)) == NULL)
216 return NULL;
218 return dir;
222 * getaline()
224 * Copyright (c) 1994 Lars Wirzenius
225 * All rights reserved.
227 * Redistribution and use in source and binary forms, with or without
228 * modification, are permitted provided that the following conditions
229 * are met:
230 * 1. Redistributions of source code must retain the above copyright
231 * notice, this list of conditions and the following disclaimer
232 * in this position and unchanged.
233 * 2. Redistributions in binary form must reproduce the above copyright
234 * notice, this list of conditions and the following disclaimer in the
235 * documentation and/or other materials provided with the distribution.
237 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
238 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
239 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
240 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
241 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
242 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
243 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
244 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
245 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
246 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
249 char *
250 getaline(FILE *f)
252 char *buf; /* buffer for line */
253 size_t size; /* size of buffer */
254 size_t inc; /* how much to enlarge buffer */
255 size_t len; /* # of chars stored into buf before '\0' */
256 char *p;
257 const size_t thres = 128; /* initial buffer size (most lines should
258 fit into this size, so think of this as
259 the "long line threshold"). */
260 const size_t mucho = 128; /* if there is at least this much wasted
261 space when the whole buffer has been
262 read, try to reclaim it. Don't make
263 this too small, else there is too much
264 time wasted trying to reclaim a couple
265 of bytes. */
266 const size_t mininc = 64; /* minimum number of bytes by which
267 to increase the allocated memory */
269 len = 0;
270 size = thres;
271 buf = xmalloc(size);
273 while (fgets(buf+len, size-len, f) != NULL) {
274 len += strlen(buf+len);
275 if (len > 0 && buf[len-1] == '\n')
276 break; /* the whole line has been read */
278 for (inc = size, p = NULL; inc > mininc; inc /= 2)
279 if ((p = xrealloc_inc(buf, size, inc)) !=
280 NULL)
281 break;
283 size += inc;
284 buf = p;
287 if (len == 0) {
288 xfree(buf);
289 return NULL; /* nothing read (eof or error) */
292 if (buf[len-1] == '\n') /* remove newline, if there */
293 buf[--len] = '\0';
295 if (size - len > mucho) { /* a plenitude of unused memory? */
296 p = xrealloc_inc(buf, len, 1);
297 if (p != NULL) {
298 buf = p;
299 size = len+1;
303 return buf;
307 strwidth(const char *s)
309 assert(s);
310 return mbswidth(s, 0);
314 bytes2width(const char *s, int width)
316 assert(s);
317 #ifdef HANDLE_MULTIBYTE
318 return mbsnbytes(s, strlen(s), width, 0);
319 #else
320 return width;
321 #endif
324 /**************************************************************
325 * Original:
326 * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
327 * A bombproof version of doprnt (dopr) included.
328 * Sigh. This sort of thing is always nasty do deal with. Note that
329 * the version here does not include floating point...
331 * snprintf() is used instead of sprintf() as it does limit checks
332 * for string length. This covers a nasty loophole.
334 * The other functions are there to prevent NULL pointers from
335 * causing nast effects.
337 * More Recently:
338 * Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43
339 * This was ugly. It is still ugly. I opted out of floating point
340 * numbers, but the formatter understands just about everything
341 * from the normal C string format, at least as far as I can tell from
342 * the Solaris 2.5 printf(3S) man page.
344 * Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1
345 * Ok, added some minimal floating point support, which means this
346 * probably requires libm on most operating systems. Don't yet
347 * support the exponent (e,E) and sigfig (g,G). Also, fmtint()
348 * was pretty badly broken, it just wasn't being exercised in ways
349 * which showed it, so that's been fixed. Also, formated the code
350 * to mutt conventions, and removed dead code left over from the
351 * original. Also, there is now a builtin-test, just compile with:
352 * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
353 * and run snprintf for results.
355 * Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i
356 * The PGP code was using unsigned hexadecimal formats.
357 * Unfortunately, unsigned formats simply didn't work.
359 * Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8
360 * The original code assumed that both snprintf() and vsnprintf() were
361 * missing. Some systems only have snprintf() but not vsnprintf(), so
362 * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
364 **************************************************************/
366 #include "config.h"
368 #if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF)
370 #include <string.h>
371 # include <ctype.h>
372 #include <sys/types.h>
374 /* Define this as a fall through, HAVE_STDARG_H is probably already set */
376 #if !defined(HAVE_STDARG_H) && !defined(HAVE_VARARGS_H)
377 # define HAVE_VARARGS_H 1
378 #endif
380 /* varargs declarations: */
382 #if defined(HAVE_STDARG_H)
383 /*# include <stdarg.h>*/
384 # define HAVE_STDARGS /* let's hope that works everywhere (mj) */
385 # define VA_LOCAL_DECL va_list ap
386 # define VA_START(f) va_start(ap, f)
387 # define VA_SHIFT(v,t) ; /* no-op for ANSI */
388 # define VA_END va_end(ap)
389 #else
390 # if defined(HAVE_VARARGS_H)
391 # include <varargs.h>
392 # undef HAVE_STDARGS
393 # define VA_LOCAL_DECL va_list ap
394 # define VA_START(f) va_start(ap) /* f is ignored! */
395 # define VA_SHIFT(v,t) v = va_arg(ap,t)
396 # define VA_END va_end(ap)
397 # else
398 /*XX ** NO VARARGS ** XX*/
399 # endif
400 #endif
402 /*int snprintf (char *str, size_t count, const char *fmt, ...);*/
403 /*int vsnprintf (char *str, size_t count, const char *fmt, va_list arg);*/
405 static void dopr (char *buffer, size_t maxlen, const char *format,
406 va_list args);
407 static void fmtstr (char *buffer, size_t *currlen, size_t maxlen,
408 char *value, int flags, int min, int max);
409 static void fmtint (char *buffer, size_t *currlen, size_t maxlen,
410 long value, int base, int min, int max, int flags);
411 static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
412 long double fvalue, int min, int max, int flags);
413 static void dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c );
416 * dopr(): poor man's version of doprintf
419 /* format read states */
420 #define DP_S_DEFAULT 0
421 #define DP_S_FLAGS 1
422 #define DP_S_MIN 2
423 #define DP_S_DOT 3
424 #define DP_S_MAX 4
425 #define DP_S_MOD 5
426 #define DP_S_CONV 6
427 #define DP_S_DONE 7
429 /* format flags - Bits */
430 #define DP_F_MINUS (1 << 0)
431 #define DP_F_PLUS (1 << 1)
432 #define DP_F_SPACE (1 << 2)
433 #define DP_F_NUM (1 << 3)
434 #define DP_F_ZERO (1 << 4)
435 #define DP_F_UP (1 << 5)
436 #define DP_F_UNSIGNED (1 << 6)
438 /* Conversion Flags */
439 #define DP_C_SHORT 1
440 #define DP_C_LONG 2
441 #define DP_C_LDOUBLE 3
443 #define char_to_int(p) (p - '0')
444 #define MAX(p,q) ((p >= q) ? p : q)
446 static void dopr (char *buffer, size_t maxlen, const char *format, va_list args)
448 char ch;
449 long value;
450 long double fvalue;
451 char *strvalue;
452 int min;
453 int max;
454 int state;
455 int flags;
456 int cflags;
457 size_t currlen;
459 state = DP_S_DEFAULT;
460 currlen = flags = cflags = min = 0;
461 max = -1;
462 ch = *format++;
464 while (state != DP_S_DONE)
466 if ((ch == '\0') || (currlen >= maxlen))
467 state = DP_S_DONE;
469 switch(state)
471 case DP_S_DEFAULT:
472 if (ch == '%')
473 state = DP_S_FLAGS;
474 else
475 dopr_outch (buffer, &currlen, maxlen, ch);
476 ch = *format++;
477 break;
478 case DP_S_FLAGS:
479 switch (ch)
481 case '-':
482 flags |= DP_F_MINUS;
483 ch = *format++;
484 break;
485 case '+':
486 flags |= DP_F_PLUS;
487 ch = *format++;
488 break;
489 case ' ':
490 flags |= DP_F_SPACE;
491 ch = *format++;
492 break;
493 case '#':
494 flags |= DP_F_NUM;
495 ch = *format++;
496 break;
497 case '0':
498 flags |= DP_F_ZERO;
499 ch = *format++;
500 break;
501 default:
502 state = DP_S_MIN;
503 break;
505 break;
506 case DP_S_MIN:
507 if (isdigit((unsigned char)ch))
509 min = 10*min + char_to_int (ch);
510 ch = *format++;
512 else if (ch == '*')
514 min = va_arg (args, int);
515 ch = *format++;
516 state = DP_S_DOT;
518 else
519 state = DP_S_DOT;
520 break;
521 case DP_S_DOT:
522 if (ch == '.')
524 state = DP_S_MAX;
525 ch = *format++;
527 else
528 state = DP_S_MOD;
529 break;
530 case DP_S_MAX:
531 if (isdigit((unsigned char)ch))
533 if (max < 0)
534 max = 0;
535 max = 10*max + char_to_int (ch);
536 ch = *format++;
538 else if (ch == '*')
540 max = va_arg (args, int);
541 ch = *format++;
542 state = DP_S_MOD;
544 else
545 state = DP_S_MOD;
546 break;
547 case DP_S_MOD:
548 /* Currently, we don't support Long Long, bummer */
549 switch (ch)
551 case 'h':
552 cflags = DP_C_SHORT;
553 ch = *format++;
554 break;
555 case 'l':
556 cflags = DP_C_LONG;
557 ch = *format++;
558 break;
559 case 'L':
560 cflags = DP_C_LDOUBLE;
561 ch = *format++;
562 break;
563 default:
564 break;
566 state = DP_S_CONV;
567 break;
568 case DP_S_CONV:
569 switch (ch)
571 case 'd':
572 case 'i':
573 if (cflags == DP_C_SHORT)
574 value = va_arg (args, short int);
575 else if (cflags == DP_C_LONG)
576 value = va_arg (args, long int);
577 else
578 value = va_arg (args, int);
579 fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
580 break;
581 case 'o':
582 flags |= DP_F_UNSIGNED;
583 if (cflags == DP_C_SHORT)
584 value = va_arg (args, unsigned short int);
585 else if (cflags == DP_C_LONG)
586 value = va_arg (args, unsigned long int);
587 else
588 value = va_arg (args, unsigned int);
589 fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags);
590 break;
591 case 'u':
592 flags |= DP_F_UNSIGNED;
593 if (cflags == DP_C_SHORT)
594 value = va_arg (args, unsigned short int);
595 else if (cflags == DP_C_LONG)
596 value = va_arg (args, unsigned long int);
597 else
598 value = va_arg (args, unsigned int);
599 fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
600 break;
601 case 'X':
602 flags |= DP_F_UP;
603 case 'x':
604 flags |= DP_F_UNSIGNED;
605 if (cflags == DP_C_SHORT)
606 value = va_arg (args, unsigned short int);
607 else if (cflags == DP_C_LONG)
608 value = va_arg (args, unsigned long int);
609 else
610 value = va_arg (args, unsigned int);
611 fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags);
612 break;
613 case 'f':
614 if (cflags == DP_C_LDOUBLE)
615 fvalue = va_arg (args, long double);
616 else
617 fvalue = va_arg (args, double);
618 /* um, floating point? */
619 fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
620 break;
621 case 'E':
622 flags |= DP_F_UP;
623 case 'e':
624 if (cflags == DP_C_LDOUBLE)
625 fvalue = va_arg (args, long double);
626 else
627 fvalue = va_arg (args, double);
628 break;
629 case 'G':
630 flags |= DP_F_UP;
631 case 'g':
632 if (cflags == DP_C_LDOUBLE)
633 fvalue = va_arg (args, long double);
634 else
635 fvalue = va_arg (args, double);
636 break;
637 case 'c':
638 dopr_outch (buffer, &currlen, maxlen, va_arg (args, int));
639 break;
640 case 's':
641 strvalue = va_arg (args, char *);
642 if (max < 0)
643 max = maxlen; /* ie, no max */
644 fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max);
645 break;
646 case 'p':
647 strvalue = va_arg (args, void *);
648 fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags);
649 break;
650 case 'n':
651 if (cflags == DP_C_SHORT)
653 short int *num;
654 num = va_arg (args, short int *);
655 *num = currlen;
657 else if (cflags == DP_C_LONG)
659 long int *num;
660 num = va_arg (args, long int *);
661 *num = currlen;
663 else
665 int *num;
666 num = va_arg (args, int *);
667 *num = currlen;
669 break;
670 case '%':
671 dopr_outch (buffer, &currlen, maxlen, ch);
672 break;
673 case 'w':
674 /* not supported yet, treat as next char */
675 ch = *format++;
676 break;
677 default:
678 /* Unknown, skip */
679 break;
681 ch = *format++;
682 state = DP_S_DEFAULT;
683 flags = cflags = min = 0;
684 max = -1;
685 break;
686 case DP_S_DONE:
687 break;
688 default:
689 /* hmm? */
690 break; /* some picky compilers need this */
693 if (currlen < maxlen - 1)
694 buffer[currlen] = '\0';
695 else
696 buffer[maxlen - 1] = '\0';
699 static void fmtstr (char *buffer, size_t *currlen, size_t maxlen,
700 char *value, int flags, int min, int max)
702 int padlen, strln; /* amount to pad */
703 int cnt = 0;
705 if (value == 0)
707 value = "<NULL>";
710 for (strln = 0; value[strln]; ++strln); /* strlen */
711 padlen = min - strln;
712 if (padlen < 0)
713 padlen = 0;
714 if (flags & DP_F_MINUS)
715 padlen = -padlen; /* Left Justify */
717 while ((padlen > 0) && (cnt < max))
719 dopr_outch (buffer, currlen, maxlen, ' ');
720 --padlen;
721 ++cnt;
723 while (*value && (cnt < max))
725 dopr_outch (buffer, currlen, maxlen, *value++);
726 ++cnt;
728 while ((padlen < 0) && (cnt < max))
730 dopr_outch (buffer, currlen, maxlen, ' ');
731 ++padlen;
732 ++cnt;
736 /* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
738 static void fmtint (char *buffer, size_t *currlen, size_t maxlen,
739 long value, int base, int min, int max, int flags)
741 int signvalue = 0;
742 unsigned long uvalue;
743 char convert[20];
744 int place = 0;
745 int spadlen = 0; /* amount to space pad */
746 int zpadlen = 0; /* amount to zero pad */
747 int caps = 0;
749 if (max < 0)
750 max = 0;
752 uvalue = value;
754 if(!(flags & DP_F_UNSIGNED))
756 if( value < 0 ) {
757 signvalue = '-';
758 uvalue = -value;
760 else
761 if (flags & DP_F_PLUS) /* Do a sign (+/i) */
762 signvalue = '+';
763 else
764 if (flags & DP_F_SPACE)
765 signvalue = ' ';
768 if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
770 do {
771 convert[place++] =
772 (caps? "0123456789ABCDEF":"0123456789abcdef")
773 [uvalue % (unsigned)base ];
774 uvalue = (uvalue / (unsigned)base );
775 } while(uvalue && (place < 20));
776 if (place == 20) place--;
777 convert[place] = 0;
779 zpadlen = max - place;
780 spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
781 if (zpadlen < 0) zpadlen = 0;
782 if (spadlen < 0) spadlen = 0;
783 if (flags & DP_F_ZERO)
785 zpadlen = MAX(zpadlen, spadlen);
786 spadlen = 0;
788 if (flags & DP_F_MINUS)
789 spadlen = -spadlen; /* Left Justifty */
791 #ifdef DEBUG_SNPRINTF
792 dprint (1, (debugfile, "zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
793 zpadlen, spadlen, min, max, place));
794 #endif
796 /* Spaces */
797 while (spadlen > 0)
799 dopr_outch (buffer, currlen, maxlen, ' ');
800 --spadlen;
803 /* Sign */
804 if (signvalue)
805 dopr_outch (buffer, currlen, maxlen, signvalue);
807 /* Zeros */
808 if (zpadlen > 0)
810 while (zpadlen > 0)
812 dopr_outch (buffer, currlen, maxlen, '0');
813 --zpadlen;
817 /* Digits */
818 while (place > 0)
819 dopr_outch (buffer, currlen, maxlen, convert[--place]);
821 /* Left Justified spaces */
822 while (spadlen < 0) {
823 dopr_outch (buffer, currlen, maxlen, ' ');
824 ++spadlen;
828 static long double abs_val (long double value)
830 long double result = value;
832 if (value < 0)
833 result = -value;
835 return result;
838 static long double pow10 (int exp)
840 long double result = 1;
842 while (exp)
844 result *= 10;
845 exp--;
848 return result;
851 static long round (long double value)
853 long intpart;
855 intpart = value;
856 value = value - intpart;
857 if (value >= 0.5)
858 intpart++;
860 return intpart;
863 static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
864 long double fvalue, int min, int max, int flags)
866 int signvalue = 0;
867 long double ufvalue;
868 char iconvert[20];
869 char fconvert[20];
870 int iplace = 0;
871 int fplace = 0;
872 int padlen = 0; /* amount to pad */
873 int zpadlen = 0;
874 int caps = 0;
875 long intpart;
876 long fracpart;
879 * AIX manpage says the default is 0, but Solaris says the default
880 * is 6, and sprintf on AIX defaults to 6
882 if (max < 0)
883 max = 6;
885 ufvalue = abs_val (fvalue);
887 if (fvalue < 0)
888 signvalue = '-';
889 else
890 if (flags & DP_F_PLUS) /* Do a sign (+/i) */
891 signvalue = '+';
892 else
893 if (flags & DP_F_SPACE)
894 signvalue = ' ';
896 #if 0
897 if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
898 #endif
900 intpart = ufvalue;
903 * Sorry, we only support 9 digits past the decimal because of our
904 * conversion method
906 if (max > 9)
907 max = 9;
909 /* We "cheat" by converting the fractional part to integer by
910 * multiplying by a factor of 10
912 fracpart = round ((pow10 (max)) * (ufvalue - intpart));
914 if (fracpart >= pow10 (max))
916 intpart++;
917 fracpart -= pow10 (max);
920 #ifdef DEBUG_SNPRINTF
921 dprint (1, (debugfile, "fmtfp: %f =? %d.%d\n", fvalue, intpart, fracpart));
922 #endif
924 /* Convert integer part */
925 do {
926 iconvert[iplace++] =
927 (caps? "0123456789ABCDEF":"0123456789abcdef")[intpart % 10];
928 intpart = (intpart / 10);
929 } while(intpart && (iplace < 20));
930 if (iplace == 20) iplace--;
931 iconvert[iplace] = 0;
933 /* Convert fractional part */
934 do {
935 fconvert[fplace++] =
936 (caps? "0123456789ABCDEF":"0123456789abcdef")[fracpart % 10];
937 fracpart = (fracpart / 10);
938 } while(fracpart && (fplace < 20));
939 if (fplace == 20) fplace--;
940 fconvert[fplace] = 0;
942 /* -1 for decimal point, another -1 if we are printing a sign */
943 padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
944 zpadlen = max - fplace;
945 if (zpadlen < 0)
946 zpadlen = 0;
947 if (padlen < 0)
948 padlen = 0;
949 if (flags & DP_F_MINUS)
950 padlen = -padlen; /* Left Justifty */
952 if ((flags & DP_F_ZERO) && (padlen > 0))
954 if (signvalue)
956 dopr_outch (buffer, currlen, maxlen, signvalue);
957 --padlen;
958 signvalue = 0;
960 while (padlen > 0)
962 dopr_outch (buffer, currlen, maxlen, '0');
963 --padlen;
966 while (padlen > 0)
968 dopr_outch (buffer, currlen, maxlen, ' ');
969 --padlen;
971 if (signvalue)
972 dopr_outch (buffer, currlen, maxlen, signvalue);
974 while (iplace > 0)
975 dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]);
978 * Decimal point. This should probably use locale to find the correct
979 * char to print out.
981 dopr_outch (buffer, currlen, maxlen, '.');
983 while (fplace > 0)
984 dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]);
986 while (zpadlen > 0)
988 dopr_outch (buffer, currlen, maxlen, '0');
989 --zpadlen;
992 while (padlen < 0)
994 dopr_outch (buffer, currlen, maxlen, ' ');
995 ++padlen;
999 static void dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c)
1001 if (*currlen < maxlen)
1002 buffer[(*currlen)++] = c;
1004 #endif /* !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) */
1006 #ifndef HAVE_VSNPRINTF
1007 int vsnprintf (char *str, size_t count, const char *fmt, va_list args)
1009 str[0] = 0;
1010 dopr(str, count, fmt, args);
1011 return(strlen(str));
1013 #endif /* !HAVE_VSNPRINTF */
1015 #ifndef HAVE_SNPRINTF
1016 /* VARARGS3 */
1017 #ifdef HAVE_STDARGS
1018 int snprintf (char *str,size_t count,const char *fmt,...)
1019 #else
1020 int snprintf (va_alist) va_dcl
1021 #endif
1023 #ifndef HAVE_STDARGS
1024 char *str;
1025 size_t count;
1026 char *fmt;
1027 #endif
1028 VA_LOCAL_DECL;
1030 VA_START (fmt);
1031 VA_SHIFT (str, char *);
1032 VA_SHIFT (count, size_t );
1033 VA_SHIFT (fmt, char *);
1034 (void) vsnprintf(str, count, fmt, ap);
1035 VA_END;
1036 return(strlen(str));
1039 #ifdef TEST_SNPRINTF
1040 #ifndef LONG_STRING
1041 #define LONG_STRING 1024
1042 #endif
1043 int main (void)
1045 char buf1[LONG_STRING];
1046 char buf2[LONG_STRING];
1047 char *fp_fmt[] = {
1048 "%-1.5f",
1049 "%1.5f",
1050 "%123.9f",
1051 "%10.5f",
1052 "% 10.5f",
1053 "%+22.9f",
1054 "%+4.9f",
1055 "%01.3f",
1056 "%4f",
1057 "%3.1f",
1058 "%3.2f",
1059 NULL
1061 double fp_nums[] = { -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996,
1062 0.9996, 1.996, 4.136, 0};
1063 char *int_fmt[] = {
1064 "%-1.5d",
1065 "%1.5d",
1066 "%123.9d",
1067 "%5.5d",
1068 "%10.5d",
1069 "% 10.5d",
1070 "%+22.33d",
1071 "%01.3d",
1072 "%4d",
1073 NULL
1075 long int_nums[] = { -1, 134, 91340, 341, 0203, 0};
1076 int x, y;
1077 int fail = 0;
1078 int num = 0;
1080 printf ("Testing snprintf format codes against system sprintf...\n");
1082 for (x = 0; fp_fmt[x] != NULL ; x++)
1083 for (y = 0; fp_nums[y] != 0 ; y++)
1085 snprintf (buf1, sizeof (buf1), fp_fmt[x], fp_nums[y]);
1086 sprintf (buf2, fp_fmt[x], fp_nums[y]);
1087 if (strcmp (buf1, buf2))
1089 printf("snprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
1090 fp_fmt[x], buf1, buf2);
1091 fail++;
1093 num++;
1096 for (x = 0; int_fmt[x] != NULL ; x++)
1097 for (y = 0; int_nums[y] != 0 ; y++)
1099 snprintf (buf1, sizeof (buf1), int_fmt[x], int_nums[y]);
1100 sprintf (buf2, int_fmt[x], int_nums[y]);
1101 if (strcmp (buf1, buf2))
1103 printf("snprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
1104 int_fmt[x], buf1, buf2);
1105 fail++;
1107 num++;
1109 printf ("%d tests failed out of %d.\n", fail, num);
1111 #endif /* SNPRINTF_TEST */
1113 #endif /* !HAVE_SNPRINTF */
1119 * List handling functions
1122 void
1123 abook_list_append(abook_list **list, char *str)
1125 abook_list *tmp;
1127 if(!str)
1128 return;
1130 for(tmp = *list; tmp && tmp->next; tmp = tmp->next)
1133 if(tmp) {
1134 tmp->next = xmalloc(sizeof(abook_list));
1135 tmp = tmp->next;
1136 } else
1137 tmp = *list = xmalloc(sizeof(abook_list));
1139 tmp->data = xstrdup(str);
1140 tmp->next = NULL;
1143 void
1144 abook_list_free(abook_list **list)
1146 abook_list *prev = NULL, *tmp = *list;
1148 if(!list)
1149 return;
1151 while(tmp) {
1152 xfree(tmp->data);
1153 prev = tmp;
1154 tmp = tmp->next;
1155 xfree(prev);
1158 *list = NULL;
1161 abook_list *
1162 csv_to_abook_list(char *str)
1164 char *start, *p = str, *end;
1165 abook_list *list = NULL;
1167 if(!str)
1168 return NULL;
1170 SKIPWS(p);
1171 start = end = p;
1173 while(*p) {
1174 if(!strchr(", ", *p)) {
1175 end = ++p;
1176 continue;
1179 if((*p == ',') && (end - start)) {
1180 abook_list_append(&list, xstrndup(start, end - start));
1181 p++;
1182 SKIPWS(p);
1183 start = end = p;
1184 continue;
1187 p++;
1189 if(end - start)
1190 abook_list_append(&list, xstrndup(start, end - start));
1192 return list;
1195 char *
1196 abook_list_to_csv(abook_list *list)
1198 abook_list *tmp;
1199 char *res = NULL;
1201 for(tmp = list; tmp; tmp = tmp->next) {
1202 if(tmp == list)
1203 res = xstrdup(tmp->data);
1204 else {
1205 res = xrealloc(res, strlen(res)+strlen(tmp->data)+2);
1206 strcat(res, ",");
1207 strcat(res, tmp->data);
1211 return res;
1214 void
1215 abook_list_rotate(abook_list **list, enum rotate_dir dir)
1217 abook_list *tmp = *list;
1219 if(!tmp || !tmp->next)
1220 return;
1222 switch(dir) {
1223 case ROTATE_LEFT:
1224 for(; tmp && tmp->next; tmp = tmp->next)
1227 tmp->next = *list;
1228 tmp = *list;
1229 *list = (*list)->next;
1230 tmp->next = NULL;
1231 break;
1232 case ROTATE_RIGHT:
1233 for(; tmp && tmp->next && tmp->next->next;
1234 tmp = tmp->next)
1237 tmp->next->next = *list;
1238 *list = tmp->next;
1239 tmp->next = NULL;
1240 break;
1241 default:
1242 assert(0);
1246 /* if str == NULL, deleting the list element */
1247 void
1248 abook_list_replace(abook_list **list, int index, char *str)
1250 abook_list *cur, *prev;
1251 int i = 0;
1253 cur = prev = *list;
1255 if((index == 0) && !str) {
1256 *list = cur->next;
1257 free(cur->data);
1258 free(cur);
1259 return;
1262 while(1) {
1263 if(!cur)
1264 return;
1266 if(i == index)
1267 break;
1269 prev = cur;
1270 cur = cur->next;
1271 i++;
1274 if(str) {
1275 free(cur->data);
1276 cur->data = xstrdup(str);
1277 } else {
1278 prev->next = cur->next;
1279 free(cur->data);
1280 free(cur);
1284 abook_list *
1285 abook_list_get(abook_list *list, int index)
1287 int i = 0;
1289 while(1) {
1290 if(!list)
1291 return NULL;
1293 if(i == index)
1294 return list;
1296 i++;
1297 list = list->next;