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