/contrib/bind9/lib/lwres/print.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 561 lines · 490 code · 25 blank · 46 comment · 168 complexity · d864588f37ad28ba2f5d416d7f4b3755 MD5 · raw file

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