NVBIO
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
vlen.c
Go to the documentation of this file.
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, 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