GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/hest/methodsHest.c Lines: 171 215 79.5 %
Date: 2017-05-26 Branches: 83 136 61.0 %

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 "hest.h"
25
#include "privateHest.h"
26
#include <limits.h>
27
28
const int
29
hestPresent = 42;
30
31
hestParm *
32
hestParmNew() {
33
  hestParm *parm;
34
35
84
  parm = AIR_CALLOC(1, hestParm);
36
42
  if (parm) {
37
42
    parm->verbosity = hestVerbosity;
38
42
    parm->respFileEnable = hestRespFileEnable;
39
42
    parm->elideSingleEnumType = hestElideSingleEnumType;
40
42
    parm->elideSingleOtherType = hestElideSingleOtherType;
41
42
    parm->elideSingleOtherDefault = hestElideSingleOtherDefault;
42
42
    parm->greedySingleString = hestGreedySingleString;
43
42
    parm->elideSingleNonExistFloatDefault =
44
42
      hestElideSingleNonExistFloatDefault;
45
42
    parm->elideMultipleNonExistFloatDefault =
46
42
      hestElideMultipleNonExistFloatDefault;
47
42
    parm->elideSingleEmptyStringDefault =
48
42
      hestElideSingleEmptyStringDefault;
49
42
    parm->elideMultipleEmptyStringDefault =
50
42
      hestElideMultipleEmptyStringDefault;
51
42
    parm->cleverPluralizeOtherY = hestCleverPluralizeOtherY;
52
42
    parm->columns = hestColumns;
53
42
    parm->respFileFlag = hestRespFileFlag;
54
42
    parm->respFileComment = hestRespFileComment;
55
42
    parm->varParamStopFlag = hestVarParamStopFlag;
56
42
    parm->multiFlagSep = hestMultiFlagSep;
57
42
  }
58
42
  return parm;
59
}
60
61
hestParm *
62
hestParmFree(hestParm *parm) {
63
64
84
  airFree(parm);
65
42
  return NULL;
66
}
67
68
void
69
_hestOptInit(hestOpt *opt) {
70
71
1742
  opt->flag = opt->name = NULL;
72
871
  opt->type = opt->min = opt->max = 0;
73
871
  opt->valueP = NULL;
74
871
  opt->dflt = opt->info = NULL;
75
871
  opt->sawP = NULL;
76
871
  opt->enm = NULL;
77
871
  opt->CB = NULL;
78
871
  opt->sawP = NULL;
79
871
  opt->kind = opt->alloc = 0;
80
871
  opt->source = hestSourceUnknown;
81
871
}
82
83
/*
84
hestOpt *
85
hestOptNew(void) {
86
  hestOpt *opt;
87
88
  opt = AIR_CALLOC(1, hestOpt);
89
  if (opt) {
90
    _hestOptInit(opt);
91
    opt->min = 1;
92
  }
93
  return opt;
94
}
95
*/
96
97
/*
98
** as of Sept 2013 this returns information: the index of the
99
** option just added.  Returns UINT_MAX in case of error.
100
*/
101
unsigned int
102
hestOptAdd(hestOpt **optP,
103
           const char *flag, const char *name,
104
           int type, int min, int max,
105
           void *valueP, const char *dflt, const char *info, ...) {
106
  hestOpt *ret = NULL;
107
  int num;
108
1742
  va_list ap;
109
  unsigned int retIdx;
110
111
871
  if (!optP)
112
    return UINT_MAX;
113
114
2482
  num = *optP ? _hestNumOpts(*optP) : 0;
115
871
  if (!( ret = AIR_CALLOC(num+2, hestOpt) )) {
116
    return UINT_MAX;
117
  }
118
871
  if (num)
119
740
    memcpy(ret, *optP, num*sizeof(hestOpt));
120
  retIdx = AIR_UINT(num);
121
871
  ret[num].flag = airStrdup(flag);
122
871
  ret[num].name = airStrdup(name);
123
871
  ret[num].type = type;
124
871
  ret[num].min = min;
125
871
  ret[num].max = max;
126
871
  ret[num].valueP = valueP;
127
871
  ret[num].dflt = airStrdup(dflt);
128
871
  ret[num].info = airStrdup(info);
129
  /* initialize the things that may be set below */
130
871
  ret[num].sawP = NULL;
131
871
  ret[num].enm = NULL;
132
871
  ret[num].CB = NULL;
133
  /* seems to be redundant with above _hestOptInit() */
134
871
  ret[num].source = hestSourceUnknown;
135
  /* deal with var args */
136
871
  if (5 == _hestKind(&(ret[num]))) {
137
58
    va_start(ap, info);
138
174
    ret[num].sawP = va_arg(ap, unsigned int*);
139
58
    va_end(ap);
140
58
  }
141
871
  if (airTypeEnum == type) {
142
43
    va_start(ap, info);
143
129
    va_arg(ap, unsigned int*);  /* skip sawP */
144
129
    ret[num].enm = va_arg(ap, airEnum*);
145
43
    va_end(ap);
146
43
  }
147
871
  if (airTypeOther == type) {
148
168
    va_start(ap, info);
149
504
    va_arg(ap, unsigned int*);  /* skip sawP */
150
504
    va_arg(ap, airEnum*);       /* skip enm */
151
504
    ret[num].CB = va_arg(ap, hestCB*);
152
168
    va_end(ap);
153
168
  }
154
871
  _hestOptInit(&(ret[num+1]));
155
871
  ret[num+1].min = 1;
156
871
  if (*optP)
157
740
    free(*optP);
158
871
  *optP = ret;
159
871
  return retIdx;
160
871
}
161
162
void
163
_hestOptFree(hestOpt *opt) {
164
165
1742
  opt->flag = (char *)airFree(opt->flag);
166
871
  opt->name = (char *)airFree(opt->name);
167
871
  opt->dflt = (char *)airFree(opt->dflt);
168
871
  opt->info = (char *)airFree(opt->info);
169
871
  return;
170
}
171
172
hestOpt *
173
hestOptFree(hestOpt *opt) {
174
  int op, num;
175
176
262
  if (!opt)
177
    return NULL;
178
179
131
  num = _hestNumOpts(opt);
180
131
  if (opt[num].min) {
181
    /* we only try to free this if it looks like something we allocated */
182
2004
    for (op=0; op<num; op++) {
183
871
      _hestOptFree(opt+op);
184
    }
185
131
    free(opt);
186
131
  }
187
131
  return NULL;
188
131
}
189
190
int
191
hestOptCheck(hestOpt *opt, char **errP) {
192
32
  char *err, me[]="hestOptCheck";
193
  hestParm *parm;
194
  int big;
195
196
16
  big = _hestErrStrlen(opt, 0, NULL);
197
16
  if (!( err = AIR_CALLOC(big, char) )) {
198
    fprintf(stderr, "%s PANIC: couldn't allocate error message "
199
            "buffer (size %d)\n", me, big);
200
    if (errP)
201
      *errP = NULL;
202
    return 1;
203
  }
204
16
  parm = hestParmNew();
205

32
  if (_hestPanic(opt, err, parm)) {
206
    /* problems */
207
16
    if (errP) {
208
      /* they did give a pointer address; they'll free it */
209
      *errP = err;
210
    }
211
    else {
212
      /* they didn't give a pointer address; their loss */
213
      free(err);
214
    }
215
    hestParmFree(parm);
216
    return 1;
217
  }
218
  /* else, no problems */
219
16
  if (errP)
220
16
    *errP = NULL;
221
16
  free(err);
222
16
  hestParmFree(parm);
223
16
  return 0;
224
16
}
225
226
227
/*
228
** _hestIdent()
229
**
230
** how to identify an option in error and usage messages
231
*/
232
char *
233
_hestIdent(char *ident, hestOpt *opt, const hestParm *parm, int brief) {
234
332
  char copy[AIR_STRLEN_HUGE], *sep;
235
236

332
  if (opt->flag && (sep = strchr(opt->flag, parm->multiFlagSep))) {
237
    strcpy(copy, opt->flag);
238
    sep = strchr(copy, parm->multiFlagSep);
239
    *sep = '\0';
240
    if (brief)
241
      sprintf(ident, "-%s%c--%s option", copy, parm->multiFlagSep, sep+1);
242
    else
243
      sprintf(ident, "-%s option", copy);
244
  }
245
  else {
246
498
    sprintf(ident, "%s%s%s option",
247
            opt->flag ? "\"-"      : "<",
248
            opt->flag ? opt->flag : opt->name,
249
            opt->flag ? "\""       : ">");
250
  }
251
166
  return ident;
252
166
}
253
254
int
255
_hestMax(int max) {
256
257
19010
  if (-1 == max) {
258
    max = INT_MAX;
259
  }
260
9505
  return max;
261
}
262
263
int
264
_hestKind(const hestOpt *opt) {
265
  int max;
266
267
5018
  max = _hestMax(opt->max);
268
2509
  if (!( (int)opt->min <= max )) {    /* HEY scrutinize casts */
269
    /* invalid */
270
    return -1;
271
  }
272
273
2509
  if (0 == opt->min && 0 == max) {
274
    /* flag */
275
226
    return 1;
276
  }
277
278
2283
  if (1 == opt->min && 1 == max) {
279
    /* single fixed parameter */
280
1877
    return 2;
281
  }
282
283

653
  if (2 <= opt->min && 2 <= max && (int)opt->min == max) {  /* HEY scrutinize casts */
284
    /* multiple fixed parameters */
285
229
    return 3;
286
  }
287
288
177
  if (0 == opt->min && 1 == max) {
289
    /* single optional parameter */
290
3
    return 4;
291
  }
292
293
  /* else multiple variable parameters */
294
174
  return 5;
295
2509
}
296
297
void
298
_hestPrintArgv(int argc, char **argv) {
299
  int a;
300
301
  printf("argc=%d : ", argc);
302
  for (a=0; a<argc; a++) {
303
    printf("%s ", argv[a]);
304
  }
305
  printf("\n");
306
}
307
308
/*
309
** _hestWhichFlag()
310
**
311
** given a string in "flag" (with the hypen prefix) finds which of
312
** the flags in the given array of options matches that.  Returns
313
** the index of the matching option, or -1 if there is no match,
314
** but returns -2 if the flag is the end-of-variable-parameter
315
** marker (according to parm->varParamStopFlag)
316
*/
317
int
318
_hestWhichFlag(hestOpt *opt, char *flag, const hestParm *parm) {
319
534
  char buff[AIR_STRLEN_HUGE], copy[AIR_STRLEN_HUGE], *sep;
320
  int op, numOpts;
321
322
267
  numOpts = _hestNumOpts(opt);
323
267
  if (parm->verbosity)
324
    printf("_hestWhichFlag: flag = %s, numOpts = %d\n", flag, numOpts);
325

6672
  for (op=0; op<numOpts; op++) {
326
4290
    if (parm->verbosity)
327
      printf("_hestWhichFlag: op = %d\n", op);
328
2066
    if (!opt[op].flag)
329
      continue;
330
2066
    if (strchr(opt[op].flag, parm->multiFlagSep) ) {
331
      strcpy(copy, opt[op].flag);
332
      sep = strchr(copy, parm->multiFlagSep);
333
      *sep = '\0';
334
      /* first try the short version */
335
      sprintf(buff, "-%s", copy);
336
      if (!strcmp(flag, buff))
337
        return op;
338
      /* then try the long version */
339
      sprintf(buff, "--%s", sep+1);
340
      if (!strcmp(flag, buff))
341
        return op;
342
    }
343
    else {
344
      /* flag has only the short version */
345
2066
      sprintf(buff, "-%s", opt[op].flag);
346
2066
      if (!strcmp(flag, buff))
347
109
        return op;
348
    }
349
  }
350
158
  if (parm->verbosity)
351
    printf("_hestWhichFlag: numOpts = %d\n", numOpts);
352
158
  if (parm->varParamStopFlag) {
353
158
    sprintf(buff, "-%c", parm->varParamStopFlag);
354
158
    if (parm->verbosity)
355
      printf("_hestWhichFlag: flag = %s, buff = %s\n", flag, buff);
356
158
    if (!strcmp(flag, buff))
357
      return -2;
358
  }
359
158
  if (parm->verbosity)
360
    printf("_hestWhichFlag: numOpts = %d\n", numOpts);
361
158
  return -1;
362
267
}
363
364
365
/*
366
** _hestCase()
367
**
368
** helps figure out logic of interpreting parameters and defaults
369
** for kind 4 and kind 5 options.
370
*/
371
int
372
_hestCase(hestOpt *opt, int *udflt, unsigned int *nprm, int *appr, int op) {
373
374

24
  if (opt[op].flag && !appr[op]) {
375
    return 0;
376
  }
377

16
  else if ( (4 == opt[op].kind && udflt[op]) ||
378
16
            (5 == opt[op].kind && !nprm[op]) ) {
379
    return 1;
380
  }
381
  else {
382
8
    return 2;
383
  }
384
8
}
385
386
/*
387
** _hestExtract()
388
**
389
** takes "pnum" parameters, starting at "base", out of the
390
** given argv, and puts them into a string WHICH THIS FUNCTION
391
** ALLOCATES, and also adjusts the argc value given as "*argcP".
392
*/
393
char *
394
_hestExtract(int *argcP, char **argv, unsigned int base, unsigned int pnum) {
395
  unsigned int len, pidx;
396
  char *ret;
397
398
412
  if (!pnum)
399
3
    return NULL;
400
401
  len = 0;
402
928
  for (pidx=0; pidx<pnum; pidx++) {
403
261
    if (base+pidx==AIR_UINT(*argcP)) {
404
      return NULL;
405
    }
406
261
    len += AIR_UINT(strlen(argv[base+pidx]));
407
261
    if (strstr(argv[base+pidx], " ")) {
408
      len += 2;
409
    }
410
  }
411
203
  len += pnum;
412
203
  ret = AIR_CALLOC(len, char);
413
203
  strcpy(ret, "");
414
928
  for (pidx=0; pidx<pnum; pidx++) {
415
    /* if a single element of argv has spaces in it, someone went
416
       to the trouble of putting it in quotes, and we perpetuate
417
       the favor by quoting it when we concatenate all the argv
418
       elements together, so that airParseStrS will recover it as a
419
       single string again */
420
261
    if (strstr(argv[base+pidx], " ")) {
421
      strcat(ret, "\"");
422
    }
423
    /* HEY: if there is a '\"' character in this string, quoted or
424
       not, its going to totally confuse later parsing */
425
261
    strcat(ret, argv[base+pidx]);
426
261
    if (strstr(argv[base+pidx], " ")) {
427
      strcat(ret, "\"");
428
    }
429
261
    if (pidx < pnum-1)
430
58
      strcat(ret, " ");
431
  }
432
3178
  for (pidx=base+pnum; pidx<=AIR_UINT(*argcP); pidx++) {
433
1386
    argv[pidx-pnum] = argv[pidx];
434
  }
435
203
  *argcP -= pnum;
436
203
  return ret;
437
206
}
438
439
int
440
_hestNumOpts(const hestOpt *opt) {
441
  int num = 0;
442
443

47245
  while (opt[num].flag || opt[num].name || opt[num].type) {
444
12083
    num++;
445
  }
446
1790
  return num;
447
}
448