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