]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/bind9/lib/lwres/print.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / bind9 / lib / lwres / print.c
1 /*
2  * Copyright (C) 2004, 2005, 2007, 2011, 2012  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$ */
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                 POST(length);
119
120                 do {
121                         if (*format == '#') {
122                                 alt = 1;
123                                 format++;
124                         } else if (*format == '-') {
125                                 left = 1;
126                                 zero = 0;
127                                 format++;
128                         } else if (*format == ' ') {
129                                 if (!plus)
130                                         space = 1;
131                                 format++;
132                         } else if (*format == '+') {
133                                 plus = 1;
134                                 space = 0;
135                                 format++;
136                         } else if (*format == '0') {
137                                 if (!left)
138                                         zero = 1;
139                                 format++;
140                         } else
141                                 break;
142                 } while (1);
143
144                 /*
145                  * Width.
146                  */
147                 if (*format == '*') {
148                         width = va_arg(ap, int);
149                         format++;
150                 } else if (isdigit((unsigned char)*format)) {
151                         char *e;
152                         width = strtoul(format, &e, 10);
153                         format = e;
154                 }
155
156                 /*
157                  * Precision.
158                  */
159                 if (*format == '.') {
160                         format++;
161                         dot = 1;
162                         if (*format == '*') {
163                                 precision = va_arg(ap, int);
164                                 format++;
165                         } else if (isdigit((unsigned char)*format)) {
166                                 char *e;
167                                 precision = strtoul(format, &e, 10);
168                                 format = e;
169                         }
170                 }
171
172                 switch (*format) {
173                 case '\0':
174                         continue;
175                 case '%':
176                         if (size > 1U) {
177                                 *str++ = *format;
178                                 size--;
179                         }
180                         count++;
181                         break;
182                 case 'q':
183                         q = 1;
184                         format++;
185                         goto doint;
186                 case 'h':
187                         h = 1;
188                         format++;
189                         goto doint;
190                 case 'l':
191                         l = 1;
192                         format++;
193                         if (*format == 'l') {
194                                 q = 1;
195                                 format++;
196                         }
197                         goto doint;
198                 case 'n':
199                 case 'i':
200                 case 'd':
201                 case 'o':
202                 case 'u':
203                 case 'x':
204                 case 'X':
205                 doint:
206                         if (precision != 0U)
207                                 zero = 0;
208                         switch (*format) {
209                         case 'n':
210                                 if (h) {
211                                         short int *p;
212                                         p = va_arg(ap, short *);
213                                         REQUIRE(p != NULL);
214                                         *p = str - save;
215                                 } else if (l) {
216                                         long int *p;
217                                         p = va_arg(ap, long *);
218                                         REQUIRE(p != NULL);
219                                         *p = str - save;
220                                 } else {
221                                         int *p;
222                                         p = va_arg(ap, int *);
223                                         REQUIRE(p != NULL);
224                                         *p = str - save;
225                                 }
226                                 break;
227                         case 'i':
228                         case 'd':
229                                 if (q)
230                                         tmpi = va_arg(ap, long long int);
231                                 else if (l)
232                                         tmpi = va_arg(ap, long int);
233                                 else
234                                         tmpi = va_arg(ap, int);
235                                 if (tmpi < 0) {
236                                         head = "-";
237                                         tmpui = -tmpi;
238                                 } else {
239                                         if (plus)
240                                                 head = "+";
241                                         else if (space)
242                                                 head = " ";
243                                         else
244                                                 head = "";
245                                         tmpui = tmpi;
246                                 }
247                                 sprintf(buf, "%" LWRES_PRINT_QUADFORMAT "u",
248                                         tmpui);
249                                 goto printint;
250                         case 'o':
251                                 if (q)
252                                         tmpui = va_arg(ap,
253                                                        unsigned long long int);
254                                 else if (l)
255                                         tmpui = va_arg(ap, long int);
256                                 else
257                                         tmpui = va_arg(ap, int);
258                                 sprintf(buf,
259                                         alt ? "%#" LWRES_PRINT_QUADFORMAT "o"
260                                             : "%" LWRES_PRINT_QUADFORMAT "o",
261                                         tmpui);
262                                 goto printint;
263                         case 'u':
264                                 if (q)
265                                         tmpui = va_arg(ap,
266                                                        unsigned long long int);
267                                 else if (l)
268                                         tmpui = va_arg(ap, unsigned long int);
269                                 else
270                                         tmpui = va_arg(ap, unsigned int);
271                                 sprintf(buf, "%" LWRES_PRINT_QUADFORMAT "u",
272                                         tmpui);
273                                 goto printint;
274                         case 'x':
275                                 if (q)
276                                         tmpui = va_arg(ap,
277                                                        unsigned long long int);
278                                 else if (l)
279                                         tmpui = va_arg(ap, unsigned long int);
280                                 else
281                                         tmpui = va_arg(ap, unsigned int);
282                                 if (alt) {
283                                         head = "0x";
284                                         if (precision > 2U)
285                                                 precision -= 2;
286                                 }
287                                 sprintf(buf, "%" LWRES_PRINT_QUADFORMAT "x",
288                                         tmpui);
289                                 goto printint;
290                         case 'X':
291                                 if (q)
292                                         tmpui = va_arg(ap,
293                                                        unsigned long long int);
294                                 else if (l)
295                                         tmpui = va_arg(ap, unsigned long int);
296                                 else
297                                         tmpui = va_arg(ap, unsigned int);
298                                 if (alt) {
299                                         head = "0X";
300                                         if (precision > 2U)
301                                                 precision -= 2;
302                                 }
303                                 sprintf(buf, "%" LWRES_PRINT_QUADFORMAT "X",
304                                         tmpui);
305                                 goto printint;
306                         printint:
307                                 if (precision != 0U || width != 0U) {
308                                         length = strlen(buf);
309                                         if (length < precision)
310                                                 zeropad = precision - length;
311                                         else if (length < width && zero)
312                                                 zeropad = width - length;
313                                         if (width != 0U) {
314                                                 pad = width - length -
315                                                       zeropad - strlen(head);
316                                                 if (pad < 0)
317                                                         pad = 0;
318                                         }
319                                 }
320                                 count += strlen(head) + strlen(buf) + pad +
321                                          zeropad;
322                                 if (!left) {
323                                         while (pad > 0 && size > 1U) {
324                                                 *str++ = ' ';
325                                                 size--;
326                                                 pad--;
327                                         }
328                                 }
329                                 cp = head;
330                                 while (*cp != '\0' && size > 1U) {
331                                         *str++ = *cp++;
332                                         size--;
333                                 }
334                                 while (zeropad > 0 && size > 1U) {
335                                         *str++ = '0';
336                                         size--;
337                                         zeropad--;
338                                 }
339                                 cp = buf;
340                                 while (*cp != '\0' && size > 1U) {
341                                         *str++ = *cp++;
342                                         size--;
343                                 }
344                                 while (pad > 0 && size > 1U) {
345                                         *str++ = ' ';
346                                         size--;
347                                         pad--;
348                                 }
349                                 break;
350                         default:
351                                 break;
352                         }
353                         break;
354                 case 's':
355                         cp = va_arg(ap, char *);
356                         REQUIRE(cp != NULL);
357
358                         if (precision != 0U) {
359                                 /*
360                                  * cp need not be NULL terminated.
361                                  */
362                                 const char *tp;
363                                 unsigned long n;
364
365                                 n = precision;
366                                 tp = cp;
367                                 while (n != 0U && *tp != '\0')
368                                         n--, tp++;
369                                 length = precision - n;
370                         } else {
371                                 length = strlen(cp);
372                         }
373                         if (width != 0U) {
374                                 pad = width - length;
375                                 if (pad < 0)
376                                         pad = 0;
377                         }
378                         count += pad + length;
379                         if (!left)
380                                 while (pad > 0 && size > 1U) {
381                                         *str++ = ' ';
382                                         size--;
383                                         pad--;
384                                 }
385                         if (precision != 0U)
386                                 while (precision > 0U && *cp != '\0' &&
387                                        size > 1U) {
388                                         *str++ = *cp++;
389                                         size--;
390                                         precision--;
391                                 }
392                         else
393                                 while (*cp != '\0' && size > 1U) {
394                                         *str++ = *cp++;
395                                         size--;
396                                 }
397                         while (pad > 0 && size > 1U) {
398                                 *str++ = ' ';
399                                 size--;
400                                 pad--;
401                         }
402                         break;
403                 case 'c':
404                         c = va_arg(ap, int);
405                         if (width > 0U) {
406                                 count += width;
407                                 width--;
408                                 if (left) {
409                                         *str++ = c;
410                                         size--;
411                                 }
412                                 while (width-- > 0U && size > 1U) {
413                                         *str++ = ' ';
414                                         size--;
415                                 }
416                                 if (!left && size > 1U) {
417                                         *str++ = c;
418                                         size--;
419                                 }
420                         } else {
421                                 count++;
422                                 if (size > 1U) {
423                                         *str++ = c;
424                                         size--;
425                                 }
426                         }
427                         break;
428                 case 'p':
429                         v = va_arg(ap, void *);
430                         sprintf(buf, "%p", v);
431                         length = strlen(buf);
432                         if (precision > length)
433                                 zeropad = precision - length;
434                         if (width > 0U) {
435                                 pad = width - length - zeropad;
436                                 if (pad < 0)
437                                         pad = 0;
438                         }
439                         count += length + pad + zeropad;
440                         if (!left)
441                                 while (pad > 0 && size > 1U) {
442                                         *str++ = ' ';
443                                         size--;
444                                         pad--;
445                                 }
446                         cp = buf;
447                         if (zeropad > 0 && buf[0] == '0' &&
448                             (buf[1] == 'x' || buf[1] == 'X')) {
449                                 if (size > 1U) {
450                                         *str++ = *cp++;
451                                         size--;
452                                 }
453                                 if (size > 1U) {
454                                         *str++ = *cp++;
455                                         size--;
456                                 }
457                                 while (zeropad > 0 && size > 1U) {
458                                         *str++ = '0';
459                                         size--;
460                                         zeropad--;
461                                 }
462                         }
463                         while (*cp != '\0' && size > 1U) {
464                                 *str++ = *cp++;
465                                 size--;
466                         }
467                         while (pad > 0 && size > 1U) {
468                                 *str++ = ' ';
469                                 size--;
470                                 pad--;
471                         }
472                         break;
473                 case 'D':       /*deprecated*/
474                         INSIST("use %ld instead of %D" == NULL);
475                 case 'O':       /*deprecated*/
476                         INSIST("use %lo instead of %O" == NULL);
477                 case 'U':       /*deprecated*/
478                         INSIST("use %lu instead of %U" == NULL);
479
480                 case 'L':
481 #ifdef HAVE_LONG_DOUBLE
482                         l = 1;
483 #else
484                         INSIST("long doubles are not supported" == NULL);
485 #endif
486                         /*FALLTHROUGH*/
487                 case 'e':
488                 case 'E':
489                 case 'f':
490                 case 'g':
491                 case 'G':
492                         if (!dot)
493                                 precision = 6;
494                         /*
495                          * IEEE floating point.
496                          * MIN 2.2250738585072014E-308
497                          * MAX 1.7976931348623157E+308
498                          * VAX floating point has a smaller range than IEEE.
499                          *
500                          * precisions > 324 don't make much sense.
501                          * if we cap the precision at 512 we will not
502                          * overflow buf.
503                          */
504                         if (precision > 512U)
505                                 precision = 512;
506                         sprintf(fmt, "%%%s%s.%lu%s%c", alt ? "#" : "",
507                                 plus ? "+" : space ? " " : "",
508                                 precision, l ? "L" : "", *format);
509                         switch (*format) {
510                         case 'e':
511                         case 'E':
512                         case 'f':
513                         case 'g':
514                         case 'G':
515 #ifdef HAVE_LONG_DOUBLE
516                                 if (l) {
517                                         ldbl = va_arg(ap, long double);
518                                         sprintf(buf, fmt, ldbl);
519                                 } else
520 #endif
521                                 {
522                                         dbl = va_arg(ap, double);
523                                         sprintf(buf, fmt, dbl);
524                                 }
525                                 length = strlen(buf);
526                                 if (width > 0U) {
527                                         pad = width - length;
528                                         if (pad < 0)
529                                                 pad = 0;
530                                 }
531                                 count += length + pad;
532                                 if (!left)
533                                         while (pad > 0 && size > 1U) {
534                                                 *str++ = ' ';
535                                                 size--;
536                                                 pad--;
537                                         }
538                                 cp = buf;
539                                 while (*cp != ' ' && size > 1U) {
540                                         *str++ = *cp++;
541                                         size--;
542                                 }
543                                 while (pad > 0 && size > 1U) {
544                                         *str++ = ' ';
545                                         size--;
546                                         pad--;
547                                 }
548                                 break;
549                         default:
550                                 continue;
551                         }
552                         break;
553                 default:
554                         continue;
555                 }
556                 format++;
557         }
558         if (size > 0U)
559                 *str = '\0';
560         return (count);
561 }