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