* cardglue.c (card_close): New.
[gnupg.git] / common / 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 #ifdef va_copy
43   va_copy (ap, args);
44 #else
45 #ifdef __va_copy
46   __va_copy (ap, args);
47 #else
48   memcpy (&ap, args, sizeof (va_list));
49 #endif /* __va_copy */
50 #endif /* va_copy */
51
52   while (*p != '\0')
53     {
54       if (*p++ == '%')
55         {
56           while (strchr ("-+ #0", *p))
57             ++p;
58           if (*p == '*')
59             {
60               ++p;
61               total_width += abs (va_arg (ap, int));
62             }
63           else
64             total_width += strtoul (p, (char**)&p, 10);
65           if (*p == '.')
66             {
67               ++p;
68               if (*p == '*')
69                 {
70                   ++p;
71                   total_width += abs (va_arg (ap, int));
72                 }
73               else
74               total_width += strtoul (p, (char**)&p, 10);
75             }
76           while (strchr ("hlL", *p))
77             ++p;
78           /* Should be big enough for any format specifier except %s
79              and floats.  */
80           total_width += 30;
81           switch (*p)
82             {
83             case 'd':
84             case 'i':
85             case 'o':
86             case 'u':
87             case 'x':
88             case 'X':
89             case 'c':
90               (void) va_arg (ap, int);
91               break;
92             case 'f':
93             case 'e':
94             case 'E':
95             case 'g':
96             case 'G':
97               (void) va_arg (ap, double);
98               /* Since an ieee double can have an exponent of 307, we'll
99                  make the buffer wide enough to cover the gross case. */
100               total_width += 307;
101               break;
102             case 's':
103               {
104                 char *tmp = va_arg (ap, char *);
105                 if (tmp)
106                   total_width += strlen (tmp);
107                 else /* in case the vsprintf does prints a text */
108                   total_width += 25; /* e.g. "(null pointer reference)" */
109               }
110               break;
111             case 'p':
112             case 'n':
113               (void) va_arg (ap, char *);
114               break;
115             }
116         }
117     }
118 #ifdef TEST
119   global_total_width = total_width;
120 #endif
121   *result = malloc (total_width);
122   if (*result != NULL)
123     return vsprintf (*result, format, *args);
124   else
125     return 0;
126 }
127
128
129 int
130 asprintf (char **buf, const char *fmt, ...)
131 {
132   int status;
133   va_list ap;
134
135   va_start (ap, fmt);
136   status = vasprintf (buf, fmt, ap);
137   va_end (ap);
138   return status;
139 }
140
141
142 #ifdef TEST
143 void
144 checkit (const char* format, ...)
145 {
146   va_list args;
147   char *result;
148
149   va_start (args, format);
150   vasprintf (&result, format, args);
151   if (strlen (result) < global_total_width)
152     printf ("PASS: ");
153   else
154     printf ("FAIL: ");
155   printf ("%d %s\n", global_total_width, result);
156 }
157
158 int
159 main (void)
160 {
161   checkit ("%d", 0x12345678);
162   checkit ("%200d", 5);
163   checkit ("%.300d", 6);
164   checkit ("%100.150d", 7);
165   checkit ("%s", "jjjjjjjjjiiiiiiiiiiiiiiioooooooooooooooooppppppppppppaa\n\
166 777777777777777777333333333333366666666666622222222222777777777777733333");
167   checkit ("%f%s%d%s", 1.0, "foo", 77, "asdjffffffffffffffiiiiiiiiiiixxxxx");
168 }
169 #endif /* TEST */