NEURON
nrn_vsscanf.cpp
Go to the documentation of this file.
1 /* modified for use for NrnFILEWrap */
2 /* now included by nrnfilewrap.cpp */
3 /*
4 * libslack - http://libslack.org/
5 *
6 * Copyright (C) 1999-2010 raf <raf@raf.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 * or visit http://www.gnu.org/copyleft/gpl.html
22 *
23 * 20100612 raf <raf@raf.org>
24 */
25 
26 /*
27 
28 =head1 NAME
29 
30 I<vsscanf(3)> - I<sscanf(3)> with a I<va_list> parameter
31 
32 =head1 SYNOPSIS
33 
34  #include <slack/std.h>
35  #ifndef HAVE_VSSCANF
36  #include <slack/vsscanf.h>
37  #endif
38 
39  int vsscanf(const char *str, const char *format, va_list args);
40 
41 =head1 DESCRIPTION
42 
43 Similar to I<sscanf(3)> with the variable argument list specified directly
44 as for I<vprintf(3)>.
45 
46 Note that this may not be identical in behaviour to the I<sscanf(3)> on your
47 system because this was implemented from scratch for systems that lack
48 I<vsscanf(3)>. So your I<sscanf(3)> and this I<vsscanf(3)> share no common
49 code. Your I<sscanf(3)> may support extensions that I<vsscanf(3)> does not
50 support. I<vsscanf(3)> complies with all of the relevant ISO C requirements
51 for I<sscanf(3)> except:
52 
53 =over 4
54 
55 =item *
56 
57 C<format> may not be a multibyte character string; and
58 
59 =item *
60 
61 Scanning a pointer (C<"%p">) may not exactly match the format that your
62 I<printf(3)> uses to print pointers on your system. This version accepts
63 pointers as a hexadecimal number with or without a preceding C<0x>.
64 
65 =back
66 
67 =head1 MT-Level
68 
69 MT-Safe if and only if no thread calls I<setlocale(3)>. Since locales are
70 inherently non-threadsafe as they are currently defined, this shouldn't be a
71 problem. Just call C<setlocale(LC_ALL, "")> once after program
72 initialisation and never again (at least not after creating any threads). If
73 it is a problem, just change C<localeconv()-E<gt>decimal_point[0]> in the source
74 to C<'.'> and it will be MT-Safe at the expense of losing locale support.
75 
76 =head1 EXAMPLE
77 
78  #include <slack/std.h>
79  #ifndef HAVE_VSSCANF
80  #include <slack/vsscanf.h>
81  #endif
82 
83  int fdscanf(int fd, const char *format, ...)
84  {
85  va_list args;
86  char buf[BUFSIZ];
87  ssize_t bytes;
88  int rc;
89 
90  if ((bytes = read(fd, buf, BUFSIZ)) <= 0)
91  return bytes;
92 
93  buf[bytes] = '\0';
94 
95  va_start(args, format);
96  rc = vsscanf(buf, format, args);
97  va_end(args);
98 
99  return rc;
100  }
101 
102  int main()
103  {
104  int rc, a = 0, b = 0;
105 
106  rc = fdscanf(STDIN_FILENO, "%d %d", &a, &b);
107  printf("rc = %d a = %d b = %d\n", rc, a, b);
108 
109  return (rc == 2) ? EXIT_SUCCESS : EXIT_FAILURE;
110  }
111 
112 =head1 NOTE
113 
114 I<gcc(1)> warns that:
115 
116  warning: ANSI C does not support the `L' length modifier
117  warning: use of `l' length character with `e' type character
118 
119 However, the ANSI C standard (Section 7.9.6.2) states that:
120 
121 "Finally, the conversion specifiers C<e>, C<f>, and C<g> shall be preceded
122 by C<l> if the corresponding argument is a pointer to I<double> rather than
123 a pointer to C<float>, or by C<L> if it is a pointer to I<long double>."
124 
125 I have chosen to disregard the I<gcc(1)> warnings in favour of the standard.
126 If you see the above warnings when compiling the unit tests for
127 I<vsscanf(3)>, just ignore them.
128 
129 =head1 SEE ALSO
130 
131 I<libslack(3)>,
132 I<sscanf(3)>
133 
134 =head1 AUTHOR
135 
136 20100612 raf <raf@raf.org>
137 
138 =cut
139 
140 */
141 
142 #if USE_NRNFILEWRAP
143 #else
144 #include "config.h"
145 #include "std.h"
146 
147 #include <locale.h>
148 #endif
149 
150 #if USE_NRNFILEWRAP
151 int nrn_vsscanf(const char *str, const char** rs, const char *format, va_list args)
152 #else
153 int vsscanf(const char *str, const char *format, va_list args)
154 #endif
155 {
156  const char *f, *s;
157 #if USE_NRNFILEWRAP
158  const char point = '.';
159 #else
160  const char point = localeconv()->decimal_point[0];
161 #endif
162  int cnv = 0;
163 
164  for (s = str, f = format; *f; ++f)
165  {
166  if (*f == '%')
167  {
168  int size = 0;
169  int width = 0;
170  int do_cnv = 1;
171 
172  if (*++f == '*')
173  ++f, do_cnv = 0;
174 
175  for (; isdigit((int)(unsigned int)*f); ++f)
176  width *= 10, width += *f - '0';
177 
178  if (*f == 'h' || *f == 'l' || *f == 'L')
179  size = *f++;
180 
181  if (*f != '[' && *f != 'c' && *f != 'n')
182  while (isspace((int)(unsigned int)*s))
183  ++s;
184 
185 #define COPY *b++ = *s++, --width
186 #define MATCH(cond) if (width && (cond)) COPY;
187 #define MATCH_ACTION(cond, action) if (width && (cond)) { COPY; action; }
188 #define MATCHES_ACTION(cond, action) while (width && (cond)) { COPY; action; }
189 #define FAIL (cnv) ? cnv : EOF
190  switch (*f)
191  {
192  case 'd': case 'i': case 'o': case 'u': case 'x': case 'X':
193  case 'p':
194  {
195  static const char types[] = "diouxXp";
196  static const int bases[] = { 10, 0, 8, 10, 16, 16, 16 };
197  static const char digitset[] = "0123456789abcdefABCDEF";
198  static const int setsizes[] = { 10, 0, 0, 0, 0, 0, 0, 0, 8, 0, 10, 0, 0, 0, 0, 0, 22 };
199  int base = bases[strchr(types, *f) - types];
200  int setsize;
201  char buf[513];
202  char *b = buf;
203  int digit = 0;
204  if (width <= 0 || width > 512) width = 512;
205  MATCH(*s == '+' || *s == '-')
206  MATCH_ACTION(*s == '0',
207  digit = 1;
208  MATCH_ACTION((*s == 'x' || *s == 'X') && (base == 0 || base == 16), base = 16) else base = 8;
209  )
210  setsize = setsizes[base];
211  MATCHES_ACTION(memchr(digitset, *s, setsize), digit = 1)
212  if (!digit) { *rs = s; return FAIL; }
213  *b = '\0';
214  if (do_cnv)
215  {
216  if (*f == 'd' || *f == 'i')
217  {
218  long data = strtol(buf, NULL, base);
219  if (size == 'h')
220  *va_arg(args, short *) = (short)data;
221  else if (size == 'l')
222  *va_arg(args, long *) = data;
223  else
224  *va_arg(args, int *) = (int)data;
225  }
226  else
227  {
228  unsigned long data = strtoul(buf, NULL, base);
229  if (size == 'p')
230  *va_arg(args, void **) = (void *)data;
231  else if (size == 'h')
232  *va_arg(args, unsigned short *) = (unsigned short)data;
233  else if (size == 'l')
234  *va_arg(args, unsigned long *) = data;
235  else
236  *va_arg(args, unsigned int *) = (unsigned int)data;
237  }
238  ++cnv;
239  }
240  break;
241  }
242 
243  case 'e': case 'E': case 'f': case 'g': case 'G':
244  {
245  char buf[513];
246  char *b = buf;
247  int digit = 0;
248  if (width <= 0 || width > 512) width = 512;
249  MATCH(*s == '+' || *s == '-')
250  MATCHES_ACTION(isdigit((int)(unsigned int)*s), digit = 1)
251  MATCH(*s == point)
252  MATCHES_ACTION(isdigit((int)(unsigned int)*s), digit = 1)
253  MATCHES_ACTION(digit && (*s == 'e' || *s == 'E'),
254  MATCH(*s == '+' || *s == '-')
255  digit = 0;
256  MATCHES_ACTION(isdigit((int)(unsigned int)*s), digit = 1)
257  )
258  if (!digit) { *rs = s; return FAIL; }
259  *b = '\0';
260  if (do_cnv)
261  {
262  double data = strtod(buf, NULL);
263  if (size == 'l')
264  *va_arg(args, double *) = data;
265  else if (size == 'L')
266  *va_arg(args, long double *) = (long double)data;
267  else
268  *va_arg(args, float *) = (float)data;
269  ++cnv;
270  }
271  break;
272  }
273 
274  case 's':
275  {
276  char *arg = va_arg(args, char *);
277  if (width <= 0) width = INT_MAX;
278  while (width-- && *s && !isspace((int)(unsigned int)*s))
279  if (do_cnv) *arg++ = *s++;
280  if (do_cnv) *arg = '\0', ++cnv;
281  break;
282  }
283 
284  case '[':
285  {
286  char *arg = va_arg(args, char *);
287  int setcomp = 0;
288  size_t setsize;
289  const char *end;
290  if (width <= 0) width = INT_MAX;
291  if (*++f == '^') setcomp = 1, ++f;
292  end = strchr((*f == ']') ? f + 1 : f, ']');
293  if (!end) { *rs = s; return FAIL; } /* Could be cnv to match glibc-2.2 */
294  setsize = end - f; /* But FAIL matches the C standard */
295  while (width-- && *s)
296  {
297  if (!setcomp && !memchr(f, *s, setsize)) break;
298  if (setcomp && memchr(f, *s, setsize)) break;
299  if (do_cnv) *arg++ = *s++;
300  }
301  if (do_cnv) *arg = '\0', ++cnv;
302  f = end;
303  break;
304  }
305 
306  case 'c':
307  {
308  char *arg = va_arg(args, char *);
309  if (width <= 0) width = 1;
310  while (width--)
311  {
312  if (!*s) { *rs = s; return FAIL; }
313  if (do_cnv) *arg++ = *s++;
314  }
315  if (do_cnv) ++cnv;
316  break;
317  }
318 
319  case 'n':
320  {
321  if (size == 'h')
322  *va_arg(args, short *) = (short)(s - str);
323  else if (size == 'l')
324  *va_arg(args, long *) = (long)(s - str);
325  else
326  *va_arg(args, int *) = (int)(s - str);
327  break;
328  }
329 
330  case '%':
331  {
332  if (*s++ != '%') { *rs = s; return cnv; }
333  break;
334  }
335 
336  default:
337  *rs = s; return FAIL;
338  }
339  }
340  else if (isspace((int)(unsigned int)*f))
341  {
342  while (isspace((int)(unsigned int)f[1]))
343  ++f;
344  while (isspace((int)(unsigned int)*s))
345  ++s;
346  }
347  else
348  {
349  if (*s++ != *f) {
350  *rs = s; return cnv;
351  }
352  }
353  }
354 
355  *rs = s; return cnv;
356 }
357 
358 #if 0
359 #ifdef TEST
360 
361 #undef _ISOC9X_SOURCE
362 #undef __USE_ISOC9X
363 #include <math.h>
364 #include <float.h>
365 
366 int test_sscanf(const char *str, const char *format, ...)
367 {
368  int rc;
369  va_list args;
370  va_start(args, format);
371  rc = vsscanf(str, format, args);
372  va_end(args);
373  return rc;
374 }
375 
376 int main(int ac, char **av)
377 {
378  int errors = 0;
379  short si1, si2;
380  int i1, i2;
381  long li1, li2;
382  float f1, f2;
383  double d1, d2;
384  long double ld1, ld2;
385  void *p1, *p2;
386  char b1[128], b2[128];
387  char c1[128], c2[128];
388  char s1[128], s2[128];
389  short sn1, sn2;
390  int in1, in2;
391  long ln1, ln2;
392  unsigned short su1, su2;
393  unsigned int u1, u2;
394  unsigned long lu1, lu2;
395  char str[512];
396  int rc1, rc2;
397 
398  if (ac == 2 && !strcmp(av[1], "help"))
399  {
400  printf("usage: %s [show]\n", *av);
401  return EXIT_SUCCESS;
402  }
403 
404  printf("Testing: %s\n", "vsscanf");
405 
406  /* Test one of everything */
407 
408  sprintf(str, " abc -12 37 101 3.4e-1 12.34 102.23 xyz %p def ghi jkl %% ",
409  p1 = (void *)0xdeadbeef
410  );
411 
412  if (ac >= 2 && !strcmp(av[1], "show"))
413  printf("%s\n", str);
414 
415  rc1 = sscanf(str,
416  " abc %hd %d %ld %e %le %Le xyz %p %[^abc ] %3c %s%hn %n%% %ln",
417  &si1, &i1, &li1, &f1, &d1, &ld1, &p1, b1, c1, s1, &sn1, &in1, &ln1
418  );
419 
420  rc2 = test_sscanf(str,
421  " abc %hd %d %ld %e %le %Le xyz %p %[^abc ] %3c %s%hn %n%% %ln",
422  &si2, &i2, &li2, &f2, &d2, &ld2, &p2, b2, c2, s2, &sn2, &in2, &ln2
423  );
424 
425  if (rc1 != rc2)
426  ++errors, printf("Test1: failed (returned %d, not %d)\n", rc2, rc1);
427  if (si1 != si2)
428  ++errors, printf("Test2: failed (%%hd scanned %hd, not %hd)\n", si2, si1);
429  if (i1 != i2)
430  ++errors, printf("Test3: failed (%%d scanned %d, not %d)\n", i2, i1);
431  if (li1 != li2)
432  ++errors, printf("Test4: failed (%%ld scanned %ld, not %ld)\n", li2, li1);
433  if (fabs(f2 - 3.4e-1) / 3.4e-1 >= 4 * FLT_EPSILON)
434  ++errors, printf("Test5: failed (%%e scanned %e, not %e)\n", f2, f1);
435  if (fabs(d2 - 12.34) / 12.34 >= 4 * DBL_EPSILON)
436  ++errors, printf("Test6: failed (%%le scanned %le, not %le)\n", d2, d1);
437  if (fabs(ld2 - 102.23) / 102.23 >= 4 * LDBL_EPSILON)
438  ++errors, printf("Test7: failed (%%Le scanned %Le, not %Le)\n", ld2, ld1);
439  if (p1 != p2)
440  ++errors, printf("Test8: failed (%%p scanned %p, not %p)\n", p2, p1);
441  if (strcmp(b1, b2))
442  ++errors, printf("Test9: failed (%%[^abc ] scanned \"%s\", not \"%s\")\n", b2, b1);
443  if (memcmp(c1, c2, 3))
444  ++errors, printf("Test10: failed (%%3c scanned \"%3.3s\", not \"%3.3s\")\n", c2, c1);
445  if (strcmp(s1, s2))
446  ++errors, printf("Test11: failed (%%s scanned \"%s\", not \"%s\")\n", s2, s1);
447  if (sn1 != sn2)
448  ++errors, printf("Test12: failed (%%hn scanned %hd, not %hd)\n", sn2, sn1);
449  if (in1 != in2)
450  ++errors, printf("Test13: failed (%%n scanned %d, not %d)\n", in2, in1);
451  if (ln1 != ln2)
452  ++errors, printf("Test14: failed (%%ln scanned %ld, not %ld)\n", ln2, ln1);
453 
454  /* Test different numeric bases */
455 
456 #define TEST_NUM(i, var, tst, str, format) \
457  rc1 = sscanf(str, format, &s##var##1, &var##1, &l##var##1); \
458  rc2 = test_sscanf(str, format, &s##var##2, &var##2, &l##var##2); \
459  if (rc1 != rc2) \
460  ++errors, printf("Test%d: failed (returned %d, not %d)\n", (i), rc2, rc1); \
461  if (s##var##1 != s##var##2) \
462  ++errors, printf("Test%d: failed (%%h%c scanned %hd, not %hd)\n", (i), tst, s##var##2, s##var##1); \
463  if (var##1 != var##2) \
464  ++errors, printf("Test%d: failed (%%%c scanned %d, not %d)\n", (i), tst, var##2, var##1); \
465  if (l##var##1 != l##var##2) \
466  ++errors, printf("Test%d: failed (%%l%c scanned %ld, not %ld)\n", (i), tst, l##var##2, l##var##1)
467 
468 #define TEST_STR(i, len, str, format) \
469  rc1 = sscanf(str, format, b1, c1, s1); \
470  rc2 = test_sscanf(str, format, b2, c2, s2); \
471  if (rc1 != rc2) \
472  ++errors, printf("Test%d: failed (returned %d, not %d)\n", (i), rc2, rc1); \
473  if (strcmp(b1, b2)) \
474  ++errors, printf("Test%d: failed (%%%d[ scanned \"%s\", not \"%s\")\n", (i), (len), b2, b1); \
475  if (memcmp(c1, c2, len)) \
476  ++errors, printf("Test%d: failed (%%%dc scanned \"%*.*s\", not \"%*.*s\")\n", (i), (len), (len), (len), c2, (len), (len), c1); \
477  if (strcmp(s1, s2)) \
478  ++errors, printf("Test%d: failed (%%%ds scanned \"%s\", not \"%s\")\n", (i), (len), s2, s1)
479 
480  TEST_NUM(15, i, 'i', "37 21 53", "%hi %i %li");
481  TEST_NUM(16, i, 'i', "037 021 053", "%hi %i %li");
482  TEST_NUM(17, i, 'i', "0x37 0x21 0x53", "%hi %i %li");
483  TEST_NUM(18, u, 'o', "037 021 053", "%ho %o %lo");
484  TEST_NUM(19, u, 'u', "37 21 53", "%hu %u %lu");
485  TEST_NUM(20, u, 'x', "0x37 0x21 0x53", "%hx %x %lx");
486  TEST_NUM(21, u, 'X', "0x37 0x21 0x53", "%hx %x %lx");
487 
488  /* Test field width handling */
489 
490  TEST_NUM(22, i, 'd', "123456789", "%3hd %2d %4ld");
491  TEST_NUM(23, i, 'i', "123456789", "%3hi %2i %4li");
492  TEST_NUM(24, i, 'i', "012340789", "%3hi %2i %4li");
493  TEST_NUM(25, i, 'x', "123456789", "%3hi %2i %4li");
494  TEST_NUM(26, u, 'o', "012340789", "%3ho %2o %4lo");
495  TEST_NUM(27, u, 'u', "123456789", "%3hu %2u %4lu");
496  TEST_NUM(28, u, 'x', "123456789", "%3hx %2x %4lx");
497  TEST_NUM(29, u, 'X', "123456789", "%3hx %2X %4lX");
498  TEST_STR(30, 1, "abcd", "%1[a]%c%1s");
499 
500  TEST_STR(31, 5, "abc\001d e f g h i", "%5[][abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789`~!@#$%^&*()_=+\\|{};':\",./<>? -]%5c%5s");
501  TEST_STR(32, 3, "abc\001d e f g h i", "%3[][abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789`~!@#$%^&*()_=+\\|{};':\",./<>? -]%3c%3s");
502  TEST_STR(33, 7, "abc\001d e f g h i", "%7[][abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789`~!@#$%^&*()_=+\\|{};':\",./<>? -]%7c%7s");
503  TEST_STR(34, 2, "abc\001d e f g h i", "%2[][abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789`~!@#$%^&*()_=+\\|{};':\",./<>? -]%2c%2s");
504 
505  /* Test error reporting */
506 
507 #define TEST_ERR(i, str, format) \
508  rc1 = sscanf(str, format); \
509  rc2 = test_sscanf(str, format); \
510  if (rc1 != rc2) \
511  ++errors, printf("Test%d: failed (returned %d, not %d)\n", (i), rc2, rc1)
512 
513 #define TEST_ERR_ARG(i, str, format, var) \
514  rc1 = sscanf(str, format, &var##1); \
515  rc2 = test_sscanf(str, format, &var##1); \
516  if (rc1 != rc2) \
517  ++errors, printf("Test%d: failed (returned %d, not %d)\n", (i), rc2, rc1)
518 
519  TEST_ERR_ARG(35, "", "%d", i);
520  TEST_ERR_ARG(36, "", "%i", i);
521  TEST_ERR_ARG(37, "", "%o", u);
522  TEST_ERR_ARG(38, "", "%u", u);
523  TEST_ERR_ARG(39, "", "%x", u);
524  TEST_ERR_ARG(40, "", "%X", u);
525  TEST_ERR_ARG(41, "", "%p", p);
526  TEST_ERR_ARG(42, "", "%e", f);
527  TEST_ERR_ARG(43, "", "%E", f);
528  TEST_ERR_ARG(44, "", "%f", f);
529  TEST_ERR_ARG(45, "", "%g", f);
530  TEST_ERR_ARG(46, "", "%G", f);
531  TEST_ERR_ARG(47, "", "%[^]", *b);
532  TEST_ERR_ARG(48, "", "%c", *c);
533  TEST_ERR(49, "a", "%%");
534  TEST_ERR(50, "a", "b");
535 
536  if (errors)
537  printf("%d/50 tests failed (This system's sscanf(3) is probably wrong)\n", errors);
538  else
539  printf("All tests passed\n");
540 
541  return (errors == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
542 }
543 
544 #endif
545 #endif
546 
547 /* vi:set ts=4 sw=4: */
#define data
Definition: rbtqueue.cpp:49
size_t p
sprintf(buf," if (secondorder) {\ " int _i;\" " for(_i=0;_i< %d;++_i) {\" " _p[_slist%d[_i]]+=dt *_p[_dlist%d[_i]];\" " }}\", numeqn, listnum, listnum)
#define e
Definition: passive0.cpp:24
#define FAIL
long
Definition: netcvode.cpp:4792
#define MATCHES_ACTION(cond, action)
_CONST char * s
Definition: system.cpp:74
int main()
Definition: macmain.cpp:5
#define printf
Definition: mwprefix.h:26
int
Definition: nrnmusic.cpp:71
inode< _nt-> end
Definition: multicore.cpp:985
static char * format
Definition: matrixio.c:386
#define i
Definition: md1redef.h:12
#define c
#define arg
Definition: redef.h:28
char buf[512]
Definition: init.cpp:13
fabs
Definition: extdef.h:3
#define INT_MAX
Definition: limits.h:21
#define MATCH_ACTION(cond, action)
int vsscanf(const char *str, const char *format, va_list args)
return NULL
Definition: cabcode.cpp:461
#define MATCH(cond)
double point