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 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 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