comparison srf2fastq/io_lib-1.12.2/io_lib/vlen.c @ 0:d901c9f41a6a default tip

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