1 /*
2 * snprintf.c - a portable implementation of snprintf
3 *
4
5 THIS MODULE WAS ADAPTED FOR NETPBM BY BRYAN HENDERSON ON 2002.03.24.
6 Bryan got the base from
7 http://www.ijs.si/software/snprintf/snprintf-2.2.tar.gz, but made
8 a lot of changes and additions.
9
10 * AUTHOR
11 * Mark Martinec <mark.martinec@ijs.si>, April 1999.
12 *
13 * Copyright 1999, Mark Martinec. All rights reserved.
14 *
15 * TERMS AND CONDITIONS
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the "Frontier Artistic License" which comes
18 * with this Kit.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty
22 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
23 * See the Frontier Artistic License for more details.
24 *
25 * You should have received a copy of the Frontier Artistic License
26 * with this Kit in the file named LICENSE.txt .
27 * If not, I'll be glad to provide one.
28 *
29 * FEATURES
30 * - careful adherence to specs regarding flags, field width and precision;
31 * - good performance for large string handling (large format, large
32 * argument or large paddings). Performance is similar to system's sprintf
33 * and in several cases significantly better (make sure you compile with
34 * optimizations turned on, tell the compiler the code is strict ANSI
35 * if necessary to give it more freedom for optimizations);
36 * - return value semantics per ISO/IEC 9899:1999 ("ISO C99");
37 * - written in standard ISO/ANSI C - requires an ANSI C compiler.
38 *
39 * IMPLEMENTED CONVERSION SPECIFIERS AND DATA TYPES
40 *
41 * This snprintf implements only the following conversion specifiers:
42 * s, c, d, u, o, x, X, p, f (and synonyms: i, D, U, O - see below)
43 * with flags: '-', '+', ' ', '0' and '#'.
44 * An asterisk is acceptable for field width as well as precision.
45 *
46 * Length modifiers 'h' (short int), 'l' (long int),
47 * and 'll' (long long int) are implemented.
48 *
49 * Conversion of numeric data (conversion specifiers d, u, o, x, X, p)
50 * with length modifiers (none or h, l, ll) is left to the system routine
51 * sprintf, but all handling of flags, field width and precision as well as
52 * c and s conversions is done very carefully by this portable routine.
53 * If a string precision (truncation) is specified (e.g. %.8s) it is
54 * guaranteed the string beyond the specified precision will not be referenced.
55 *
56 * Length modifiers h, l and ll are ignored for c and s conversions (you
57 * can't use data types wint_t and wchar_t).
58 *
59 * The following common synonyms for conversion characters are acceptable:
60 * - i is a synonym for d
61 * - D is a synonym for ld, explicit length modifiers are ignored
62 * - U is a synonym for lu, explicit length modifiers are ignored
63 * - O is a synonym for lo, explicit length modifiers are ignored
64 * The D, O and U conversion characters are nonstandard, they are accepted
65 * for backward compatibility only, and should not be used for new code.
66 *
67 * The following is specifically NOT implemented:
68 * - flag ' (thousands' grouping character) is recognized but ignored
69 * - numeric conversion specifiers: e, E, g, G and synonym F,
70 * as well as the new a and A conversion specifiers
71 * - length modifier 'L' (long double) and 'q' (quad - use 'll' instead)
72 * - wide character/string conversions: lc, ls, and nonstandard
73 * synonyms C and S
74 * - writeback of converted string length: conversion character n
75 * - the n$ specification for direct reference to n-th argument
76 * - locales
77 *
78 * It is permitted for str_m to be zero, and it is permitted to specify NULL
79 * pointer for resulting string argument if str_m is zero (as per ISO C99).
80 *
81 * The return value is the number of characters which would be generated
82 * for the given input, excluding the trailing null. If this value
83 * is greater or equal to str_m, not all characters from the result
84 * have been stored in str, output bytes beyond the (str_m-1) -th character
85 * are discarded. If str_m is greater than zero it is guaranteed
86 * the resulting string will be null-terminated.
87 *
88 * NOTE that this matches the ISO C99, OpenBSD, and GNU C library 2.1,
89 * but is different from some older and vendor implementations,
90 * and is also different from XPG, XSH5, SUSv2 specifications.
91 * For historical discussion on changes in the semantics and standards
92 * of snprintf see printf(3) man page in the Linux programmers manual.
93 *
94 * Routines asprintf and vasprintf return a pointer (in the ptr argument)
95 * to a buffer sufficiently large to hold the resulting string. This pointer
96 * should be passed to free(3) to release the allocated storage when it is
97 * no longer needed. If sufficient space cannot be allocated, these functions
98 * will return -1 and set ptr to be a NULL pointer. These two routines are a
99 * GNU C library extensions (glibc).
100 *
101 * Routines asnprintf and vasnprintf are similar to asprintf and vasprintf,
102 * yet, like snprintf and vsnprintf counterparts, will write at most str_m-1
103 * characters into the allocated output string, the last character in the
104 * allocated buffer then gets the terminating null. If the formatted string
105 * length (the return value) is greater than or equal to the str_m argument,
106 * the resulting string was truncated and some of the formatted characters
107 * were discarded. These routines present a handy way to limit the amount
108 * of allocated memory to some sane value.
109 *
110 * AVAILABILITY
111 * http://www.ijs.si/software/snprintf/
112 *
113 */
114
115
116 #define _DEFAULT_SOURCE /* New name for SVID & BSD source defines */
117 #define _XOPEN_SOURCE 500 /* Make sure strdup() is in string.h */
118 #define _BSD_SOURCE /* Make sure strdup() is in string.h */
119 #define _GNU_SOURCE
120 /* Because of conditional compilation, this is GNU source only if the C
121 library is GNU.
122 */
123 #define PORTABLE_SNPRINTF_VERSION_MAJOR 2
124 #define PORTABLE_SNPRINTF_VERSION_MINOR 2
125
126 #include <sys/types.h>
127 #include <limits.h>
128 #include <string.h>
129 #include <stdlib.h>
130 #include <stdio.h>
131 #include <stdarg.h>
132 #include <assert.h>
133 #include <errno.h>
134
135 #include "pm.h"
136 #include "pm_c_util.h"
137
138 #include "nstring.h"
139
140 #ifdef isdigit
141 #undef isdigit
142 #endif
143 #define isdigit(c) ((c) >= '0' && (c) <= '9')
144
145 /* For copying strings longer or equal to 'breakeven_point'
146 * it is more efficient to call memcpy() than to do it inline.
147 * The value depends mostly on the processor architecture,
148 * but also on the compiler and its optimization capabilities.
149 * The value is not critical, some small value greater than zero
150 * will be just fine if you don't care to squeeze every drop
151 * of performance out of the code.
152 *
153 * Small values favor memcpy, large values favor inline code.
154 */
155 #if defined(__alpha__) || defined(__alpha)
156 # define breakeven_point 2 /* AXP (DEC Alpha) - gcc or cc or egcs */
157 #endif
158 #if defined(__i386__) || defined(__i386)
159 # define breakeven_point 12 /* Intel Pentium/Linux - gcc 2.96 */
160 #endif
161 #if defined(__hppa)
162 # define breakeven_point 10 /* HP-PA - gcc */
163 #endif
164 #if defined(__sparc__) || defined(__sparc)
165 # define breakeven_point 33 /* Sun Sparc 5 - gcc 2.8.1 */
166 #endif
167
168 /* some other values of possible interest: */
169 /* #define breakeven_point 8 */ /* VAX 4000 - vaxc */
170 /* #define breakeven_point 19 */ /* VAX 4000 - gcc 2.7.0 */
171
172 #ifndef breakeven_point
173 # define breakeven_point 6 /* some reasonable one-size-fits-all value */
174 #endif
175
176 #define fast_memcpy(d,s,n) \
177 { register size_t nn = (size_t)(n); \
178 if (nn >= breakeven_point) memcpy((d), (s), nn); \
179 else if (nn > 0) { /* proc call overhead is worth only for large strings*/\
180 register char *dd; register const char *ss; \
181 for (ss=(s), dd=(d); nn>0; nn--) *dd++ = *ss++; } }
182
183 #define fast_memset(d,c,n) \
184 { register size_t nn = (size_t)(n); \
185 if (nn >= breakeven_point) memset((d), (int)(c), nn); \
186 else if (nn > 0) { /* proc call overhead is worth only for large strings*/\
187 register char *dd; register const int cc=(int)(c); \
188 for (dd=(d); nn>0; nn--) *dd++ = cc; } }
189
190 /* declarations */
191
192 static char credits[] = "\n\
193 @(#)snprintf.c, v2.2: Mark Martinec, <mark.martinec@ijs.si>\n\
194 @(#)snprintf.c, v2.2: Copyright 1999, Mark Martinec. Frontier Artistic License applies.\n\
195 @(#)snprintf.c, v2.2: http://www.ijs.si/software/snprintf/\n";
196
197
198 /* MacOS X before 10.7, for one, does not have strnlen */
199 size_t
pm_strnlen(const char * const s,size_t const maxlen)200 pm_strnlen(const char * const s,
201 size_t const maxlen) {
202
203 unsigned int i;
204
205 for (i = 0; i < maxlen && s[i]; ++i) {}
206
207 return i;
208 }
209
210
211
212 void
pm_vsnprintf(char * const str,size_t const str_m,const char * const fmt,va_list ap,size_t * const sizeP)213 pm_vsnprintf(char * const str,
214 size_t const str_m,
215 const char * const fmt,
216 va_list ap,
217 size_t * const sizeP) {
218
219 size_t str_l = 0;
220 const char *p = fmt;
221
222 /* In contrast with POSIX, the ISO C99 now says that str can be
223 NULL and str_m can be 0. This is more useful than the old:
224 if (str_m < 1) return -1;
225 */
226
227 if (!p) p = "";
228 while (*p) {
229 if (*p != '%') {
230 /* if (str_l < str_m) str[str_l++] = *p++; -- this would
231 be sufficient but the following code achieves better
232 performance for cases * where format string is long and
233 contains few conversions
234 */
235 const char *q = strchr(p + 1,'%');
236 size_t n = !q ? strlen(p) : (q - p);
237 if (str_l < str_m) {
238 size_t const avail = str_m - str_l;
239 fast_memcpy(str + str_l, p, (MIN(n, avail)));
240 }
241 p += n; str_l += n;
242 } else {
243 size_t min_field_width;
244 size_t precision = 0;
245 bool precision_specified;
246 bool justify_left;
247 bool alternate_form;
248 bool force_sign;
249 bool space_for_positive;
250 /* If both the ' ' and '+' flags appear,
251 the ' ' flag should be ignored.
252 */
253 char length_modifier = '\0'; /* allowed values: \0, h, l, L */
254 char tmp[32];
255 /* temporary buffer for simple numeric->string conversion */
256
257 const char *str_arg;
258 /* string address in case of string argument */
259 size_t str_arg_l;
260 /* natural field width of arg without padding and sign */
261 unsigned char uchar_arg;
262 /* unsigned char argument value - only defined for c
263 conversion. N.B. standard explicitly states the char
264 argument for the c conversion is unsigned.
265 */
266
267 bool zero_padding;
268
269 size_t number_of_zeros_to_pad;
270 /* number of zeros to be inserted for numeric
271 conversions as required by the precision or minimal
272 field width
273 */
274
275 size_t zero_padding_insertion_ind;
276 /* index into tmp where zero padding is to be inserted */
277
278 char fmt_spec;
279 /* current conversion specifier character */
280
281 str_arg = credits;
282 /* just to make compiler happy (defined but not used) */
283 str_arg = NULL;
284 ++p; /* skip '%' */
285
286 /* parse flags */
287 justify_left = false; /* initial value */
288 alternate_form = false; /* initial value */
289 force_sign = false; /* initial value */
290 space_for_positive = false; /* initial value */
291 zero_padding = false; /* initial value */
292 number_of_zeros_to_pad = 0; /* initial value */
293 zero_padding_insertion_ind = 0; /* initial value */
294 fmt_spec = '\0'; /* initial value */
295
296 while (*p == '0' || *p == '-' || *p == '+' ||
297 *p == ' ' || *p == '#' || *p == '\'') {
298 switch (*p) {
299 case '0': zero_padding = true; break;
300 case '-': justify_left = true; break;
301 case '+': force_sign = true; space_for_positive = false; break;
302 case ' ': force_sign = true; break;
303 /* If both the ' ' and '+' flags appear, the ' '
304 flag should be ignored
305 */
306 case '#': alternate_form = true; break;
307 case '\'': break;
308 }
309 ++p;
310 }
311 /* If the '0' and '-' flags both appear, the '0' flag
312 should be ignored.
313 */
314
315 /* parse field width */
316 if (*p == '*') {
317 int j;
318 ++p;
319 j = va_arg(ap, int);
320 if (j >= 0) { min_field_width = j; justify_left = false; }
321 else { min_field_width = -j; justify_left = true; }
322 } else if (isdigit((int)(*p))) {
323 /* size_t could be wider than unsigned int; make sure
324 we treat argument like common implementations do
325 */
326 unsigned int uj = *p++ - '0';
327 while (isdigit((int)(*p)))
328 uj = 10*uj + (unsigned int)(*p++ - '0');
329 min_field_width = uj;
330 } else
331 min_field_width = 0;
332
333 /* parse precision */
334 if (*p == '.') {
335 ++p;
336 precision_specified = true;
337 if (*p == '*') {
338 int j = va_arg(ap, int);
339 p++;
340 if (j >= 0) precision = j;
341 else {
342 precision_specified = false; precision = 0;
343 /* NOTE: Solaris 2.6 man page claims that in
344 this case the precision should be set to 0.
345 Digital Unix 4.0, HPUX 10 and BSD man page
346 claim that this case should be treated as
347 unspecified precision, which is what we do
348 here.
349 */
350 }
351 } else if (isdigit((int)(*p))) {
352 /* size_t could be wider than unsigned int; make
353 sure we treat argument like common
354 implementations do
355 */
356 unsigned int uj = *p++ - '0';
357 while (isdigit((int)(*p)))
358 uj = 10*uj + (unsigned int)(*p++ - '0');
359 precision = uj;
360 }
361 } else
362 precision_specified = false;
363
364 /* parse 'h', 'l' and 'll' length modifiers */
365 if (*p == 'h' || *p == 'l') {
366 length_modifier = *p; p++;
367 if (length_modifier == 'l' && *p == 'l') {
368 /* double l = long long */
369 length_modifier = 'l'; /* treat it as a single 'l' */
370 p++;
371 }
372 }
373 fmt_spec = *p;
374
375 /* common synonyms: */
376 switch (fmt_spec) {
377 case 'i': fmt_spec = 'd'; break;
378 case 'D': fmt_spec = 'd'; length_modifier = 'l'; break;
379 case 'U': fmt_spec = 'u'; length_modifier = 'l'; break;
380 case 'O': fmt_spec = 'o'; length_modifier = 'l'; break;
381 default: break;
382 }
383 /* get parameter value, do initial processing */
384 switch (fmt_spec) {
385 case '%':
386 /* % behaves similar to 's' regarding flags and field widths */
387 case 'c':
388 /* c behaves similar to 's' regarding flags and field widths */
389 case 's':
390 /* wint_t and wchar_t not handled */
391 length_modifier = '\0';
392 /* the result of zero padding flag with non-numeric
393 conversion specifier is undefined. Solaris and
394 HPUX 10 does zero padding in this case, Digital
395 Unix and Linux does not.
396 */
397
398 zero_padding = false;
399 /* turn zero padding off for string conversions */
400 str_arg_l = 1;
401 switch (fmt_spec) {
402 case '%':
403 str_arg = p; break;
404 case 'c': {
405 int j = va_arg(ap, int);
406 uchar_arg = (unsigned char) j;
407 /* standard demands unsigned char */
408 str_arg = (const char *) &uchar_arg;
409 break;
410 }
411 case 's':
412 str_arg = va_arg(ap, const char *);
413 if (!str_arg)
414 /* make sure not to address string beyond the
415 specified precision !!!
416 */
417 str_arg_l = 0;
418 else if (!precision_specified)
419 /* truncate string if necessary as requested by
420 precision
421 */
422 str_arg_l = strlen(str_arg);
423 else if (precision == 0)
424 str_arg_l = 0;
425 else {
426 /* memchr on HP does not like n > 2^31 !!! */
427 const char * q =
428 memchr(str_arg, '\0', MIN(precision, 0x7fffffff));
429 str_arg_l = !q ? precision : (q-str_arg);
430 }
431 break;
432 default: break;
433 }
434 break;
435 case 'd': case 'u': case 'o': case 'x': case 'X': case 'p': {
436 /* NOTE: the u, o, x, X and p conversion specifiers imply
437 the value is unsigned; d implies a signed value
438 */
439 int arg_sign = 0;
440 /* 0 if numeric argument is zero (or if pointer is NULL
441 for 'p'),
442 +1 if greater than zero (or nonzero for unsigned arguments),
443 -1 if negative (unsigned argument is never negative)
444 */
445
446 int int_arg = 0;
447 unsigned int uint_arg = 0;
448 /* defined only for length modifier h, or for no
449 length modifiers
450 */
451
452 long int long_arg = 0; unsigned long int ulong_arg = 0;
453 /* only defined for length modifier l */
454
455 void *ptr_arg = NULL;
456 /* pointer argument value -only defined for p conversion */
457
458 if (fmt_spec == 'p') {
459 /* HPUX 10: An l, h, ll or L before any other
460 conversion character (other than d, i, u, o,
461 x, or X) is ignored.
462
463 Digital Unix: not specified, but seems to behave
464 as HPUX does.
465
466 Solaris: If an h, l, or L appears before any
467 other conversion specifier (other than d, i, u,
468 o, x, or X), the behavior is
469 undefined. (Actually %hp converts only 16-bits
470 of address and %llp treats address as 64-bit
471 data which is incompatible with (void *)
472 argument on a 32-bit system).
473 */
474
475 length_modifier = '\0';
476 ptr_arg = va_arg(ap, void *);
477 if (ptr_arg != NULL) arg_sign = 1;
478 } else if (fmt_spec == 'd') { /* signed */
479 switch (length_modifier) {
480 case '\0':
481 case 'h':
482 /* It is non-portable to specify a second
483 argument of char or short to va_arg,
484 because arguments seen by the called
485 function are not char or short. C converts
486 char and short arguments to int before
487 passing them to a function.
488 */
489 int_arg = va_arg(ap, int);
490 if (int_arg > 0) arg_sign = 1;
491 else if (int_arg < 0) arg_sign = -1;
492 break;
493 case 'l':
494 long_arg = va_arg(ap, long int);
495 if (long_arg > 0) arg_sign = 1;
496 else if (long_arg < 0) arg_sign = -1;
497 break;
498 }
499 } else { /* unsigned */
500 switch (length_modifier) {
501 case '\0':
502 case 'h':
503 uint_arg = va_arg(ap, unsigned int);
504 if (uint_arg)
505 arg_sign = 1;
506 break;
507 case 'l':
508 ulong_arg = va_arg(ap, unsigned long int);
509 if (ulong_arg)
510 arg_sign = 1;
511 break;
512 }
513 }
514 str_arg = tmp; str_arg_l = 0;
515 /* NOTE: For d, i, u, o, x, and X conversions, if
516 precision is specified, the '0' flag should be
517 ignored. This is so with Solaris 2.6, Digital UNIX
518 4.0, HPUX 10, Linux, FreeBSD, NetBSD; but not with
519 Perl.
520 */
521 if (precision_specified)
522 zero_padding = false;
523 if (fmt_spec == 'd') {
524 if (force_sign && arg_sign >= 0)
525 tmp[str_arg_l++] = space_for_positive ? ' ' : '+';
526 /* leave negative numbers for sprintf to handle,
527 to avoid handling tricky cases like (short
528 int)(-32768)
529 */
530 } else if (alternate_form) {
531 if (arg_sign != 0 && (fmt_spec == 'x' ||
532 fmt_spec == 'X')) {
533 tmp[str_arg_l++] = '0';
534 tmp[str_arg_l++] = fmt_spec;
535 }
536 /* alternate form should have no effect for p
537 conversion, but ...
538 */
539 }
540 zero_padding_insertion_ind = str_arg_l;
541 if (!precision_specified)
542 precision = 1; /* default precision is 1 */
543 if (precision == 0 && arg_sign == 0) {
544 /* converted to null string */
545 /* When zero value is formatted with an explicit
546 precision 0, the resulting formatted string is
547 empty (d, i, u, o, x, X, p).
548 */
549 } else {
550 char f[5]; int f_l = 0;
551 f[f_l++] = '%';
552 /* construct a simple format string for sprintf */
553 if (!length_modifier) { }
554 else if (length_modifier=='2') {
555 f[f_l++] = 'l'; f[f_l++] = 'l';
556 }
557 else
558 f[f_l++] = length_modifier;
559 f[f_l++] = fmt_spec; f[f_l++] = '\0';
560 if (fmt_spec == 'p')
561 str_arg_l += sprintf(tmp+str_arg_l, f, ptr_arg);
562 else if (fmt_spec == 'd') { /* signed */
563 switch (length_modifier) {
564 case '\0':
565 case 'h':
566 str_arg_l+=sprintf(tmp+str_arg_l, f, int_arg);
567 break;
568 case 'l':
569 str_arg_l+=sprintf(tmp+str_arg_l, f, long_arg);
570 break;
571 }
572 } else { /* unsigned */
573 switch (length_modifier) {
574 case '\0':
575 case 'h':
576 str_arg_l += sprintf(tmp+str_arg_l, f, uint_arg);
577 break;
578 case 'l':
579 str_arg_l += sprintf(tmp+str_arg_l, f, ulong_arg);
580 break;
581 }
582 }
583 /* include the optional minus sign and possible "0x"
584 in the region before the zero padding insertion point
585 */
586 if (zero_padding_insertion_ind < str_arg_l &&
587 tmp[zero_padding_insertion_ind] == '-') {
588 zero_padding_insertion_ind += 1;
589 }
590 if (zero_padding_insertion_ind + 1 < str_arg_l &&
591 tmp[zero_padding_insertion_ind] == '0' &&
592 (tmp[zero_padding_insertion_ind+1] == 'x' ||
593 tmp[zero_padding_insertion_ind+1] == 'X') ) {
594 zero_padding_insertion_ind += 2;
595 }
596 }
597 {
598 size_t const num_of_digits =
599 str_arg_l - zero_padding_insertion_ind;
600 if (alternate_form && fmt_spec == 'o'
601 /* unless zero is already the first character */
602 && !(zero_padding_insertion_ind < str_arg_l
603 && tmp[zero_padding_insertion_ind] == '0')) {
604 /* assure leading zero for alternate-form
605 octal numbers
606 */
607 if (!precision_specified ||
608 precision < num_of_digits+1) {
609 /* precision is increased to force the
610 first character to be zero, except if a
611 zero value is formatted with an
612 explicit precision of zero
613 */
614 precision = num_of_digits+1;
615 precision_specified = true;
616 }
617 }
618 /* zero padding to specified precision? */
619 if (num_of_digits < precision)
620 number_of_zeros_to_pad = precision - num_of_digits;
621 }
622 /* zero padding to specified minimal field width? */
623 if (!justify_left && zero_padding) {
624 int const n =
625 min_field_width - (str_arg_l+number_of_zeros_to_pad);
626 if (n > 0)
627 number_of_zeros_to_pad += n;
628 }
629 } break;
630 case 'f': {
631 char f[10];
632 if (precision_specified)
633 snprintf(f, ARRAY_SIZE(f), "%%%u.%uf",
634 (unsigned)min_field_width, (unsigned)precision);
635 else
636 snprintf(f, ARRAY_SIZE(f), "%%%uf",
637 (unsigned)min_field_width);
638
639 str_arg_l = sprintf(tmp, f, va_arg(ap, double));
640 str_arg = &tmp[0];
641
642 min_field_width = 0;
643 zero_padding_insertion_ind = 0;
644 } break;
645 default:
646 /* Unrecognized conversion specifier. Discard the
647 unrecognized conversion, just keep the unrecognized
648 conversion character.
649 */
650 zero_padding = false;
651 /* turn zero padding off for non-numeric convers. */
652 /* reset flags */
653 justify_left = true;
654 min_field_width = 0;
655 str_arg = p;
656 str_arg_l = 0;
657 if (*p)
658 /* include invalid conversion specifier unchanged
659 if not at end-of-string
660 */
661 ++str_arg_l;
662 break;
663 }
664 if (*p)
665 p++; /* step over the just processed conversion specifier */
666 /* insert padding to the left as requested by
667 min_field_width; this does not include the zero padding
668 in case of numerical conversions
669 */
670
671 if (!justify_left) {
672 /* left padding with blank or zero */
673 int n = min_field_width - (str_arg_l + number_of_zeros_to_pad);
674 if (n > 0) {
675 if (str_l < str_m) {
676 size_t const avail = str_m - str_l;
677 fast_memset(str + str_l, (zero_padding ? '0' : ' '),
678 (MIN(n, avail)));
679 }
680 str_l += n;
681 }
682 }
683 /* zero padding as requested by the precision or by the
684 minimal field width for numeric conversions required?
685 */
686 if (number_of_zeros_to_pad <= 0) {
687 /* will not copy first part of numeric right now,
688 force it to be copied later in its entirety
689 */
690 zero_padding_insertion_ind = 0;
691 } else {
692 {
693 /* insert first part of numerics (sign or '0x') before
694 zero padding
695 */
696 int const n = zero_padding_insertion_ind;
697 if (n > 0) {
698 if (str_l < str_m) {
699 size_t const avail = str_m - str_l;
700 fast_memcpy(str + str_l, str_arg, (MIN(n, avail)));
701 }
702 str_l += n;
703 }
704 }
705 {
706 /* insert zero padding as requested by the precision
707 or min field width
708 */
709 int const n = number_of_zeros_to_pad;
710 if (n > 0) {
711 if (str_l < str_m) {
712 size_t const avail = str_m - str_l;
713 fast_memset(str + str_l, '0', (MIN(n, avail)));
714 }
715 str_l += n;
716 }
717 }
718 }
719 /* insert formatted string (or as-is conversion specifier
720 for unknown conversions)
721 */
722 {
723 int const n = str_arg_l - zero_padding_insertion_ind;
724 if (n > 0) {
725 if (str_l < str_m) {
726 size_t const avail = str_m-str_l;
727 fast_memcpy(str + str_l,
728 str_arg + zero_padding_insertion_ind,
729 MIN(n, avail));
730 }
731 str_l += n;
732 }
733 }
734 /* insert right padding */
735 if (justify_left) {
736 /* right blank padding to the field width */
737 int const n =
738 min_field_width - (str_arg_l + number_of_zeros_to_pad);
739 if (n > 0) {
740 if (str_l < str_m) {
741 size_t const avail = str_m - str_l;
742 fast_memset(str+str_l, ' ', (MIN(n, avail)));
743 }
744 str_l += n;
745 }
746 }
747 }
748 }
749 if (str_m > 0) {
750 /* make sure the string is null-terminated even at the expense
751 of overwriting the last character (shouldn't happen, but
752 just in case)
753 */
754 str[MIN(str_l, str_m - 1)] = '\0';
755 }
756 *sizeP = str_l;
757 }
758
759
760
761 int
pm_snprintf(char * const dest,size_t const str_m,const char * const fmt,...)762 pm_snprintf(char * const dest,
763 size_t const str_m,
764 const char * const fmt,
765 ...) {
766
767 size_t size;
768 va_list ap;
769
770 va_start(ap, fmt);
771
772 pm_vsnprintf(dest, str_m, fmt, ap, &size);
773
774 va_end(ap);
775
776 assert(size <= INT_MAX);
777
778 return size;
779 }
780
781
782
783 /* When a function that is supposed to return a malloc'ed string cannot
784 get the memory for it, it should return 'pm_strsol'. That has a much
785 better effect on the caller, if the caller doesn't explicitly allow for
786 the out of memory case, than returning NULL. Note that it is very
787 rare for the system not to have enough memory to return a small string,
788 so it's OK to have somewhat nonsensical behavior when it happens. We
789 just don't want catastrophic behavior.
790
791 'pm_strsol' is an external symbol, so if Caller wants to detect the
792 out-of-memory failure, he certainly can.
793 */
794 const char * const pm_strsol = "NO MEMORY TO CREATE STRING!";
795
796
797
798 const char *
pm_strdup(const char * const arg)799 pm_strdup(const char * const arg) {
800
801 const char * const dup = strdup(arg);
802
803 return dup ? dup : pm_strsol;
804 }
805
806
807
808 void PM_GNU_PRINTF_ATTR(2,3)
pm_asprintf(const char ** const resultP,const char * const fmt,...)809 pm_asprintf(const char ** const resultP,
810 const char * const fmt,
811 ...) {
812
813 const char * result;
814 va_list varargs;
815
816 #if HAVE_VASPRINTF
817 int rc;
818 va_start(varargs, fmt);
819 rc = vasprintf((char **)&result, fmt, varargs);
820 va_end(varargs);
821 if (rc < 0)
822 result = pm_strsol;
823 #else
824 size_t dryRunLen;
825
826 va_start(varargs, fmt);
827
828 pm_vsnprintf(NULL, 0, fmt, varargs, &dryRunLen);
829
830 va_end(varargs);
831
832 if (dryRunLen + 1 < dryRunLen)
833 /* arithmetic overflow */
834 result = pm_strsol;
835 else {
836 size_t const allocSize = dryRunLen + 1;
837 char * buffer;
838 buffer = malloc(allocSize);
839 if (buffer != NULL) {
840 va_list varargs;
841 size_t realLen;
842
843 va_start(varargs, fmt);
844
845 pm_vsnprintf(buffer, allocSize, fmt, varargs, &realLen);
846
847 assert(realLen == dryRunLen);
848 va_end(varargs);
849
850 result = buffer;
851 }
852 }
853 #endif
854
855 if (result == NULL)
856 *resultP = pm_strsol;
857 else
858 *resultP = result;
859 }
860
861
862
863 void
pm_strfree(const char * const string)864 pm_strfree(const char * const string) {
865
866 if (string != pm_strsol)
867 free((void *) string);
868 }
869
870
871
872 const char *
pm_strsep(char ** const stringP,const char * const delim)873 pm_strsep(char ** const stringP, const char * const delim) {
874 const char * retval;
875
876 if (stringP == NULL || *stringP == NULL)
877 retval = NULL;
878 else {
879 char * p;
880
881 retval = *stringP;
882
883 for (p = *stringP; *p && strchr(delim, *p) == NULL; ++p);
884
885 if (*p) {
886 /* We hit a delimiter, not end-of-string. So null out the
887 delimiter and advance user's pointer to the next token
888 */
889 *p++ = '\0';
890 *stringP = p;
891 } else {
892 /* We ran out of string. So the end-of-string delimiter is
893 already there, and we set the user's pointer to NULL to
894 indicate there are no more tokens.
895 */
896 *stringP = NULL;
897 }
898 }
899 return retval;
900 }
901
902
903
904 int
pm_stripeq(const char * const comparand,const char * const comparator)905 pm_stripeq(const char * const comparand,
906 const char * const comparator) {
907 /*----------------------------------------------------------------------------
908 Compare two strings, ignoring leading and trailing white space.
909
910 Return 1 (true) if the strings are identical; 0 (false) otherwise.
911 -----------------------------------------------------------------------------*/
912 const char * p;
913 const char * q;
914 const char * px;
915 const char * qx;
916 bool equal;
917
918 /* Make p and q point to the first non-blank character in each string.
919 If there are no non-blank characters, make them point to the terminating
920 NUL.
921 */
922
923 p = &comparand[0];
924 while (ISSPACE(*p))
925 p++;
926 q = &comparator[0];
927 while (ISSPACE(*q))
928 q++;
929
930 /* Make px and qx point to the last non-blank character in each string.
931 If there are no nonblank characters (which implies the string is
932 null), make them point to the terminating NUL.
933 */
934
935 if (*p == '\0')
936 px = p;
937 else {
938 px = p + strlen(p) - 1;
939 while (ISSPACE(*px))
940 --px;
941 }
942
943 if (*q == '\0')
944 qx = q;
945 else {
946 qx = q + strlen(q) - 1;
947 while (ISSPACE(*qx))
948 --qx;
949 }
950
951 if (px - p != qx - q) {
952 /* The stripped strings aren't the same length, so we know they aren't
953 equal.
954 */
955 equal = false;
956 } else {
957 /* Move p and q through the nonblank characters, comparing. */
958 for (equal = true; p <= px; ++p, ++q) {
959 assert(q <= qx); /* Because stripped strings are same length */
960 if (*p != *q)
961 equal = false;
962 }
963 }
964 return equal ? 1 : 0;
965 }
966
967
968
969 const void *
pm_memmem(const void * const haystackArg,size_t const haystacklen,const void * const needleArg,size_t const needlelen)970 pm_memmem(const void * const haystackArg,
971 size_t const haystacklen,
972 const void * const needleArg,
973 size_t const needlelen) {
974
975 const unsigned char * const haystack = haystackArg;
976 const unsigned char * const needle = needleArg;
977
978 /* This does the same as the function of the same name in the GNU
979 C library
980 */
981 const unsigned char * p;
982
983 for (p = haystack; p <= haystack + haystacklen - needlelen; ++p)
984 if (memeq(p, needle, needlelen))
985 return p;
986
987 return NULL;
988 }
989
990
991
992 bool
pm_strishex(const char * const subject)993 pm_strishex(const char * const subject) {
994
995 bool retval;
996 unsigned int i;
997
998 retval = TRUE; /* initial assumption */
999
1000 for (i = 0; i < strlen(subject); ++i)
1001 if (!ISXDIGIT(subject[i]))
1002 retval = FALSE;
1003
1004 return retval;
1005 }
1006
1007
1008
1009 void
pm_string_to_long(const char * const string,long * const longP,const char ** const errorP)1010 pm_string_to_long(const char * const string,
1011 long * const longP,
1012 const char ** const errorP) {
1013
1014 if (strlen(string) == 0)
1015 pm_asprintf(errorP, "Value is a null string");
1016 else {
1017 char * tailptr;
1018
1019 /* strtol() does a bizarre thing where if the number is out
1020 of range, it returns a clamped value but tells you about it
1021 by setting errno = ERANGE. If it is not out of range,
1022 strtol() leaves errno alone.
1023 */
1024 errno = 0; /* So we can tell if strtol() overflowed */
1025
1026 *longP = strtol(string, &tailptr, 10);
1027
1028 if (*tailptr != '\0')
1029 pm_asprintf(errorP, "Non-numeric crap in string: '%s'", tailptr);
1030 else {
1031 if (errno == ERANGE)
1032 pm_asprintf(errorP, "Number is too large for computation");
1033 else
1034 *errorP = NULL;
1035 }
1036 }
1037 }
1038
1039
1040
1041 void
pm_string_to_int(const char * const string,int * const intP,const char ** const errorP)1042 pm_string_to_int(const char * const string,
1043 int * const intP,
1044 const char ** const errorP) {
1045
1046 long longValue;
1047
1048 pm_string_to_long(string, &longValue, errorP);
1049
1050 if (!*errorP) {
1051 if ((int)longValue != longValue)
1052 pm_asprintf(errorP,
1053 "Number is too large for computation");
1054 else {
1055 *intP = (int)longValue;
1056 *errorP = NULL;
1057 }
1058 }
1059 }
1060
1061
1062
1063 void
pm_string_to_uint(const char * const string,unsigned int * const uintP,const char ** const errorP)1064 pm_string_to_uint(const char * const string,
1065 unsigned int * const uintP,
1066 const char ** const errorP) {
1067
1068 /* We can't use 'strtoul'. Contrary to expectations, though as
1069 designed, it returns junk if there is a minus sign.
1070 */
1071
1072 long longValue;
1073
1074 pm_string_to_long(string, &longValue, errorP);
1075
1076 if (!*errorP) {
1077 if (longValue < 0)
1078 pm_asprintf(errorP, "Number is negative");
1079 else {
1080 if ((unsigned int)longValue != longValue)
1081 pm_asprintf(errorP,
1082 "Number is too large for computation");
1083 else {
1084 *uintP = (unsigned int)longValue;
1085 *errorP = NULL;
1086 }
1087 }
1088 }
1089 }
1090
1091
1092
1093