blob: 6be42523f95c306e62b457a018d2c5140f78b489 [file] [log] [blame]
Jon Medhurstaaf37a32013-06-11 12:10:56 +01001/*
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
51int /* 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
75char * /* 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
96char * /* 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
122int /* 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
431char * /* 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 */