Subversion Repositories tpanel

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 andreas 1
/*
2
 * String functions for Mini-XML, a small XML file parsing library.
3
 *
4
 * https://www.msweet.org/mxml
5
 *
6
 * Copyright © 2003-2019 by Michael R Sweet.
7
 *
8
 * Licensed under Apache License v2.0.  See the file "LICENSE" for more
9
 * information.
10
 */
11
 
12
/*
13
 * Include necessary headers...
14
 */
15
 
16
#include "config.h"
17
 
18
 
19
/*
20
 * The va_copy macro is part of C99, but many compilers don't implement it.
21
 * Provide a "direct assignment" implmentation when va_copy isn't defined...
22
 */
23
 
24
#ifndef va_copy
25
#  ifdef __va_copy
26
#    define va_copy(dst,src) __va_copy(dst,src)
27
#  else
28
#    define va_copy(dst,src) memcpy(&dst, &src, sizeof(va_list))
29
#  endif /* __va_copy */
30
#endif /* va_copy */
31
 
32
 
33
#ifndef HAVE_SNPRINTF
34
/*
35
 * '_mxml_snprintf()' - Format a string.
36
 */
37
 
38
int					/* O - Number of bytes formatted */
39
_mxml_snprintf(char       *buffer,	/* I - Output buffer */
40
               size_t     bufsize,	/* I - Size of output buffer */
41
	       const char *format,	/* I - Printf-style format string */
42
	       ...)			/* I - Additional arguments as needed */
43
{
44
  va_list	ap;			/* Argument list */
45
  int		bytes;			/* Number of bytes formatted */
46
 
47
 
48
  va_start(ap, format);
49
  bytes = vsnprintf(buffer, bufsize, format, ap);
50
  va_end(ap);
51
 
52
  return (bytes);
53
}
54
#endif /* !HAVE_SNPRINTF */
55
 
56
 
57
/*
58
 * '_mxml_strdup()' - Duplicate a string.
59
 */
60
 
61
#ifndef HAVE_STRDUP
62
char *					/* O - New string pointer */
63
_mxml_strdup(const char *s)		/* I - String to duplicate */
64
{
65
  char	*t;				/* New string pointer */
66
 
67
 
68
  if (s == NULL)
69
    return (NULL);
70
 
71
  if ((t = malloc(strlen(s) + 1)) == NULL)
72
    return (NULL);
73
 
74
  return (strcpy(t, s));
75
}
76
#endif /* !HAVE_STRDUP */
77
 
78
 
79
/*
80
 * '_mxml_strdupf()' - Format and duplicate a string.
81
 */
82
 
83
char *					/* O - New string pointer */
84
_mxml_strdupf(const char *format,	/* I - Printf-style format string */
85
              ...)			/* I - Additional arguments as needed */
86
{
87
  va_list	ap;			/* Pointer to additional arguments */
88
  char		*s;			/* Pointer to formatted string */
89
 
90
 
91
 /*
92
  * Get a pointer to the additional arguments, format the string,
93
  * and return it...
94
  */
95
 
96
  va_start(ap, format);
97
#ifdef HAVE_VASPRINTF
98
  if (vasprintf(&s, format, ap) < 0)
99
    s = NULL;
100
#else
101
  s = _mxml_vstrdupf(format, ap);
102
#endif /* HAVE_VASPRINTF */
103
  va_end(ap);
104
 
105
  return (s);
106
}
107
 
108
 
109
#ifndef HAVE_STRLCAT
110
/*
111
 * '_mxml_strlcat()' - Safely concatenate a string.
112
 */
113
 
114
size_t					/* O - Number of bytes copied */
115
_mxml_strlcat(char       *dst,		/* I - Destination buffer */
116
              const char *src,		/* I - Source string */
117
              size_t     dstsize)	/* I - Size of destinatipon buffer */
118
{
119
  size_t	srclen;			/* Length of source string */
120
  size_t	dstlen;			/* Length of destination string */
121
 
122
 
123
 /*
124
  * Figure out how much room is left...
125
  */
126
 
127
  dstlen = strlen(dst);
128
 
129
  if (dstsize <= (dstlen + 1))
130
    return (dstlen);		        /* No room, return immediately... */
131
 
132
  dstsize -= dstlen + 1;
133
 
134
 /*
135
  * Figure out how much room is needed...
136
  */
137
 
138
  srclen = strlen(src);
139
 
140
 /*
141
  * Copy the appropriate amount...
142
  */
143
 
144
  if (srclen > dstsize)
145
    srclen = dstsize;
146
 
147
  memmove(dst + dstlen, src, srclen);
148
  dst[dstlen + srclen] = '\0';
149
 
150
  return (dstlen + srclen);
151
}
152
#endif /* !HAVE_STRLCAT */
153
 
154
 
155
#ifndef HAVE_STRLCPY
156
/*
157
 * '_mxml_strlcpy()' - Safely copy a string.
158
 */
159
 
160
size_t					/* O - Number of bytes copied */
161
_mxml_strlcpy(char       *dst,		/* I - Destination buffer */
162
              const char *src,		/* I - Source string */
163
              size_t     dstsize)	/* I - Size of destinatipon buffer */
164
{
165
  size_t        srclen;                 /* Length of source string */
166
 
167
 
168
 /*
169
  * Figure out how much room is needed...
170
  */
171
 
172
  dstsize --;
173
 
174
  srclen = strlen(src);
175
 
176
 /*
177
  * Copy the appropriate amount...
178
  */
179
 
180
  if (srclen > dstsize)
181
    srclen = dstsize;
182
 
183
  memmove(dst, src, srclen);
184
  dst[srclen] = '\0';
185
 
186
  return (srclen);
187
}
188
#endif /* !HAVE_STRLCPY */
189
 
190
 
191
#ifndef HAVE_VSNPRINTF
192
/*
193
 * '_mxml_vsnprintf()' - Format a string into a fixed size buffer.
194
 */
195
 
196
int					/* O - Number of bytes formatted */
197
_mxml_vsnprintf(char       *buffer,	/* O - Output buffer */
198
                size_t     bufsize,	/* O - Size of output buffer */
199
		const char *format,	/* I - Printf-style format string */
200
 		va_list    ap)		/* I - Pointer to additional arguments */
201
{
202
  char		*bufptr,		/* Pointer to position in buffer */
203
		*bufend,		/* Pointer to end of buffer */
204
		sign,			/* Sign of format width */
205
		size,			/* Size character (h, l, L) */
206
		type;			/* Format type character */
207
  int		width,			/* Width of field */
208
		prec;			/* Number of characters of precision */
209
  char		tformat[100],		/* Temporary format string for sprintf() */
210
		*tptr,			/* Pointer into temporary format */
211
		temp[1024];		/* Buffer for formatted numbers */
212
  char		*s;			/* Pointer to string */
213
  int		slen;			/* Length of string */
214
  int		bytes;			/* Total number of bytes needed */
215
 
216
 
217
 /*
218
  * Loop through the format string, formatting as needed...
219
  */
220
 
221
  bufptr = buffer;
222
  bufend = buffer + bufsize - 1;
223
  bytes  = 0;
224
 
225
  while (*format)
226
  {
227
    if (*format == '%')
228
    {
229
      tptr = tformat;
230
      *tptr++ = *format++;
231
 
232
      if (*format == '%')
233
      {
234
        if (bufptr && bufptr < bufend)
235
          *bufptr++ = *format;
236
        bytes ++;
237
        format ++;
238
	continue;
239
      }
240
      else if (strchr(" -+#\'", *format))
241
      {
242
        *tptr++ = *format;
243
        sign = *format++;
244
      }
245
      else
246
        sign = 0;
247
 
248
      if (*format == '*')
249
      {
250
       /*
251
        * Get width from argument...
252
	*/
253
 
254
	format ++;
255
	width = va_arg(ap, int);
256
 
257
	snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", width);
258
	tptr += strlen(tptr);
259
      }
260
      else
261
      {
262
	width = 0;
263
 
264
	while (isdigit(*format & 255))
265
	{
266
	  if (tptr < (tformat + sizeof(tformat) - 1))
267
	    *tptr++ = *format;
268
 
269
	  width = width * 10 + *format++ - '0';
270
	}
271
      }
272
 
273
      if (*format == '.')
274
      {
275
	if (tptr < (tformat + sizeof(tformat) - 1))
276
	  *tptr++ = *format;
277
 
278
        format ++;
279
 
280
        if (*format == '*')
281
	{
282
         /*
283
	  * Get precision from argument...
284
	  */
285
 
286
	  format ++;
287
	  prec = va_arg(ap, int);
288
 
289
	  snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", prec);
290
	  tptr += strlen(tptr);
291
	}
292
	else
293
	{
294
	  prec = 0;
295
 
296
	  while (isdigit(*format & 255))
297
	  {
298
	    if (tptr < (tformat + sizeof(tformat) - 1))
299
	      *tptr++ = *format;
300
 
301
	    prec = prec * 10 + *format++ - '0';
302
	  }
303
	}
304
      }
305
      else
306
        prec = -1;
307
 
308
      if (*format == 'l' && format[1] == 'l')
309
      {
310
        size = 'L';
311
 
312
	if (tptr < (tformat + sizeof(tformat) - 2))
313
	{
314
	  *tptr++ = 'l';
315
	  *tptr++ = 'l';
316
	}
317
 
318
	format += 2;
319
      }
320
      else if (*format == 'h' || *format == 'l' || *format == 'L')
321
      {
322
	if (tptr < (tformat + sizeof(tformat) - 1))
323
	  *tptr++ = *format;
324
 
325
        size = *format++;
326
      }
327
 
328
      if (!*format)
329
        break;
330
 
331
      if (tptr < (tformat + sizeof(tformat) - 1))
332
        *tptr++ = *format;
333
 
334
      type  = *format++;
335
      *tptr = '\0';
336
 
337
      switch (type)
338
      {
339
	case 'E' : /* Floating point formats */
340
	case 'G' :
341
	case 'e' :
342
	case 'f' :
343
	case 'g' :
344
	    if ((width + 2) > sizeof(temp))
345
	      break;
346
 
347
	    sprintf(temp, tformat, va_arg(ap, double));
348
 
349
            bytes += strlen(temp);
350
 
351
            if (bufptr)
352
	    {
353
	      if ((bufptr + strlen(temp)) > bufend)
354
	      {
355
		strncpy(bufptr, temp, (size_t)(bufend - bufptr));
356
		bufptr = bufend;
357
	      }
358
	      else
359
	      {
360
		strcpy(bufptr, temp);
361
		bufptr += strlen(temp);
362
	      }
363
	    }
364
	    break;
365
 
366
        case 'B' : /* Integer formats */
367
	case 'X' :
368
	case 'b' :
369
        case 'd' :
370
	case 'i' :
371
	case 'o' :
372
	case 'u' :
373
	case 'x' :
374
	    if ((width + 2) > sizeof(temp))
375
	      break;
376
 
377
#ifdef HAVE_LONG_LONG
378
	    if (size == 'L')
379
	      sprintf(temp, tformat, va_arg(ap, long long));
380
	    else
381
#endif /* HAVE_LONG_LONG */
382
	    sprintf(temp, tformat, va_arg(ap, int));
383
 
384
            bytes += strlen(temp);
385
 
386
	    if (bufptr)
387
	    {
388
	      if ((bufptr + strlen(temp)) > bufend)
389
	      {
390
		strncpy(bufptr, temp, (size_t)(bufend - bufptr));
391
		bufptr = bufend;
392
	      }
393
	      else
394
	      {
395
		strcpy(bufptr, temp);
396
		bufptr += strlen(temp);
397
	      }
398
	    }
399
	    break;
400
 
401
	case 'p' : /* Pointer value */
402
	    if ((width + 2) > sizeof(temp))
403
	      break;
404
 
405
	    sprintf(temp, tformat, va_arg(ap, void *));
406
 
407
            bytes += strlen(temp);
408
 
409
	    if (bufptr)
410
	    {
411
	      if ((bufptr + strlen(temp)) > bufend)
412
	      {
413
		strncpy(bufptr, temp, (size_t)(bufend - bufptr));
414
		bufptr = bufend;
415
	      }
416
	      else
417
	      {
418
		strcpy(bufptr, temp);
419
		bufptr += strlen(temp);
420
	      }
421
	    }
422
	    break;
423
 
424
        case 'c' : /* Character or character array */
425
	    bytes += width;
426
 
427
	    if (bufptr)
428
	    {
429
	      if (width <= 1)
430
	        *bufptr++ = va_arg(ap, int);
431
	      else
432
	      {
433
		if ((bufptr + width) > bufend)
434
		  width = bufend - bufptr;
435
 
436
		memcpy(bufptr, va_arg(ap, char *), (size_t)width);
437
		bufptr += width;
438
	      }
439
	    }
440
	    break;
441
 
442
	case 's' : /* String */
443
	    if ((s = va_arg(ap, char *)) == NULL)
444
	      s = "(null)";
445
 
446
	    slen = strlen(s);
447
	    if (slen > width && prec != width)
448
	      width = slen;
449
 
450
            bytes += width;
451
 
452
	    if (bufptr)
453
	    {
454
	      if ((bufptr + width) > bufend)
455
	        width = bufend - bufptr;
456
 
457
              if (slen > width)
458
	        slen = width;
459
 
460
	      if (sign == '-')
461
	      {
462
		strncpy(bufptr, s, (size_t)slen);
463
		memset(bufptr + slen, ' ', (size_t)(width - slen));
464
	      }
465
	      else
466
	      {
467
		memset(bufptr, ' ', (size_t)(width - slen));
468
		strncpy(bufptr + width - slen, s, (size_t)slen);
469
	      }
470
 
471
	      bufptr += width;
472
	    }
473
	    break;
474
 
475
	case 'n' : /* Output number of chars so far */
476
	    *(va_arg(ap, int *)) = bytes;
477
	    break;
478
      }
479
    }
480
    else
481
    {
482
      bytes ++;
483
 
484
      if (bufptr && bufptr < bufend)
485
        *bufptr++ = *format;
486
 
487
      format ++;
488
    }
489
  }
490
 
491
 /*
492
  * Nul-terminate the string and return the number of characters needed.
493
  */
494
 
495
  *bufptr = '\0';
496
 
497
  return (bytes);
498
}
499
#endif /* !HAVE_VSNPRINTF */
500
 
501
 
502
/*
503
 * '_mxml_vstrdupf()' - Format and duplicate a string.
504
 */
505
 
506
char *					/* O - New string pointer */
507
_mxml_vstrdupf(const char *format,	/* I - Printf-style format string */
508
               va_list    ap)		/* I - Pointer to additional arguments */
509
{
510
#ifdef HAVE_VASPRINTF
511
  char		*s;			/* String */
512
 
513
  if (vasprintf(&s, format, ap) < 0)
514
    s = NULL;
515
 
516
  return (s);
517
 
518
#else
519
  int		bytes;			/* Number of bytes required */
520
  char		*buffer,		/* String buffer */
521
		temp[256];		/* Small buffer for first vsnprintf */
522
 
523
 
524
 /*
525
  * First format with a tiny buffer; this will tell us how many bytes are
526
  * needed...
527
  */
528
 
529
#  ifdef _WIN32
530
  bytes = _vscprintf(format, ap);
531
 
532
#  else
533
  va_list	apcopy;			/* Copy of argument list */
534
 
535
  va_copy(apcopy, ap);
536
  if ((bytes = vsnprintf(temp, sizeof(temp), format, apcopy)) < sizeof(temp))
537
  {
538
   /*
539
    * Hey, the formatted string fits in the tiny buffer, so just dup that...
540
    */
541
 
542
    return (strdup(temp));
543
  }
544
#  endif /* _WIN32 */
545
 
546
 /*
547
  * Allocate memory for the whole thing and reformat to the new buffer...
548
  */
549
 
550
  if ((buffer = calloc(1, bytes + 1)) != NULL)
551
    vsnprintf(buffer, bytes + 1, format, ap);
552
 
553
 /*
554
  * Return the new string...
555
  */
556
 
557
  return (buffer);
558
#endif /* HAVE_VASPRINTF */
559
}