6be42523f95c306e62b457a018d2c5140f78b489
[firefly-linux-kernel-4.4.55.git] / tools / gator / daemon / mxml / mxml-string.c
1 /*
2  * "$Id: mxml-string.c 424 2010-12-25 16:21:50Z mike $"
3  *
4  * String functions for Mini-XML, a small XML-like file parsing library.
5  *
6  * Copyright 2003-2010 by Michael R Sweet.
7  *
8  * These coded instructions, statements, and computer programs are the
9  * property of Michael R Sweet and are protected by Federal copyright
10  * law.  Distribution and use rights are outlined in the file "COPYING"
11  * which should have been included with this file.  If this file is
12  * missing or damaged, see the license at:
13  *
14  *     http://www.minixml.org/
15  *
16  * Contents:
17  *
18  *   _mxml_snprintf()  - Format a string.
19  *   _mxml_strdup()    - Duplicate a string.
20  *   _mxml_strdupf()   - Format and duplicate a string.
21  *   _mxml_vsnprintf() - Format a string into a fixed size buffer.
22  *   _mxml_vstrdupf()  - Format and duplicate a string.
23  */
24
25 /*
26  * Include necessary headers...
27  */
28
29 #include "config.h"
30
31
32 /*
33  * The va_copy macro is part of C99, but many compilers don't implement it.
34  * Provide a "direct assignment" implmentation when va_copy isn't defined...
35  */
36
37 #ifndef va_copy
38 #  ifdef __va_copy
39 #    define va_copy(dst,src) __va_copy(dst,src)
40 #  else
41 #    define va_copy(dst,src) memcpy(&dst, &src, sizeof(va_list))
42 #  endif /* __va_copy */
43 #endif /* va_copy */
44
45
46 #ifndef HAVE_SNPRINTF
47 /*
48  * '_mxml_snprintf()' - Format a string.
49  */
50
51 int                                     /* O - Number of bytes formatted */
52 _mxml_snprintf(char       *buffer,      /* I - Output buffer */
53                size_t     bufsize,      /* I - Size of output buffer */
54                const char *format,      /* I - Printf-style format string */
55                ...)                     /* I - Additional arguments as needed */
56 {
57   va_list       ap;                     /* Argument list */
58   int           bytes;                  /* Number of bytes formatted */
59
60
61   va_start(ap, format);
62   bytes = vsnprintf(buffer, bufsize, format, ap);
63   va_end(ap);
64
65   return (bytes);
66 }
67 #endif /* !HAVE_SNPRINTF */
68
69
70 /*
71  * '_mxml_strdup()' - Duplicate a string.
72  */
73
74 #ifndef HAVE_STRDUP
75 char *                                  /* O - New string pointer */
76 _mxml_strdup(const char *s)             /* I - String to duplicate */
77 {
78   char  *t;                             /* New string pointer */
79
80
81   if (s == NULL)
82     return (NULL);
83
84   if ((t = malloc(strlen(s) + 1)) == NULL)
85     return (NULL);
86
87   return (strcpy(t, s));
88 }
89 #endif /* !HAVE_STRDUP */
90
91
92 /*
93  * '_mxml_strdupf()' - Format and duplicate a string.
94  */
95
96 char *                                  /* O - New string pointer */
97 _mxml_strdupf(const char *format,       /* I - Printf-style format string */
98               ...)                      /* I - Additional arguments as needed */
99 {
100   va_list       ap;                     /* Pointer to additional arguments */
101   char          *s;                     /* Pointer to formatted string */
102
103
104  /*
105   * Get a pointer to the additional arguments, format the string,
106   * and return it...
107   */
108
109   va_start(ap, format);
110   s = _mxml_vstrdupf(format, ap);
111   va_end(ap);
112
113   return (s);
114 }
115
116
117 #ifndef HAVE_VSNPRINTF
118 /*
119  * '_mxml_vsnprintf()' - Format a string into a fixed size buffer.
120  */
121
122 int                                     /* O - Number of bytes formatted */
123 _mxml_vsnprintf(char       *buffer,     /* O - Output buffer */
124                 size_t     bufsize,     /* O - Size of output buffer */
125                 const char *format,     /* I - Printf-style format string */
126                 va_list    ap)          /* I - Pointer to additional arguments */
127 {
128   char          *bufptr,                /* Pointer to position in buffer */
129                 *bufend,                /* Pointer to end of buffer */
130                 sign,                   /* Sign of format width */
131                 size,                   /* Size character (h, l, L) */
132                 type;                   /* Format type character */
133   int           width,                  /* Width of field */
134                 prec;                   /* Number of characters of precision */
135   char          tformat[100],           /* Temporary format string for sprintf() */
136                 *tptr,                  /* Pointer into temporary format */
137                 temp[1024];             /* Buffer for formatted numbers */
138   char          *s;                     /* Pointer to string */
139   int           slen;                   /* Length of string */
140   int           bytes;                  /* Total number of bytes needed */
141
142
143  /*
144   * Loop through the format string, formatting as needed...
145   */
146
147   bufptr = buffer;
148   bufend = buffer + bufsize - 1;
149   bytes  = 0;
150
151   while (*format)
152   {
153     if (*format == '%')
154     {
155       tptr = tformat;
156       *tptr++ = *format++;
157
158       if (*format == '%')
159       {
160         if (bufptr && bufptr < bufend) *bufptr++ = *format;
161         bytes ++;
162         format ++;
163         continue;
164       }
165       else if (strchr(" -+#\'", *format))
166       {
167         *tptr++ = *format;
168         sign = *format++;
169       }
170       else
171         sign = 0;
172
173       if (*format == '*')
174       {
175        /*
176         * Get width from argument...
177         */
178
179         format ++;
180         width = va_arg(ap, int);
181
182         snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", width);
183         tptr += strlen(tptr);
184       }
185       else
186       {
187         width = 0;
188
189         while (isdigit(*format & 255))
190         {
191           if (tptr < (tformat + sizeof(tformat) - 1))
192             *tptr++ = *format;
193
194           width = width * 10 + *format++ - '0';
195         }
196       }
197
198       if (*format == '.')
199       {
200         if (tptr < (tformat + sizeof(tformat) - 1))
201           *tptr++ = *format;
202
203         format ++;
204
205         if (*format == '*')
206         {
207          /*
208           * Get precision from argument...
209           */
210
211           format ++;
212           prec = va_arg(ap, int);
213
214           snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", prec);
215           tptr += strlen(tptr);
216         }
217         else
218         {
219           prec = 0;
220
221           while (isdigit(*format & 255))
222           {
223             if (tptr < (tformat + sizeof(tformat) - 1))
224               *tptr++ = *format;
225
226             prec = prec * 10 + *format++ - '0';
227           }
228         }
229       }
230       else
231         prec = -1;
232
233       if (*format == 'l' && format[1] == 'l')
234       {
235         size = 'L';
236
237         if (tptr < (tformat + sizeof(tformat) - 2))
238         {
239           *tptr++ = 'l';
240           *tptr++ = 'l';
241         }
242
243         format += 2;
244       }
245       else if (*format == 'h' || *format == 'l' || *format == 'L')
246       {
247         if (tptr < (tformat + sizeof(tformat) - 1))
248           *tptr++ = *format;
249
250         size = *format++;
251       }
252
253       if (!*format)
254         break;
255
256       if (tptr < (tformat + sizeof(tformat) - 1))
257         *tptr++ = *format;
258
259       type  = *format++;
260       *tptr = '\0';
261
262       switch (type)
263       {
264         case 'E' : /* Floating point formats */
265         case 'G' :
266         case 'e' :
267         case 'f' :
268         case 'g' :
269             if ((width + 2) > sizeof(temp))
270               break;
271
272             sprintf(temp, tformat, va_arg(ap, double));
273
274             bytes += strlen(temp);
275
276             if (bufptr)
277             {
278               if ((bufptr + strlen(temp)) > bufend)
279               {
280                 strncpy(bufptr, temp, (size_t)(bufend - bufptr));
281                 bufptr = bufend;
282               }
283               else
284               {
285                 strcpy(bufptr, temp);
286                 bufptr += strlen(temp);
287               }
288             }
289             break;
290
291         case 'B' : /* Integer formats */
292         case 'X' :
293         case 'b' :
294         case 'd' :
295         case 'i' :
296         case 'o' :
297         case 'u' :
298         case 'x' :
299             if ((width + 2) > sizeof(temp))
300               break;
301
302 #ifdef HAVE_LONG_LONG
303             if (size == 'L')
304               sprintf(temp, tformat, va_arg(ap, long long));
305             else
306 #endif /* HAVE_LONG_LONG */
307             sprintf(temp, tformat, va_arg(ap, int));
308
309             bytes += strlen(temp);
310
311             if (bufptr)
312             {
313               if ((bufptr + strlen(temp)) > bufend)
314               {
315                 strncpy(bufptr, temp, (size_t)(bufend - bufptr));
316                 bufptr = bufend;
317               }
318               else
319               {
320                 strcpy(bufptr, temp);
321                 bufptr += strlen(temp);
322               }
323             }
324             break;
325
326         case 'p' : /* Pointer value */
327             if ((width + 2) > sizeof(temp))
328               break;
329
330             sprintf(temp, tformat, va_arg(ap, void *));
331
332             bytes += strlen(temp);
333
334             if (bufptr)
335             {
336               if ((bufptr + strlen(temp)) > bufend)
337               {
338                 strncpy(bufptr, temp, (size_t)(bufend - bufptr));
339                 bufptr = bufend;
340               }
341               else
342               {
343                 strcpy(bufptr, temp);
344                 bufptr += strlen(temp);
345               }
346             }
347             break;
348
349         case 'c' : /* Character or character array */
350             bytes += width;
351
352             if (bufptr)
353             {
354               if (width <= 1)
355                 *bufptr++ = va_arg(ap, int);
356               else
357               {
358                 if ((bufptr + width) > bufend)
359                   width = bufend - bufptr;
360
361                 memcpy(bufptr, va_arg(ap, char *), (size_t)width);
362                 bufptr += width;
363               }
364             }
365             break;
366
367         case 's' : /* String */
368             if ((s = va_arg(ap, char *)) == NULL)
369               s = "(null)";
370
371             slen = strlen(s);
372             if (slen > width && prec != width)
373               width = slen;
374
375             bytes += width;
376
377             if (bufptr)
378             {
379               if ((bufptr + width) > bufend)
380                 width = bufend - bufptr;
381
382               if (slen > width)
383                 slen = width;
384
385               if (sign == '-')
386               {
387                 strncpy(bufptr, s, (size_t)slen);
388                 memset(bufptr + slen, ' ', (size_t)(width - slen));
389               }
390               else
391               {
392                 memset(bufptr, ' ', (size_t)(width - slen));
393                 strncpy(bufptr + width - slen, s, (size_t)slen);
394               }
395
396               bufptr += width;
397             }
398             break;
399
400         case 'n' : /* Output number of chars so far */
401             *(va_arg(ap, int *)) = bytes;
402             break;
403       }
404     }
405     else
406     {
407       bytes ++;
408
409       if (bufptr && bufptr < bufend)
410         *bufptr++ = *format;
411
412       format ++;
413     }
414   }
415
416  /*
417   * Nul-terminate the string and return the number of characters needed.
418   */
419
420   *bufptr = '\0';
421
422   return (bytes);
423 }
424 #endif /* !HAVE_VSNPRINTF */
425
426
427 /*
428  * '_mxml_vstrdupf()' - Format and duplicate a string.
429  */
430
431 char *                                  /* O - New string pointer */
432 _mxml_vstrdupf(const char *format,      /* I - Printf-style format string */
433                va_list    ap)           /* I - Pointer to additional arguments */
434 {
435   int           bytes;                  /* Number of bytes required */
436   char          *buffer,                /* String buffer */
437                 temp[256];              /* Small buffer for first vsnprintf */
438   va_list       apcopy;                 /* Copy of argument list */
439
440
441  /*
442   * First format with a tiny buffer; this will tell us how many bytes are
443   * needed...
444   */
445
446   va_copy(apcopy, ap);
447   bytes = vsnprintf(temp, sizeof(temp), format, apcopy);
448
449   if (bytes < sizeof(temp))
450   {
451    /*
452     * Hey, the formatted string fits in the tiny buffer, so just dup that...
453     */
454
455     return (strdup(temp));
456   }
457
458  /*
459   * Allocate memory for the whole thing and reformat to the new, larger
460   * buffer...
461   */
462
463   if ((buffer = calloc(1, bytes + 1)) != NULL)
464     vsnprintf(buffer, bytes + 1, format, ap);
465
466  /*
467   * Return the new string...
468   */
469
470   return (buffer);
471 }
472
473
474 /*
475  * End of "$Id: mxml-string.c 424 2010-12-25 16:21:50Z mike $".
476  */