Merge from vendor branch TCPDUMP:
[dragonfly.git] / contrib / bind-9.3 / lib / lwres / print.c
1 /*
2  * Copyright (C) 2004, 2005  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.2.4.7 2005/10/14 01:38:51 marka Exp $ */
19
20 #include <config.h>
21
22 #include <ctype.h>
23 #include <stdio.h>              /* for sprintf */
24 #include <string.h>
25
26 #define LWRES__PRINT_SOURCE     /* Used to get the lwres_print_* prototypes. */
27
28 #include <lwres/stdlib.h>
29
30 #include "assert_p.h"
31 #include "print_p.h"
32
33 #define LWRES_PRINT_QUADFORMAT LWRES_PLATFORM_QUADFORMAT
34
35 int
36 lwres__print_sprintf(char *str, const char *format, ...) {
37         va_list ap;
38
39         va_start(ap, format);
40         vsprintf(str, format, ap);
41         va_end(ap);
42         return (strlen(str));
43 }
44
45 /*
46  * Return length of string that would have been written if not truncated.
47  */
48
49 int
50 lwres__print_snprintf(char *str, size_t size, const char *format, ...) {
51         va_list ap;
52         int ret;
53
54         va_start(ap, format);
55         ret = vsnprintf(str, size, format, ap);
56         va_end(ap);
57         return (ret);
58
59 }
60
61 /*
62  * Return length of string that would have been written if not truncated.
63  */
64
65 int
66 lwres__print_vsnprintf(char *str, size_t size, const char *format, va_list ap) {
67         int h;
68         int l;
69         int q;
70         int alt;
71         int zero;
72         int left;
73         int plus;
74         int space;
75         long long tmpi;
76         unsigned long long 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 > 1U) {
102                                 *str++ = *format;
103                                 size--;
104                         }
105                         count++;
106                         format++;
107                         continue;
108                 }
109                 format++;
110
111                 /*
112                  * Reset flags.
113                  */
114                 dot = 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 > 1U) {
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 != 0U)
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, long long int);
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, "%" LWRES_PRINT_QUADFORMAT "u",
247                                         tmpui);
248                                 goto printint;
249                         case 'o':
250                                 if (q)
251                                         tmpui = va_arg(ap,
252                                                        unsigned long long int);
253                                 else if (l)
254                                         tmpui = va_arg(ap, long int);
255                                 else
256                                         tmpui = va_arg(ap, int);
257                                 sprintf(buf,
258                                         alt ? "%#" LWRES_PRINT_QUADFORMAT "o"
259                                             : "%" LWRES_PRINT_QUADFORMAT "o",
260                                         tmpui);
261                                 goto printint;
262                         case 'u':
263                                 if (q)
264                                         tmpui = va_arg(ap,
265                                                        unsigned long long int);
266                                 else if (l)
267                                         tmpui = va_arg(ap, unsigned long int);
268                                 else
269                                         tmpui = va_arg(ap, unsigned int);
270                                 sprintf(buf, "%" LWRES_PRINT_QUADFORMAT "u",
271                                         tmpui);
272                                 goto printint;
273                         case 'x':
274                                 if (q)
275                                         tmpui = va_arg(ap,
276                                                        unsigned long long int);
277                                 else if (l)
278                                         tmpui = va_arg(ap, unsigned long int);
279                                 else
280                                         tmpui = va_arg(ap, unsigned int);
281                                 if (alt) {
282                                         head = "0x";
283                                         if (precision > 2U)
284                                                 precision -= 2;
285                                 }
286                                 sprintf(buf, "%" LWRES_PRINT_QUADFORMAT "x",
287                                         tmpui);
288                                 goto printint;
289                         case 'X':
290                                 if (q)
291                                         tmpui = va_arg(ap,
292                                                        unsigned long long int);
293                                 else if (l)
294                                         tmpui = va_arg(ap, unsigned long int);
295                                 else
296                                         tmpui = va_arg(ap, unsigned int);
297                                 if (alt) {
298                                         head = "0X";
299                                         if (precision > 2U)
300                                                 precision -= 2;
301                                 }
302                                 sprintf(buf, "%" LWRES_PRINT_QUADFORMAT "X",
303                                         tmpui);
304                                 goto printint;
305                         printint:
306                                 if (precision != 0U || width != 0U) {
307                                         length = strlen(buf);
308                                         if (length < precision)
309                                                 zeropad = precision - length;
310                                         else if (length < width && zero)
311                                                 zeropad = width - length;
312                                         if (width != 0U) {
313                                                 pad = width - length -
314                                                       zeropad - strlen(head);
315                                                 if (pad < 0)
316                                                         pad = 0;
317                                         }
318                                 }
319                                 count += strlen(head) + strlen(buf) + pad +
320                                          zeropad;
321                                 if (!left) {
322                                         while (pad > 0 && size > 1U) {
323                                                 *str++ = ' ';
324                                                 size--;
325                                                 pad--;
326                                         }
327                                 }
328                                 cp = head;
329                                 while (*cp != '\0' && size > 1U) {
330                                         *str++ = *cp++;
331                                         size--;
332                                 }
333                                 while (zeropad > 0 && size > 1U) {
334                                         *str++ = '0';
335                                         size--;
336                                         zeropad--;
337                                 }
338                                 cp = buf;
339                                 while (*cp != '\0' && size > 1U) {
340                                         *str++ = *cp++;
341                                         size--;
342                                 }
343                                 while (pad > 0 && size > 1U) {
344                                         *str++ = ' ';
345                                         size--;
346                                         pad--;
347                                 }
348                                 break;
349                         default:
350                                 break;
351                         }
352                         break;
353                 case 's':
354                         cp = va_arg(ap, char *);
355                         REQUIRE(cp != NULL);
356
357                         if (precision != 0U) {
358                                 /*
359                                  * cp need not be NULL terminated.
360                                  */
361                                 const char *tp;
362                                 unsigned long n;
363
364                                 n = precision;
365                                 tp = cp;
366                                 while (n != 0U && *tp != '\0')
367                                         n--, tp++;
368                                 length = precision - n;
369                         } else {
370                                 length = strlen(cp);
371                         }
372                         if (width != 0U) {
373                                 pad = width - length;
374                                 if (pad < 0)
375                                         pad = 0;
376                         }
377                         count += pad + length;
378                         if (!left)
379                                 while (pad > 0 && size > 1U) {
380                                         *str++ = ' ';
381                                         size--;
382                                         pad--;
383                                 }
384                         if (precision != 0U)
385                                 while (precision > 0U && *cp != '\0' &&
386                                        size > 1U) {
387                                         *str++ = *cp++;
388                                         size--;
389                                         precision--;
390                                 }
391                         else
392                                 while (*cp != '\0' && size > 1U) {
393                                         *str++ = *cp++;
394                                         size--;
395                                 }
396                         while (pad > 0 && size > 1U) {
397                                 *str++ = ' ';
398                                 size--;
399                                 pad--;
400                         }
401                         break;
402                 case 'c':
403                         c = va_arg(ap, int);
404                         if (width > 0U) {
405                                 count += width;
406                                 width--;
407                                 if (left) {
408                                         *str++ = c;
409                                         size--;
410                                 }
411                                 while (width-- > 0U && size > 1U) {
412                                         *str++ = ' ';
413                                         size--;
414                                 }
415                                 if (!left && size > 1U) {
416                                         *str++ = c;
417                                         size--;
418                                 }
419                         } else {
420                                 count++;
421                                 if (size > 1U) {
422                                         *str++ = c;
423                                         size--;
424                                 }
425                         }
426                         break;
427                 case 'p':
428                         v = va_arg(ap, void *);
429                         sprintf(buf, "%p", v);
430                         length = strlen(buf);
431                         if (precision > length)
432                                 zeropad = precision - length;
433                         if (width > 0U) {
434                                 pad = width - length - zeropad;
435                                 if (pad < 0)
436                                         pad = 0;
437                         }
438                         count += length + pad + zeropad;
439                         if (!left)
440                                 while (pad > 0 && size > 1U) {
441                                         *str++ = ' ';
442                                         size--;
443                                         pad--;
444                                 }
445                         cp = buf;
446                         if (zeropad > 0 && buf[0] == '0' &&
447                             (buf[1] == 'x' || buf[1] == 'X')) {
448                                 if (size > 1U) {
449                                         *str++ = *cp++;
450                                         size--;
451                                 }
452                                 if (size > 1U) {
453                                         *str++ = *cp++;
454                                         size--;
455                                 }
456                                 while (zeropad > 0 && size > 1U) {
457                                         *str++ = '0';
458                                         size--;
459                                         zeropad--;
460                                 }
461                         }
462                         while (*cp != '\0' && size > 1U) {
463                                 *str++ = *cp++;
464                                 size--;
465                         }
466                         while (pad > 0 && size > 1U) {
467                                 *str++ = ' ';
468                                 size--;
469                                 pad--;
470                         }
471                         break;
472                 case 'D':       /*deprecated*/
473                         INSIST("use %ld instead of %D" == NULL);
474                 case 'O':       /*deprecated*/
475                         INSIST("use %lo instead of %O" == NULL);
476                 case 'U':       /*deprecated*/
477                         INSIST("use %lu instead of %U" == NULL);
478
479                 case 'L':
480 #ifdef HAVE_LONG_DOUBLE
481                         l = 1;
482 #else
483                         INSIST("long doubles are not supported" == NULL);
484 #endif
485                         /*FALLTHROUGH*/
486                 case 'e':
487                 case 'E':
488                 case 'f':
489                 case 'g':
490                 case 'G':
491                         if (!dot)
492                                 precision = 6;
493                         /*
494                          * IEEE floating point.
495                          * MIN 2.2250738585072014E-308
496                          * MAX 1.7976931348623157E+308
497                          * VAX floating point has a smaller range than IEEE.
498                          *
499                          * precisions > 324 don't make much sense.
500                          * if we cap the precision at 512 we will not
501                          * overflow buf.
502                          */
503                         if (precision > 512U)
504                                 precision = 512;
505                         sprintf(fmt, "%%%s%s.%lu%s%c", alt ? "#" : "",
506                                 plus ? "+" : space ? " " : "",
507                                 precision, l ? "L" : "", *format);
508                         switch (*format) {
509                         case 'e':
510                         case 'E':
511                         case 'f':
512                         case 'g':
513                         case 'G':
514 #ifdef HAVE_LONG_DOUBLE
515                                 if (l) {
516                                         ldbl = va_arg(ap, long double);
517                                         sprintf(buf, fmt, ldbl);
518                                 } else
519 #endif
520                                 {
521                                         dbl = va_arg(ap, double);
522                                         sprintf(buf, fmt, dbl);
523                                 }
524                                 length = strlen(buf);
525                                 if (width > 0U) {
526                                         pad = width - length;
527                                         if (pad < 0)
528                                                 pad = 0;
529                                 }
530                                 count += length + pad;
531                                 if (!left)
532                                         while (pad > 0 && size > 1U) {
533                                                 *str++ = ' ';
534                                                 size--;
535                                                 pad--;
536                                         }
537                                 cp = buf;
538                                 while (*cp != ' ' && size > 1U) {
539                                         *str++ = *cp++;
540                                         size--;
541                                 }
542                                 while (pad > 0 && size > 1U) {
543                                         *str++ = ' ';
544                                         size--;
545                                         pad--;
546                                 }
547                                 break;
548                         default:
549                                 continue;
550                         }
551                         break;
552                 default:
553                         continue;
554                 }
555                 format++;
556         }
557         if (size > 0U)
558                 *str = '\0';
559         return (count);
560 }