snprintf.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625
  1. /*
  2. * Copyright (c) 1995-1999 Kungliga Tekniska Högskolan
  3. * (Royal Institute of Technology, Stockholm, Sweden).
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. *
  10. * 1. Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. *
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in the
  15. * documentation and/or other materials provided with the distribution.
  16. *
  17. * 3. Neither the name of the Institute nor the names of its contributors
  18. * may be used to endorse or promote products derived from this software
  19. * without specific prior written permission.
  20. *
  21. * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
  22. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24. * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
  25. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31. * SUCH DAMAGE.
  32. */
  33. #ifdef HAVE_CONFIG_H
  34. #include <config.h>
  35. #endif
  36. #include <stdio.h>
  37. #include <stdarg.h>
  38. #include <stdlib.h>
  39. #include <string.h>
  40. #include <ctype.h>
  41. #include <sys/types.h>
  42. #include "netdissect.h"
  43. enum format_flags {
  44. minus_flag = 1,
  45. plus_flag = 2,
  46. space_flag = 4,
  47. alternate_flag = 8,
  48. zero_flag = 16
  49. };
  50. /*
  51. * Common state
  52. */
  53. struct state {
  54. unsigned char *str;
  55. unsigned char *s;
  56. unsigned char *theend;
  57. size_t sz;
  58. size_t max_sz;
  59. int (*append_char)(struct state *, unsigned char);
  60. int (*reserve)(struct state *, size_t);
  61. /* XXX - methods */
  62. };
  63. #ifndef HAVE_VSNPRINTF
  64. static int
  65. sn_reserve (struct state *state, size_t n)
  66. {
  67. return state->s + n > state->theend;
  68. }
  69. static int
  70. sn_append_char (struct state *state, unsigned char c)
  71. {
  72. if (sn_reserve (state, 1)) {
  73. return 1;
  74. } else {
  75. *state->s++ = c;
  76. return 0;
  77. }
  78. }
  79. #endif
  80. #if 0
  81. static int
  82. as_reserve (struct state *state, size_t n)
  83. {
  84. if (state->s + n > state->theend) {
  85. int off = state->s - state->str;
  86. unsigned char *tmp;
  87. if (state->max_sz && state->sz >= state->max_sz)
  88. return 1;
  89. state->sz = max(state->sz * 2, state->sz + n);
  90. if (state->max_sz)
  91. state->sz = min(state->sz, state->max_sz);
  92. tmp = realloc (state->str, state->sz);
  93. if (tmp == NULL)
  94. return 1;
  95. state->str = tmp;
  96. state->s = state->str + off;
  97. state->theend = state->str + state->sz - 1;
  98. }
  99. return 0;
  100. }
  101. static int
  102. as_append_char (struct state *state, unsigned char c)
  103. {
  104. if(as_reserve (state, 1))
  105. return 1;
  106. else {
  107. *state->s++ = c;
  108. return 0;
  109. }
  110. }
  111. #endif
  112. static int
  113. append_number(struct state *state,
  114. unsigned long num, unsigned base, char *rep,
  115. int width, int prec, int flags, int minusp)
  116. {
  117. int len = 0;
  118. int i;
  119. /* given precision, ignore zero flag */
  120. if(prec != -1)
  121. flags &= ~zero_flag;
  122. else
  123. prec = 1;
  124. /* zero value with zero precision -> "" */
  125. if(prec == 0 && num == 0)
  126. return 0;
  127. do{
  128. if((*state->append_char)(state, rep[num % base]))
  129. return 1;
  130. len++;
  131. num /= base;
  132. }while(num);
  133. prec -= len;
  134. /* pad with prec zeros */
  135. while(prec-- > 0){
  136. if((*state->append_char)(state, '0'))
  137. return 1;
  138. len++;
  139. }
  140. /* add length of alternate prefix (added later) to len */
  141. if(flags & alternate_flag && (base == 16 || base == 8))
  142. len += base / 8;
  143. /* pad with zeros */
  144. if(flags & zero_flag){
  145. width -= len;
  146. if(minusp || (flags & space_flag) || (flags & plus_flag))
  147. width--;
  148. while(width-- > 0){
  149. if((*state->append_char)(state, '0'))
  150. return 1;
  151. len++;
  152. }
  153. }
  154. /* add alternate prefix */
  155. if(flags & alternate_flag && (base == 16 || base == 8)){
  156. if(base == 16)
  157. if((*state->append_char)(state, rep[10] + 23)) /* XXX */
  158. return 1;
  159. if((*state->append_char)(state, '0'))
  160. return 1;
  161. }
  162. /* add sign */
  163. if(minusp){
  164. if((*state->append_char)(state, '-'))
  165. return 1;
  166. len++;
  167. } else if(flags & plus_flag) {
  168. if((*state->append_char)(state, '+'))
  169. return 1;
  170. len++;
  171. } else if(flags & space_flag) {
  172. if((*state->append_char)(state, ' '))
  173. return 1;
  174. len++;
  175. }
  176. if(flags & minus_flag)
  177. /* swap before padding with spaces */
  178. for(i = 0; i < len / 2; i++){
  179. char c = state->s[-i-1];
  180. state->s[-i-1] = state->s[-len+i];
  181. state->s[-len+i] = c;
  182. }
  183. width -= len;
  184. while(width-- > 0){
  185. if((*state->append_char)(state, ' '))
  186. return 1;
  187. len++;
  188. }
  189. if(!(flags & minus_flag))
  190. /* swap after padding with spaces */
  191. for(i = 0; i < len / 2; i++){
  192. char c = state->s[-i-1];
  193. state->s[-i-1] = state->s[-len+i];
  194. state->s[-len+i] = c;
  195. }
  196. return 0;
  197. }
  198. static int
  199. append_string (struct state *state,
  200. unsigned char *arg,
  201. int width,
  202. int prec,
  203. int flags)
  204. {
  205. if(prec != -1)
  206. width -= prec;
  207. else
  208. width -= strlen((char *)arg);
  209. if(!(flags & minus_flag))
  210. while(width-- > 0)
  211. if((*state->append_char) (state, ' '))
  212. return 1;
  213. if (prec != -1) {
  214. while (*arg && prec--)
  215. if ((*state->append_char) (state, *arg++))
  216. return 1;
  217. } else {
  218. while (*arg)
  219. if ((*state->append_char) (state, *arg++))
  220. return 1;
  221. }
  222. if(flags & minus_flag)
  223. while(width-- > 0)
  224. if((*state->append_char) (state, ' '))
  225. return 1;
  226. return 0;
  227. }
  228. static int
  229. append_char(struct state *state,
  230. unsigned char arg,
  231. int width,
  232. int flags)
  233. {
  234. while(!(flags & minus_flag) && --width > 0)
  235. if((*state->append_char) (state, ' '))
  236. return 1;
  237. if((*state->append_char) (state, arg))
  238. return 1;
  239. while((flags & minus_flag) && --width > 0)
  240. if((*state->append_char) (state, ' '))
  241. return 1;
  242. return 0;
  243. }
  244. /*
  245. * This can't be made into a function...
  246. */
  247. #define PARSE_INT_FORMAT(res, arg, unsig) \
  248. if (long_flag) \
  249. res = (unsig long)va_arg(arg, unsig long); \
  250. else if (short_flag) \
  251. res = (unsig short)va_arg(arg, unsig int); \
  252. else \
  253. res = (unsig int)va_arg(arg, unsig int)
  254. /*
  255. * zyxprintf - return 0 or -1
  256. */
  257. static int
  258. xyzprintf (struct state *state, const char *char_format, va_list ap)
  259. {
  260. const unsigned char *format = (const unsigned char *)char_format;
  261. unsigned char c;
  262. while((c = *format++)) {
  263. if (c == '%') {
  264. int flags = 0;
  265. int width = 0;
  266. int prec = -1;
  267. int long_flag = 0;
  268. int short_flag = 0;
  269. /* flags */
  270. while((c = *format++)){
  271. if(c == '-')
  272. flags |= minus_flag;
  273. else if(c == '+')
  274. flags |= plus_flag;
  275. else if(c == ' ')
  276. flags |= space_flag;
  277. else if(c == '#')
  278. flags |= alternate_flag;
  279. else if(c == '0')
  280. flags |= zero_flag;
  281. else
  282. break;
  283. }
  284. if((flags & space_flag) && (flags & plus_flag))
  285. flags ^= space_flag;
  286. if((flags & minus_flag) && (flags & zero_flag))
  287. flags ^= zero_flag;
  288. /* width */
  289. if (isdigit(c))
  290. do {
  291. width = width * 10 + c - '0';
  292. c = *format++;
  293. } while(isdigit(c));
  294. else if(c == '*') {
  295. width = va_arg(ap, int);
  296. c = *format++;
  297. }
  298. /* precision */
  299. if (c == '.') {
  300. prec = 0;
  301. c = *format++;
  302. if (isdigit(c))
  303. do {
  304. prec = prec * 10 + c - '0';
  305. c = *format++;
  306. } while(isdigit(c));
  307. else if (c == '*') {
  308. prec = va_arg(ap, int);
  309. c = *format++;
  310. }
  311. }
  312. /* size */
  313. if (c == 'h') {
  314. short_flag = 1;
  315. c = *format++;
  316. } else if (c == 'l') {
  317. long_flag = 1;
  318. c = *format++;
  319. }
  320. switch (c) {
  321. case 'c' :
  322. if(append_char(state, va_arg(ap, int), width, flags))
  323. return -1;
  324. break;
  325. case 's' :
  326. if (append_string(state,
  327. va_arg(ap, unsigned char*),
  328. width,
  329. prec,
  330. flags))
  331. return -1;
  332. break;
  333. case 'd' :
  334. case 'i' : {
  335. long arg;
  336. unsigned long num;
  337. int minusp = 0;
  338. PARSE_INT_FORMAT(arg, ap, signed);
  339. if (arg < 0) {
  340. minusp = 1;
  341. num = -arg;
  342. } else
  343. num = arg;
  344. if (append_number (state, num, 10, "0123456789",
  345. width, prec, flags, minusp))
  346. return -1;
  347. break;
  348. }
  349. case 'u' : {
  350. unsigned long arg;
  351. PARSE_INT_FORMAT(arg, ap, unsigned);
  352. if (append_number (state, arg, 10, "0123456789",
  353. width, prec, flags, 0))
  354. return -1;
  355. break;
  356. }
  357. case 'o' : {
  358. unsigned long arg;
  359. PARSE_INT_FORMAT(arg, ap, unsigned);
  360. if (append_number (state, arg, 010, "01234567",
  361. width, prec, flags, 0))
  362. return -1;
  363. break;
  364. }
  365. case 'x' : {
  366. unsigned long arg;
  367. PARSE_INT_FORMAT(arg, ap, unsigned);
  368. if (append_number (state, arg, 0x10, "0123456789abcdef",
  369. width, prec, flags, 0))
  370. return -1;
  371. break;
  372. }
  373. case 'X' :{
  374. unsigned long arg;
  375. PARSE_INT_FORMAT(arg, ap, unsigned);
  376. if (append_number (state, arg, 0x10, "0123456789ABCDEF",
  377. width, prec, flags, 0))
  378. return -1;
  379. break;
  380. }
  381. case 'p' : {
  382. unsigned long arg = (unsigned long)va_arg(ap, void*);
  383. if (append_number (state, arg, 0x10, "0123456789ABCDEF",
  384. width, prec, flags, 0))
  385. return -1;
  386. break;
  387. }
  388. case 'n' : {
  389. int *arg = va_arg(ap, int*);
  390. *arg = state->s - state->str;
  391. break;
  392. }
  393. case '\0' :
  394. --format;
  395. /* FALLTHROUGH */
  396. case '%' :
  397. if ((*state->append_char)(state, c))
  398. return -1;
  399. break;
  400. default :
  401. if ( (*state->append_char)(state, '%')
  402. || (*state->append_char)(state, c))
  403. return -1;
  404. break;
  405. }
  406. } else
  407. if ((*state->append_char) (state, c))
  408. return -1;
  409. }
  410. return 0;
  411. }
  412. #ifndef HAVE_SNPRINTF
  413. int
  414. snprintf (char *str, size_t sz, const char *format, ...)
  415. {
  416. va_list args;
  417. int ret;
  418. va_start(args, format);
  419. ret = vsnprintf (str, sz, format, args);
  420. #ifdef PARANOIA
  421. {
  422. int ret2;
  423. char *tmp;
  424. tmp = malloc (sz);
  425. if (tmp == NULL)
  426. abort ();
  427. ret2 = vsprintf (tmp, format, args);
  428. if (ret != ret2 || strcmp(str, tmp))
  429. abort ();
  430. free (tmp);
  431. }
  432. #endif
  433. va_end(args);
  434. return ret;
  435. }
  436. #endif
  437. #if 0
  438. #ifndef HAVE_ASPRINTF
  439. int
  440. asprintf (char **ret, const char *format, ...)
  441. {
  442. va_list args;
  443. int val;
  444. va_start(args, format);
  445. val = vasprintf (ret, format, args);
  446. #ifdef PARANOIA
  447. {
  448. int ret2;
  449. char *tmp;
  450. tmp = malloc (val + 1);
  451. if (tmp == NULL)
  452. abort ();
  453. ret2 = vsprintf (tmp, format, args);
  454. if (val != ret2 || strcmp(*ret, tmp))
  455. abort ();
  456. free (tmp);
  457. }
  458. #endif
  459. va_end(args);
  460. return val;
  461. }
  462. #endif
  463. #ifndef HAVE_ASNPRINTF
  464. int
  465. asnprintf (char **ret, size_t max_sz, const char *format, ...)
  466. {
  467. va_list args;
  468. int val;
  469. va_start(args, format);
  470. val = vasnprintf (ret, max_sz, format, args);
  471. #ifdef PARANOIA
  472. {
  473. int ret2;
  474. char *tmp;
  475. tmp = malloc (val + 1);
  476. if (tmp == NULL)
  477. abort ();
  478. ret2 = vsprintf (tmp, format, args);
  479. if (val != ret2 || strcmp(*ret, tmp))
  480. abort ();
  481. free (tmp);
  482. }
  483. #endif
  484. va_end(args);
  485. return val;
  486. }
  487. #endif
  488. #ifndef HAVE_VASPRINTF
  489. int
  490. vasprintf (char **ret, const char *format, va_list args)
  491. {
  492. return vasnprintf (ret, 0, format, args);
  493. }
  494. #endif
  495. #ifndef HAVE_VASNPRINTF
  496. int
  497. vasnprintf (char **ret, size_t max_sz, const char *format, va_list args)
  498. {
  499. int st;
  500. size_t len;
  501. struct state state;
  502. state.max_sz = max_sz;
  503. state.sz = 1;
  504. state.str = malloc(state.sz);
  505. if (state.str == NULL) {
  506. *ret = NULL;
  507. return -1;
  508. }
  509. state.s = state.str;
  510. state.theend = state.s + state.sz - 1;
  511. state.append_char = as_append_char;
  512. state.reserve = as_reserve;
  513. st = xyzprintf (&state, format, args);
  514. if (st) {
  515. free (state.str);
  516. *ret = NULL;
  517. return -1;
  518. } else {
  519. char *tmp;
  520. *state.s = '\0';
  521. len = state.s - state.str;
  522. tmp = realloc (state.str, len+1);
  523. if (tmp == NULL) {
  524. free (state.str);
  525. *ret = NULL;
  526. return -1;
  527. }
  528. *ret = tmp;
  529. return len;
  530. }
  531. }
  532. #endif
  533. #endif
  534. #ifndef HAVE_VSNPRINTF
  535. int
  536. vsnprintf (char *str, size_t sz, const char *format, va_list args)
  537. {
  538. struct state state;
  539. int ret;
  540. unsigned char *ustr = (unsigned char *)str;
  541. state.max_sz = 0;
  542. state.sz = sz;
  543. state.str = ustr;
  544. state.s = ustr;
  545. state.theend = ustr + sz - 1;
  546. state.append_char = sn_append_char;
  547. state.reserve = sn_reserve;
  548. ret = xyzprintf (&state, format, args);
  549. *state.s = '\0';
  550. if (ret)
  551. return sz;
  552. else
  553. return state.s - state.str;
  554. }
  555. #endif