2 * "$Id: mxml-string.c 424 2010-12-25 16:21:50Z mike $"
4 * String functions for Mini-XML, a small XML-like file parsing library.
6 * Copyright 2003-2010 by Michael R Sweet.
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:
14 * http://www.minixml.org/
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.
26 * Include necessary headers...
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...
39 # define va_copy(dst,src) __va_copy(dst,src)
41 # define va_copy(dst,src) memcpy(&dst, &src, sizeof(va_list))
42 # endif /* __va_copy */
48 * '_mxml_snprintf()' - Format a string.
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 */
57 va_list ap; /* Argument list */
58 int bytes; /* Number of bytes formatted */
62 bytes = vsnprintf(buffer, bufsize, format, ap);
67 #endif /* !HAVE_SNPRINTF */
71 * '_mxml_strdup()' - Duplicate a string.
75 char * /* O - New string pointer */
76 _mxml_strdup(const char *s) /* I - String to duplicate */
78 char *t; /* New string pointer */
84 if ((t = malloc(strlen(s) + 1)) == NULL)
87 return (strcpy(t, s));
89 #endif /* !HAVE_STRDUP */
93 * '_mxml_strdupf()' - Format and duplicate a string.
96 char * /* O - New string pointer */
97 _mxml_strdupf(const char *format, /* I - Printf-style format string */
98 ...) /* I - Additional arguments as needed */
100 va_list ap; /* Pointer to additional arguments */
101 char *s; /* Pointer to formatted string */
105 * Get a pointer to the additional arguments, format the string,
109 va_start(ap, format);
110 s = _mxml_vstrdupf(format, ap);
117 #ifndef HAVE_VSNPRINTF
119 * '_mxml_vsnprintf()' - Format a string into a fixed size buffer.
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 */
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 */
144 * Loop through the format string, formatting as needed...
148 bufend = buffer + bufsize - 1;
160 if (bufptr && bufptr < bufend) *bufptr++ = *format;
165 else if (strchr(" -+#\'", *format))
176 * Get width from argument...
180 width = va_arg(ap, int);
182 snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", width);
183 tptr += strlen(tptr);
189 while (isdigit(*format & 255))
191 if (tptr < (tformat + sizeof(tformat) - 1))
194 width = width * 10 + *format++ - '0';
200 if (tptr < (tformat + sizeof(tformat) - 1))
208 * Get precision from argument...
212 prec = va_arg(ap, int);
214 snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", prec);
215 tptr += strlen(tptr);
221 while (isdigit(*format & 255))
223 if (tptr < (tformat + sizeof(tformat) - 1))
226 prec = prec * 10 + *format++ - '0';
233 if (*format == 'l' && format[1] == 'l')
237 if (tptr < (tformat + sizeof(tformat) - 2))
245 else if (*format == 'h' || *format == 'l' || *format == 'L')
247 if (tptr < (tformat + sizeof(tformat) - 1))
256 if (tptr < (tformat + sizeof(tformat) - 1))
264 case 'E' : /* Floating point formats */
269 if ((width + 2) > sizeof(temp))
272 sprintf(temp, tformat, va_arg(ap, double));
274 bytes += strlen(temp);
278 if ((bufptr + strlen(temp)) > bufend)
280 strncpy(bufptr, temp, (size_t)(bufend - bufptr));
285 strcpy(bufptr, temp);
286 bufptr += strlen(temp);
291 case 'B' : /* Integer formats */
299 if ((width + 2) > sizeof(temp))
302 #ifdef HAVE_LONG_LONG
304 sprintf(temp, tformat, va_arg(ap, long long));
306 #endif /* HAVE_LONG_LONG */
307 sprintf(temp, tformat, va_arg(ap, int));
309 bytes += strlen(temp);
313 if ((bufptr + strlen(temp)) > bufend)
315 strncpy(bufptr, temp, (size_t)(bufend - bufptr));
320 strcpy(bufptr, temp);
321 bufptr += strlen(temp);
326 case 'p' : /* Pointer value */
327 if ((width + 2) > sizeof(temp))
330 sprintf(temp, tformat, va_arg(ap, void *));
332 bytes += strlen(temp);
336 if ((bufptr + strlen(temp)) > bufend)
338 strncpy(bufptr, temp, (size_t)(bufend - bufptr));
343 strcpy(bufptr, temp);
344 bufptr += strlen(temp);
349 case 'c' : /* Character or character array */
355 *bufptr++ = va_arg(ap, int);
358 if ((bufptr + width) > bufend)
359 width = bufend - bufptr;
361 memcpy(bufptr, va_arg(ap, char *), (size_t)width);
367 case 's' : /* String */
368 if ((s = va_arg(ap, char *)) == NULL)
372 if (slen > width && prec != width)
379 if ((bufptr + width) > bufend)
380 width = bufend - bufptr;
387 strncpy(bufptr, s, (size_t)slen);
388 memset(bufptr + slen, ' ', (size_t)(width - slen));
392 memset(bufptr, ' ', (size_t)(width - slen));
393 strncpy(bufptr + width - slen, s, (size_t)slen);
400 case 'n' : /* Output number of chars so far */
401 *(va_arg(ap, int *)) = bytes;
409 if (bufptr && bufptr < bufend)
417 * Nul-terminate the string and return the number of characters needed.
424 #endif /* !HAVE_VSNPRINTF */
428 * '_mxml_vstrdupf()' - Format and duplicate a string.
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 */
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 */
442 * First format with a tiny buffer; this will tell us how many bytes are
447 bytes = vsnprintf(temp, sizeof(temp), format, apcopy);
449 if (bytes < sizeof(temp))
452 * Hey, the formatted string fits in the tiny buffer, so just dup that...
455 return (strdup(temp));
459 * Allocate memory for the whole thing and reformat to the new, larger
463 if ((buffer = calloc(1, bytes + 1)) != NULL)
464 vsnprintf(buffer, bytes + 1, format, ap);
467 * Return the new string...
475 * End of "$Id: mxml-string.c 424 2010-12-25 16:21:50Z mike $".