mxml-string.c

Go to the documentation of this file.
00001 /*
00002  * "$Id: mxml-string.c 312 2007-10-03 06:25:07Z mike $"
00003  *
00004  * String functions for Mini-XML, a small XML-like file parsing library.
00005  *
00006  * Copyright 2003-2007 by Michael Sweet.
00007  *
00008  * This program is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU Library General Public
00010  * License as published by the Free Software Foundation; either
00011  * version 2, or (at your option) any later version.
00012  *
00013  * This program is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * Contents:
00019  *
00020  *   _mxml_snprintf()  - Format a string.
00021  *   _mxml_strdup()    - Duplicate a string.
00022  *   _mxml_strdupf()   - Format and duplicate a string.
00023  *   _mxml_vsnprintf() - Format a string into a fixed size buffer.
00024  *   _mxml_vstrdupf()  - Format and duplicate a string.
00025  */
00026 
00027 /*
00028  * Include necessary headers...
00029  */
00030 
00031 #include "config.h"
00032 
00033 
00034 #ifndef HAVE_SNPRINTF
00035 /*
00036  * '_mxml_snprintf()' - Format a string.
00037  */
00038 
00039 int                 /* O - Number of bytes formatted */
00040 _mxml_snprintf(char       *buffer,  /* I - Output buffer */
00041                size_t     bufsize,  /* I - Size of output buffer */
00042            const char *format,  /* I - Printf-style format string */
00043            ...)         /* I - Additional arguments as needed */
00044 {
00045   va_list   ap;         /* Argument list */
00046   int       bytes;          /* Number of bytes formatted */
00047 
00048 
00049   va_start(ap, format);
00050   bytes = vsnprintf(buffer, bufsize, format, ap);
00051   va_end(ap);
00052 
00053   return (bytes);
00054 }
00055 #endif /* !HAVE_SNPRINTF */
00056 
00057 
00058 /*
00059  * '_mxml_strdup()' - Duplicate a string.
00060  */
00061 
00062 #ifndef HAVE_STRDUP
00063 char    *               /* O - New string pointer */
00064 _mxml_strdup(const char *s)     /* I - String to duplicate */
00065 {
00066   char  *t;             /* New string pointer */
00067 
00068 
00069   if (s == NULL)
00070     return (NULL);
00071 
00072   if ((t = malloc(strlen(s) + 1)) == NULL)
00073     return (NULL);
00074 
00075   return (strcpy(t, s));
00076 }
00077 #endif /* !HAVE_STRDUP */
00078 
00079 
00080 /*
00081  * '_mxml_strdupf()' - Format and duplicate a string.
00082  */
00083 
00084 char *                  /* O - New string pointer */
00085 _mxml_strdupf(const char *format,   /* I - Printf-style format string */
00086               ...)          /* I - Additional arguments as needed */
00087 {
00088   va_list   ap;         /* Pointer to additional arguments */
00089   char      *s;         /* Pointer to formatted string */
00090 
00091 
00092  /*
00093   * Get a pointer to the additional arguments, format the string,
00094   * and return it...
00095   */
00096 
00097   va_start(ap, format);
00098   s = _mxml_vstrdupf(format, ap);
00099   va_end(ap);
00100 
00101   return (s);
00102 }
00103 
00104 
00105 #ifndef HAVE_VSNPRINTF
00106 /*
00107  * '_mxml_vsnprintf()' - Format a string into a fixed size buffer.
00108  */
00109 
00110 int                 /* O - Number of bytes formatted */
00111 _mxml_vsnprintf(char       *buffer, /* O - Output buffer */
00112                 size_t     bufsize, /* O - Size of output buffer */
00113         const char *format, /* I - Printf-style format string */
00114         va_list    ap)      /* I - Pointer to additional arguments */
00115 {
00116   char      *bufptr,        /* Pointer to position in buffer */
00117         *bufend,        /* Pointer to end of buffer */
00118         sign,           /* Sign of format width */
00119         size,           /* Size character (h, l, L) */
00120         type;           /* Format type character */
00121   int       width,          /* Width of field */
00122         prec;           /* Number of characters of precision */
00123   char      tformat[100],       /* Temporary format string for sprintf() */
00124         *tptr,          /* Pointer into temporary format */
00125         temp[1024];     /* Buffer for formatted numbers */
00126   char      *s;         /* Pointer to string */
00127   int       slen;           /* Length of string */
00128   int       bytes;          /* Total number of bytes needed */
00129 
00130 
00131  /*
00132   * Loop through the format string, formatting as needed...
00133   */
00134 
00135   bufptr = buffer;
00136   bufend = buffer + bufsize - 1;
00137   bytes  = 0;
00138 
00139   while (*format)
00140   {
00141     if (*format == '%')
00142     {
00143       tptr = tformat;
00144       *tptr++ = *format++;
00145 
00146       if (*format == '%')
00147       {
00148         if (bufptr && bufptr < bufend) *bufptr++ = *format;
00149         bytes ++;
00150         format ++;
00151     continue;
00152       }
00153       else if (strchr(" -+#\'", *format))
00154       {
00155         *tptr++ = *format;
00156         sign = *format++;
00157       }
00158       else
00159         sign = 0;
00160 
00161       if (*format == '*')
00162       {
00163        /*
00164         * Get width from argument...
00165     */
00166 
00167     format ++;
00168     width = va_arg(ap, int);
00169 
00170     snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", width);
00171     tptr += strlen(tptr);
00172       }
00173       else
00174       {
00175     width = 0;
00176 
00177     while (isdigit(*format & 255))
00178     {
00179       if (tptr < (tformat + sizeof(tformat) - 1))
00180         *tptr++ = *format;
00181 
00182       width = width * 10 + *format++ - '0';
00183     }
00184       }
00185 
00186       if (*format == '.')
00187       {
00188     if (tptr < (tformat + sizeof(tformat) - 1))
00189       *tptr++ = *format;
00190 
00191         format ++;
00192 
00193         if (*format == '*')
00194     {
00195          /*
00196       * Get precision from argument...
00197       */
00198 
00199       format ++;
00200       prec = va_arg(ap, int);
00201 
00202       snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", prec);
00203       tptr += strlen(tptr);
00204     }
00205     else
00206     {
00207       prec = 0;
00208 
00209       while (isdigit(*format & 255))
00210       {
00211         if (tptr < (tformat + sizeof(tformat) - 1))
00212           *tptr++ = *format;
00213 
00214         prec = prec * 10 + *format++ - '0';
00215       }
00216     }
00217       }
00218       else
00219         prec = -1;
00220 
00221       if (*format == 'l' && format[1] == 'l')
00222       {
00223         size = 'L';
00224 
00225     if (tptr < (tformat + sizeof(tformat) - 2))
00226     {
00227       *tptr++ = 'l';
00228       *tptr++ = 'l';
00229     }
00230 
00231     format += 2;
00232       }
00233       else if (*format == 'h' || *format == 'l' || *format == 'L')
00234       {
00235     if (tptr < (tformat + sizeof(tformat) - 1))
00236       *tptr++ = *format;
00237 
00238         size = *format++;
00239       }
00240 
00241       if (!*format)
00242         break;
00243 
00244       if (tptr < (tformat + sizeof(tformat) - 1))
00245         *tptr++ = *format;
00246 
00247       type  = *format++;
00248       *tptr = '\0';
00249 
00250       switch (type)
00251       {
00252     case 'E' : /* Floating point formats */
00253     case 'G' :
00254     case 'e' :
00255     case 'f' :
00256     case 'g' :
00257         if ((width + 2) > sizeof(temp))
00258           break;
00259 
00260         sprintf(temp, tformat, va_arg(ap, double));
00261 
00262             bytes += strlen(temp);
00263 
00264             if (bufptr)
00265         {
00266           if ((bufptr + strlen(temp)) > bufend)
00267           {
00268         strncpy(bufptr, temp, (size_t)(bufend - bufptr));
00269         bufptr = bufend;
00270           }
00271           else
00272           {
00273         strcpy(bufptr, temp);
00274         bufptr += strlen(temp);
00275           }
00276         }
00277         break;
00278 
00279         case 'B' : /* Integer formats */
00280     case 'X' :
00281     case 'b' :
00282         case 'd' :
00283     case 'i' :
00284     case 'o' :
00285     case 'u' :
00286     case 'x' :
00287         if ((width + 2) > sizeof(temp))
00288           break;
00289 
00290         sprintf(temp, tformat, va_arg(ap, int));
00291 
00292             bytes += strlen(temp);
00293 
00294         if (bufptr)
00295         {
00296           if ((bufptr + strlen(temp)) > bufend)
00297           {
00298         strncpy(bufptr, temp, (size_t)(bufend - bufptr));
00299         bufptr = bufend;
00300           }
00301           else
00302           {
00303         strcpy(bufptr, temp);
00304         bufptr += strlen(temp);
00305           }
00306         }
00307         break;
00308 
00309     case 'p' : /* Pointer value */
00310         if ((width + 2) > sizeof(temp))
00311           break;
00312 
00313         sprintf(temp, tformat, va_arg(ap, void *));
00314 
00315             bytes += strlen(temp);
00316 
00317         if (bufptr)
00318         {
00319           if ((bufptr + strlen(temp)) > bufend)
00320           {
00321         strncpy(bufptr, temp, (size_t)(bufend - bufptr));
00322         bufptr = bufend;
00323           }
00324           else
00325           {
00326         strcpy(bufptr, temp);
00327         bufptr += strlen(temp);
00328           }
00329         }
00330         break;
00331 
00332         case 'c' : /* Character or character array */
00333         bytes += width;
00334 
00335         if (bufptr)
00336         {
00337           if (width <= 1)
00338             *bufptr++ = va_arg(ap, int);
00339           else
00340           {
00341         if ((bufptr + width) > bufend)
00342           width = bufend - bufptr;
00343 
00344         memcpy(bufptr, va_arg(ap, char *), (size_t)width);
00345         bufptr += width;
00346           }
00347         }
00348         break;
00349 
00350     case 's' : /* String */
00351         if ((s = va_arg(ap, char *)) == NULL)
00352           s = "(null)";
00353 
00354         slen = strlen(s);
00355         if (slen > width && prec != width)
00356           width = slen;
00357 
00358             bytes += width;
00359 
00360         if (bufptr)
00361         {
00362           if ((bufptr + width) > bufend)
00363             width = bufend - bufptr;
00364 
00365               if (slen > width)
00366             slen = width;
00367 
00368           if (sign == '-')
00369           {
00370         strncpy(bufptr, s, (size_t)slen);
00371         memset(bufptr + slen, ' ', (size_t)(width - slen));
00372           }
00373           else
00374           {
00375         memset(bufptr, ' ', (size_t)(width - slen));
00376         strncpy(bufptr + width - slen, s, (size_t)slen);
00377           }
00378 
00379           bufptr += width;
00380         }
00381         break;
00382 
00383     case 'n' : /* Output number of chars so far */
00384         *(va_arg(ap, int *)) = bytes;
00385         break;
00386       }
00387     }
00388     else
00389     {
00390       bytes ++;
00391 
00392       if (bufptr && bufptr < bufend)
00393         *bufptr++ = *format;
00394 
00395       format ++;
00396     }
00397   }
00398 
00399  /*
00400   * Nul-terminate the string and return the number of characters needed.
00401   */
00402 
00403   *bufptr = '\0';
00404 
00405   return (bytes);
00406 }
00407 #endif /* !HAVE_VSNPRINTF */
00408 
00409 
00410 /*
00411  * '_mxml_vstrdupf()' - Format and duplicate a string.
00412  */
00413 
00414 char *                  /* O - New string pointer */
00415 _mxml_vstrdupf(const char *format,  /* I - Printf-style format string */
00416                va_list    ap)       /* I - Pointer to additional arguments */
00417 {
00418   int   bytes;              /* Number of bytes required */
00419   char  *buffer,            /* String buffer */
00420     temp[256];          /* Small buffer for first vsnprintf */
00421 
00422 
00423  /*
00424   * First format with a tiny buffer; this will tell us how many bytes are
00425   * needed...
00426   */
00427 
00428   bytes = vsnprintf(temp, sizeof(temp), format, ap);
00429 
00430   if (bytes < sizeof(temp))
00431   {
00432    /*
00433     * Hey, the formatted string fits in the tiny buffer, so just dup that...
00434     */
00435 
00436     return (strdup(temp));
00437   }
00438 
00439  /*
00440   * Allocate memory for the whole thing and reformat to the new, larger
00441   * buffer...
00442   */
00443 
00444   if ((buffer = calloc(1, bytes + 1)) != NULL)
00445     vsnprintf(buffer, bytes + 1, format, ap);
00446 
00447  /*
00448   * Return the new string...
00449   */
00450 
00451   return (buffer);
00452 }

Generated by  doxygen 1.6.2