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