00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <config.h>
00023
00024 #include <ctype.h>
00025 #include <stdio.h>
00026 #include <string.h>
00027
00028 #define ISC__PRINT_SOURCE
00029
00030 #include <isc/assertions.h>
00031 #include <isc/int.h>
00032 #include <isc/msgs.h>
00033 #include <isc/print.h>
00034 #include <isc/stdlib.h>
00035 #include <isc/util.h>
00036
00037 int
00038 isc_print_sprintf(char *str, const char *format, ...) {
00039 va_list ap;
00040
00041 va_start(ap, format);
00042 vsprintf(str, format, ap);
00043 va_end(ap);
00044 return (strlen(str));
00045 }
00046
00047
00048
00049
00050
00051 int
00052 isc_print_snprintf(char *str, size_t size, const char *format, ...) {
00053 va_list ap;
00054 int ret;
00055
00056 va_start(ap, format);
00057 ret = vsnprintf(str, size, format, ap);
00058 va_end(ap);
00059 return (ret);
00060
00061 }
00062
00063
00064
00065
00066
00067 int
00068 isc_print_vsnprintf(char *str, size_t size, const char *format, va_list ap) {
00069 int h;
00070 int l;
00071 int q;
00072 int alt;
00073 int zero;
00074 int left;
00075 int plus;
00076 int space;
00077 int neg;
00078 isc_int64_t tmpi;
00079 isc_uint64_t tmpui;
00080 unsigned long width;
00081 unsigned long precision;
00082 unsigned int length;
00083 char buf[1024];
00084 char c;
00085 void *v;
00086 char *save = str;
00087 const char *cp;
00088 const char *head;
00089 int count = 0;
00090 int pad;
00091 int zeropad;
00092 int dot;
00093 double dbl;
00094 #ifdef HAVE_LONG_DOUBLE
00095 long double ldbl;
00096 #endif
00097 char fmt[32];
00098
00099 INSIST(str != NULL);
00100 INSIST(format != NULL);
00101
00102 while (*format != '\0') {
00103 if (*format != '%') {
00104 if (size > 1) {
00105 *str++ = *format;
00106 size--;
00107 }
00108 count++;
00109 format++;
00110 continue;
00111 }
00112 format++;
00113
00114
00115
00116
00117 dot = neg = space = plus = left = zero = alt = h = l = q = 0;
00118 width = precision = 0;
00119 head = "";
00120 pad = zeropad = 0;
00121
00122 do {
00123 if (*format == '#') {
00124 alt = 1;
00125 format++;
00126 } else if (*format == '-') {
00127 left = 1;
00128 zero = 0;
00129 format++;
00130 } else if (*format == ' ') {
00131 if (!plus)
00132 space = 1;
00133 format++;
00134 } else if (*format == '+') {
00135 plus = 1;
00136 space = 0;
00137 format++;
00138 } else if (*format == '0') {
00139 if (!left)
00140 zero = 1;
00141 format++;
00142 } else
00143 break;
00144 } while (1);
00145
00146
00147
00148
00149 if (*format == '*') {
00150 width = va_arg(ap, int);
00151 format++;
00152 } else if (isdigit((unsigned char)*format)) {
00153 char *e;
00154 width = strtoul(format, &e, 10);
00155 format = e;
00156 }
00157
00158
00159
00160
00161 if (*format == '.') {
00162 format++;
00163 dot = 1;
00164 if (*format == '*') {
00165 precision = va_arg(ap, int);
00166 format++;
00167 } else if (isdigit((unsigned char)*format)) {
00168 char *e;
00169 precision = strtoul(format, &e, 10);
00170 format = e;
00171 }
00172 }
00173
00174 switch (*format) {
00175 case '\0':
00176 continue;
00177 case '%':
00178 if (size > 1) {
00179 *str++ = *format;
00180 size--;
00181 }
00182 count++;
00183 break;
00184 case 'q':
00185 q = 1;
00186 format++;
00187 goto doint;
00188 case 'h':
00189 h = 1;
00190 format++;
00191 goto doint;
00192 case 'l':
00193 l = 1;
00194 format++;
00195 if (*format == 'l') {
00196 q = 1;
00197 format++;
00198 }
00199 goto doint;
00200 case 'n':
00201 case 'i':
00202 case 'd':
00203 case 'o':
00204 case 'u':
00205 case 'x':
00206 case 'X':
00207 doint:
00208 if (precision != 0)
00209 zero = 0;
00210 switch (*format) {
00211 case 'n':
00212 if (h) {
00213 short int *p;
00214 p = va_arg(ap, short *);
00215 REQUIRE(p != NULL);
00216 *p = str - save;
00217 } else if (l) {
00218 long int *p;
00219 p = va_arg(ap, long *);
00220 REQUIRE(p != NULL);
00221 *p = str - save;
00222 } else {
00223 int *p;
00224 p = va_arg(ap, int *);
00225 REQUIRE(p != NULL);
00226 *p = str - save;
00227 }
00228 break;
00229 case 'i':
00230 case 'd':
00231 if (q)
00232 tmpi = va_arg(ap, isc_int64_t);
00233 else if (l)
00234 tmpi = va_arg(ap, long int);
00235 else
00236 tmpi = va_arg(ap, int);
00237 if (tmpi < 0) {
00238 head = "-";
00239 tmpui = -tmpi;
00240 } else {
00241 if (plus)
00242 head = "+";
00243 else if (space)
00244 head = " ";
00245 else
00246 head = "";
00247 tmpui = tmpi;
00248 }
00249 if (tmpui <= 0xffffffffU)
00250 sprintf(buf, "%lu",
00251 (unsigned long)tmpui);
00252 else {
00253 unsigned long mid;
00254 unsigned long lo;
00255 unsigned long hi;
00256 lo = tmpui % 1000000000;
00257 tmpui /= 1000000000;
00258 mid = tmpui % 1000000000;
00259 hi = tmpui / 1000000000;
00260 if (hi != 0)
00261 sprintf(buf, "%lu", hi);
00262 else
00263 buf[0] = '\0';
00264 sprintf(buf + strlen(buf), "%lu", mid);
00265 sprintf(buf + strlen(buf), "%lu", lo);
00266 }
00267 goto printint;
00268 case 'o':
00269 if (q)
00270 tmpui = va_arg(ap, isc_uint64_t);
00271 else if (l)
00272 tmpui = va_arg(ap, long int);
00273 else
00274 tmpui = va_arg(ap, int);
00275 if (tmpui <= 0xffffffffU)
00276 sprintf(buf, alt ? "%#lo" : "%lo",
00277 (unsigned long)tmpui);
00278 else {
00279 unsigned long mid;
00280 unsigned long lo;
00281 unsigned long hi;
00282 lo = tmpui % 010000000000;
00283 tmpui /= 010000000000;
00284 mid = tmpui % 010000000000;
00285 hi = tmpui / 010000000000;
00286 if (hi != 0) {
00287 sprintf(buf,
00288 alt ? "%#lo" : "%lo",
00289 hi);
00290 sprintf(buf + strlen(buf),
00291 "%lo", mid);
00292 } else
00293 sprintf(buf,
00294 alt ? "%#lo" : "%lo",
00295 mid);
00296 sprintf(buf + strlen(buf), "%lo", lo);
00297 }
00298 goto printint;
00299 case 'u':
00300 if (q)
00301 tmpui = va_arg(ap, isc_uint64_t);
00302 else if (l)
00303 tmpui = va_arg(ap, unsigned long int);
00304 else
00305 tmpui = va_arg(ap, unsigned int);
00306 if (tmpui <= 0xffffffffU)
00307 sprintf(buf, "%lu",
00308 (unsigned long)tmpui);
00309 else {
00310 unsigned long mid;
00311 unsigned long lo;
00312 unsigned long hi;
00313 lo = tmpui % 1000000000;
00314 tmpui /= 1000000000;
00315 mid = tmpui % 1000000000;
00316 hi = tmpui / 1000000000;
00317 if (hi != 0)
00318 sprintf(buf, "%lu", hi);
00319 else
00320 buf[0] = '\0';
00321 sprintf(buf + strlen(buf), "%lu", mid);
00322 sprintf(buf + strlen(buf), "%lu", lo);
00323 }
00324 goto printint;
00325 case 'x':
00326 if (q)
00327 tmpui = va_arg(ap, isc_uint64_t);
00328 else if (l)
00329 tmpui = va_arg(ap, unsigned long int);
00330 else
00331 tmpui = va_arg(ap, unsigned int);
00332 if (alt) {
00333 head = "0x";
00334 if (precision > 2)
00335 precision -= 2;
00336 }
00337 if (tmpui <= 0xffffffffU)
00338 sprintf(buf, "%lx",
00339 (unsigned long)tmpui);
00340 else {
00341 unsigned long hi = tmpui>>32;
00342 unsigned long lo = tmpui & 0xffffffff;
00343 sprintf(buf, "%lx", hi);
00344 sprintf(buf + strlen(buf), "%lx", lo);
00345 }
00346 goto printint;
00347 case 'X':
00348 if (q)
00349 tmpui = va_arg(ap, isc_uint64_t);
00350 else if (l)
00351 tmpui = va_arg(ap, unsigned long int);
00352 else
00353 tmpui = va_arg(ap, unsigned int);
00354 if (alt) {
00355 head = "0X";
00356 if (precision > 2)
00357 precision -= 2;
00358 }
00359 if (tmpui <= 0xffffffffU)
00360 sprintf(buf, "%lX",
00361 (unsigned long)tmpui);
00362 else {
00363 unsigned long hi = tmpui>>32;
00364 unsigned long lo = tmpui & 0xffffffff;
00365 sprintf(buf, "%lX", hi);
00366 sprintf(buf + strlen(buf), "%lX", lo);
00367 }
00368 goto printint;
00369 printint:
00370 if (precision != 0 || width != 0) {
00371 length = strlen(buf);
00372 if (length < precision)
00373 zeropad = precision - length;
00374 else if (length < width && zero)
00375 zeropad = width - length;
00376 if (width != 0) {
00377 pad = width - length -
00378 zeropad - strlen(head);
00379 if (pad < 0)
00380 pad = 0;
00381 }
00382 }
00383 count += strlen(head) + strlen(buf) + pad +
00384 zeropad;
00385 if (!left) {
00386 while (pad > 0 && size > 1) {
00387 *str++ = ' ';
00388 size--;
00389 pad--;
00390 }
00391 }
00392 cp = head;
00393 while (*cp != '\0' && size > 1) {
00394 *str++ = *cp++;
00395 size--;
00396 }
00397 while (zeropad > 0 && size > 1) {
00398 *str++ = '0';
00399 size--;
00400 zeropad--;
00401 }
00402 cp = buf;
00403 while (*cp != '\0' && size > 1) {
00404 *str++ = *cp++;
00405 size--;
00406 }
00407 while (pad > 0 && size > 1) {
00408 *str++ = ' ';
00409 size--;
00410 pad--;
00411 }
00412 break;
00413 default:
00414 break;
00415 }
00416 break;
00417 case 's':
00418 cp = va_arg(ap, char *);
00419 REQUIRE(cp != NULL);
00420
00421 if (precision != 0) {
00422
00423
00424
00425 const char *tp;
00426 unsigned long n;
00427
00428 n = precision;
00429 tp = cp;
00430 while (n != 0 && *tp != '\0')
00431 n--, tp++;
00432 length = precision - n;
00433 } else {
00434 length = strlen(cp);
00435 }
00436 if (width != 0) {
00437 pad = width - length;
00438 if (pad < 0)
00439 pad = 0;
00440 }
00441 count += pad + length;
00442 if (!left)
00443 while (pad > 0 && size > 1) {
00444 *str++ = ' ';
00445 size--;
00446 pad--;
00447 }
00448 if (precision != 0)
00449 while (precision > 0 && *cp != '\0' &&
00450 size > 1) {
00451 *str++ = *cp++;
00452 size--;
00453 precision--;
00454 }
00455 else
00456 while (*cp != '\0' && size > 1) {
00457 *str++ = *cp++;
00458 size--;
00459 }
00460 while (pad > 0 && size > 1) {
00461 *str++ = ' ';
00462 size--;
00463 pad--;
00464 }
00465 break;
00466 case 'c':
00467 c = va_arg(ap, int);
00468 if (width > 0) {
00469 count += width;
00470 width--;
00471 if (left && size > 1) {
00472 *str++ = c;
00473 size--;
00474 }
00475 while (width-- > 0 && size > 1) {
00476 *str++ = ' ';
00477 size--;
00478 }
00479 if (!left && size > 1) {
00480 *str++ = c;
00481 size--;
00482 }
00483 } else {
00484 count++;
00485 if (size > 1) {
00486 *str++ = c;
00487 size--;
00488 }
00489 }
00490 break;
00491 case 'p':
00492 v = va_arg(ap, void *);
00493 sprintf(buf, "%p", v);
00494 length = strlen(buf);
00495 if (precision > length)
00496 zeropad = precision - length;
00497 if (width > 0) {
00498 pad = width - length - zeropad;
00499 if (pad < 0)
00500 pad = 0;
00501 }
00502 count += length + pad + zeropad;
00503 if (!left)
00504 while (pad > 0 && size > 1) {
00505 *str++ = ' ';
00506 size--;
00507 pad--;
00508 }
00509 cp = buf;
00510 if (zeropad > 0 && buf[0] == '0' &&
00511 (buf[1] == 'x' || buf[1] == 'X')) {
00512 if (size > 1) {
00513 *str++ = *cp++;
00514 size--;
00515 }
00516 if (size > 1) {
00517 *str++ = *cp++;
00518 size--;
00519 }
00520 while (zeropad > 0 && size > 1) {
00521 *str++ = '0';
00522 size--;
00523 zeropad--;
00524 }
00525 }
00526 while (*cp != '\0' && size > 1) {
00527 *str++ = *cp++;
00528 size--;
00529 }
00530 while (pad > 0 && size > 1) {
00531 *str++ = ' ';
00532 size--;
00533 pad--;
00534 }
00535 break;
00536 case 'D':
00537 INSIST("use %ld instead of %D" == NULL);
00538 case 'O':
00539 INSIST("use %lo instead of %O" == NULL);
00540 case 'U':
00541 INSIST("use %lu instead of %U" == NULL);
00542
00543 case 'L':
00544 #ifdef HAVE_LONG_DOUBLE
00545 l = 1;
00546 #else
00547 INSIST("long doubles are not supported" == NULL);
00548 #endif
00549
00550 case 'e':
00551 case 'E':
00552 case 'f':
00553 case 'g':
00554 case 'G':
00555 if (!dot)
00556 precision = 6;
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567 if (precision > 512)
00568 precision = 512;
00569 sprintf(fmt, "%%%s%s.%lu%s%c", alt ? "#" : "",
00570 plus ? "+" : space ? " " : "",
00571 precision, l ? "L" : "", *format);
00572 switch (*format) {
00573 case 'e':
00574 case 'E':
00575 case 'f':
00576 case 'g':
00577 case 'G':
00578 #ifdef HAVE_LONG_DOUBLE
00579 if (l) {
00580 ldbl = va_arg(ap, long double);
00581 sprintf(buf, fmt, ldbl);
00582 } else
00583 #endif
00584 {
00585 dbl = va_arg(ap, double);
00586 sprintf(buf, fmt, dbl);
00587 }
00588 length = strlen(buf);
00589 if (width > 0) {
00590 pad = width - length;
00591 if (pad < 0)
00592 pad = 0;
00593 }
00594 count += length + pad;
00595 if (!left)
00596 while (pad > 0 && size > 1) {
00597 *str++ = ' ';
00598 size--;
00599 pad--;
00600 }
00601 cp = buf;
00602 while (*cp != ' ' && size > 1) {
00603 *str++ = *cp++;
00604 size--;
00605 }
00606 while (pad > 0 && size > 1) {
00607 *str++ = ' ';
00608 size--;
00609 pad--;
00610 }
00611 break;
00612 default:
00613 continue;
00614 }
00615 break;
00616 default:
00617 continue;
00618 }
00619 format++;
00620 }
00621 if (size > 0)
00622 *str = '\0';
00623 return (count);
00624 }