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