don't blow up if a jitterbuffer is not in use
[asterisk/asterisk.git] / mxml / mxml-string.c
1 /*
2  * "$Id$"
3  *
4  * String functions for Mini-XML, a small XML-like file parsing library.
5  *
6  * Copyright 2003-2005 by Michael Sweet.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * Contents:
19  *
20  *   mxml_strdup()    - Duplicate a string.
21  *   mxml_strdupf()   - Format and duplicate a string.
22  *   mxml_vsnprintf() - Format a string into a fixed size buffer.
23  */
24
25 /*
26  * Include necessary headers...
27  */
28
29 #include "config.h"
30
31
32 /*
33  * 'mxml_strdup()' - Duplicate a string.
34  */
35
36 #ifndef HAVE_STRDUP
37 char    *                               /* O - New string pointer */
38 mxml_strdup(const char *s)              /* I - String to duplicate */
39 {
40   char  *t;                             /* New string pointer */
41
42
43   if (s == NULL)
44     return (NULL);
45
46   if ((t = malloc(strlen(s) + 1)) == NULL)
47     return (NULL);
48
49   return (strcpy(t, s));
50 }
51 #endif /* !HAVE_STRDUP */
52
53
54 /*
55  * 'mxml_strdupf()' - Format and duplicate a string.
56  */
57
58 char *                                  /* O - New string pointer */
59 mxml_strdupf(const char *format,        /* I - Printf-style format string */
60              va_list    ap)             /* I - Pointer to additional arguments */
61 {
62   int   bytes;                          /* Number of bytes required */
63   char  *buffer,                        /* String buffer */
64         temp[256];                      /* Small buffer for first vsnprintf */
65
66
67  /*
68   * First format with a tiny buffer; this will tell us how many bytes are
69   * needed...
70   */
71
72   bytes = vsnprintf(temp, sizeof(temp), format, ap);
73
74   if (bytes < sizeof(temp))
75   {
76    /*
77     * Hey, the formatted string fits in the tiny buffer, so just dup that...
78     */
79
80     return (strdup(temp));
81   }
82
83  /*
84   * Allocate memory for the whole thing and reformat to the new, larger
85   * buffer...
86   */
87
88   if ((buffer = calloc(1, bytes + 1)) != NULL)
89     vsnprintf(buffer, bytes + 1, format, ap);
90
91  /*
92   * Return the new string...
93   */
94
95   return (buffer);
96 }
97
98
99 #ifndef HAVE_VSNPRINTF
100 /*
101  * 'mxml_vsnprintf()' - Format a string into a fixed size buffer.
102  */
103
104 int                                     /* O - Number of bytes formatted */
105 mxml_vsnprintf(char       *buffer,      /* O - Output buffer */
106                size_t     bufsize,      /* O - Size of output buffer */
107                const char *format,      /* I - Printf-style format string */
108                va_list    ap)           /* I - Pointer to additional arguments */
109 {
110   char          *bufptr,                /* Pointer to position in buffer */
111                 *bufend,                /* Pointer to end of buffer */
112                 sign,                   /* Sign of format width */
113                 size,                   /* Size character (h, l, L) */
114                 type;                   /* Format type character */
115   const char    *bufformat;             /* Start of format */
116   int           width,                  /* Width of field */
117                 prec;                   /* Number of characters of precision */
118   char          tformat[100],           /* Temporary format string for sprintf() */
119                 temp[1024];             /* Buffer for formatted numbers */
120   char          *s;                     /* Pointer to string */
121   int           slen;                   /* Length of string */
122   int           bytes;                  /* Total number of bytes needed */
123
124
125  /*
126   * Loop through the format string, formatting as needed...
127   */
128
129   bufptr = buffer;
130   bufend = buffer + bufsize - 1;
131   bytes  = 0;
132
133   while (*format)
134   {
135     if (*format == '%')
136     {
137       bufformat = format;
138       format ++;
139
140       if (*format == '%')
141       {
142         *bufptr++ = *format++;
143         continue;
144       }
145       else if (strchr(" -+#\'", *format))
146         sign = *format++;
147       else
148         sign = 0;
149
150       width = 0;
151       while (isdigit(*format))
152         width = width * 10 + *format++ - '0';
153
154       if (*format == '.')
155       {
156         format ++;
157         prec = 0;
158
159         while (isdigit(*format))
160           prec = prec * 10 + *format++ - '0';
161       }
162       else
163         prec = -1;
164
165       if (*format == 'l' && format[1] == 'l')
166       {
167         size = 'L';
168         format += 2;
169       }
170       else if (*format == 'h' || *format == 'l' || *format == 'L')
171         size = *format++;
172
173       if (!*format)
174         break;
175
176       type = *format++;
177
178       switch (type)
179       {
180         case 'E' : /* Floating point formats */
181         case 'G' :
182         case 'e' :
183         case 'f' :
184         case 'g' :
185             if ((format - bufformat + 1) > sizeof(tformat) ||
186                 (width + 2) > sizeof(temp))
187               break;
188
189             strncpy(tformat, bufformat, format - bufformat);
190             tformat[format - bufformat] = '\0';
191
192             sprintf(temp, tformat, va_arg(ap, double));
193
194             bytes += strlen(temp);
195
196             if (bufptr)
197             {
198               if ((bufptr + strlen(temp)) > bufend)
199               {
200                 strncpy(bufptr, temp, bufend - bufptr);
201                 bufptr = bufend;
202                 break;
203               }
204               else
205               {
206                 strcpy(bufptr, temp);
207                 bufptr += strlen(temp);
208               }
209             }
210             break;
211
212         case 'B' : /* Integer formats */
213         case 'X' :
214         case 'b' :
215         case 'd' :
216         case 'i' :
217         case 'o' :
218         case 'u' :
219         case 'x' :
220             if ((format - bufformat + 1) > sizeof(tformat) ||
221                 (width + 2) > sizeof(temp))
222               break;
223
224             strncpy(tformat, bufformat, format - bufformat);
225             tformat[format - bufformat] = '\0';
226
227             sprintf(temp, tformat, va_arg(ap, int));
228
229             bytes += strlen(temp);
230
231             if (bufptr)
232             {
233               if ((bufptr + strlen(temp)) > bufend)
234               {
235                 strncpy(bufptr, temp, bufend - bufptr);
236                 bufptr = bufend;
237                 break;
238               }
239               else
240               {
241                 strcpy(bufptr, temp);
242                 bufptr += strlen(temp);
243               }
244             }
245             break;
246             
247         case 'p' : /* Pointer value */
248             if ((format - bufformat + 1) > sizeof(tformat) ||
249                 (width + 2) > sizeof(temp))
250               break;
251
252             strncpy(tformat, bufformat, format - bufformat);
253             tformat[format - bufformat] = '\0';
254
255             sprintf(temp, tformat, va_arg(ap, void *));
256
257             bytes += strlen(temp);
258
259             if (bufptr)
260             {
261               if ((bufptr + strlen(temp)) > bufend)
262               {
263                 strncpy(bufptr, temp, bufend - bufptr);
264                 bufptr = bufend;
265                 break;
266               }
267               else
268               {
269                 strcpy(bufptr, temp);
270                 bufptr += strlen(temp);
271               }
272             }
273             break;
274
275         case 'c' : /* Character or character array */
276             bytes += width;
277
278             if (bufptr)
279             {
280               if (width <= 1)
281                 *bufptr++ = va_arg(ap, int);
282               else
283               {
284                 if ((bufptr + width) > bufend)
285                   width = bufend - bufptr;
286
287                 memcpy(bufptr, va_arg(ap, char *), width);
288                 bufptr += width;
289               }
290             }
291             break;
292
293         case 's' : /* String */
294             if ((s = va_arg(ap, char *)) == NULL)
295               s = "(null)";
296
297             slen = strlen(s);
298             if (slen > width && prec != width)
299               width = slen;
300
301             bytes += width;
302
303             if (bufptr)
304             {
305               if ((bufptr + width) > bufend)
306                 width = bufend - bufptr;
307
308               if (slen > width)
309                 slen = width;
310
311               if (sign == '-')
312               {
313                 strncpy(bufptr, s, slen);
314                 memset(bufptr + slen, ' ', width - slen);
315               }
316               else
317               {
318                 memset(bufptr, ' ', width - slen);
319                 strncpy(bufptr + width - slen, s, slen);
320               }
321
322               bufptr += width;
323             }
324             break;
325
326         case 'n' : /* Output number of chars so far */
327             if ((format - bufformat + 1) > sizeof(tformat) ||
328                 (width + 2) > sizeof(temp))
329               break;
330
331             strncpy(tformat, bufformat, format - bufformat);
332             tformat[format - bufformat] = '\0';
333
334             sprintf(temp, tformat, va_arg(ap, int));
335
336             bytes += strlen(temp);
337
338             if (bufptr)
339             {
340               if ((bufptr + strlen(temp)) > bufend)
341               {
342                 strncpy(bufptr, temp, bufend - bufptr);
343                 bufptr = bufend;
344                 break;
345               }
346               else
347               {
348                 strcpy(bufptr, temp);
349                 bufptr += strlen(temp);
350               }
351             }
352             break;
353       }
354     }
355     else
356     {
357       bytes ++;
358
359       if (bufptr && bufptr < bufend)
360         *bufptr++ = *format++;
361     }
362   }
363
364  /*
365   * Nul-terminate the string and return the number of characters needed.
366   */
367
368   *bufptr = '\0';
369
370   return (bytes);
371 }
372 #endif /* !HAVE_VSNPRINTF */
373
374
375 /*
376  * End of "$Id$".
377  */