vlen.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  1. /*
  2. Author: James Bonfield (jkb@sanger.ac.uk)
  3. Copyright (c) 1995-1996 MEDICAL RESEARCH COUNCIL
  4. All rights reserved
  5. Redistribution and use in source and binary forms, with or without
  6. modification, are permitted provided that the following conditions are met:
  7. 1 Redistributions of source code must retain the above copyright notice,
  8. this list of conditions and the following disclaimer.
  9. 2 Redistributions in binary form must reproduce the above copyright notice,
  10. this list of conditions and the following disclaimer in the documentation
  11. and/or other materials provided with the distribution.
  12. 3 Neither the name of the MEDICAL RESEARCH COUNCIL, THE LABORATORY OF
  13. MOLECULAR BIOLOGY nor the names of its contributors may be used to endorse or
  14. promote products derived from this software without specific prior written
  15. permission.
  16. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  17. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18. WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19. DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
  20. ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21. (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  23. ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. /*
  28. Copyright (c) 2004, 2009, 2011-2012 Genome Research Ltd.
  29. Author: James Bonfield <jkb@sanger.ac.uk>
  30. Redistribution and use in source and binary forms, with or without
  31. modification, are permitted provided that the following conditions are met:
  32. 1. Redistributions of source code must retain the above copyright notice,
  33. this list of conditions and the following disclaimer.
  34. 2. Redistributions in binary form must reproduce the above copyright notice,
  35. this list of conditions and the following disclaimer in the documentation
  36. and/or other materials provided with the distribution.
  37. 3. Neither the names Genome Research Ltd and Wellcome Trust Sanger
  38. Institute nor the names of its contributors may be used to endorse or promote
  39. products derived from this software without specific prior written permission.
  40. THIS SOFTWARE IS PROVIDED BY GENOME RESEARCH LTD AND CONTRIBUTORS "AS IS" AND
  41. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  42. WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  43. DISCLAIMED. IN NO EVENT SHALL GENOME RESEARCH LTD OR CONTRIBUTORS BE LIABLE
  44. FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  45. DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  46. SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  47. CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  48. OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  49. OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  50. */
  51. #ifdef HAVE_CONFIG_H
  52. #include "io_lib_config.h"
  53. #endif
  54. #include <stdio.h>
  55. #include <stdlib.h>
  56. #include <stdarg.h>
  57. #include <sys/types.h>
  58. #include <string.h>
  59. #include "cram/vlen.h"
  60. #include "cram/os.h"
  61. #ifndef MAX
  62. #define MAX(a,b) ((a)>(b)?(a):(b))
  63. #endif
  64. #ifndef ABS
  65. #define ABS(a) ((a)>0?(a):-(a))
  66. #endif
  67. /* #define DEBUG_printf(a,n) printf(a,n) */
  68. #define DEBUG_printf(a,n)
  69. /*
  70. * vlen: 27/10/95 written by James Bonfield, jkb@mrc-lmb.cam.ac.uk
  71. *
  72. * Given sprintf style of arguments this routine returns the maximum
  73. * size of buffer needed to allocate to use with sprintf. It errs on
  74. * the side of caution by being simplistic in its approach: we assume
  75. * all numbers are of maximum length.
  76. *
  77. * Handles the usual type conversions (%[%diuaxXcfeEgGpns]), but not
  78. * the 'wide' character conversions (%C and %S).
  79. * Precision is handled in the correct formats, including %*.*
  80. * notations.
  81. * Additionally, some of the more dubious (but probably illegal) cases
  82. * are supported (eg "%10%" will expand to " %" on many
  83. * systems).
  84. *
  85. * We also assume that the largest integer and larger pointer are 64
  86. * bits, which at least covers the machines we'll need it for.
  87. */
  88. int flen(char *fmt, ...)
  89. {
  90. va_list args;
  91. va_start(args, fmt);
  92. return vflen(fmt, args);
  93. }
  94. int vflen(char *fmt, va_list ap)
  95. {
  96. int len = 0;
  97. char *cp, c;
  98. long long l;
  99. int i;
  100. double d;
  101. /*
  102. * This code modifies 'ap', but we do not know if va_list is a structure
  103. * or a pointer to an array so we do not know if it is a local variable
  104. * or not.
  105. * C99 gets around this by defining va_copy() to make copies of ap, but
  106. * this does not exist on all systems.
  107. * For now, I just assume that when va_list is a pointer the system also
  108. * provides a va_copy macro to work around this problem. The only system
  109. * I have seen needing this so far was Linux on AMD64.
  110. */
  111. #if defined(HAVE_VA_COPY)
  112. va_list ap_local;
  113. va_copy(ap_local, ap);
  114. # define ap ap_local
  115. #endif
  116. for(cp = fmt; *cp; cp++) {
  117. switch(*cp) {
  118. /* A format specifier */
  119. case '%': {
  120. char *endp;
  121. long conv_len1=0, conv_len2=0, conv_len=0;
  122. signed int arg_size;
  123. /* Firstly, strip the modifier flags (+-#0 and [space]) */
  124. for(; (c=*++cp);) {
  125. if ('#' == c)
  126. len+=2; /* Worst case of "0x" */
  127. else if ('-' == c || '+' == c || ' ' == c)
  128. len++;
  129. else
  130. break;
  131. }
  132. /* Width specifier */
  133. l = strtol(cp, &endp, 10);
  134. if (endp != cp) {
  135. cp = endp;
  136. conv_len = conv_len1 = l;
  137. } else if (*cp == '*') {
  138. conv_len = conv_len1 = (int)va_arg(ap, int);
  139. cp++;
  140. }
  141. /* Precision specifier */
  142. if ('.' == *cp) {
  143. cp++;
  144. conv_len2 = strtol(cp, &endp, 10);
  145. if (endp != cp) {
  146. cp = endp;
  147. } else if (*cp == '*') {
  148. conv_len2 = (int)va_arg(ap, int);
  149. cp++;
  150. }
  151. conv_len = MAX(conv_len1, conv_len2);
  152. }
  153. /* Short/long identifier */
  154. if ('h' == *cp) {
  155. arg_size = -1; /* short */
  156. cp++;
  157. } else if ('l' == *cp) {
  158. arg_size = 1; /* long */
  159. cp++;
  160. if ('l' == *cp) {
  161. arg_size = 2; /* long long */
  162. cp++;
  163. }
  164. } else {
  165. arg_size = 0; /* int */
  166. }
  167. /* The actual type */
  168. switch (*cp) {
  169. case '%':
  170. /*
  171. * Not real ANSI I suspect, but we'll allow for the
  172. * completely daft "%10%" example.
  173. */
  174. len += MAX(conv_len1, 1);
  175. break;
  176. case 'd':
  177. case 'i':
  178. case 'u':
  179. case 'a':
  180. case 'x':
  181. case 'X':
  182. /* Remember: char and short are sent as int on the stack */
  183. if (arg_size == -1)
  184. l = (long)va_arg(ap, int);
  185. else if (arg_size == 1)
  186. l = va_arg(ap, long);
  187. else if (arg_size == 2)
  188. l = va_arg(ap, long long);
  189. else
  190. l = (long)va_arg(ap, int);
  191. DEBUG_printf("%d", l);
  192. /*
  193. * No number can be more than 24 characters so we'll take
  194. * the max of conv_len and 24 (23 is len(2^64) in octal).
  195. * All that work above and we then go and estimate ;-),
  196. * but it's needed incase someone does %500d.
  197. */
  198. len += MAX(conv_len, 23);
  199. break;
  200. case 'c':
  201. i = va_arg(ap, int);
  202. DEBUG_printf("%c", i);
  203. /*
  204. * Note that %10c and %.10c act differently.
  205. * Besides, I think precision is not really allowed for %c.
  206. */
  207. len += MAX(conv_len1, 1);
  208. break;
  209. case 'f':
  210. d = va_arg(ap, double);
  211. DEBUG_printf("%f", d);
  212. /*
  213. * Maybe "Inf" or "NaN", but we'll not worry about that.
  214. * Again, err on side of caution and take max of conv_len
  215. * and max length of a double. The worst case I can
  216. * think of is 317 characters (-1[308 zeros].000000)
  217. * without using precision codes. That's horrid. I
  218. * cheat and either use 317 or 15 depending on how
  219. * large the number is as I reckon 99% of floats
  220. * aren't that long.
  221. */
  222. l = (ABS(d) > 1000000) ? 317 : 15;
  223. l = MAX(l, conv_len1 + 2);
  224. if (conv_len2) l += conv_len2 - 6;
  225. len += l;
  226. break;
  227. case 'e':
  228. case 'E':
  229. case 'g':
  230. case 'G':
  231. d = va_arg(ap, double);
  232. DEBUG_printf("%g", d);
  233. /*
  234. * Maybe "Inf" or "NaN", but we'll not worry about that
  235. * Again, err on side of caution and take max of conv_len
  236. * and max length of a double (which defaults to only
  237. * '-' + 6 + '.' + 'E[+-]xxx' == 13.
  238. */
  239. len += MAX(conv_len, 13);
  240. break;
  241. case 'p':
  242. l = (long)va_arg(ap, void *);
  243. /*
  244. * Max pointer is 64bits == 16 chars (on alpha),
  245. * == 20 with + "0x".
  246. */
  247. DEBUG_printf("%p", (void *)l);
  248. len += MAX(conv_len, 20);
  249. break;
  250. case 'n':
  251. /* produces no output */
  252. break;
  253. case 's': {
  254. char *s = (char *)va_arg(ap, char *);
  255. DEBUG_printf("%s", s);
  256. if (!conv_len2) {
  257. len += MAX(conv_len, (int)strlen(s));
  258. } else {
  259. len += conv_len;
  260. }
  261. break;
  262. }
  263. default:
  264. /* wchar_t types of 'C' and 'S' aren't supported */
  265. DEBUG_printf("Arg is %c\n", *cp);
  266. }
  267. }
  268. case '\0':
  269. break;
  270. default:
  271. DEBUG_printf("%c", *cp);
  272. len++;
  273. }
  274. }
  275. va_end(ap);
  276. return len+1; /* one for the null character */
  277. }
  278. #if 0
  279. int main() {
  280. int l;
  281. char buf[10000];
  282. sprintf(buf, "d: %d\n", 500);
  283. l = flen("d: %d\n", 500);
  284. printf("%d %d\n\n", strlen(buf), l);
  285. sprintf(buf, "");
  286. l = flen("");
  287. printf("%d %d\n\n", strlen(buf), l);
  288. sprintf(buf, "%s\n","test");
  289. l = flen("%s\n", "test");
  290. printf("%d %d\n\n", strlen(buf), l);
  291. sprintf(buf, "%c\n", 'a');
  292. l = flen("%c\n", 'a');
  293. printf("%d %d\n\n", strlen(buf), l);
  294. sprintf(buf, "%31.30f\n", -9999.99);
  295. l = flen("%31.30f\n", -9999.99);
  296. printf("%d %d\n\n", strlen(buf), l);
  297. sprintf(buf, "%f\n", -1e308);
  298. l = flen("%f\n", -1e308);
  299. printf("%d %d\n\n", strlen(buf), l);
  300. sprintf(buf, "%.9f\n", -1e308);
  301. l = flen("%.9f\n", -1e308);
  302. printf("%d %d\n\n", strlen(buf), l);
  303. sprintf(buf, "%10.20f\n", -1.999222333);
  304. l = flen("%10.20f\n", -1.999222333);
  305. printf("%d %d\n\n", strlen(buf), l);
  306. sprintf(buf, "%#g\n", -3.14159265358e-222);
  307. l = flen("%#g\n", -3.1415927e-222);
  308. printf("%d %d\n\n", strlen(buf), l);
  309. sprintf(buf, "%e\n", -123456789123456789.1);
  310. l = flen("%e\n", -123456789123456789.1);
  311. printf("%d %d\n\n", strlen(buf), l);
  312. sprintf(buf, "%c %f %d %s %c %g %ld %s\n", 'a', 3.1, 9, "one", 'b', 4.2, 9, "two");
  313. l = flen("%c %f %d %s %c %g %ld %s\n", 'a', 3.1, 9, "one", 'b', 4.2, 9, "two");
  314. printf("%d %d\n\n", strlen(buf), l);
  315. sprintf(buf, "%*.*e %*c\n", 10, 5, 9.0, 20, 'x');
  316. l = flen("%*.*e %*c\n", 10, 5, 9.0, 20, 'x');
  317. printf("%d %d\n\n", strlen(buf), l);
  318. sprintf(buf, "%10c\n", 'z');
  319. l = flen("%10c\n", 'z');
  320. printf("%d %d\n\n", strlen(buf), l);
  321. sprintf(buf, "%.10c\n", 'z');
  322. l = flen("%.10c\n", 'z');
  323. printf("%d %d\n\n", strlen(buf), l);
  324. sprintf(buf, "%10d\n", 'z');
  325. l = flen("%10d\n", 'z');
  326. printf("%d %d\n\n", strlen(buf), l);
  327. sprintf(buf, "%.10d\n", 'z');
  328. l = flen("%.10d\n", 'z');
  329. printf("%d %d\n\n", strlen(buf), l);
  330. sprintf(buf, "%10%\n");
  331. l = flen("%10%\n");
  332. printf("%d %d\n\n", strlen(buf), l);
  333. sprintf(buf, "%.10%\n");
  334. l = flen("%.10%\n");
  335. printf("%d %d\n\n", strlen(buf), l);
  336. sprintf(buf, "%s\n", "0123456789");
  337. l = flen("%s\n", "0123456789");
  338. printf("%d %d\n\n", strlen(buf), l);
  339. sprintf(buf, "%5s\n", "0123456789");
  340. l = flen("%5s\n", "0123456789");
  341. printf("%d %d\n\n", strlen(buf), l);
  342. sprintf(buf, "%50s\n", "0123456789");
  343. l = flen("%50s\n", "0123456789");
  344. printf("%d %d\n\n", strlen(buf), l);
  345. sprintf(buf, "%.5s\n", "0123456789");
  346. l = flen("%.5s\n", "0123456789");
  347. printf("%d %d\n\n", strlen(buf), l);
  348. sprintf(buf, "%.50s\n", "0123456789");
  349. l = flen("%.50s\n", "0123456789");
  350. printf("%d %d\n\n", strlen(buf), l);
  351. sprintf(buf, "%5.50s\n", "0123456789");
  352. l = flen("%5.50s\n", "0123456789");
  353. printf("%d %d\n\n", strlen(buf), l);
  354. sprintf(buf, "%50.5s\n", "0123456789");
  355. l = flen("%50.5s\n", "0123456789");
  356. printf("%d %d\n\n", strlen(buf), l);
  357. return 0;
  358. }
  359. #endif