GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/unrrdu/flotsam.c Lines: 59 292 20.2 %
Date: 2017-05-26 Branches: 27 170 15.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 "unrrdu.h"
25
#include "privateUnrrdu.h"
26
27
#include <ctype.h>
28
29
const int
30
unrrduPresent = 42;
31
32
const char *
33
unrrduBiffKey = "unrrdu";
34
35
/* number of columns that hest will used */
36
unsigned int
37
unrrduDefNumColumns = 78;
38
39
/*
40
******** unrrduCmdList[]
41
**
42
** NULL-terminated array of unrrduCmd pointers, as ordered by UNRRDU_MAP macro
43
*/
44
unrrduCmd *
45
unrrduCmdList[] = {
46
  UNRRDU_MAP(UNRRDU_LIST)
47
  NULL
48
};
49
50
/*
51
******** unrrduCmdMain
52
**
53
** A "main" function for unu-like programs, which is very similar to
54
** teem/src/bin/unu.c:main(), and
55
** teem/src/bin/tend.c:main(), and
56
** teem/src/limn/test/lpu.c:main().
57
** With more time (and a major Teem release), this function may change,
58
** and those programs may use this.
59
**
60
** A sneaky but basic issue is the const-correctness of how the hestParm
61
** is used; we'd like to take a const hestParm* to communicate parameters
62
** the caller has set, but the show-stopper is that unrrduCmd->main()
63
** takes a non-const hestParm, and it has to be that way, because some
64
** unu commands alter the given hparm (which probably shouldn't happen).
65
** Until that's fixed, we have a non-const hestParm* coming in here.
66
*/
67
int
68
unrrduCmdMain(int argc, const char **argv,
69
              const char *cmd, const char *title,
70
              const unrrduCmd *const *cmdList,
71
              hestParm *_hparm, FILE *fusage) {
72
  int i, ret;
73
  const char *me;
74
  char *argv0 = NULL;
75
  hestParm *hparm;
76
  airArray *mop;
77
78
  me = argv[0];
79
80
  /* parse environment variables first, in case they break nrrdDefault*
81
     or nrrdState* variables in a way that nrrdSanity() should see */
82
  nrrdDefaultGetenv();
83
  nrrdStateGetenv();
84
85
  /* unu does some unu-specific environment-variable handling here */
86
87
  nrrdSanityOrDie(me);
88
89
  mop = airMopNew();
90
  if (_hparm) {
91
    hparm = _hparm;
92
  } else {
93
    hparm = hestParmNew();
94
    airMopAdd(mop, hparm, (airMopper)hestParmFree, airMopAlways);
95
    hparm->elideSingleEnumType = AIR_TRUE;
96
    hparm->elideSingleOtherType = AIR_TRUE;
97
    hparm->elideSingleOtherDefault = AIR_FALSE;
98
    hparm->elideSingleNonExistFloatDefault = AIR_TRUE;
99
    hparm->elideMultipleNonExistFloatDefault = AIR_TRUE;
100
    hparm->elideSingleEmptyStringDefault = AIR_TRUE;
101
    hparm->elideMultipleEmptyStringDefault = AIR_TRUE;
102
    hparm->cleverPluralizeOtherY = AIR_TRUE;
103
    /* learning columns from current window; if ioctl is available
104
    if (1) {
105
      struct winsize ws;
106
      ioctl(1, TIOCGWINSZ, &ws);
107
      hparm->columns = ws.ws_col - 1;
108
    }
109
    */
110
    hparm->columns = 78;
111
  }
112
113
  /* if there are no arguments, then we give general usage information */
114
  if (1 >= argc) {
115
    /* this is like unrrduUsageUnu() */
116
    unsigned int ii, maxlen = 0;
117
    char *buff, *fmt, tdash[] = "--- %s ---";
118
    for (ii=0; cmdList[ii]; ii++) {
119
      if (cmdList[ii]->hidden) {
120
        continue;
121
      }
122
      maxlen = AIR_MAX(maxlen, AIR_UINT(strlen(cmdList[ii]->name)));
123
    }
124
    if (!maxlen) {
125
      fprintf(fusage, "%s: problem: maxlen = %u\n", me, maxlen);
126
      airMopError(mop); return 1;
127
    }
128
    buff = AIR_CALLOC(strlen(tdash) + strlen(title) + 1, char);
129
    airMopAdd(mop, buff, airFree, airMopAlways);
130
    sprintf(buff, tdash, title);
131
    fmt = AIR_CALLOC(hparm->columns + strlen(buff) + 1, char); /* generous */
132
    airMopAdd(mop, buff, airFree, airMopAlways);
133
    sprintf(fmt, "%%%us\n",
134
            AIR_UINT((hparm->columns-strlen(buff))/2 + strlen(buff) - 1));
135
    fprintf(fusage, fmt, buff);
136
137
    for (ii=0; cmdList[ii]; ii++) {
138
      unsigned int cc, len;
139
      if (cmdList[ii]->hidden) {
140
        continue;
141
      }
142
      len = AIR_UINT(strlen(cmdList[ii]->name));
143
      strcpy(buff, "");
144
      for (cc=len; cc<maxlen; cc++)
145
        strcat(buff, " ");
146
      strcat(buff, cmd);
147
      strcat(buff, " ");
148
      strcat(buff, cmdList[ii]->name);
149
      strcat(buff, " ... ");
150
      len = strlen(buff);
151
      fprintf(fusage, "%s", buff);
152
      _hestPrintStr(fusage, len, len, hparm->columns,
153
                    cmdList[ii]->info, AIR_FALSE);
154
    }
155
    airMopError(mop);
156
    return 1;
157
  }
158
  /* else, we see if its --version */
159
  if (!strcmp("--version", argv[1])) {
160
    char vbuff[AIR_STRLEN_LARGE];
161
    airTeemVersionSprint(vbuff);
162
    printf("%s\n", vbuff);
163
    exit(0);
164
  }
165
  /* else, we should see if they're asking for a command we know about */
166
  for (i=0; cmdList[i]; i++) {
167
    if (!strcmp(argv[1], cmdList[i]->name)) {
168
      break;
169
    }
170
    /* if user typed "prog --help" we treat it as "prog about",
171
       but only if there is an "about" command */
172
    if (!strcmp("--help", argv[1])
173
        && !strcmp("about", cmdList[i]->name)) {
174
      break;
175
    }
176
  }
177
  if (cmdList[i]) {
178
    /* yes, we have that command */
179
    /* initialize variables used by the various commands */
180
    argv0 = AIR_CALLOC(strlen(cmd) + strlen(argv[1]) + 2, char);
181
182
    airMopMem(mop, &argv0, airMopAlways);
183
    sprintf(argv0, "%s %s", cmd, argv[1]);
184
185
    /* run the individual command, saving its exit status */
186
    ret = cmdList[i]->main(argc-2, argv+2, argv0, hparm);
187
  } else {
188
    fprintf(stderr, "%s: unrecognized command: \"%s\"; type \"%s\" for "
189
            "complete list\n", me, argv[1], me);
190
    ret = 1;
191
  }
192
193
  airMopDone(mop, ret);
194
  return ret;
195
}
196
197
/*
198
******** unrrduUsageUnu
199
**
200
** prints out a little banner, and a listing of all available commands
201
** with their one-line descriptions
202
*/
203
void
204
unrrduUsageUnu(const char *me, hestParm *hparm) {
205
2
  char buff[AIR_STRLEN_LARGE], fmt[AIR_STRLEN_LARGE];
206
  unsigned int cmdi, chi, len, maxlen;
207
208
  maxlen = 0;
209
142
  for (cmdi=0; unrrduCmdList[cmdi]; cmdi++) {
210
210
    maxlen = AIR_MAX(maxlen, AIR_UINT(strlen(unrrduCmdList[cmdi]->name)));
211
  }
212
213
1
  sprintf(buff, "--- unu: Utah Nrrd Utilities command-line interface ---");
214
1
  len = AIR_UINT(strlen(buff));
215
3
  sprintf(fmt, "%%%us\n", (hparm->columns > len
216
                           ? hparm->columns-len
217
                           : 0)/2 + len - 1);
218
1
  fprintf(stdout, fmt, buff);
219
142
  for (cmdi=0; unrrduCmdList[cmdi]; cmdi++) {
220
    int nofft;
221
70
    if (unrrduCmdList[cmdi]->hidden) {
222
      /* nothing to see here! */
223
7
      continue;
224
    }
225
127
    nofft = !strcmp(unrrduCmdList[cmdi]->name, "fft") && !nrrdFFTWEnabled;
226
63
    len = AIR_UINT(strlen(unrrduCmdList[cmdi]->name));
227
63
    len += !!nofft;
228
63
    strcpy(buff, "");
229
718
    for (chi=len; chi<maxlen; chi++)
230
296
      strcat(buff, " ");
231
63
    if (nofft) {
232
1
      strcat(buff, "(");
233
1
    }
234
63
    strcat(buff, me);
235
63
    strcat(buff, " ");
236
63
    strcat(buff, unrrduCmdList[cmdi]->name);
237
63
    strcat(buff, " ... ");
238
63
    len = AIR_UINT(strlen(buff));
239
63
    fprintf(stdout, "%s", buff);
240
63
    if (nofft) {
241
      char *infop;
242
      /* luckily, still fits within 80 columns */
243
1
      fprintf(stdout, "Not Enabled: ");
244
1
      infop = AIR_CALLOC(strlen(unrrduCmdList[cmdi]->info) + 2, char);
245
1
      sprintf(infop, "%s)", unrrduCmdList[cmdi]->info);
246
1
      _hestPrintStr(stdout, len, len, hparm->columns,
247
                    infop, AIR_FALSE);
248
1
      free(infop);
249
1
    } else {
250
124
      _hestPrintStr(stdout, len, len, hparm->columns,
251
62
                    unrrduCmdList[cmdi]->info, AIR_FALSE);
252
    }
253
63
  }
254
  return;
255
1
}
256
257
/*
258
******** unrrduUsage
259
**
260
** A generic version of the usage command, which can be used by other
261
** programs that are leveraging the unrrduCmd infrastructure.
262
**
263
** does not use biff
264
*/
265
int
266
unrrduUsage(const char *me, hestParm *hparm,
267
            const char *title, unrrduCmd **cmdList) {
268
2
  char buff[AIR_STRLEN_LARGE], fmt[AIR_STRLEN_LARGE];
269
  unsigned int cmdi, chi, len, maxlen;
270
271
1
  if (!(title && cmdList)) {
272
    /* got NULL pointer */
273
    return 1;
274
  }
275
  maxlen = 0;
276
82
  for (cmdi=0; cmdList[cmdi]; cmdi++) {
277
120
    maxlen = AIR_MAX(maxlen, AIR_UINT(strlen(cmdList[cmdi]->name)));
278
  }
279
280
1
  sprintf(buff, "--- %s ---", title);
281
1
  len = AIR_UINT(strlen(buff));
282
3
  sprintf(fmt, "%%%us\n", (hparm->columns > len
283
                           ? hparm->columns-len
284
                           : 0)/2 + len - 1);
285
1
  fprintf(stdout, fmt, buff);
286
82
  for (cmdi=0; cmdList[cmdi]; cmdi++) {
287
40
    len = AIR_UINT(strlen(cmdList[cmdi]->name));
288
40
    strcpy(buff, "");
289
394
    for (chi=len; chi<maxlen; chi++)
290
157
      strcat(buff, " ");
291
40
    strcat(buff, me);
292
40
    strcat(buff, " ");
293
40
    strcat(buff, cmdList[cmdi]->name);
294
40
    strcat(buff, " ... ");
295
40
    len = AIR_UINT(strlen(buff));
296
40
    fprintf(stdout, "%s", buff);
297
80
    _hestPrintStr(stdout, len, len, hparm->columns,
298
40
                  cmdList[cmdi]->info, AIR_FALSE);
299
  }
300
1
  return 0;
301
1
}
302
303
/* --------------------------------------------------------- */
304
/* --------------------------------------------------------- */
305
/* --------------------------------------------------------- */
306
307
/*
308
******** unrrduHestPosCB
309
**
310
** For parsing position along an axis. Can be a simple (long) integer,
311
** or M to signify last position along axis (#samples-1), or
312
** M+<int> or M-<int> to signify some position relative to the end.
313
**
314
** It can also be m+<int> to signify some position relative to some
315
** "minimum", assuming that a minimum position is being specified
316
** at the same time as this one.  Obviously, there has to be some
317
** error handling to make sure that no one is trying to define a
318
** minimum position with respect to itself.  And, the ability to
319
** specify a position as "m+<int>" shouldn't be advertised in situations
320
** (unu slice) where you only have one position, rather than an interval
321
** between two positions (unu crop and unu pad).
322
**
323
** This information is represented with two integers, pos[0] and pos[1]:
324
** pos[0] ==  0: pos[1] gives the absolute position
325
** pos[0] ==  1: pos[1] gives the position relative to the last index
326
** pos[0] == -1: pos[1] gives the position relative to a "minimum" position
327
*/
328
int
329
unrrduParsePos(void *ptr, char *str, char err[AIR_STRLEN_HUGE]) {
330
  char me[]="unrrduParsePos";
331
  long int *pos;
332
333
  if (!(ptr && str)) {
334
    sprintf(err, "%s: got NULL pointer", me);
335
    return 1;
336
  }
337
  pos = (long int*)ptr;
338
  if (!strcmp("M", str)) {
339
    pos[0] = 1;
340
    pos[1] = 0;
341
    return 0;
342
  }
343
  if ('M' == str[0]) {
344
    if (!( '-' == str[1] || '+' == str[1] )) {
345
      sprintf(err, "%s: \'M\' can be followed only by \'+\' or \'-\'", me);
346
      return 1;
347
    }
348
    pos[0] = 1;
349
    if (1 != sscanf(str+1, "%ld", &(pos[1]))) {
350
      sprintf(err, "%s: can't parse \"%s\" as M+<int> or M-<int>", me, str);
351
      return 1;
352
    }
353
    return 0;
354
  }
355
  if ('m' == str[0]) {
356
    if ('+' != str[1]) {
357
      sprintf(err, "%s: \'m\' can only be followed by \'+\'", me);
358
      return 1;
359
    }
360
    pos[0] = -1;
361
    if (1 != sscanf(str+1, "%ld", &(pos[1]))) {
362
      sprintf(err, "%s: can't parse \"%s\" as m+<int>", me, str);
363
      return 1;
364
    }
365
    if (pos[1] < 0 ) {
366
      sprintf(err, "%s: int in m+<int> must be non-negative (not %ld)",
367
              me, pos[1]);
368
      return 1;
369
    }
370
    return 0;
371
  }
372
  /* else its just a plain unadorned integer */
373
  pos[0] = 0;
374
  if (1 != sscanf(str, "%ld", &(pos[1]))) {
375
    sprintf(err, "%s: can't parse \"%s\" as int", me, str);
376
    return 1;
377
  }
378
  return 0;
379
}
380
381
hestCB unrrduHestPosCB = {
382
  2*sizeof(long int),
383
  "position",
384
  unrrduParsePos,
385
  NULL
386
};
387
388
/* --------------------------------------------------------- */
389
/* --------------------------------------------------------- */
390
/* --------------------------------------------------------- */
391
392
/*
393
******** unrrduHestMaybeTypeCB
394
**
395
** although nrrdType is an airEnum that hest already knows how
396
** to parse, we want the ability to have "unknown" be a valid
397
** parsable value, contrary to how airEnums usually work with hest.
398
** For instance, we might want to use "unknown" to represent
399
** "same type as the input, whatever that is".
400
**
401
** 18 July 03: with new nrrdTypeDefault, this function becomes
402
** less of a hack, and more necessary, because the notion of an
403
** unknown but valid type (as a default type is) falls squarely
404
** outside the nrrdType airEnum framework.  Added a separate test
405
** for "default", even though currently nrrdTypeUnknown is the same
406
** value as nrrdTypeDefault.
407
*/
408
int
409
unrrduParseMaybeType(void *ptr, char *str, char err[AIR_STRLEN_HUGE]) {
410
  char me[]="unrrduParseMaybeType";
411
  int *typeP;
412
413
  /* fprintf(stderr, "!%s: str = \"%s\"\n", me, str); */
414
  if (!(ptr && str)) {
415
    sprintf(err, "%s: got NULL pointer", me);
416
    return 1;
417
  }
418
  typeP = (int*)ptr;
419
  if (!strcmp("unknown", str)) {
420
    *typeP = nrrdTypeUnknown;
421
  } else if (!strcmp("default", str)) {
422
    *typeP = nrrdTypeDefault;
423
  } else {
424
    *typeP = airEnumVal(nrrdType, str);
425
    if (nrrdTypeUnknown == *typeP) {
426
      sprintf(err, "%s: can't parse \"%s\" as type", me, str);
427
      return 1;
428
    }
429
  }
430
  /* fprintf(stderr, "!%s: *typeP = %d\n", me, *typeP); */
431
  return 0;
432
}
433
434
hestCB unrrduHestMaybeTypeCB = {
435
  sizeof(int),
436
  "type",
437
  unrrduParseMaybeType,
438
  NULL
439
};
440
441
/* --------------------------------------------------------- */
442
/* --------------------------------------------------------- */
443
/* --------------------------------------------------------- */
444
445
/*
446
******** unrrduHestBitsCB
447
**
448
** for parsing an int that can be 8, 16, or 32
449
*/
450
int
451
unrrduParseBits(void *ptr, char *str, char err[AIR_STRLEN_HUGE]) {
452
  char me[]="unrrduParseBits";
453
  unsigned int *bitsP;
454
455
  if (!(ptr && str)) {
456
    sprintf(err, "%s: got NULL pointer", me);
457
    return 1;
458
  }
459
  bitsP = (unsigned int*)ptr;
460
  if (1 != sscanf(str, "%u", bitsP)) {
461
    sprintf(err, "%s: can't parse \"%s\" as int", me, str);
462
    return 1;
463
  }
464
  if (!( 8 == *bitsP || 16 == *bitsP || 32 == *bitsP )) {
465
    sprintf(err, "%s: bits (%d) not 8, 16, or 32", me, *bitsP);
466
    return 1;
467
  }
468
  return 0;
469
}
470
471
hestCB unrrduHestBitsCB = {
472
  sizeof(int),
473
  "quantization bits",
474
  unrrduParseBits,
475
  NULL
476
};
477
478
/* --------------------------------------------------------- */
479
/* --------------------------------------------------------- */
480
/* --------------------------------------------------------- */
481
482
/*
483
******** unrrduParseScale
484
**
485
** parse the strings used with "unu resample -s" to indicate
486
** the new number of samples.
487
** =         : unrrduScaleNothing
488
** a         : unrrduScaleAspectRatio
489
** x<float>  : unrrduScaleMultiply
490
** x=<float> : unrrduScaleMultiply
491
** /<float>  : unrrduScaleDivide
492
** /=<float> : unrrduScaleDivide
493
** +=<uint>  : unrrduScaleAdd
494
** -=<uint>  : unrrduScaleSubstract
495
** <uint>    : unrrduScaleExact
496
** s<float>  : unrrduScaleSpacingTarget
497
*/
498
int
499
unrrduParseScale(void *ptr, char *str, char err[AIR_STRLEN_HUGE]) {
500
  char me[]="unrrduParseScale";
501
  double *scale;
502
  unsigned int num;
503
504
  if (!(ptr && str)) {
505
    sprintf(err, "%s: got NULL pointer", me);
506
    return 1;
507
  }
508
  scale = AIR_CAST(double *, ptr);
509
  if (!strcmp("=", str)) {
510
    scale[0] = AIR_CAST(double, unrrduScaleNothing);
511
    scale[1] = 0.0;
512
  } else if (!strcmp("a", str)) {
513
    scale[0] = AIR_CAST(double, unrrduScaleAspectRatio);
514
    scale[1] = 0.0;
515
  } else if (strlen(str) > 2
516
      && ('x' == str[0] || '/' == str[0])
517
      && '=' == str[1]) {
518
    if (1 != sscanf(str+2, "%lf", scale+1)) {
519
      sprintf(err, "%s: can't parse \"%s\" as x=<float> or /=<float>",
520
              me, str);
521
      return 1;
522
    }
523
    if (!( scale[1] > 0 )) {
524
      sprintf(err, "%s: need positive float from \"%s\" (not %g)",
525
              me, str, scale[1]);
526
      return 1;
527
    }
528
    scale[0] = AIR_CAST(double, ('x' == str[0]
529
                                 ? unrrduScaleMultiply
530
                                 : unrrduScaleDivide));
531
  } else if (strlen(str) > 1
532
             && ('x' == str[0] || '/' == str[0] || 's' == str[0])) {
533
    if (1 != sscanf(str+1, "%lf", scale+1)) {
534
      sprintf(err, "%s: can't parse \"%s\" as x<float>, /<float>, "
535
              "or s<float>", me, str);
536
      return 1;
537
    }
538
    if (!( scale[1] > 0 )) {
539
      sprintf(err, "%s: need positive float from \"%s\" (not %g)",
540
              me, str, scale[1]);
541
      return 1;
542
    }
543
    scale[0] = AIR_CAST(double, ('x' == str[0]
544
                                 ? unrrduScaleMultiply
545
                                 : ('/' == str[0]
546
                                    ? unrrduScaleDivide
547
                                    : unrrduScaleSpacingTarget)));
548
  } else if (strlen(str) > 2
549
             && ('+' == str[0] || '-' == str[0])
550
             && '=' == str[1]) {
551
    if (1 != sscanf(str+2, "%u", &num)) {
552
      sprintf(err, "%s: can't parse \"%s\" as +=<uint> or -=<uint>",
553
              me, str);
554
      return 1;
555
    }
556
    scale[0] = AIR_CAST(double, ('+' == str[0]
557
                                 ? unrrduScaleAdd
558
                                 : unrrduScaleSubtract));
559
    scale[1] = AIR_CAST(double, num);
560
  } else {
561
    if (1 != sscanf(str, "%u", &num)) {
562
      sprintf(err, "%s: can't parse \"%s\" as uint", me, str);
563
      return 1;
564
    }
565
    scale[0] = AIR_CAST(double, unrrduScaleExact);
566
    scale[1] = AIR_CAST(double, num);
567
  }
568
  return 0;
569
}
570
571
hestCB unrrduHestScaleCB = {
572
  2*sizeof(double),
573
  "sampling specification",
574
  unrrduParseScale,
575
  NULL
576
};
577
578
/* --------------------------------------------------------- */
579
/* --------------------------------------------------------- */
580
/* --------------------------------------------------------- */
581
582
/*
583
******** unrrduHestFileCB
584
**
585
** for parsing a filename, which means opening it in "rb" mode and
586
** getting a FILE *.  "-" is interpreted as stdin, which is not
587
** fclose()ed at the end, unlike all other files.
588
*/
589
void *
590
unrrduMaybeFclose(void *_file) {
591
  FILE *file;
592
593
  file = (FILE *)_file;
594
  if (stdin != file) {
595
    file = airFclose(file);
596
  }
597
  return NULL;
598
}
599
600
int
601
unrrduParseFile(void *ptr, char *str, char err[AIR_STRLEN_HUGE]) {
602
  char me[]="unrrduParseFile";
603
  FILE **fileP;
604
605
  if (!(ptr && str)) {
606
    sprintf(err, "%s: got NULL pointer", me);
607
    return 1;
608
  }
609
  fileP = (FILE **)ptr;
610
  if (!( *fileP = airFopen(str, stdin, "rb") )) {
611
    sprintf(err, "%s: fopen(\"%s\",\"rb\") failed: %s",
612
            me, str, strerror(errno));
613
    return 1;
614
  }
615
  return 0;
616
}
617
618
hestCB unrrduHestFileCB = {
619
  sizeof(FILE *),
620
  "filename",
621
  unrrduParseFile,
622
  unrrduMaybeFclose,
623
};
624
625
/* --------------------------------------------------------- */
626
/* --------------------------------------------------------- */
627
/* --------------------------------------------------------- */
628
629
/*
630
******** unrrduHestEncodingCB
631
**
632
** for parsing output encoding, including compression flags
633
** enc[0]: which encoding, from nrrdEncodingType* enum
634
** enc[1]: for compressions: zlib "level" and bzip2 "blocksize"
635
** enc[2]: for zlib: strategy, from nrrdZlibStrategy* enum
636
*/
637
int
638
unrrduParseEncoding(void *ptr, char *_str, char err[AIR_STRLEN_HUGE]) {
639
  char me[]="unrrduParseEncoding", *str, *opt;
640
  int *enc;
641
  airArray *mop;
642
643
  if (!(ptr && _str)) {
644
    sprintf(err, "%s: got NULL pointer", me);
645
    return 1;
646
  }
647
  enc = (int *)ptr;
648
  /* these are the defaults, they may not get over-written */
649
  enc[1] = -1;
650
  enc[2] = nrrdZlibStrategyDefault;
651
652
  enc[0] = airEnumVal(nrrdEncodingType, _str);
653
  if (nrrdEncodingTypeUnknown != enc[0]) {
654
    /* we're done; encoding was simple: "raw" or "gz" */
655
    return 0;
656
  }
657
  mop = airMopNew();
658
  str = airStrdup(_str);
659
  airMopMem(mop, &str, airMopAlways);
660
  opt = strchr(str, ':');
661
  if (!opt) {
662
    /* couldn't parse string as nrrdEncodingType, but there wasn't a colon */
663
    sprintf(err, "%s: didn't recognize \"%s\" as an encoding", me, str);
664
    airMopError(mop); return 1;
665
  } else {
666
    *opt = '\0';
667
    opt++;
668
    enc[0] = airEnumVal(nrrdEncodingType, str);
669
    if (nrrdEncodingTypeUnknown == enc[0]) {
670
      sprintf(err, "%s: didn't recognize \"%s\" as an encoding", me, str);
671
      airMopError(mop); return 1;
672
    }
673
    if (!nrrdEncodingArray[enc[0]]->isCompression) {
674
      sprintf(err, "%s: only compression encodings have parameters", me);
675
      airMopError(mop); return 1;
676
    }
677
    while (*opt) {
678
      int opti = AIR_INT(*opt);
679
      if (isdigit(opti)) {
680
        enc[1] = *opt - '0';
681
      } else if ('d' == tolower(opti)) {
682
        enc[2] = nrrdZlibStrategyDefault;
683
      } else if ('h' == tolower(opti)) {
684
        enc[2] = nrrdZlibStrategyHuffman;
685
      } else if ('f' == tolower(opti)) {
686
        enc[2] = nrrdZlibStrategyFiltered;
687
      } else {
688
        sprintf(err, "%s: parameter char \"%c\" not a digit or 'd','h','f'",
689
                me, *opt);
690
        airMopError(mop); return 1;
691
      }
692
      opt++;
693
    }
694
  }
695
  airMopOkay(mop);
696
  return 0;
697
}
698
699
hestCB unrrduHestEncodingCB = {
700
  3*sizeof(int),
701
  "encoding",
702
  unrrduParseEncoding,
703
  NULL
704
};
705