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