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