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 |
|
|
|