/contrib/bind9/lib/isc/print.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 624 lines · 553 code · 24 blank · 47 comment · 185 complexity · 71ab27a09e204509ad74ab4478623b99 MD5 · raw file

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