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