GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/hest/parseHest.c Lines: 284 654 43.4 %
Date: 2017-05-26 Branches: 210 726 28.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
/*
25
learned: well duh: when you send arguments to printf(), they will
26
be evaluated before printf() sees them, so you can't use _hestIdent()
27
twice with differen values
28
*/
29
30
#include "hest.h"
31
#include "privateHest.h"
32
33
#include <string.h>
34
35
#define ME ((parm && parm->verbosity) ? me : "")
36
37
/*
38
** _hestArgsInResponseFiles()
39
**
40
** returns the number of args that will be parsed from the response files.
41
** The role of this function is solely to simplify the task of avoiding
42
** memory leaks.  By knowing exactly how many args we'll get in the response
43
** file, then hestParse() can allocate its local argv[] for exactly as
44
** long as it needs to be, and we can avoid using an airArray.  The drawback
45
** is that we open and read through the response files twice.  Alas.
46
*/
47
int
48
_hestArgsInResponseFiles(int *argcP, int *nrfP,
49
                         const char **argv, char *err,
50
                         const hestParm *parm) {
51
  FILE *file;
52
48
  char me[]="_hestArgsInResponseFiles: ", line[AIR_STRLEN_HUGE], *pound;
53
  int ai, len;
54
55
24
  *argcP = 0;
56
24
  *nrfP = 0;
57
24
  if (!parm->respFileEnable) {
58
    /* don't do response files; we're done */
59
24
    return 0;
60
  }
61
62
  ai = 0;
63
  while (argv[ai]) {
64
    if (parm->respFileFlag == argv[ai][0]) {
65
      if (!(file = fopen(argv[ai]+1, "rb"))) {
66
        /* can't open the indicated response file for reading */
67
        sprintf(err, "%scouldn't open \"%s\" for reading as response file",
68
                ME, argv[ai]+1);
69
        *argcP = 0;
70
        *nrfP = 0;
71
        return 1;
72
      }
73
      len = airOneLine(file, line, AIR_STRLEN_HUGE);
74
      while (len > 0) {
75
        if ( (pound = strchr(line, parm->respFileComment)) )
76
          *pound = '\0';
77
        airOneLinify(line);
78
        *argcP += airStrntok(line, AIR_WHITESPACE);
79
        len = airOneLine(file, line, AIR_STRLEN_HUGE);
80
      }
81
      fclose(file);
82
      (*nrfP)++;
83
    }
84
    ai++;
85
  }
86
  return 0;
87
24
}
88
89
/*
90
** _hestResponseFiles()
91
**
92
** This function is badly named.  Even if there are no response files,
93
** even if response files are disabled, this is the function that
94
** copies from the user's argc,argv to our local copy.
95
*/
96
int
97
_hestResponseFiles(char **newArgv, const char **oldArgv,
98
                   const hestParm *parm, airArray *pmop) {
99
48
  char line[AIR_STRLEN_HUGE], *pound;
100
  int len, newArgc, oldArgc, incr, ai;
101
  FILE *file;
102
103
  newArgc = oldArgc = 0;
104
309
  while(oldArgv[oldArgc]) {
105
261
    if (parm->verbosity) {
106
      printf("!%s:________ newArgc = %d, oldArgc = %d\n",
107
             "dammit", newArgc, oldArgc);
108
      _hestPrintArgv(newArgc, newArgv);
109
    }
110
261
    if (!parm->respFileEnable
111
261
        || parm->respFileFlag != oldArgv[oldArgc][0]) {
112
      /* nothing to do with a response file */
113
261
      newArgv[newArgc] = airStrdup(oldArgv[oldArgc]);
114
261
      airMopAdd(pmop, newArgv[newArgc], airFree, airMopAlways);
115
261
      newArgc += 1;
116
261
    }
117
    else {
118
      /* It is a response file.  Error checking on open-ability
119
         should have been done by _hestArgsInResponseFiles() */
120
      file = fopen(oldArgv[oldArgc]+1, "rb");
121
      len = airOneLine(file, line, AIR_STRLEN_HUGE);
122
      while (len > 0) {
123
        if (parm->verbosity)
124
          printf("_hestResponseFiles: line: |%s|\n", line);
125
        if ( (pound = strchr(line, parm->respFileComment)) )
126
          *pound = '\0';
127
        if (parm->verbosity)
128
          printf("_hestResponseFiles: -0-> line: |%s|\n", line);
129
        airOneLinify(line);
130
        incr = airStrntok(line, AIR_WHITESPACE);
131
        if (parm->verbosity)
132
          printf("_hestResponseFiles: -1-> line: |%s|, incr=%d\n",
133
                 line, incr);
134
        airParseStrS(newArgv + newArgc, line, AIR_WHITESPACE, incr, AIR_FALSE);
135
        for (ai=0; ai<incr; ai++) {
136
          /* This time, we did allocate memory.  We can use airFree and
137
             not airFreeP because these will not be reset before mopping */
138
          airMopAdd(pmop, newArgv[newArgc+ai], airFree, airMopAlways);
139
        }
140
        len = airOneLine(file, line, AIR_STRLEN_HUGE);
141
        newArgc += incr;
142
      }
143
      fclose(file);
144
    }
145
261
    oldArgc++;
146
261
    if (parm->verbosity) {
147
      _hestPrintArgv(newArgc, newArgv);
148
      printf("!%s: ^^^^^^^ newArgc = %d, oldArgc = %d\n",
149
             "dammit", newArgc, oldArgc);
150
    }
151
  }
152
24
  newArgv[newArgc] = NULL;
153
154
24
  return 0;
155
24
}
156
157
/*
158
** _hestPanic()
159
**
160
** all error checking on the given hest array itself (not the
161
** command line to be parsed).  Also, sets the "kind" field of
162
** the opt struct
163
*/
164
int
165
_hestPanic(hestOpt *opt, char *err, const hestParm *parm) {
166
508
  char me[]="_hestPanic: ", tbuff[AIR_STRLEN_HUGE], *sep;
167
  int numvar, op, numOpts;
168
169
254
  numOpts = _hestNumOpts(opt);
170
  numvar = 0;
171
3784
  for (op=0; op<numOpts; op++) {
172
1638
    opt[op].kind = _hestKind(opt + op);
173

3276
    if (!(AIR_IN_OP(airTypeUnknown, opt[op].type, airTypeLast))) {
174
      if (err)
175
        sprintf(err, "%s!!!!!! opt[%d].type (%d) not in valid range [%d,%d]",
176
                ME, op, opt[op].type, airTypeUnknown+1, airTypeLast-1);
177
      else
178
        fprintf(stderr, "%s: panic 0\n", me);
179
      return 1;
180
    }
181
1638
    if (!( opt[op].valueP )) {
182
      if (err)
183
        sprintf(err, "%s!!!!!! opt[%d]'s valueP is NULL!", ME, op);
184
      else
185
        fprintf(stderr, "%s: panic 0.5\n", me);
186
      return 1;
187
    }
188
1638
    if (-1 == opt[op].kind) {
189
      if (err)
190
        sprintf(err, "%s!!!!!! opt[%d]'s min (%d) and max (%d) incompatible",
191
                ME, op, opt[op].min, opt[op].max);
192
      else
193
        fprintf(stderr, "%s: panic 1\n", me);
194
      return 1;
195
    }
196

1754
    if (5 == opt[op].kind && !(opt[op].sawP)) {
197
      if (err)
198
        sprintf(err, "%s!!!!!! have multiple variable parameters, "
199
                "but sawP is NULL", ME);
200
      else
201
        fprintf(stderr, "%s: panic 2\n", me);
202
      return 1;
203
    }
204
1638
    if (airTypeEnum == opt[op].type) {
205
86
      if (!(opt[op].enm)) {
206
        if (err) {
207
          sprintf(err, "%s!!!!!! opt[%d] (%s) is type \"enum\", but no "
208
                  "airEnum pointer given", ME, op,
209
                  opt[op].flag ? opt[op].flag : "?");
210
        } else {
211
          fprintf(stderr, "%s: panic 3\n", me);
212
        }
213
        return 1;
214
      }
215
    }
216
1638
    if (airTypeOther == opt[op].type) {
217
336
      if (!(opt[op].CB)) {
218
        if (err) {
219
          sprintf(err, "%s!!!!!! opt[%d] (%s) is type \"other\", but no "
220
                  "callbacks given", ME, op,
221
                  opt[op].flag ? opt[op].flag : "?");
222
        } else {
223
          fprintf(stderr, "%s: panic 4\n", me);
224
        }
225
        return 1;
226
      }
227
336
      if (!( opt[op].CB->size > 0 )) {
228
        if (err)
229
          sprintf(err, "%s!!!!!! opt[%d]'s \"size\" (%d) invalid",
230
                  ME, op, (int)(opt[op].CB->size));
231
        else
232
          fprintf(stderr, "%s: panic 5\n", me);
233
        return 1;
234
      }
235
336
      if (!( opt[op].type )) {
236
        if (err)
237
          sprintf(err, "%s!!!!!! opt[%d]'s \"type\" is NULL",
238
                  ME, op);
239
        else
240
          fprintf(stderr, "%s: panic 6\n", me);
241
        return 1;
242
243
      }
244
336
      if (!( opt[op].CB->parse )) {
245
        if (err)
246
          sprintf(err, "%s!!!!!! opt[%d]'s \"parse\" callback NULL", ME, op);
247
        else
248
          fprintf(stderr, "%s: panic 7\n", me);
249
        return 1;
250
      }
251

624
      if (opt[op].CB->destroy && (sizeof(void*) != opt[op].CB->size)) {
252
        if (err)
253
          sprintf(err, "%s!!!!!! opt[%d] has a \"destroy\", but size isn't "
254
                  "sizeof(void*)", ME, op);
255
        else
256
          fprintf(stderr, "%s: panic 8\n", me);
257
        return 1;
258
      }
259
    }
260
1638
    if (opt[op].flag) {
261
1574
      strcpy(tbuff, opt[op].flag);
262
1574
      if (( sep = strchr(tbuff, parm->multiFlagSep) )) {
263
664
        *sep = '\0';
264

1328
        if (!( strlen(tbuff) && strlen(sep+1) )) {
265
          if (err)
266
            sprintf(err, "%s!!!!!! either short (\"%s\") or long (\"%s\") flag"
267
                    " of opt[%d] is zero length", ME, tbuff, sep+1, op);
268
          else
269
            fprintf(stderr, "%s: panic 9\n", me);
270
          return 1;
271
        }
272
      }
273
      else {
274
910
        if (!strlen(opt[op].flag)) {
275
          if (err)
276
            sprintf(err, "%s!!!!!! opt[%d].flag is zero length",
277
                    ME, op);
278
          else
279
            fprintf(stderr, "%s: panic 10\n", me);
280
          return 1;
281
        }
282
      }
283
1574
      if (4 == opt[op].kind) {
284
2
        if (!opt[op].dflt) {
285
          if (err)
286
            sprintf(err, "%s!!!!!! flagged single variable parameter must "
287
                    "specify a default", ME);
288
          else
289
            fprintf(stderr, "%s: panic 11\n", me);
290
          return 1;
291
        }
292
2
        if (!strlen(opt[op].dflt)) {
293
          if (err)
294
            sprintf(err, "%s!!!!!! flagged single variable parameter default "
295
                    "must be non-zero length", ME);
296
          else
297
            fprintf(stderr, "%s: panic 12\n", me);
298
          return 1;
299
        }
300
      }
301
      /*
302
      sprintf(tbuff, "-%s", opt[op].flag);
303
      if (1 == sscanf(tbuff, "%f", &tmpF)) {
304
        if (err)
305
          sprintf(err, "%s!!!!!! opt[%d].flag (\"%s\") is numeric, bad news",
306
                  ME, op, opt[op].flag);
307
        return 1;
308
      }
309
      */
310
    }
311
1638
    if (1 == opt[op].kind) {
312
148
      if (!opt[op].flag) {
313
        if (err)
314
          sprintf(err, "%s!!!!!! flags must have flags", ME);
315
        else
316
          fprintf(stderr, "%s: panic 13\n", me);
317
        return 1;
318
      }
319
    }
320
    else {
321
1490
      if (!opt[op].name) {
322
        if (err)
323
          sprintf(err, "%s!!!!!! opt[%d] isn't a flag: must have \"name\"",
324
                  ME, op);
325
        else
326
          fprintf(stderr, "%s: panic 14\n", me);
327
        return 1;
328
      }
329
    }
330

1640
    if (4 == opt[op].kind && !opt[op].dflt) {
331
      if (err)
332
        sprintf(err, "%s!!!!!! opt[%d] is single variable parameter, but "
333
                "no default set", ME, op);
334
      else
335
        fprintf(stderr, "%s: panic 15\n", me);
336
      return 1;
337
    }
338
3394
    numvar += ((int)opt[op].min < _hestMax(opt[op].max) && (NULL == opt[op].flag)); /* HEY scrutinize casts */
339
  }
340
254
  if (numvar > 1) {
341
    if (err)
342
      sprintf(err, "%s!!!!!! can't have %d unflagged min<max opts, only one",
343
              ME, numvar);
344
    else
345
      fprintf(stderr, "%s: panic 16\n", me);
346
    return 1;
347
  }
348
254
  return 0;
349
254
}
350
351
int
352
_hestErrStrlen(const hestOpt *opt, int argc, const char **argv) {
353
  int a, numOpts, ret, other;
354
355
  ret = 0;
356
80
  numOpts = _hestNumOpts(opt);
357
  other = AIR_FALSE;
358
40
  if (argv) {
359
570
    for (a=0; a<argc; a++) {
360
783
      ret = AIR_MAX(ret, (int)airStrlen(argv[a]));
361
    }
362
  }
363
536
  for (a=0; a<numOpts; a++) {
364
684
    ret = AIR_MAX(ret, (int)airStrlen(opt[a].flag));
365
684
    ret = AIR_MAX(ret, (int)airStrlen(opt[a].name));
366
228
    other |= opt[a].type == airTypeOther;
367
  }
368
1040
  for (a=airTypeUnknown+1; a<airTypeLast; a++) {
369
1440
    ret = AIR_MAX(ret, (int)airStrlen(airTypeStr[a]));
370
  }
371
40
  if (other) {
372
    /* the callback's error() function may sprintf an error message
373
       into a buffer which is size AIR_STRLEN_HUGE */
374
4
    ret += AIR_STRLEN_HUGE;
375
4
  }
376
40
  ret += 4 * 12;  /* as many as 4 ints per error message */
377
40
  ret += 257;     /* function name and text of hest's error message */
378
379
40
  return ret;
380
}
381
382
/*
383
** _hestExtractFlagged()
384
**
385
** extracts the parameters associated with all flagged options from the
386
** given argc and argv, storing them in prms[], recording the number
387
** of parameters in nprm[], and whether or not the flagged option appeared
388
** in appr[].
389
**
390
** The "saw" information is not set here, since it is better set
391
** at value parsing time, which happens after defaults are enstated.
392
*/
393
int
394
_hestExtractFlagged(char **prms, unsigned int *nprm, int *appr,
395
                     int *argcP, char **argv,
396
                     hestOpt *opt,
397
                     char *err, const hestParm *parm, airArray *pmop) {
398
48
  char me[]="_hestExtractFlagged: ", ident1[AIR_STRLEN_HUGE],
399
    ident2[AIR_STRLEN_HUGE];
400
  int a, np, flag, endflag, numOpts, op;
401
402
  a = 0;
403
24
  if (parm->verbosity)
404
    printf("!%s: *argcP = %d\n", me, *argcP);
405
127
  while (a<=*argcP-1) {
406
103
    if (parm->verbosity)
407
      printf("!%s: a = %d -> argv[a] = %s\n", me, a, argv[a]);
408
103
    flag = _hestWhichFlag(opt, argv[a], parm);
409
103
    if (parm->verbosity)
410
      printf("!%s: A: a = %d -> flag = %d\n", me, a, flag);
411
103
    if (!(0 <= flag)) {
412
      /* not a flag, move on */
413
      a++;
414
      continue;
415
    }
416
    /* see if we can associate some parameters with the flag */
417
    np = 0;
418
    endflag = 0;
419

528
    while (np < _hestMax(opt[flag].max) &&
420
166
           a+np+1 <= *argcP-1 &&
421
164
           -1 == (endflag = _hestWhichFlag(opt, argv[a+np+1], parm))) {
422
158
      np++;
423
158
      if (parm->verbosity)
424
        printf("!%s: np --> %d with endflag = %d\n", me, np, endflag);
425
    }
426
    /* we stopped because we got the max number of parameters, or
427
       because we hit the end of the command line, or
428
       because _hestWhichFlag() returned something other than -1,
429
       which means it returned -2, or a valid option index.  If
430
       we stopped because of _hestWhichFlag()'s return value,
431
       endflag has been set to that return value */
432
103
    if (parm->verbosity)
433
      printf("!%s: B: np = %d; endflag = %d\n", me, np, endflag);
434
103
    if (np < (int)opt[flag].min) { /* HEY scrutinize casts */
435
      /* didn't get minimum number of parameters */
436
      if (!( a+np+1 <= *argcP-1 )) {
437
        sprintf(err, "%shit end of line before getting %d parameter%s "
438
                "for %s (got %d)",
439
                ME, opt[flag].min, opt[flag].min > 1 ? "s" : "",
440
                _hestIdent(ident1, opt+flag, parm, AIR_TRUE), np);
441
      }
442
      else {
443
        sprintf(err, "%shit %s before getting %d parameter%s for %s (got %d)",
444
                ME, _hestIdent(ident1, opt+endflag, parm, AIR_FALSE),
445
                opt[flag].min, opt[flag].min > 1 ? "s" : "",
446
                _hestIdent(ident2, opt+flag, parm, AIR_FALSE), np);
447
      }
448
      return 1;
449
    }
450
103
    nprm[flag] = np;
451
103
    if (parm->verbosity) {
452
      printf("!%s:________ a=%d, *argcP = %d -> flag = %d\n",
453
             me, a, *argcP, flag);
454
      _hestPrintArgv(*argcP, argv);
455
    }
456
    /* lose the flag argument */
457
103
    free(_hestExtract(argcP, argv, a, 1));
458
    /* extract the args after the flag */
459
103
    if (appr[flag]) {
460
      airMopSub(pmop, prms[flag], airFree);
461
      prms[flag] = (char *)airFree(prms[flag]);
462
    }
463
103
    prms[flag] = _hestExtract(argcP, argv, a, nprm[flag]);
464
103
    airMopAdd(pmop, prms[flag], airFree, airMopAlways);
465
103
    appr[flag] = AIR_TRUE;
466
103
    if (-2 == endflag) {
467
      /* we should lose the end-of-variable-parameter marker */
468
      free(_hestExtract(argcP, argv, a, 1));
469
    }
470
103
    if (parm->verbosity) {
471
      _hestPrintArgv(*argcP, argv);
472
      printf("!%s:^^^^^^^^ *argcP = %d\n", me, *argcP);
473
      printf("!%s: prms[%d] = %s\n", me, flag,
474
             prms[flag] ? prms[flag] : "(null)");
475
    }
476
  }
477
478
  /* make sure that flagged options without default were given */
479
24
  numOpts = _hestNumOpts(opt);
480
380
  for (op=0; op<numOpts; op++) {
481


500
    if (1 != opt[op].kind && opt[op].flag && !opt[op].dflt && !appr[op]) {
482
      sprintf(err, "%sdidn't get required %s",
483
              ME, _hestIdent(ident1, opt+op, parm, AIR_FALSE));
484
      return 1;
485
    }
486
  }
487
488
24
  return 0;
489
24
}
490
491
int
492
_hestNextUnflagged(int op, hestOpt *opt, int numOpts) {
493
494
404
  for(; op<=numOpts-1; op++) {
495
166
    if (!opt[op].flag)
496
      break;
497
  }
498
24
  return op;
499
}
500
501
int
502
_hestExtractUnflagged(char **prms, unsigned int *nprm,
503
                      int *argcP, char **argv,
504
                      hestOpt *opt,
505
                      char *err, const hestParm *parm, airArray *pmop) {
506
48
  char me[]="_hestExtractUnflagged: ", ident[AIR_STRLEN_HUGE];
507
  int nvp, np, op, unflag1st, unflagVar, numOpts;
508
509
24
  numOpts = _hestNumOpts(opt);
510
24
  unflag1st = _hestNextUnflagged(0, opt, numOpts);
511
24
  if (numOpts == unflag1st) {
512
    /* no unflagged options; we're done */
513
24
    return 0;
514
  }
515
516
  for (unflagVar = unflag1st;
517
       unflagVar != numOpts;
518
       unflagVar = _hestNextUnflagged(unflagVar+1, opt, numOpts)) {
519
    if ((int)opt[unflagVar].min < _hestMax(opt[unflagVar].max)) /* HEY scrutinize casts */
520
      break;
521
  }
522
  /* now, if there is a variable parameter unflagged opt, unflagVar is its
523
     index in opt[], or else unflagVar is numOpts */
524
525
  /* grab parameters for all unflagged opts before opt[t] */
526
  for (op = _hestNextUnflagged(0, opt, numOpts);
527
       op < unflagVar;
528
       op = _hestNextUnflagged(op+1, opt, numOpts)) {
529
    /* printf("!%s: op = %d; unflagVar = %d\n", me, op, unflagVar); */
530
    np = opt[op].min;  /* min == max */
531
    if (!(np <= *argcP)) {
532
      sprintf(err, "%sdon't have %d parameter%s %s%s%sfor %s",
533
              ME, np, np > 1 ? "s" : "",
534
              argv[0] ? "starting at \"" : "",
535
              argv[0] ? argv[0] : "",
536
              argv[0] ? "\" " : "",
537
              _hestIdent(ident, opt+op, parm, AIR_TRUE));
538
      return 1;
539
    }
540
    prms[op] = _hestExtract(argcP, argv, 0, np);
541
    airMopAdd(pmop, prms[op], airFree, airMopAlways);
542
    nprm[op] = np;
543
  }
544
  /*
545
  _hestPrintArgv(*argcP, argv);
546
  */
547
  /* we skip over the variable parameter unflagged option, subtract from *argcP
548
     the number of parameters in all the opts which follow it, in order to get
549
     the number of parameters in the sole variable parameter option,
550
     store this in nvp */
551
  nvp = *argcP;
552
  for (op = _hestNextUnflagged(unflagVar+1, opt, numOpts);
553
       op < numOpts;
554
       op = _hestNextUnflagged(op+1, opt, numOpts)) {
555
    nvp -= opt[op].min;  /* min == max */
556
  }
557
  if (nvp < 0) {
558
    op = _hestNextUnflagged(unflagVar+1, opt, numOpts);
559
    np = opt[op].min;
560
    sprintf(err, "%sdon't have %d parameter%s for %s",
561
            ME, np, np > 1 ? "s" : "",
562
            _hestIdent(ident, opt+op, parm, AIR_FALSE));
563
    return 1;
564
  }
565
  /* else we had enough args for all the unflagged options following
566
     the sole variable parameter unflagged option, so snarf them up */
567
  for (op = _hestNextUnflagged(unflagVar+1, opt, numOpts);
568
       op < numOpts;
569
       op = _hestNextUnflagged(op+1, opt, numOpts)) {
570
    np = opt[op].min;
571
    prms[op] = _hestExtract(argcP, argv, nvp, np);
572
    airMopAdd(pmop, prms[op], airFree, airMopAlways);
573
    nprm[op] = np;
574
  }
575
576
  /* now we grab the parameters of the sole variable parameter unflagged opt,
577
     if it exists (unflagVar < numOpts) */
578
  if (unflagVar < numOpts) {
579
    /*
580
    printf("!%s: unflagVar=%d: min, nvp, max = %d %d %d\n", me, unflagVar,
581
           opt[unflagVar].min, nvp, _hestMax(opt[unflagVar].max));
582
    */
583
    /* we'll do error checking for unexpected args later */
584
    nvp = AIR_MIN(nvp, _hestMax(opt[unflagVar].max));
585
    if (nvp < (int)opt[unflagVar].min) { /* HEY scrutinize casts */
586
      sprintf(err, "%sdidn't get minimum of %d arg%s for %s (got %d)",
587
              ME, opt[unflagVar].min,
588
              opt[unflagVar].min > 1 ? "s" : "",
589
              _hestIdent(ident, opt+unflagVar, parm, AIR_TRUE), nvp);
590
      return 1;
591
    }
592
    if (nvp) {
593
      prms[unflagVar] = _hestExtract(argcP, argv, 0, nvp);
594
      airMopAdd(pmop, prms[unflagVar], airFree, airMopAlways);
595
      nprm[unflagVar] = nvp;
596
    }
597
    else {
598
      prms[unflagVar] = NULL;
599
      nprm[unflagVar] = 0;
600
    }
601
  }
602
  return 0;
603
24
}
604
605
int
606
_hestDefaults(char **prms, int *udflt, unsigned int *nprm, int *appr,
607
              hestOpt *opt,
608
              char *err, const hestParm *parm, airArray *mop) {
609
48
  char *tmpS, me[]="_hestDefaults: ", ident[AIR_STRLEN_HUGE];
610
  int op, numOpts;
611
612
24
  numOpts = _hestNumOpts(opt);
613
380
  for (op=0; op<numOpts; op++) {
614
166
    if (parm->verbosity)
615
      printf("%s op=%d/%d: \"%s\" --> kind=%d, nprm=%u, appr=%d\n",
616
             me, op, numOpts-1, prms[op], opt[op].kind,
617
             nprm[op], appr[op]);
618

332
    switch(opt[op].kind) {
619
    case 1:
620
      /* -------- (no-parameter) boolean flags -------- */
621
      /* default is indeed always ignored for the sake of setting the
622
         option's value, but udflt is used downstream to set
623
         the option's source. The info came from the user if
624
         the flag appears, otherwise it is from the default. */
625
14
      udflt[op] = !appr[op];
626
14
      break;
627
    case 2:
628
    case 3:
629
      /* -------- one required parameter -------- */
630
      /* -------- multiple required parameters -------- */
631
      /* we'll used defaults if the flag didn't appear */
632
432
      udflt[op] = opt[op].flag && !appr[op];
633
144
      break;
634
    case 4:
635
      /* -------- optional single variables -------- */
636
      /* if the flag appeared (if there is a flag) but the paramter didn't,
637
         we'll "invert" the default; if the flag didn't appear (or if there
638
         isn't a flag) and the parameter also didn't appear, we'll use the
639
         default.  In either case, nprm[op] will be zero, and in both cases,
640
         we need to use the default information. */
641
      udflt[op] = (0 == nprm[op]);
642
      /*
643
      fprintf(stderr, "%s nprm[%d] = %u --> udflt[%d] = %d\n", me,
644
              op, nprm[op], op, udflt[op]);
645
      */
646
      break;
647
    case 5:
648
      /* -------- multiple optional parameters -------- */
649
      /* we'll use the default if the flag didn't appear (if there is a
650
         flag) Otherwise, if nprm[op] is zero, then the user is saying,
651
         I want zero parameters */
652
24
      udflt[op] = opt[op].flag && !appr[op];
653
8
      break;
654
    }
655
166
    if (!udflt[op])
656
      continue;
657
63
    prms[op] = airStrdup(opt[op].dflt);
658
    /* fprintf(stderr, "%s: prms[%d] = |%s|\n", me, op, prms[op]); */
659
63
    if (prms[op]) {
660
52
      airMopAdd(mop, prms[op], airFree, airMopAlways);
661
52
      airOneLinify(prms[op]);
662
52
      tmpS = airStrdup(prms[op]);
663
52
      nprm[op] = airStrntok(tmpS, " ");
664
52
      airFree(tmpS);
665
      /* printf("!%s: nprm[%d] in default = %u\n", me, op, nprm[op]); */
666
52
      if ((int)opt[op].min < _hestMax(opt[op].max)) { /* HEY scrutinize casts */
667
        if (!( AIR_IN_CL((int)opt[op].min, (int)nprm[op], _hestMax(opt[op].max)) /* HEY scrutinize casts */
668
               || (airTypeString == opt[op].type
669
                   && parm->elideMultipleEmptyStringDefault) )) {
670
          sprintf(err, "%s# parameters (in default) for %s is %d, "
671
                  "but need between %d and %d",
672
                  ME, _hestIdent(ident, opt+op, parm, AIR_TRUE), nprm[op],
673
                  opt[op].min, _hestMax(opt[op].max));
674
          return 1;
675
        }
676
      }
677
    }
678
  }
679
24
  return 0;
680
24
}
681
682
/*
683
** this function moved from air/miscAir; the usage below
684
** is its only usage in Teem
685
*/
686
static int
687
airIStore(void *v, int t, int i) {
688
689
  switch(t) {
690
  case airTypeBool:   return (*((int*)v) = !!i); break;
691
  case airTypeInt:    return (*((int*)v) = i); break;
692
  case airTypeUInt:   return (int)(*((unsigned int*)v) = i); break;
693
  case airTypeLongInt:return (int)(*((long int*)v) = i); break;
694
  case airTypeULongInt:return (int)(*((unsigned long int*)v) = i); break;
695
  case airTypeSize_t: return (int)(*((size_t*)v) = i); break;
696
  case airTypeFloat:  return (int)(*((float*)v) = (float)(i)); break;
697
  case airTypeDouble: return (int)(*((double*)v) = (double)(i)); break;
698
  case airTypeChar:   return (*((char*)v) = (char)(i)); break;
699
  default: return 0; break;
700
  }
701
}
702
703
/*
704
** this function moved from air/miscAir; the usage below
705
** is its only usage in Teem
706
*/
707
double
708
airDLoad(void *v, int t) {
709
710
  switch(t) {
711
  case airTypeBool:   return AIR_CAST(double,*((int*)v)); break;
712
  case airTypeInt:    return AIR_CAST(double,*((int*)v)); break;
713
  case airTypeUInt:   return AIR_CAST(double,*((unsigned int*)v)); break;
714
  case airTypeLongInt:return AIR_CAST(double,*((long int*)v)); break;
715
  case airTypeULongInt:return AIR_CAST(double,*((unsigned long int*)v)); break;
716
  case airTypeSize_t: return AIR_CAST(double, *((size_t*)v)); break;
717
  case airTypeFloat:  return AIR_CAST(double,*((float*)v)); break;
718
  case airTypeDouble: return *((double*)v); break;
719
  case airTypeChar:   return AIR_CAST(double,*((char*)v)); break;
720
  default: return 0; break;
721
  }
722
}
723
724
725
int
726
_hestSetValues(char **prms, int *udflt, unsigned int *nprm, int *appr,
727
               hestOpt *opt,
728
               char *err, const hestParm *parm, airArray *pmop) {
729
48
  char ident[AIR_STRLEN_HUGE], me[]="_hestSetValues: ",
730
    cberr[AIR_STRLEN_HUGE], *tok, *last, *prmsCopy;
731
  double tmpD;
732
  int op, type, numOpts, p, ret;
733
  void *vP;
734
  char *cP;
735
  size_t size;
736
737
24
  numOpts = _hestNumOpts(opt);
738
380
  for (op=0; op<numOpts; op++) {
739
166
    _hestIdent(ident, opt+op, parm, AIR_TRUE);
740
166
    opt[op].source = udflt[op] ? hestSourceDefault : hestSourceUser;
741
166
    type = opt[op].type;
742
498
    size = (airTypeEnum == type
743
            ? (int)sizeof(int)             /* HEY scrutinize casts */
744
332
            : (airTypeOther == type
745
168
               ? (int)opt[op].CB->size     /* HEY scrutinize casts */
746
164
               : (int)airTypeSize[type])); /* HEY scrutinize casts */
747
166
    cP = (char *)(vP = opt[op].valueP);
748
166
    if (parm->verbosity) {
749
      printf("%s %d of %d: \"%s\": |%s| --> kind=%d, type=%d, size=%d\n",
750
             me, op, numOpts-1, prms[op], ident, opt[op].kind, type,
751
             (int)size);
752
    }
753
    /* we may over-write these */
754
166
    opt[op].alloc = 0;
755
166
    if (opt[op].sawP) {
756
8
      *(opt[op].sawP) = 0;
757
8
    }
758

180
    switch(opt[op].kind) {
759
    case 1:
760
      /* -------- parameter-less boolean flags -------- */
761
14
      if (vP)
762
14
        *((int*)vP) = appr[op];
763
      break;
764
    case 2:
765
      /* -------- one required parameter -------- */
766
100
      if (prms[op] && vP) {
767

100
        switch (type) {
768
        case airTypeEnum:
769
          if (1 != airParseStrE((int *)vP, prms[op], " ", 1, opt[op].enm)) {
770
            sprintf(err, "%scouldn\'t parse %s\"%s\" as %s for %s",
771
                    ME, udflt[op] ? "(default) " : "", prms[op],
772
                    opt[op].enm->name, ident);
773
            return 1;
774
          }
775
          break;
776
        case airTypeOther:
777
          strcpy(cberr, "");
778
          ret = opt[op].CB->parse(vP, prms[op], cberr);
779
          if (ret) {
780
            if (strlen(cberr)) {
781
              sprintf(err, "%serror parsing \"%s\" as %s for %s:\n%s",
782
                      ME, prms[op], opt[op].CB->type, ident, cberr);
783
            } else {
784
              sprintf(err, "%serror parsing \"%s\" as %s for %s: returned %d",
785
                      ME, prms[op], opt[op].CB->type, ident, ret);
786
            }
787
            return ret;
788
          }
789
          if (opt[op].CB->destroy) {
790
            /* vP is the address of a void*, we manage the void * */
791
            opt[op].alloc = 1;
792
            airMopAdd(pmop, (void**)vP, (airMopper)airSetNull, airMopOnError);
793
            airMopAdd(pmop, *((void**)vP), opt[op].CB->destroy, airMopOnError);
794
          }
795
          break;
796
        case airTypeString:
797

32
          if (1 != airParseStrS((char **)vP, prms[op], " ", 1,
798
16
                                parm->greedySingleString)) {
799
            sprintf(err, "%scouldn't parse %s\"%s\" as %s for %s",
800
                    ME, udflt[op] ? "(default) " : "", prms[op],
801
                    airTypeStr[type], ident);
802
            return 1;
803
          }
804
          /* vP is the address of a char* (a char **), but what we
805
             manage with airMop is the char * */
806
16
          opt[op].alloc = 1;
807
16
          airMopMem(pmop, vP, airMopOnError);
808
16
          break;
809
        default:
810
          /* type isn't string or enum, so no last arg to airParseStr[type] */
811
84
          if (1 != airParseStr[type](vP, prms[op], " ", 1)) {
812
            sprintf(err, "%scouldn't parse %s\"%s\" as %s for %s",
813
                    ME, udflt[op] ? "(default) " : "", prms[op],
814
                    airTypeStr[type], ident);
815
            return 1;
816
          }
817
          break;
818
        }
819
      }
820
      break;
821
    case 3:
822
      /* -------- multiple required parameters -------- */
823
44
      if (prms[op] && vP) {
824

44
        switch (type) {
825
        case airTypeEnum:
826
          if (opt[op].min !=   /* min == max */
827
              airParseStrE((int *)vP, prms[op], " ", opt[op].min, opt[op].enm)) {
828
            sprintf(err, "%scouldn't parse %s\"%s\" as %d %s%s for %s",
829
                    ME, udflt[op] ? "(default) " : "", prms[op],
830
                    opt[op].min, opt[op].enm->name,
831
                    opt[op].min > 1 ? "s" : "", ident);
832
            return 1;
833
          }
834
          break;
835
        case airTypeOther:
836
          prmsCopy = airStrdup(prms[op]);
837
          for (p=0; p<(int)opt[op].min; p++) { /* HEY scrutinize casts */
838
            tok = airStrtok(!p ? prmsCopy : NULL, " ", &last);
839
            strcpy(cberr, "");
840
            ret = opt[op].CB->parse(cP + p*size, tok, cberr);
841
            if (ret) {
842
              if (strlen(cberr))
843
                sprintf(err, "%serror parsing \"%s\" (in \"%s\") as %s "
844
                        "for %s:\n%s",
845
                        ME, tok, prms[op], opt[op].CB->type, ident, cberr);
846
              else
847
                sprintf(err, "%serror parsing \"%s\" (in \"%s\") as %s "
848
                        "for %s: returned %d",
849
                        ME, tok, prms[op], opt[op].CB->type, ident, ret);
850
              free(prmsCopy);
851
              return 1;
852
            }
853
          }
854
          free(prmsCopy);
855
          if (opt[op].CB->destroy) {
856
            /* vP is an array of void*s, we manage the individual void*s */
857
            opt[op].alloc = 2;
858
            for (p=0; p<(int)opt[op].min; p++) { /* HEY scrutinize casts */
859
              airMopAdd(pmop, ((void**)vP)+p, (airMopper)airSetNull,
860
                        airMopOnError);
861
              airMopAdd(pmop, *(((void**)vP)+p), opt[op].CB->destroy,
862
                        airMopOnError);
863
            }
864
          }
865
          break;
866
        case airTypeString:
867

12
          if (opt[op].min !=   /* min == max */
868
6
              airParseStr[type](vP, prms[op], " ", opt[op].min, AIR_FALSE)) {
869
            sprintf(err, "%scouldn't parse %s\"%s\" as %d %s%s for %s",
870
                    ME, udflt[op] ? "(default) " : "", prms[op],
871
                    opt[op].min, airTypeStr[type],
872
                    opt[op].min > 1 ? "s" : "", ident);
873
            return 1;
874
          }
875
          /* vP is an array of char*s, (a char**), and what we manage
876
             with airMop are the individual vP[p]. */
877
6
          opt[op].alloc = 2;
878
36
          for (p=0; p<(int)opt[op].min; p++) { /* HEY scrutinize casts */
879
12
            airMopMem(pmop, &(((char**)vP)[p]), airMopOnError);
880
          }
881
          break;
882
        default:
883

76
          if (opt[op].min !=   /* min == max */
884
38
              airParseStr[type](vP, prms[op], " ", opt[op].min)) {
885
            sprintf(err, "%scouldn't parse %s\"%s\" as %d %s%s for %s",
886
                    ME, udflt[op] ? "(default) " : "", prms[op],
887
                    opt[op].min, airTypeStr[type],
888
                    opt[op].min > 1 ? "s" : "", ident);
889
            return 1;
890
          }
891
          break;
892
        }
893
      }
894
      break;
895
    case 4:
896
      /* -------- optional single variables -------- */
897
      if (prms[op] && vP) {
898
        switch (type) {
899
        case airTypeEnum:
900
          if (1 != airParseStrE((int *)vP, prms[op], " ", 1, opt[op].enm)) {
901
            sprintf(err, "%scouldn't parse %s\"%s\" as %s for %s",
902
                    ME, udflt[op] ? "(default) " : "", prms[op],
903
                    opt[op].enm->name, ident);
904
            return 1;
905
          }
906
          break;
907
        case airTypeOther:
908
          /* we're parsing an "other".  We will not perform the special
909
             flagged single variable parameter games as done above, so
910
             whether this option is flagged or unflagged, we're going
911
             to treat it like an unflagged single variable parameter option:
912
             if the parameter didn't appear, we'll parse it from the default,
913
             if it did appear, we'll parse it from the command line.  Setting
914
             up prms[op] thusly has already been done by _hestDefaults() */
915
          strcpy(cberr, "");
916
          ret = opt[op].CB->parse(vP, prms[op], cberr);
917
          if (ret) {
918
            if (strlen(cberr))
919
              sprintf(err, "%serror parsing \"%s\" as %s for %s:\n%s",
920
                      ME, prms[op], opt[op].CB->type, ident, cberr);
921
            else
922
              sprintf(err, "%serror parsing \"%s\" as %s for %s: returned %d",
923
                      ME, prms[op], opt[op].CB->type, ident, ret);
924
            return 1;
925
          }
926
          if (opt[op].CB->destroy) {
927
            /* vP is the address of a void*, we manage the void* */
928
            opt[op].alloc = 1;
929
            airMopAdd(pmop, vP, (airMopper)airSetNull, airMopOnError);
930
            airMopAdd(pmop, *((void**)vP), opt[op].CB->destroy, airMopOnError);
931
          }
932
          break;
933
        case airTypeString:
934
          if (1 != airParseStr[type](vP, prms[op], " ", 1,
935
                                     parm->greedySingleString)) {
936
            sprintf(err, "%scouldn't parse %s\"%s\" as %s for %s",
937
                    ME, udflt[op] ? "(default) " : "", prms[op],
938
                    airTypeStr[type], ident);
939
            return 1;
940
          }
941
          opt[op].alloc = 1;
942
          if (opt[op].flag && 1 == _hestCase(opt, udflt, nprm, appr, op)) {
943
            /* we just parsed the default, but now we want to "invert" it */
944
            *((char**)vP) = (char *)airFree(*((char**)vP));
945
            opt[op].alloc = 0;
946
          }
947
          /* vP is the address of a char* (a char**), and what we
948
             manage with airMop is the char * */
949
          airMopMem(pmop, vP, airMopOnError);
950
          break;
951
        default:
952
          if (1 != airParseStr[type](vP, prms[op], " ", 1)) {
953
            sprintf(err, "%scouldn't parse %s\"%s\" as %s for %s",
954
                    ME, udflt[op] ? "(default) " : "", prms[op],
955
                    airTypeStr[type], ident);
956
            return 1;
957
          }
958
          opt[op].alloc = 0;
959
          if (1 == _hestCase(opt, udflt, nprm, appr, op)) {
960
            /* we just parsed the default, but now we want to "invert" it */
961
            tmpD = airDLoad(vP, type);
962
            airIStore(vP, type, tmpD ? 0 : 1);
963
          }
964
          break;
965
        }
966
      }
967
      break;
968
    case 5:
969
      /* -------- multiple optional parameters -------- */
970
      /* hammerhead problems in this case;
971
         may have been from calloc(0), fixed below */
972
8
      if (prms[op] && vP) {
973
8
        if (1 == _hestCase(opt, udflt, nprm, appr, op)) {
974
          *((void**)vP) = NULL;
975
          /* alloc and sawP set above */
976
        } else {
977

16
          if (airTypeString == type) {
978
            /* this is sneakiness: we allocate one more element so that
979
               the resulting char** is, like argv, NULL-terminated */
980
8
            *((void**)vP) = calloc(nprm[op]+1, size);
981
          } else {
982
8
            if (nprm[op]) {
983
              /* only allocate if there's something to allocate */
984
8
              *((void**)vP) = calloc(nprm[op], size);
985
8
            } else {
986
              *((void**)vP) = NULL;
987
            }
988
          }
989
8
          if (parm->verbosity) {
990
            printf("!%s: nprm[%d] = %u\n", me, op, nprm[op]);
991
            printf("!%s: new array (size %u*%u) is at 0x%p\n", me,
992
                   nprm[op], (unsigned int)size, *((void**)vP));
993
          }
994
8
          if (*((void**)vP)) {
995
8
            airMopMem(pmop, vP, airMopOnError);
996
8
          }
997
8
          *(opt[op].sawP) = nprm[op];
998
          /* so far everything we've done is regardless of type */
999

8
          switch (type) {
1000
          case airTypeEnum:
1001
            opt[op].alloc = 1;
1002
            if (nprm[op] !=
1003
                airParseStrE((int *)(*((void**)vP)), prms[op], " ", nprm[op],
1004
                             opt[op].enm)) {
1005
              sprintf(err, "%scouldn't parse %s\"%s\" as %u %s%s for %s",
1006
                      ME, udflt[op] ? "(default) " : "", prms[op],
1007
                      nprm[op], opt[op].enm->name,
1008
                      nprm[op] > 1 ? "s" : "", ident);
1009
              return 1;
1010
            }
1011
            break;
1012
          case airTypeOther:
1013
2
            cP = (char *)(*((void**)vP));
1014
2
            prmsCopy = airStrdup(prms[op]);
1015
2
            opt[op].alloc = (opt[op].CB->destroy ? 3 : 1);
1016
12
            for (p=0; p<(int)nprm[op]; p++) {  /* HEY scrutinize casts */
1017
4
              tok = airStrtok(!p ? prmsCopy : NULL, " ", &last);
1018
              /* hammerhead problems went away when this line
1019
                 was replaced by the following one:
1020
                 strcpy(cberr, "");
1021
              */
1022
4
              cberr[0] = 0;
1023
4
              ret = opt[op].CB->parse(cP + p*size, tok, cberr);
1024
4
              if (ret) {
1025
                if (strlen(cberr))
1026
                  sprintf(err,"%serror parsing \"%s\" (in \"%s\") as %s "
1027
                          "for %s:\n%s",
1028
                          ME, tok, prms[op], opt[op].CB->type, ident, cberr);
1029
1030
                else
1031
                  sprintf(err, "%serror parsing \"%s\" (in \"%s\") as %s "
1032
                          "for %s: returned %d",
1033
                          ME, tok, prms[op], opt[op].CB->type, ident, ret);
1034
                free(prmsCopy);
1035
                return 1;
1036
              }
1037
            }
1038
2
            free(prmsCopy);
1039
2
            if (opt[op].CB->destroy) {
1040
12
              for (p=0; p<(int)nprm[op]; p++) { /* HEY scrutinize casts */
1041
                /* avert your eyes.  vP is the address of an array of void*s.
1042
                   We manage the void*s */
1043
4
                airMopAdd(pmop, (*((void***)vP))+p, (airMopper)airSetNull,
1044
                          airMopOnError);
1045
4
                airMopAdd(pmop, *((*((void***)vP))+p), opt[op].CB->destroy,
1046
                          airMopOnError);
1047
              }
1048
            }
1049
            break;
1050
          case airTypeString:
1051
            opt[op].alloc = 3;
1052
            if (nprm[op] !=
1053
                airParseStrS((char **)(*((void**)vP)), prms[op], " ", nprm[op],
1054
                             parm->greedySingleString)) {
1055
              sprintf(err, "%scouldn't parse %s\"%s\" as %d %s%s for %s",
1056
                      ME, udflt[op] ? "(default) " : "", prms[op],
1057
                      nprm[op], airTypeStr[type],
1058
                      nprm[op] > 1 ? "s" : "", ident);
1059
              return 1;
1060
            }
1061
            /* vP is the address of an array of char*s (a char ***), and
1062
               what we manage with airMop is the individual (*vP)[p],
1063
               as well as vP itself (above). */
1064
            for (p=0; p<(int)nprm[op]; p++) { /* HEY scrutinize casts */
1065
              airMopAdd(pmop, (*((char***)vP))[p], airFree, airMopOnError);
1066
            }
1067
            /* do the NULL-termination described above */
1068
            (*((char***)vP))[nprm[op]] = NULL;
1069
            break;
1070
          default:
1071
6
            opt[op].alloc = 1;
1072

12
            if (nprm[op] !=
1073
6
                airParseStr[type](*((void**)vP), prms[op], " ", nprm[op])) {
1074
              sprintf(err, "%scouldn't parse %s\"%s\" as %d %s%s for %s",
1075
                      ME, udflt[op] ? "(default) " : "", prms[op],
1076
                      nprm[op], airTypeStr[type],
1077
                      nprm[op] > 1 ? "s" : "", ident);
1078
              return 1;
1079
            }
1080
            break;
1081
          }
1082
        }
1083
      }
1084
      break;
1085
    }
1086
  }
1087
24
  return 0;
1088
24
}
1089
1090
/*
1091
******** hestParse()
1092
**
1093
** documentation?
1094
*/
1095
int
1096
hestParse(hestOpt *opt, int _argc, const char **_argv,
1097
          char **_errP, const hestParm *_parm) {
1098
48
  char me[]="hestParse: ";
1099
  char *param, *param_copy;
1100
24
  char **argv, **prms, *err;
1101
24
  int a, argc, argr, *appr, *udflt, nrf, numOpts, big, ret, i;
1102
24
  unsigned int *nprm;
1103
  airArray *mop;
1104
  hestParm *parm;
1105
  size_t start_index, end_index;
1106
1107
24
  numOpts = _hestNumOpts(opt);
1108
1109
  /* -------- initialize the mop! */
1110
24
  mop = airMopNew();
1111
1112
  /* -------- either copy given _parm, or allocate one */
1113
24
  if (_parm) {
1114
    parm = NULL;
1115
24
  }
1116
  else {
1117
    parm = hestParmNew();
1118
    airMopAdd(mop, parm, (airMopper)hestParmFree, airMopAlways);
1119
  }
1120
  /* how to const-correctly use parm or _parm in an expression */
1121
#define PARM (_parm ? _parm : parm)
1122
1123
  /* -------- allocate the err string.  To determine its size with total
1124
     ridiculous safety we have to find the biggest things which can appear
1125
     in the string. */
1126
24
  big = _hestErrStrlen(opt, _argc, _argv);
1127
24
  if (!( err = AIR_CALLOC(big, char) )) {
1128
    fprintf(stderr, "%s PANIC: couldn't allocate error message "
1129
            "buffer (size %d)\n", me, big);
1130
    /* exit(1); */
1131
  }
1132
24
  if (_errP) {
1133
    /* if they care about the error string, than it is mopped only
1134
       when there _wasn't_ an error */
1135
24
    *_errP = err;
1136
24
    airMopAdd(mop, _errP, (airMopper)airSetNull, airMopOnOkay);
1137
24
    airMopAdd(mop, err, airFree, airMopOnOkay);
1138
24
  }
1139
  else {
1140
    /* otherwise, we're making the error string just for our own
1141
       convenience, and we'll always clean it up on exit */
1142
    airMopAdd(mop, err, airFree, airMopAlways);
1143
  }
1144
1145
  /* -------- check on validity of the hestOpt array */
1146
24
  if (_hestPanic(opt, err, PARM)) {
1147
    airMopError(mop); return 1;
1148
  }
1149
1150
  /* -------- Create all the local arrays used to save state during
1151
     the processing of all the different options */
1152
24
  nprm = AIR_CALLOC(numOpts, unsigned int);
1153
24
  airMopMem(mop, &nprm, airMopAlways);
1154
24
  appr = AIR_CALLOC(numOpts, int);
1155
24
  airMopMem(mop, &appr, airMopAlways);
1156
24
  udflt = AIR_CALLOC(numOpts, int);
1157
24
  airMopMem(mop, &udflt, airMopAlways);
1158
24
  prms = AIR_CALLOC(numOpts, char *);
1159
24
  airMopMem(mop, &prms, airMopAlways);
1160
380
  for (a=0; a<numOpts; a++) {
1161
166
    prms[a] = NULL;
1162
  }
1163
1164
  /* -------- find out how big the argv array needs to be, first
1165
     by seeing how many args are in the response files, and then adding
1166
     on the args from the actual argv (getting this right the first time
1167
     greatly simplifies the problem of eliminating memory leaks) */
1168
24
  if (_hestArgsInResponseFiles(&argr, &nrf, _argv, err, PARM)) {
1169
    airMopError(mop); return 1;
1170
  }
1171
24
  argc = argr + _argc - nrf;
1172
1173
24
  if (PARM->verbosity) {
1174
    printf("!%s: nrf = %d; argr = %d; _argc = %d --> argc = %d\n",
1175
           me, nrf, argr, _argc, argc);
1176
  }
1177
24
  argv = AIR_CALLOC(argc+1, char *);
1178
24
  airMopMem(mop, &argv, airMopAlways);
1179
1180
  /* -------- process response files (if any) and set the remaining
1181
     elements of argv */
1182
24
  if (PARM->verbosity) printf("%s: #### calling hestResponseFiles\n", me);
1183
24
  if (_hestResponseFiles(argv, _argv, PARM, mop)) {
1184
    airMopError(mop); return 1;
1185
  }
1186
24
  if (PARM->verbosity) printf("%s: #### hestResponseFiles done!\n", me);
1187
  /*
1188
  _hestPrintArgv(argc, argv);
1189
  */
1190
1191
  /* -------- extract flags and their associated parameters from argv */
1192
24
  if (PARM->verbosity) printf("%s: #### calling hestExtractFlagged\n", me);
1193

48
  if (_hestExtractFlagged(prms, nprm, appr,
1194
24
                           &argc, argv,
1195
                           opt,
1196
                           err, PARM, mop)) {
1197
    airMopError(mop); return 1;
1198
  }
1199
24
  if (PARM->verbosity) printf("%s: #### hestExtractFlagged done!\n", me);
1200
  /*
1201
  _hestPrintArgv(argc, argv);
1202
  */
1203
1204
  /* -------- extract args for unflagged options */
1205
24
  if (PARM->verbosity) printf("%s: #### calling hestExtractUnflagged\n", me);
1206

48
  if (_hestExtractUnflagged(prms, nprm,
1207
24
                            &argc, argv,
1208
                            opt,
1209
                            err, PARM, mop)) {
1210
    airMopError(mop); return 1;
1211
  }
1212
24
  if (PARM->verbosity) printf("%s: #### hestExtractUnflagged done!\n", me);
1213
1214
  /* currently, any left over arguments indicate error */
1215
24
  if (argc) {
1216
    sprintf(err, "%sunexpected arg%s: \"%s\"", ME,
1217
            ('-' == argv[0][0]
1218
             ? " (or unrecognized flag)"
1219
             : ""), argv[0]);
1220
    airMopError(mop); return 1;
1221
  }
1222
1223
  /* -------- learn defaults */
1224
24
  if (PARM->verbosity) printf("%s: #### calling hestDefaults\n", me);
1225
24
  if (_hestDefaults(prms, udflt, nprm, appr,
1226
                    opt,
1227
                    err, PARM, mop)) {
1228
    airMopError(mop); return 1;
1229
  }
1230
24
  if (PARM->verbosity) printf("%s: #### hestDefaults done!\n", me);
1231
1232
  /* remove quotes from strings
1233
         if greedy wasn't turned on for strings, then we have no hope
1234
         of capturing filenames with spaces. */
1235
24
  if ( PARM->greedySingleString ) {
1236
380
    for (i=0; i<numOpts; i++) {
1237
166
      param = prms[i];
1238
      param_copy = NULL;
1239

318
      if (param && strstr(param, " ")) {
1240
        start_index = 0;
1241
51
        end_index = strlen(param)-1;
1242
51
        if (param[start_index] == '\"')
1243
          start_index++;
1244
51
        if (param[end_index] == '\"')
1245
           end_index--;
1246
51
        param_copy = AIR_CALLOC(end_index-start_index+2, char);
1247
51
        strncpy(param_copy,&param[start_index],end_index-start_index+1);
1248
51
        param_copy[end_index-start_index+1] = '\0';
1249
51
        strcpy(param,param_copy);
1250
51
        free(param_copy);
1251
51
      }
1252
    }
1253
  }
1254
1255
  /* -------- now, the actual parsing of values */
1256
  /* hammerhead problems in _hestSetValues */
1257
24
  if (PARM->verbosity) printf("%s: #### calling hestSetValues\n", me);
1258
24
  ret = _hestSetValues(prms, udflt, nprm, appr,
1259
                       opt,
1260
                       err, PARM, mop);
1261
24
  if (ret) {
1262
    airMopError(mop); return ret;
1263
  }
1264
1265
24
  if (PARM->verbosity) printf("%s: #### hestSetValues done!\n", me);
1266
#undef PARM
1267
1268
24
  airMopOkay(mop);
1269
24
  return 0;
1270
24
}
1271
1272
/*
1273
******** hestParseFree()
1274
**
1275
** free()s whatever was allocated by hestParse()
1276
**
1277
** returns NULL only to facilitate use with the airMop functions.
1278
** You should probably just ignore this quirk.
1279
*/
1280
void *
1281
hestParseFree(hestOpt *opt) {
1282
  int op, i, numOpts;
1283
  unsigned int ui;
1284
  void **vP;
1285
  void ***vAP;
1286
  char **str;
1287
  char ***strP;
1288
1289
48
  numOpts = _hestNumOpts(opt);
1290
380
  for (op=0; op<numOpts; op++) {
1291
    /*
1292
    printf("!hestParseFree: op = %d/%d -> kind = %d; type = %d; alloc = %d\n",
1293
           op, numOpts-1, opt[op].kind, opt[op].type, opt[op].alloc);
1294
    */
1295
196
    vP = (void **)opt[op].valueP;
1296
196
    vAP = (void ***)opt[op].valueP;
1297
    str = (char **)opt[op].valueP;
1298
    strP = (char ***)opt[op].valueP;
1299

196
    switch (opt[op].alloc) {
1300
    case 0:
1301
      /* nothing was allocated */
1302
      break;
1303
    case 1:
1304
22
      if (airTypeOther != opt[op].type) {
1305
22
        *vP = airFree(*vP);
1306
22
      }
1307
      else {
1308
        /* alloc is one either because we parsed one thing, and we have a
1309
           destroy callback, or, because we parsed a dynamically-created array
1310
           of things, and we don't have a destroy callback */
1311
        if (opt[op].CB->destroy) {
1312
          *vP = opt[op].CB->destroy(*vP);
1313
        }
1314
        else {
1315
          *vP = airFree(*vP);
1316
        }
1317
      }
1318
      break;
1319
    case 2:
1320
6
      if (airTypeString == opt[op].type) {
1321
30
        for (i=0; i<(int)opt[op].min; i++) { /* HEY scrutinize casts */
1322
12
          str[i] = (char *)airFree(str[i]);
1323
        }
1324
      }
1325
      else {
1326
        for (i=0; i<(int)opt[op].min; i++) { /* HEY scrutinize casts */
1327
          vP[i] = opt[op].CB->destroy(vP[i]);
1328
        }
1329
      }
1330
      break;
1331
    case 3:
1332
2
      if (airTypeString == opt[op].type) {
1333
        for (ui=0; ui<*(opt[op].sawP); ui++) {
1334
          (*strP)[ui] = (char *)airFree((*strP)[ui]);
1335
        }
1336
        *strP = (char **)airFree(*strP);
1337
      }
1338
      else {
1339
10
        for (ui=0; ui<*(opt[op].sawP); ui++) {
1340
4
          (*vAP)[ui] = opt[op].CB->destroy((*vAP)[ui]);
1341
        }
1342
2
        *vAP = (void **)airFree(*vAP);
1343
      }
1344
      break;
1345
    }
1346
  }
1347
24
  return NULL;
1348
}
1349
1350
/*
1351
******** hestParseOrDie()
1352
**
1353
** dumb little function which encapsulate a common usage of hest:
1354
** first, make sure hestOpt is valid with hestOptCheck().  Then,
1355
** if argc is 0 (and !parm->noArgsIsNoProblem): maybe show
1356
**    info, usage, and glossary, all according to given flags, then exit(1)
1357
** if parsing failed: show error message, and maybe usage and glossary,
1358
**    again according to boolean flags, then exit(1)
1359
** if parsing succeeded: return
1360
*/
1361
void
1362
hestParseOrDie(hestOpt *opt, int argc, const char **argv,
1363
               hestParm *parm,
1364
               const char *me, const char *info,
1365
               int doInfo, int doUsage, int doGlossary) {
1366
  int E;
1367
  int argcBad;
1368
32
  char *errS;
1369
1370
16
  if (opt) {
1371
16
    if (hestOptCheck(opt, &errS)) {
1372
      fprintf(stderr, "ERROR in hest usage:\n%s\n", errS); free(errS);
1373
      exit(1);
1374
    }
1375
    E = 0;
1376
    /* argc is good if its non-zero, or (else) being zero is ok */
1377

32
    argcBad = !(argc || (parm && parm->noArgsIsNoProblem));
1378

32
    if ( argcBad ||
1379
16
         (E = hestParse(opt, argc, argv, &errS, parm)) ) {
1380
      if (E) {
1381
        if (argv[0] && !strcmp(argv[0], "--version")) {
1382
          /* print version info and bail */
1383
          char vbuff[AIR_STRLEN_LARGE];
1384
          airTeemVersionSprint(vbuff);
1385
          printf("%s\n", vbuff);
1386
          hestParmFree(parm);
1387
          hestOptFree(opt);
1388
          exit(0);
1389
        } else if (argv[0] && !strcmp(argv[0], "--help")) {
1390
          /* actually, not an error, they were asking for help */
1391
          E = 0;
1392
        } else {
1393
          fprintf(stderr, "ERROR: %s\n", errS);
1394
        }
1395
        free(errS);
1396
      }
1397
      if (!E) {
1398
        /* no error, just !argc */
1399
        if (doInfo && info) hestInfo(stdout, me?me:"", info, parm);
1400
      }
1401
      if (doUsage) hestUsage(E ? stderr : stdout, opt, me?me:"", parm);
1402
      if (doGlossary) hestGlossary(E ? stderr : stdout, opt, parm);
1403
      hestParmFree(parm);
1404
      hestOptFree(opt);
1405
      exit(1);
1406
    }
1407
  }
1408
1409
  return;
1410
16
}