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