Merge from vendor branch BSDTAR:
[dragonfly.git] / contrib / bind-9.2.4rc7 / lib / isc / print.c
1 /*
2  * Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 1999-2001, 2003  Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15  * PERFORMANCE OF THIS SOFTWARE.
16  */
17
18 /* $Id: print.c,v 1.22.2.4 2004/03/09 06:11:50 marka Exp $ */
19
20 #include <config.h>
21
22 #include <ctype.h>
23 #include <stdio.h>              /* for sprintf */
24 #include <stdlib.h>
25
26 #define ISC__PRINT_SOURCE       /* Used to get the isc_print_* prototypes. */
27
28 #include <isc/assertions.h>
29 #include <isc/int.h>
30 #include <isc/msgs.h>
31 #include <isc/print.h>
32 #include <isc/util.h>
33
34 /*
35  * Return length of string that would have been written if not truncated.
36  */
37
38 int
39 isc_print_snprintf(char *str, size_t size, const char *format, ...) {
40         va_list ap;
41         int ret;
42
43         va_start(ap, format);
44         ret = vsnprintf(str, size, format, ap);
45         va_end(ap);
46         return (ret);
47
48 }
49
50 /*
51  * Return length of string that would have been written if not truncated.
52  */
53
54 int
55 isc_print_vsnprintf(char *str, size_t size, const char *format, va_list ap) {
56         int h;
57         int l;
58         int q;
59         int alt;
60         int zero;
61         int left;
62         int plus;
63         int space;
64         int neg;
65         isc_int64_t tmpi;
66         isc_uint64_t tmpui;
67         unsigned long width;
68         unsigned long precision;
69         unsigned int length;
70         char buf[1024];
71         char c;
72         void *v;
73         char *save = str;
74         const char *cp;
75         const char *head;
76         int count = 0;
77         int pad;
78         int zeropad;
79         int dot;
80         double dbl;
81 #ifdef HAVE_LONG_DOUBLE
82         long double ldbl;
83 #endif
84         char fmt[32];
85
86         INSIST(str != NULL);
87         INSIST(format != NULL);
88
89         while (*format != '\0') {
90                 if (*format != '%') {
91                         if (size > 1) {
92                                 *str++ = *format;
93                                 size--;
94                         }
95                         count++;
96                         format++;
97                         continue;
98                 }
99                 format++;
100
101                 /*
102                  * Reset flags.
103                  */
104                 dot = neg = space = plus = left = zero = alt = h = l = q = 0;
105                 width = precision = 0;
106                 head = "";
107                 length = pad = zeropad = 0;
108
109                 do {
110                         if (*format == '#') {
111                                 alt = 1;
112                                 format++;
113                         } else if (*format == '-') {
114                                 left = 1;
115                                 zero = 0;
116                                 format++;
117                         } else if (*format == ' ') {
118                                 if (!plus)
119                                         space = 1;
120                                 format++;
121                         } else if (*format == '+') {
122                                 plus = 1;
123                                 space = 0;
124                                 format++;
125                         } else if (*format == '0') {
126                                 if (!left)
127                                         zero = 1;
128                                 format++;
129                         } else
130                                 break;
131                 } while (1);
132
133                 /*
134                  * Width.
135                  */
136                 if (*format == '*') {
137                         width = va_arg(ap, int);
138                         format++;
139                 } else if (isdigit((unsigned char)*format)) {
140                         char *e;
141                         width = strtoul(format, &e, 10);
142                         format = e;
143                 }
144
145                 /*
146                  * Precision.
147                  */
148                 if (*format == '.') {
149                         format++;
150                         dot = 1;
151                         if (*format == '*') {
152                                 precision = va_arg(ap, int);
153                                 format++;
154                         } else if (isdigit((unsigned char)*format)) {
155                                 char *e;
156                                 precision = strtoul(format, &e, 10);
157                                 format = e;
158                         }
159                 }
160
161                 switch (*format) {
162                 case '\0':
163                         continue;
164                 case '%':
165                         if (size > 1) {
166                                 *str++ = *format;
167                                 size--;
168                         }
169                         count++;
170                         break;
171                 case 'q':
172                         q = 1;
173                         format++;
174                         goto doint;
175                 case 'h':
176                         h = 1;
177                         format++;
178                         goto doint;
179                 case 'l':
180                         l = 1;
181                         format++;
182                         if (*format == 'l') {
183                                 q = 1;
184                                 format++;
185                         }
186                         goto doint;
187                 case 'n':
188                 case 'i':
189                 case 'd':
190                 case 'o':
191                 case 'u':
192                 case 'x':
193                 case 'X':
194                 doint:
195                         if (precision != 0)
196                                 zero = 0;
197                         switch (*format) {
198                         case 'n':
199                                 if (h) {
200                                         short int *p;
201                                         p = va_arg(ap, short *);
202                                         REQUIRE(p != NULL);
203                                         *p = str - save;
204                                 } else if (l) {
205                                         long int *p;
206                                         p = va_arg(ap, long *);
207                                         REQUIRE(p != NULL);
208                                         *p = str - save;
209                                 } else {
210                                         int *p;
211                                         p = va_arg(ap, int *);
212                                         REQUIRE(p != NULL);
213                                         *p = str - save;
214                                 }
215                                 break;
216                         case 'i':
217                         case 'd':
218                                 if (q)
219                                         tmpi = va_arg(ap, isc_int64_t);
220                                 else if (l)
221                                         tmpi = va_arg(ap, long int);
222                                 else
223                                         tmpi = va_arg(ap, int);
224                                 if (tmpi < 0) {
225                                         head = "-";
226                                         tmpui = -tmpi;
227                                 } else {
228                                         if (plus)
229                                                 head = "+";
230                                         else if (space)
231                                                 head = " ";
232                                         else
233                                                 head = "";
234                                         tmpui = tmpi;
235                                 }
236                                 sprintf(buf, "%" ISC_PRINT_QUADFORMAT "u",
237                                         tmpui);
238                                 goto printint;
239                         case 'o':
240                                 if (q)
241                                         tmpui = va_arg(ap, isc_uint64_t);
242                                 else if (l)
243                                         tmpui = va_arg(ap, long int);
244                                 else
245                                         tmpui = va_arg(ap, int);
246                                 sprintf(buf,
247                                         alt ? "%#" ISC_PRINT_QUADFORMAT "o"
248                                             : "%" ISC_PRINT_QUADFORMAT "o",
249                                         tmpui);
250                                 goto printint;
251                         case 'u':
252                                 if (q)
253                                         tmpui = va_arg(ap, isc_uint64_t);
254                                 else if (l)
255                                         tmpui = va_arg(ap, unsigned long int);
256                                 else
257                                         tmpui = va_arg(ap, unsigned int);
258                                 sprintf(buf, "%" ISC_PRINT_QUADFORMAT "u",
259                                         tmpui);
260                                 goto printint;
261                         case 'x':
262                                 if (q)
263                                         tmpui = va_arg(ap, isc_uint64_t);
264                                 else if (l)
265                                         tmpui = va_arg(ap, unsigned long int);
266                                 else
267                                         tmpui = va_arg(ap, unsigned int);
268                                 if (alt) {
269                                         head = "0x";
270                                         if (precision > 2)
271                                                 precision -= 2;
272                                 }
273                                 sprintf(buf, "%" ISC_PRINT_QUADFORMAT "x",
274                                         tmpui);
275                                 goto printint;
276                         case 'X':
277                                 if (q)
278                                         tmpui = va_arg(ap, isc_uint64_t);
279                                 else if (l)
280                                         tmpui = va_arg(ap, unsigned long int);
281                                 else
282                                         tmpui = va_arg(ap, unsigned int);
283                                 if (alt) {
284                                         head = "0X";
285                                         if (precision > 2)
286                                                 precision -= 2;
287                                 }
288                                 sprintf(buf, "%" ISC_PRINT_QUADFORMAT "X",
289                                         tmpui);
290                                 goto printint;
291                         printint:
292                                 if (precision != 0 || width != 0) {
293                                         length = strlen(buf);
294                                         if (length < precision)
295                                                 zeropad = precision - length;
296                                         else if (length < width && zero)
297                                                 zeropad = width - length;
298                                         if (width != 0) {
299                                                 pad = width - length -
300                                                       zeropad - strlen(head);
301                                                 if (pad < 0)
302                                                         pad = 0;
303                                         }
304                                 }
305                                 count += strlen(head) + strlen(buf) + pad +
306                                          zeropad;
307                                 if (!left) {
308                                         while (pad > 0 && size > 1) {
309                                                 *str++ = ' ';
310                                                 size--;
311                                                 pad--;
312                                         }
313                                 }
314                                 cp = head;
315                                 while (*cp != '\0' && size > 1) {
316                                         *str++ = *cp++;
317                                         size--;
318                                 }
319                                 while (zeropad > 0 && size > 1) {
320                                         *str++ = '0';
321                                         size--;
322                                         zeropad--;
323                                 }
324                                 cp = buf;
325                                 while (*cp != '\0' && size > 1) {
326                                         *str++ = *cp++;
327                                         size--;
328                                 }
329                                 while (pad > 0 && size > 1) {
330                                         *str++ = ' ';
331                                         size--;
332                                         pad--;
333                                 }
334                                 break;
335                         default:
336                                 break;
337                         }
338                         break;
339                 case 's':
340                         cp = va_arg(ap, char *);
341                         REQUIRE(cp != NULL);
342
343                         if (precision != 0) {
344                                 /*
345                                  * cp need not be NULL terminated.
346                                  */
347                                 const char *tp;
348                                 unsigned long n;
349
350                                 n = precision;
351                                 tp = cp;
352                                 while (n != 0 && *tp != '\0')
353                                         n--, tp++;
354                                 length = precision - n;
355                         } else {
356                                 length = strlen(cp);
357                         }
358                         if (width != 0) {
359                                 pad = width - length;
360                                 if (pad < 0)
361                                         pad = 0;
362                         }
363                         count += pad + length;
364                         if (!left)
365                                 while (pad > 0 && size > 1) {
366                                         *str++ = ' ';
367                                         size--;
368                                         pad--;
369                                 }
370                         if (precision != 0)
371                                 while (precision > 0 && *cp != '\0' &&
372                                        size > 1) {
373                                         *str++ = *cp++;
374                                         size--;
375                                         precision--;
376                                 }
377                         else
378                                 while (*cp != '\0' && size > 1) {
379                                         *str++ = *cp++;
380                                         size--;
381                                 }
382                         while (pad > 0 && size > 1) {
383                                 *str++ = ' ';
384                                 size--;
385                                 pad--;
386                         }
387                         break;
388                 case 'c':
389                         c = va_arg(ap, int);
390                         if (width > 0) {
391                                 count += width;
392                                 width--;
393                                 if (left) {
394                                         *str++ = c;
395                                         size--;
396                                 }
397                                 while (width-- > 0 && size > 1) {
398                                         *str++ = ' ';
399                                         size--;
400                                 }
401                                 if (!left && size > 1) {
402                                         *str++ = c;
403                                         size--;
404                                 }
405                         } else {
406                                 count++;
407                                 if (size > 1) {
408                                         *str++ = c;
409                                         size--;
410                                 }
411                         }
412                         break;
413                 case 'p':
414                         v = va_arg(ap, void *);
415                         sprintf(buf, "%p", v);
416                         length = strlen(buf);
417                         if (precision > length)
418                                 zeropad = precision - length;
419                         if (width > 0) {
420                                 pad = width - length - zeropad;
421                                 if (pad < 0)
422                                         pad = 0;
423                         }
424                         count += length + pad + zeropad;
425                         if (!left)
426                                 while (pad > 0 && size > 1) {
427                                         *str++ = ' ';
428                                         size--;
429                                         pad--;
430                                 }
431                         cp = buf;
432                         if (zeropad > 0 && buf[0] == '0' &&
433                             (buf[1] == 'x' || buf[1] == 'X')) {
434                                 if (size > 1) {
435                                         *str++ = *cp++;
436                                         size--;
437                                 }
438                                 if (size > 1) {
439                                         *str++ = *cp++;
440                                         size--;
441                                 }
442                                 while (zeropad > 0 && size > 1) {
443                                         *str++ = '0';
444                                         size--;
445                                         zeropad--;
446                                 }
447                         }
448                         while (*cp != '\0' && size > 1) {
449                                 *str++ = *cp++;
450                                 size--;
451                         }
452                         while (pad > 0 && size > 1) {
453                                 *str++ = ' ';
454                                 size--;
455                                 pad--;
456                         }
457                         break;
458                 case 'D':       /*deprecated*/
459                         INSIST("use %ld instead of %D" == NULL);
460                 case 'O':       /*deprecated*/
461                         INSIST("use %lo instead of %O" == NULL);
462                 case 'U':       /*deprecated*/
463                         INSIST("use %lu instead of %U" == NULL);
464
465                 case 'L':
466 #ifdef HAVE_LONG_DOUBLE
467                         l = 1;
468 #else
469                         INSIST("long doubles are not supported" == NULL);
470 #endif
471                         /*FALLTHROUGH*/
472                 case 'e':
473                 case 'E':
474                 case 'f':
475                 case 'g':
476                 case 'G':
477                         if (!dot)
478                                 precision = 6;
479                         /*
480                          * IEEE floating point.
481                          * MIN 2.2250738585072014E-308
482                          * MAX 1.7976931348623157E+308
483                          * VAX floating point has a smaller range than IEEE.
484                          *
485                          * precisions > 324 don't make much sense.
486                          * if we cap the precision at 512 we will not
487                          * overflow buf.
488                          */
489                         if (precision > 512)
490                                 precision = 512;
491                         sprintf(fmt, "%%%s%s.%lu%s%c", alt ? "#" : "",
492                                 plus ? "+" : space ? " " : "",
493                                 precision, l ? "L" : "", *format);
494                         switch (*format) {
495                         case 'e':
496                         case 'E':
497                         case 'f':
498                         case 'g':
499                         case 'G':
500 #ifdef HAVE_LONG_DOUBLE
501                                 if (l) {
502                                         ldbl = va_arg(ap, long double);
503                                         sprintf(buf, fmt, ldbl);
504                                 } else
505 #endif
506                                 {
507                                         dbl = va_arg(ap, double);
508                                         sprintf(buf, fmt, dbl);
509                                 }
510                                 length = strlen(buf);
511                                 if (width > 0) {
512                                         pad = width - length;
513                                         if (pad < 0)
514                                                 pad = 0;
515                                 }
516                                 count += length + pad;
517                                 if (!left)
518                                         while (pad > 0 && size > 1) {
519                                                 *str++ = ' ';
520                                                 size--;
521                                                 pad--;
522                                         }
523                                 cp = buf;
524                                 while (*cp != ' ' && size > 1) {
525                                         *str++ = *cp++;
526                                         size--;
527                                 }
528                                 while (pad > 0 && size > 1) {
529                                         *str++ = ' ';
530                                         size--;
531                                         pad--;
532                                 }
533                                 break;
534                         default:
535                                 continue;
536                         }
537                         break;
538                 default:
539                         continue;
540                 }
541                 format++;
542         }
543         if (size > 0)
544                 *str = '\0';
545         return (count);
546 }