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