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