GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/air/parseAir.c Lines: 62 126 49.2 %
Date: 2017-05-26 Branches: 54 132 40.9 %

Line Branch Exec Source
1
/*
2
  Teem: Tools to process and visualize scientific data and images             .
3
  Copyright (C) 2013, 2012, 2011, 2010, 2009  University of Chicago
4
  Copyright (C) 2008, 2007, 2006, 2005  Gordon Kindlmann
5
  Copyright (C) 2004, 2003, 2002, 2001, 2000, 1999, 1998  University of Utah
6
7
  This library is free software; you can redistribute it and/or
8
  modify it under the terms of the GNU Lesser General Public License
9
  (LGPL) as published by the Free Software Foundation; either
10
  version 2.1 of the License, or (at your option) any later version.
11
  The terms of redistributing and/or modifying this software also
12
  include exceptions to the LGPL that facilitate static linking.
13
14
  This library is distributed in the hope that it will be useful,
15
  but WITHOUT ANY WARRANTY; without even the implied warranty of
16
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17
  Lesser General Public License for more details.
18
19
  You should have received a copy of the GNU Lesser General Public License
20
  along with this library; if not, write to Free Software Foundation, Inc.,
21
  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22
*/
23
24
#include "air.h"
25
26
static const char *
27
_airBoolStr[] = {
28
  "(unknown bool)",
29
  "false",
30
  "true"
31
};
32
33
static const char *
34
_airBoolDesc[] = {
35
  "unknown boolean",
36
  "false",
37
  "true"
38
};
39
40
static const int
41
_airBoolVal[] = {
42
  -1,
43
  AIR_FALSE,
44
  AIR_TRUE
45
};
46
47
static const char *
48
_airBoolStrEqv[] = {
49
  "0", "no", "n", "false", "f", "off", "nope",
50
  "1", "yes", "y", "true", "t", "on", "yea",
51
  ""
52
};
53
54
static const int
55
_airBoolValEqv[] = {
56
  AIR_FALSE, AIR_FALSE, AIR_FALSE, AIR_FALSE, AIR_FALSE, AIR_FALSE, AIR_FALSE,
57
  AIR_TRUE, AIR_TRUE, AIR_TRUE, AIR_TRUE, AIR_TRUE, AIR_TRUE, AIR_TRUE
58
};
59
60
static const airEnum
61
_airBool = {
62
  "boolean",
63
  2,
64
  _airBoolStr,
65
  _airBoolVal,
66
  _airBoolDesc,
67
  _airBoolStrEqv,
68
  _airBoolValEqv,
69
  AIR_FALSE
70
};
71
72
const airEnum *const
73
airBool = &_airBool;
74
75
double
76
airAtod(const char *str) {
77
520
  double val = 0.0;
78
79
260
  airSingleSscanf(str, "%lf", &val);
80
520
  return val;
81
260
}
82
83
int
84
airSingleSscanf(const char *str, const char *fmt, void *ptr) {
85
  char *tmp;
86
  double val;
87
  int ret;
88
89

7049
  if (!strcmp(fmt, "%e") || !strcmp(fmt, "%f") || !strcmp(fmt, "%g")
90

5516
      || !strcmp(fmt, "%le") || !strcmp(fmt, "%lf") || !strcmp(fmt, "%lg")) {
91
1282
    tmp = airStrdup(str);
92
1282
    if (!tmp) {
93
      return 0;
94
    }
95
1282
    airToLower(tmp);
96
1282
    if (strstr(tmp, "nan")) {
97
66
      val = AIR_NAN;
98
66
    }
99
/* ---- BEGIN non-NrrdIO */
100
1216
    else if (strstr(tmp, "-pi")) {
101
      val = -AIR_PI;
102
    }
103
1216
    else if (strstr(tmp, "pi")) {
104
      val = AIR_PI;
105
    }
106
/* ---- END non-NrrdIO */
107
1216
    else if (strstr(tmp, "-inf")) {
108
      val = AIR_NEG_INF;
109
    }
110
1216
    else if (strstr(tmp, "inf")) {
111
      val = AIR_POS_INF;
112
    }
113
    else {
114
      /* nothing special matched; pass it off to sscanf() */
115
      /* (save setlocale here) */
116
1216
      ret = sscanf(str, fmt, ptr);
117
      /* (return setlocale here) */
118
1216
      free(tmp);
119
1216
      return ret;
120
    }
121
    /* else we matched "nan", "-inf", or "inf", and set val accordingly */
122
66
    if (!strncmp(fmt, "%l", 2)) {
123
      /* we were given a double pointer */
124
66
      *((double *)(ptr)) = val;
125
66
    }
126
    else {
127
      /* we were given a float pointer */
128
      *((float *)(ptr)) = AIR_CAST(float, val);
129
    }
130
66
    free(tmp);
131
66
    return 1;
132
251
  } else if (!strcmp(fmt, "%z")) {
133
    /* its a size_t */
134
    size_t tsz = 0;  /* tmp size_t */
135
    const char *chh = str; /* char here */
136

730
    while (chh) {
137
      int dig;
138
562
      dig = AIR_CAST(int, *chh - '0');
139
562
      if (AIR_IN_CL(0, dig, 9)) {
140
394
        tsz = 10*tsz + AIR_CAST(size_t, dig);
141
      } else {
142
168
        break;
143
      }
144
394
      chh++;
145
394
    }
146
168
    *((size_t *)(ptr)) = tsz;
147
    return 1;
148
  } else {
149
    /* not a float, double, or size_t, let sscanf handle it */
150
83
    return sscanf(str, fmt, ptr);
151
  }
152
1533
}
153
154
#define _PARSE_STR_ARGS(type) type *out, const char *_s, \
155
                              const char *ct, unsigned int n, ...
156
#define _PARSE_STR_BODY(format) \
157
  unsigned int i; \
158
  char *tmp, *s, *last; \
159
  \
160
  /* if we got NULL, there's nothing to do */ \
161
  if (!(out && _s && ct)) \
162
    return 0; \
163
  \
164
  /* copy the input so that we don't change it */ \
165
  s = airStrdup(_s); \
166
  \
167
  /* keep calling airStrtok() until we have everything */ \
168
  for (i=0; i<n; i++) { \
169
    tmp = airStrtok(i ? NULL : s, ct, &last); \
170
    if (!tmp) { \
171
      free(s); \
172
      return i; \
173
    } \
174
    if (1 != airSingleSscanf(tmp, format, out+i)) { \
175
      free(s); \
176
      return i; \
177
    } \
178
  } \
179
  free(s); \
180
  return n; \
181
182
/*
183
******* airParse*()
184
**
185
** parse ints, floats, doubles, or single characters, from some
186
** given string "s"; try to parse "n" of them, as delimited by
187
** characters in "ct", and put the results in "out".
188
**
189
** Returns the number of things succesfully parsed- should be n;
190
** there's been an error if return is < n.
191
**
192
** The embarrassing reason for the var-args ("...") is that I want the
193
** type signature of all these functions to be the same, and I have a function
194
** for parsing airEnums, in case the airEnum must be supplied as a final
195
** argument.
196
**
197
** This uses air's thread-safe strtok() replacement: airStrtok()
198
*/
199
unsigned int
200


224
airParseStrI(_PARSE_STR_ARGS(int))           { _PARSE_STR_BODY("%d") }
201
202
unsigned int
203


200
airParseStrUI(_PARSE_STR_ARGS(unsigned int)) { _PARSE_STR_BODY("%u") }
204
205
unsigned int
206
airParseStrLI(_PARSE_STR_ARGS(long int)) { _PARSE_STR_BODY("%ld") }
207
208
unsigned int
209
airParseStrULI(_PARSE_STR_ARGS(unsigned long int)) { _PARSE_STR_BODY("%lu") }
210
211
unsigned int
212


1043
airParseStrZ(_PARSE_STR_ARGS(size_t)) { _PARSE_STR_BODY("%z") }
213
214
unsigned int
215
airParseStrF(_PARSE_STR_ARGS(float))         { _PARSE_STR_BODY("%f") }
216
217
unsigned int
218


2416
airParseStrD(_PARSE_STR_ARGS(double))        { _PARSE_STR_BODY("%lf") }
219
220
unsigned int
221
airParseStrB(int *out, const char *_s, const char *ct, unsigned int n, ...) {
222
  unsigned int i;
223
  char *tmp, *s, *last;
224
225
  /* if we got NULL, there's nothing to do */
226
  if (!(out && _s && ct))
227
    return 0;
228
229
  /* copy the input so that we don't change it */
230
  s = airStrdup(_s);
231
232
  /* keep calling airStrtok() until we have everything */
233
  for (i=0; i<n; i++) {
234
    tmp = airStrtok(i ? NULL : s, ct, &last);
235
    if (!tmp) {
236
      free(s);
237
      return i;
238
    }
239
    out[i] = airEnumVal(airBool, tmp);
240
    if (airEnumUnknown(airBool) == out[i]) {
241
      free(s);
242
      return i;
243
    }
244
  }
245
  free(s);
246
  return n;
247
}
248
249
unsigned int
250
airParseStrC(char *out, const char *_s, const char *ct, unsigned int n, ...) {
251
  unsigned int i;
252
  char *tmp, *s, *last;
253
254
  /* if we got NULL, there's nothing to do */
255
  if (!(out && _s && ct))
256
    return 0;
257
258
  /* copy the input so that we don't change it */
259
  s = airStrdup(_s);
260
261
  /* keep calling airStrtok() until we have everything */
262
  for (i=0; i<n; i++) {
263
    tmp = airStrtok(i ? NULL : s, ct, &last);
264
    if (!tmp) {
265
      free(s);
266
      return i;
267
    }
268
    out[i] = tmp[0];
269
  }
270
  free(s);
271
  return n;
272
}
273
274
unsigned int
275
airParseStrS(char **out, const char *_s, const char *ct, unsigned int n, ...) {
276
  unsigned int i;
277
  int greedy;
278
1004
  char *tmp, *s, *last;
279
  airArray *mop;
280
502
  va_list ap;
281
282
  /* grab "greedy" every time, prior to error checking */
283
502
  va_start(ap, n);
284
1506
  greedy = va_arg(ap, int);
285
502
  va_end(ap);
286
287
  /* if we got NULL, there's nothing to do */
288
502
  if (!(out && _s && ct))
289
    return 0;
290
291
502
  mop = airMopNew();
292
  /* copy the input so that we don't change it */
293
502
  s = airStrdup(_s);
294
502
  airMopMem(mop, &s, airMopAlways);
295
296
  /* keep calling airStrtok() until we have everything */
297
4260
  for (i=0; i<n; i++) {
298
    /* if n == 1, then with greediness, the whole string is used,
299
       and without greediness, we use airStrtok() to get only
300
       the first part of it */
301
1788
    if (n > 1 || !greedy) {
302
1772
      tmp = airStrtok(i ? NULL : s, ct, &last);
303
1772
    }
304
    else {
305
16
      tmp = s;
306
    }
307
1788
    if (!tmp) {
308
160
      airMopError(mop);
309
160
      return i;
310
    }
311
1628
    out[i] = airStrdup(tmp);
312
1628
    if (!out[i]) {
313
      airMopError(mop);
314
      return i;
315
    }
316
1628
    airMopMem(mop, out+i, airMopOnError);
317
  }
318
342
  airMopOkay(mop);
319
342
  return n;
320
502
}
321
322
unsigned int
323
airParseStrE(int *out, const char *_s, const char *ct, unsigned int n, ...) {
324
  unsigned int i;
325
  char *tmp, *s, *last;
326
  airArray *mop;
327
  va_list ap;
328
  airEnum *enm;
329
330
  /* grab the enum every time, prior to error checking */
331
  va_start(ap, n);
332
  enm = va_arg(ap, airEnum *);
333
  va_end(ap);
334
335
  /* if we got NULL, there's nothing to do */
336
  if (!(out && _s && ct)) {
337
    return 0;
338
  }
339
340
  mop = airMopNew();
341
  /* copy the input so that we don't change it */
342
  s = airStrdup(_s);
343
  airMopMem(mop, &s, airMopAlways);
344
345
  if (1 == n) {
346
    /* Because it should be permissible to have spaces in what is
347
       intended to be only a single string from an airEnum, we treat
348
       1==n differently, and do NOT use airStrtok to tokenize the
349
       input string s into spaces.  We check the whole s string */
350
    out[0] = airEnumVal(enm, s);
351
    if (airEnumUnknown(enm) == out[0]) {
352
      airMopError(mop);
353
      return 0;
354
    }
355
  } else {
356
    /* keep calling airStrtok() until we have everything */
357
    for (i=0; i<n; i++) {
358
      tmp = airStrtok(i ? NULL : s, ct, &last);
359
      if (!tmp) {
360
        airMopError(mop);
361
        return i;
362
      }
363
      out[i] = airEnumVal(enm, tmp);
364
      if (airEnumUnknown(enm) == out[i]
365
          /* getting the unknown value is not a parse failure if the
366
             string was actually the string for the unknown value! */
367
          && strcmp(tmp, enm->str[0])) {
368
        airMopError(mop);
369
        return i;
370
      }
371
    }
372
  }
373
  airMopOkay(mop);
374
  return n;
375
}
376
377
unsigned int
378
(*airParseStr[AIR_TYPE_MAX+1])(void *, const char *,
379
                               const char *, unsigned int, ...) = {
380
  NULL,
381
  (unsigned int (*)(void *, const char *, const char *,
382
                    unsigned int, ...))airParseStrB,
383
  (unsigned int (*)(void *, const char *, const char *,
384
                    unsigned int, ...))airParseStrI,
385
  (unsigned int (*)(void *, const char *, const char *,
386
                    unsigned int, ...))airParseStrUI,
387
  (unsigned int (*)(void *, const char *, const char *,
388
                    unsigned int, ...))airParseStrLI,
389
  (unsigned int (*)(void *, const char *, const char *,
390
                    unsigned int, ...))airParseStrULI,
391
  (unsigned int (*)(void *, const char *, const char *,
392
                    unsigned int, ...))airParseStrZ,
393
  (unsigned int (*)(void *, const char *, const char *,
394
                    unsigned int, ...))airParseStrF,
395
  (unsigned int (*)(void *, const char *, const char *,
396
                    unsigned int, ...))airParseStrD,
397
  (unsigned int (*)(void *, const char *, const char *,
398
                    unsigned int, ...))airParseStrC,
399
  (unsigned int (*)(void *, const char *, const char *,
400
                    unsigned int, ...))airParseStrS,
401
  (unsigned int (*)(void *, const char *, const char *,
402
                    unsigned int, ...))airParseStrE,
403
  NULL   /* no standard way of parsing type "other" */
404
};
405