Statistics
| Revision:

root / logic / trunk / src / mxml / mxml-string.c @ 49

History | View | Annotate | Download (9.34 KB)

1
/*
2
 * "$Id: mxml-string.c 387 2009-04-18 17:05:52Z mike $"
3
 *
4
 * String functions for Mini-XML, a small XML-like file parsing library.
5
 *
6
 * Copyright 2003-2009 by Michael Sweet.
7
 *
8
 * This program is free software; you can redistribute it and/or
9
 * modify it under the terms of the GNU Library General Public
10
 * License as published by the Free Software Foundation; either
11
 * version 2, or (at your option) any later version.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU General Public License for more details.
17
 *
18
 * Contents:
19
 *
20
 *   _mxml_snprintf()  - Format a string.
21
 *   _mxml_strdup()    - Duplicate a string.
22
 *   _mxml_strdupf()   - Format and duplicate a string.
23
 *   _mxml_vsnprintf() - Format a string into a fixed size buffer.
24
 *   _mxml_vstrdupf()  - Format and duplicate a string.
25
 */
26

    
27
/*
28
 * Include necessary headers...
29
 */
30

    
31
#include "config.h"
32

    
33

    
34
#ifndef HAVE_SNPRINTF
35
/*
36
 * '_mxml_snprintf()' - Format a string.
37
 */
38

    
39
int                                        /* O - Number of bytes formatted */
40
_mxml_snprintf(char       *buffer,        /* I - Output buffer */
41
               size_t     bufsize,        /* I - Size of output buffer */
42
               const char *format,        /* I - Printf-style format string */
43
               ...)                        /* I - Additional arguments as needed */
44
{
45
  va_list        ap;                        /* Argument list */
46
  int                bytes;                        /* Number of bytes formatted */
47

    
48

    
49
  va_start(ap, format);
50
  bytes = vsnprintf(buffer, bufsize, format, ap);
51
  va_end(ap);
52

    
53
  return (bytes);
54
}
55
#endif /* !HAVE_SNPRINTF */
56

    
57

    
58
/*
59
 * '_mxml_strdup()' - Duplicate a string.
60
 */
61

    
62
#ifndef HAVE_STRDUP
63
char         *                                /* O - New string pointer */
64
_mxml_strdup(const char *s)                /* I - String to duplicate */
65
{
66
  char        *t;                                /* New string pointer */
67

    
68

    
69
  if (s == NULL)
70
    return (NULL);
71

    
72
  if ((t = malloc(strlen(s) + 1)) == NULL)
73
    return (NULL);
74

    
75
  return (strcpy(t, s));
76
}
77
#endif /* !HAVE_STRDUP */
78

    
79

    
80
/*
81
 * '_mxml_strdupf()' - Format and duplicate a string.
82
 */
83

    
84
char *                                        /* O - New string pointer */
85
_mxml_strdupf(const char *format,        /* I - Printf-style format string */
86
              ...)                        /* I - Additional arguments as needed */
87
{
88
  va_list        ap;                        /* Pointer to additional arguments */
89
  char                *s;                        /* Pointer to formatted string */
90

    
91

    
92
 /*
93
  * Get a pointer to the additional arguments, format the string,
94
  * and return it...
95
  */
96

    
97
  va_start(ap, format);
98
  s = _mxml_vstrdupf(format, ap);
99
  va_end(ap);
100

    
101
  return (s);
102
}
103

    
104

    
105
#ifndef HAVE_VSNPRINTF
106
/*
107
 * '_mxml_vsnprintf()' - Format a string into a fixed size buffer.
108
 */
109

    
110
int                                        /* O - Number of bytes formatted */
111
_mxml_vsnprintf(char       *buffer,        /* O - Output buffer */
112
                size_t     bufsize,        /* O - Size of output buffer */
113
                const char *format,        /* I - Printf-style format string */
114
                 va_list    ap)                /* I - Pointer to additional arguments */
115
{
116
  char                *bufptr,                /* Pointer to position in buffer */
117
                *bufend,                /* Pointer to end of buffer */
118
                sign,                        /* Sign of format width */
119
                size,                        /* Size character (h, l, L) */
120
                type;                        /* Format type character */
121
  int                width,                        /* Width of field */
122
                prec;                        /* Number of characters of precision */
123
  char                tformat[100],                /* Temporary format string for sprintf() */
124
                *tptr,                        /* Pointer into temporary format */
125
                temp[1024];                /* Buffer for formatted numbers */
126
  char                *s;                        /* Pointer to string */
127
  int                slen;                        /* Length of string */
128
  int                bytes;                        /* Total number of bytes needed */
129

    
130

    
131
 /*
132
  * Loop through the format string, formatting as needed...
133
  */
134

    
135
  bufptr = buffer;
136
  bufend = buffer + bufsize - 1;
137
  bytes  = 0;
138

    
139
  while (*format)
140
  {
141
    if (*format == '%')
142
    {
143
      tptr = tformat;
144
      *tptr++ = *format++;
145

    
146
      if (*format == '%')
147
      {
148
        if (bufptr && bufptr < bufend) *bufptr++ = *format;
149
        bytes ++;
150
        format ++;
151
        continue;
152
      }
153
      else if (strchr(" -+#\'", *format))
154
      {
155
        *tptr++ = *format;
156
        sign = *format++;
157
      }
158
      else
159
        sign = 0;
160

    
161
      if (*format == '*')
162
      {
163
       /*
164
        * Get width from argument...
165
        */
166

    
167
        format ++;
168
        width = va_arg(ap, int);
169

    
170
        snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", width);
171
        tptr += strlen(tptr);
172
      }
173
      else
174
      {
175
        width = 0;
176

    
177
        while (isdigit(*format & 255))
178
        {
179
          if (tptr < (tformat + sizeof(tformat) - 1))
180
            *tptr++ = *format;
181

    
182
          width = width * 10 + *format++ - '0';
183
        }
184
      }
185

    
186
      if (*format == '.')
187
      {
188
        if (tptr < (tformat + sizeof(tformat) - 1))
189
          *tptr++ = *format;
190

    
191
        format ++;
192

    
193
        if (*format == '*')
194
        {
195
         /*
196
          * Get precision from argument...
197
          */
198

    
199
          format ++;
200
          prec = va_arg(ap, int);
201

    
202
          snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", prec);
203
          tptr += strlen(tptr);
204
        }
205
        else
206
        {
207
          prec = 0;
208

    
209
          while (isdigit(*format & 255))
210
          {
211
            if (tptr < (tformat + sizeof(tformat) - 1))
212
              *tptr++ = *format;
213

    
214
            prec = prec * 10 + *format++ - '0';
215
          }
216
        }
217
      }
218
      else
219
        prec = -1;
220

    
221
      if (*format == 'l' && format[1] == 'l')
222
      {
223
        size = 'L';
224

    
225
        if (tptr < (tformat + sizeof(tformat) - 2))
226
        {
227
          *tptr++ = 'l';
228
          *tptr++ = 'l';
229
        }
230

    
231
        format += 2;
232
      }
233
      else if (*format == 'h' || *format == 'l' || *format == 'L')
234
      {
235
        if (tptr < (tformat + sizeof(tformat) - 1))
236
          *tptr++ = *format;
237

    
238
        size = *format++;
239
      }
240

    
241
      if (!*format)
242
        break;
243

    
244
      if (tptr < (tformat + sizeof(tformat) - 1))
245
        *tptr++ = *format;
246

    
247
      type  = *format++;
248
      *tptr = '\0';
249

    
250
      switch (type)
251
      {
252
        case 'E' : /* Floating point formats */
253
        case 'G' :
254
        case 'e' :
255
        case 'f' :
256
        case 'g' :
257
            if ((width + 2) > sizeof(temp))
258
              break;
259

    
260
            sprintf(temp, tformat, va_arg(ap, double));
261

    
262
            bytes += strlen(temp);
263

    
264
            if (bufptr)
265
            {
266
              if ((bufptr + strlen(temp)) > bufend)
267
              {
268
                strncpy(bufptr, temp, (size_t)(bufend - bufptr));
269
                bufptr = bufend;
270
              }
271
              else
272
              {
273
                strcpy(bufptr, temp);
274
                bufptr += strlen(temp);
275
              }
276
            }
277
            break;
278

    
279
        case 'B' : /* Integer formats */
280
        case 'X' :
281
        case 'b' :
282
        case 'd' :
283
        case 'i' :
284
        case 'o' :
285
        case 'u' :
286
        case 'x' :
287
            if ((width + 2) > sizeof(temp))
288
              break;
289

    
290
#ifdef HAVE_LONG_LONG
291
            if (size == 'L')
292
              sprintf(temp, tformat, va_arg(ap, long long));
293
            else
294
#endif /* HAVE_LONG_LONG */
295
            sprintf(temp, tformat, va_arg(ap, int));
296

    
297
            bytes += strlen(temp);
298

    
299
            if (bufptr)
300
            {
301
              if ((bufptr + strlen(temp)) > bufend)
302
              {
303
                strncpy(bufptr, temp, (size_t)(bufend - bufptr));
304
                bufptr = bufend;
305
              }
306
              else
307
              {
308
                strcpy(bufptr, temp);
309
                bufptr += strlen(temp);
310
              }
311
            }
312
            break;
313

    
314
        case 'p' : /* Pointer value */
315
            if ((width + 2) > sizeof(temp))
316
              break;
317

    
318
            sprintf(temp, tformat, va_arg(ap, void *));
319

    
320
            bytes += strlen(temp);
321

    
322
            if (bufptr)
323
            {
324
              if ((bufptr + strlen(temp)) > bufend)
325
              {
326
                strncpy(bufptr, temp, (size_t)(bufend - bufptr));
327
                bufptr = bufend;
328
              }
329
              else
330
              {
331
                strcpy(bufptr, temp);
332
                bufptr += strlen(temp);
333
              }
334
            }
335
            break;
336

    
337
        case 'c' : /* Character or character array */
338
            bytes += width;
339

    
340
            if (bufptr)
341
            {
342
              if (width <= 1)
343
                *bufptr++ = va_arg(ap, int);
344
              else
345
              {
346
                if ((bufptr + width) > bufend)
347
                  width = bufend - bufptr;
348

    
349
                memcpy(bufptr, va_arg(ap, char *), (size_t)width);
350
                bufptr += width;
351
              }
352
            }
353
            break;
354

    
355
        case 's' : /* String */
356
            if ((s = va_arg(ap, char *)) == NULL)
357
              s = "(null)";
358

    
359
            slen = strlen(s);
360
            if (slen > width && prec != width)
361
              width = slen;
362

    
363
            bytes += width;
364

    
365
            if (bufptr)
366
            {
367
              if ((bufptr + width) > bufend)
368
                width = bufend - bufptr;
369

    
370
              if (slen > width)
371
                slen = width;
372

    
373
              if (sign == '-')
374
              {
375
                strncpy(bufptr, s, (size_t)slen);
376
                memset(bufptr + slen, ' ', (size_t)(width - slen));
377
              }
378
              else
379
              {
380
                memset(bufptr, ' ', (size_t)(width - slen));
381
                strncpy(bufptr + width - slen, s, (size_t)slen);
382
              }
383

    
384
              bufptr += width;
385
            }
386
            break;
387

    
388
        case 'n' : /* Output number of chars so far */
389
            *(va_arg(ap, int *)) = bytes;
390
            break;
391
      }
392
    }
393
    else
394
    {
395
      bytes ++;
396

    
397
      if (bufptr && bufptr < bufend)
398
        *bufptr++ = *format;
399

    
400
      format ++;
401
    }
402
  }
403

    
404
 /*
405
  * Nul-terminate the string and return the number of characters needed.
406
  */
407

    
408
  *bufptr = '\0';
409

    
410
  return (bytes);
411
}
412
#endif /* !HAVE_VSNPRINTF */
413

    
414

    
415
/*
416
 * '_mxml_vstrdupf()' - Format and duplicate a string.
417
 */
418

    
419
char *                                        /* O - New string pointer */
420
_mxml_vstrdupf(const char *format,        /* I - Printf-style format string */
421
               va_list    ap)                /* I - Pointer to additional arguments */
422
{
423
  int        bytes;                                /* Number of bytes required */
424
  char        *buffer,                        /* String buffer */
425
        temp[256];                        /* Small buffer for first vsnprintf */
426

    
427

    
428
 /*
429
  * First format with a tiny buffer; this will tell us how many bytes are
430
  * needed...
431
  */
432

    
433
  bytes = vsnprintf(temp, sizeof(temp), format, ap);
434

    
435
  if (bytes < sizeof(temp))
436
  {
437
   /*
438
    * Hey, the formatted string fits in the tiny buffer, so just dup that...
439
    */
440

    
441
    return (strdup(temp));
442
  }
443

    
444
 /*
445
  * Allocate memory for the whole thing and reformat to the new, larger
446
  * buffer...
447
  */
448

    
449
  if ((buffer = calloc(1, bytes + 1)) != NULL)
450
    vsnprintf(buffer, bytes + 1, format, ap);
451

    
452
 /*
453
  * Return the new string...
454
  */
455

    
456
  return (buffer);
457
}
458

    
459

    
460
/*
461
 * End of "$Id: mxml-string.c 387 2009-04-18 17:05:52Z mike $".
462
 */