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