typo fix in comment.
[gpgme.git] / gpgme / vasprintf.c
1 /* Like vsprintf but provides a pointer to malloc'd storage, which must
2    be freed by the caller.
3    Copyright (C) 1994, 2002 Free Software Foundation, Inc.
4
5 This file is part of the libiberty library.
6 Libiberty is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
10
11 Libiberty is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 Library General Public License for more details.
15
16 You should have received a copy of the GNU Library General Public
17 License along with libiberty; see the file COPYING.LIB.  If
18 not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.  */
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24 #include <stdio.h>
25 #include <string.h>
26 #include <stdlib.h>
27 #include <stdarg.h>
28
29 #ifdef TEST
30 int global_total_width;
31 #endif
32
33 int
34 vasprintf (char **result, const char *format, va_list *args)
35 {
36   const char *p = format;
37   /* Add one to make sure that it is never zero, which might cause malloc
38      to return NULL.  */
39   int total_width = strlen (format) + 1;
40   va_list ap;
41
42   /* FIXME: use va_copy() */
43   memcpy (&ap, args, sizeof (va_list));
44
45   while (*p != '\0')
46     {
47       if (*p++ == '%')
48         {
49           while (strchr ("-+ #0", *p))
50             ++p;
51           if (*p == '*')
52             {
53               ++p;
54               total_width += abs (va_arg (ap, int));
55             }
56           else
57             total_width += strtoul (p, (char**)&p, 10);
58           if (*p == '.')
59             {
60               ++p;
61               if (*p == '*')
62                 {
63                   ++p;
64                   total_width += abs (va_arg (ap, int));
65                 }
66               else
67               total_width += strtoul (p, (char**)&p, 10);
68             }
69           while (strchr ("hlL", *p))
70             ++p;
71           /* Should be big enough for any format specifier except %s and floats.  */
72           total_width += 30;
73           switch (*p)
74             {
75             case 'd':
76             case 'i':
77             case 'o':
78             case 'u':
79             case 'x':
80             case 'X':
81             case 'c':
82               (void) va_arg (ap, int);
83               break;
84             case 'f':
85             case 'e':
86             case 'E':
87             case 'g':
88             case 'G':
89               (void) va_arg (ap, double);
90               /* Since an ieee double can have an exponent of 307, we'll
91                  make the buffer wide enough to cover the gross case. */
92               total_width += 307;
93               break;
94             case 's':
95               total_width += strlen (va_arg (ap, char *));
96               break;
97             case 'p':
98             case 'n':
99               (void) va_arg (ap, char *);
100               break;
101             }
102         }
103     }
104 #ifdef TEST
105   global_total_width = total_width;
106 #endif
107   *result = malloc (total_width);
108   if (*result != NULL)
109     return vsprintf (*result, format, *args);
110   else
111     return 0;
112 }
113
114
115 int
116 asprintf (char **buf, const char *fmt, ...)
117 {
118   int status;
119   va_list ap;
120
121   va_start (ap, fmt);
122   status = vasprintf (buf, fmt, ap);
123   va_end (ap);
124   return status;
125 }
126
127
128 #ifdef TEST
129 void
130 checkit (const char* format, ...)
131 {
132   va_list args;
133   char *result;
134
135   va_start (args, format);
136   vasprintf (&result, format, args);
137   if (strlen (result) < global_total_width)
138     printf ("PASS: ");
139   else
140     printf ("FAIL: ");
141   printf ("%d %s\n", global_total_width, result);
142 }
143
144 int
145 main (void)
146 {
147   checkit ("%d", 0x12345678);
148   checkit ("%200d", 5);
149   checkit ("%.300d", 6);
150   checkit ("%100.150d", 7);
151   checkit ("%s", "jjjjjjjjjiiiiiiiiiiiiiiioooooooooooooooooppppppppppppaa\n\
152 777777777777777777333333333333366666666666622222222222777777777777733333");
153   checkit ("%f%s%d%s", 1.0, "foo", 77, "asdjffffffffffffffiiiiiiiiiiixxxxx");
154 }
155 #endif /* TEST */