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 "biff.h" |
25 |
|
|
#include "privateBiff.h" |
26 |
|
|
|
27 |
|
|
/* |
28 |
|
|
** Until Teem has its own printf implementation, this will have to do; |
29 |
|
|
** it is imperfect because these are not functionally identical. |
30 |
|
|
*/ |
31 |
|
|
#if defined(WIN32) || defined(_WIN32) |
32 |
|
|
# define snprintf _snprintf |
33 |
|
|
#endif |
34 |
|
|
|
35 |
|
|
static biffMsg ** |
36 |
|
|
_bmsg=NULL; /* master array of biffMsg pointers */ |
37 |
|
|
static unsigned int |
38 |
|
|
_bmsgNum=0; /* length of _biffErr == # keys maintained */ |
39 |
|
|
static airArray * |
40 |
|
|
_bmsgArr=NULL; /* air array of _biffErr and _biffNum */ |
41 |
|
|
|
42 |
|
|
#define __INCR 2 |
43 |
|
|
|
44 |
|
|
typedef union { |
45 |
|
|
biffMsg ***b; |
46 |
|
|
void **v; |
47 |
|
|
} _beu; |
48 |
|
|
|
49 |
|
|
/* |
50 |
|
|
** _bmsgStart() |
51 |
|
|
** |
52 |
|
|
** allocates data structers needed by biff. Panics if |
53 |
|
|
** anything goes wrong. |
54 |
|
|
** |
55 |
|
|
** NOTE: Can be harmlessly called multiple times. |
56 |
|
|
*/ |
57 |
|
|
static void |
58 |
|
|
_bmsgStart(void) { |
59 |
|
|
static const char me[]="[biff] _bmsgStart"; |
60 |
|
|
_beu uu; |
61 |
|
|
|
62 |
✓✓ |
236 |
if (_bmsgArr) { |
63 |
|
|
/* its non-NULL, must have been called already */ |
64 |
|
100 |
return; |
65 |
|
|
} |
66 |
|
|
uu.b = &_bmsg; |
67 |
|
18 |
_bmsgArr = airArrayNew(uu.v, &_bmsgNum, sizeof(biffMsg*), __INCR); |
68 |
✗✓ |
18 |
if (!_bmsgArr) { |
69 |
|
|
fprintf(stderr, "%s: PANIC: couldn't allocate internal data\n", me); |
70 |
|
|
/* exit(1); */ |
71 |
|
|
} |
72 |
|
|
/* airArrayPointerCB(_bmsgArr, NULL, (airMopper)biffMsgNix);*/ |
73 |
|
18 |
return; |
74 |
|
118 |
} |
75 |
|
|
|
76 |
|
|
static void |
77 |
|
|
_bmsgFinish(void) { |
78 |
|
|
|
79 |
✓✗ |
32 |
if (_bmsgArr) { |
80 |
|
|
/* setting _bmsgArr to NULL is needed to put biff back in initial state |
81 |
|
|
so that next calls to biff re-trigger _bmsgStart() */ |
82 |
|
16 |
_bmsgArr = airArrayNuke(_bmsgArr); |
83 |
|
16 |
} |
84 |
|
16 |
return; |
85 |
|
|
} |
86 |
|
|
|
87 |
|
|
/* |
88 |
|
|
** _bmsgFind() |
89 |
|
|
** |
90 |
|
|
** returns the biffMsg (in _bmsg) of the entry with the given key, or |
91 |
|
|
** NULL if it was not found |
92 |
|
|
*/ |
93 |
|
|
static biffMsg * |
94 |
|
|
_bmsgFind(const char *key) { |
95 |
|
|
static const char me[]="[biff] _bmsgFind"; |
96 |
|
|
biffMsg *msg; |
97 |
|
|
unsigned int ii; |
98 |
|
|
|
99 |
✗✓ |
112 |
if (!key) { |
100 |
|
|
fprintf(stderr, "%s: PANIC got NULL key", me); |
101 |
|
|
return NULL; /* exit(1); */ |
102 |
|
|
} |
103 |
|
|
msg = NULL; |
104 |
✓✗ |
56 |
if (_bmsgNum) { |
105 |
✓✗ |
162 |
for (ii=0; ii<_bmsgNum; ii++) { |
106 |
✓✓ |
81 |
if (!strcmp(_bmsg[ii]->key, key)) { |
107 |
|
56 |
msg = _bmsg[ii]; |
108 |
|
56 |
break; |
109 |
|
|
} |
110 |
|
|
} |
111 |
|
|
} |
112 |
|
56 |
return msg; |
113 |
|
56 |
} |
114 |
|
|
|
115 |
|
|
/* |
116 |
|
|
** assumes that msg really is in _bmsg[] |
117 |
|
|
*/ |
118 |
|
|
static unsigned int |
119 |
|
|
_bmsgFindIdx(biffMsg *msg) { |
120 |
|
|
unsigned int ii; |
121 |
|
|
|
122 |
✓✗ |
97 |
for (ii=0; ii<_bmsgNum; ii++) { |
123 |
✓✓ |
36 |
if (msg == _bmsg[ii]) { |
124 |
|
|
break; |
125 |
|
|
} |
126 |
|
|
} |
127 |
|
25 |
return ii; |
128 |
|
|
} |
129 |
|
|
|
130 |
|
|
/* |
131 |
|
|
** _bmsgAdd() |
132 |
|
|
** |
133 |
|
|
** if given key already has a biffMsg in _bmsg, returns that. |
134 |
|
|
** otherise, adds a new biffMsg for given key to _bmsg, and returns it |
135 |
|
|
** panics if there is a problem |
136 |
|
|
*/ |
137 |
|
|
static biffMsg * |
138 |
|
|
_bmsgAdd(const char *key) { |
139 |
|
|
static const char me[]="[biff] _bmsgAdd"; |
140 |
|
|
unsigned int ii; |
141 |
|
|
biffMsg *msg; |
142 |
|
|
|
143 |
|
|
msg = NULL; |
144 |
|
|
/* find if key exists already */ |
145 |
✓✓ |
193 |
for (ii=0; ii<_bmsgNum; ii++) { |
146 |
✓✓ |
46 |
if (!strcmp(key, _bmsg[ii]->key)) { |
147 |
|
17 |
msg = _bmsg[ii]; |
148 |
|
17 |
break; |
149 |
|
|
} |
150 |
|
|
} |
151 |
✓✓ |
45 |
if (!msg) { |
152 |
|
|
/* have to add new biffMsg */ |
153 |
|
28 |
ii = airArrayLenIncr(_bmsgArr, 1); |
154 |
✗✓ |
28 |
if (!_bmsg) { |
155 |
|
|
fprintf(stderr, "%s: PANIC: couldn't accommodate one more key\n", me); |
156 |
|
|
return NULL; /* exit(1); */ |
157 |
|
|
} |
158 |
|
28 |
msg = _bmsg[ii] = biffMsgNew(key); |
159 |
|
28 |
} |
160 |
|
45 |
return msg; |
161 |
|
45 |
} |
162 |
|
|
|
163 |
|
|
/***********************************************************************/ |
164 |
|
|
/***********************************************************************/ |
165 |
|
|
|
166 |
|
|
/* |
167 |
|
|
******** biffAdd() |
168 |
|
|
** |
169 |
|
|
** Adds string "err" at key "key", whether or not there are any |
170 |
|
|
** existing messages there. Since biffSet() was killed |
171 |
|
|
** Wed Apr 20 11:11:51 EDT 2005, this has become the main biff |
172 |
|
|
** function. |
173 |
|
|
*/ |
174 |
|
|
void |
175 |
|
|
biffAdd(const char *key, const char *err) { |
176 |
|
|
biffMsg *msg; |
177 |
|
|
|
178 |
|
36 |
_bmsgStart(); |
179 |
|
18 |
msg = _bmsgAdd(key); |
180 |
|
18 |
biffMsgAdd(msg, err); |
181 |
|
|
return; |
182 |
|
18 |
} |
183 |
|
|
|
184 |
|
|
static void |
185 |
|
|
_biffAddVL(const char *key, const char *errfmt, va_list args) { |
186 |
|
|
biffMsg *msg; |
187 |
|
|
|
188 |
|
44 |
_bmsgStart(); |
189 |
|
22 |
msg = _bmsgAdd(key); |
190 |
|
22 |
_biffMsgAddVL(msg, errfmt, args); |
191 |
|
|
return; |
192 |
|
22 |
} |
193 |
|
|
|
194 |
|
|
/* |
195 |
|
|
******** biffAddf() |
196 |
|
|
** |
197 |
|
|
** Adds string "err" at key "key", whether or not there are any |
198 |
|
|
** existing messages there. This version accepts a printf style |
199 |
|
|
** format string as input. |
200 |
|
|
*/ |
201 |
|
|
void |
202 |
|
|
biffAddf(const char *key, const char *errfmt, ...) { |
203 |
|
44 |
va_list args; |
204 |
|
|
|
205 |
|
22 |
va_start(args, errfmt); |
206 |
|
22 |
_biffAddVL(key, errfmt, args); |
207 |
|
22 |
va_end(args); |
208 |
|
|
return; |
209 |
|
22 |
} |
210 |
|
|
|
211 |
|
|
#if 0 |
212 |
|
|
/* |
213 |
|
|
******** biffAddf_e |
214 |
|
|
** |
215 |
|
|
** calls (eventually) biffMsgAdd if msg is non-NULL, otherwise calls |
216 |
|
|
** biffAdd if msg is NULL. |
217 |
|
|
*/ |
218 |
|
|
void |
219 |
|
|
biffAddf_e(biffMsg *msg, const char *key, const char *errfmt, ...) { |
220 |
|
|
va_list args; |
221 |
|
|
|
222 |
|
|
va_start(args, errfmt); |
223 |
|
|
if (msg) { |
224 |
|
|
_biffMsgAddVL(msg, errfmt, args); |
225 |
|
|
} else { |
226 |
|
|
_biffAddVL(key, errfmt, args); |
227 |
|
|
} |
228 |
|
|
va_end(args); |
229 |
|
|
return; |
230 |
|
|
} |
231 |
|
|
#endif |
232 |
|
|
|
233 |
|
|
/* |
234 |
|
|
******** biffMaybeAdd() |
235 |
|
|
** |
236 |
|
|
** wrapper around biffAdd() but doesn't actually do anything if !useBiff |
237 |
|
|
*/ |
238 |
|
|
void |
239 |
|
|
biffMaybeAdd(const char *key, const char *err, int useBiff) { |
240 |
|
|
|
241 |
|
|
if (useBiff) { |
242 |
|
|
biffAdd(key, err); |
243 |
|
|
} |
244 |
|
|
return; |
245 |
|
|
} |
246 |
|
|
|
247 |
|
|
void |
248 |
|
|
biffMaybeAddf(int useBiff, const char *key, const char *errfmt, ...) { |
249 |
|
2 |
va_list args; |
250 |
|
|
|
251 |
|
1 |
va_start(args, errfmt); |
252 |
✗✓ |
1 |
if (useBiff) { |
253 |
|
|
_biffAddVL(key, errfmt, args); |
254 |
|
|
} |
255 |
|
1 |
va_end(args); |
256 |
|
|
return; |
257 |
|
1 |
} |
258 |
|
|
|
259 |
|
|
|
260 |
|
|
/* |
261 |
|
|
******** biffGet() |
262 |
|
|
** |
263 |
|
|
** creates a string which records all the errors at given key and |
264 |
|
|
** returns it. Returns NULL in case of error. This function should |
265 |
|
|
** be considered a glorified strdup(): it is the callers responsibility |
266 |
|
|
** to free() this string later |
267 |
|
|
*/ |
268 |
|
|
char * /*Teem: allocates char* */ /* this comment is an experiment */ |
269 |
|
|
biffGet(const char *key) { |
270 |
|
|
static const char me[]="biffGet"; |
271 |
|
|
char *ret; |
272 |
|
|
biffMsg *msg; |
273 |
|
|
|
274 |
|
52 |
_bmsgStart(); |
275 |
|
26 |
msg = _bmsgFind(key); |
276 |
✗✓ |
26 |
if (!msg) { |
277 |
|
|
static const char err[]="[%s] No information for this key!"; |
278 |
|
|
size_t errlen; |
279 |
|
|
fprintf(stderr, "%s: WARNING: no information for key \"%s\"\n", me, key); |
280 |
|
|
errlen = strlen(err)+strlen(key)+1; |
281 |
|
|
ret = AIR_CALLOC(errlen, char); |
282 |
|
|
if (!ret) { |
283 |
|
|
fprintf(stderr, "%s: PANIC: unable to allocate buffer\n", me); |
284 |
|
|
return NULL; /* exit(1); */ |
285 |
|
|
} |
286 |
|
|
snprintf(ret, errlen, err, key); |
287 |
|
|
return ret; |
288 |
|
|
} |
289 |
|
|
|
290 |
|
26 |
ret = AIR_CALLOC(biffMsgStrlen(msg)+1, char); |
291 |
✗✓ |
26 |
if (!ret) { |
292 |
|
|
fprintf(stderr, "%s: PANIC: unable to allocate buffer\n", me); |
293 |
|
|
return NULL; /* exit(1); */ |
294 |
|
|
} |
295 |
|
26 |
biffMsgStrSet(ret, msg); |
296 |
|
26 |
return ret; |
297 |
|
26 |
} |
298 |
|
|
|
299 |
|
|
/* |
300 |
|
|
******** biffGetStrlen() |
301 |
|
|
** |
302 |
|
|
** for when you want to allocate the buffer for the biff string, this is |
303 |
|
|
** how you learn its length |
304 |
|
|
*/ |
305 |
|
|
unsigned int |
306 |
|
|
biffGetStrlen(const char *key) { |
307 |
|
|
static const char me[]="biffGetStrlen"; |
308 |
|
|
biffMsg *msg; |
309 |
|
|
unsigned int len; |
310 |
|
|
|
311 |
|
|
_bmsgStart(); |
312 |
|
|
msg = _bmsgFind(key); |
313 |
|
|
if (!msg) { |
314 |
|
|
fprintf(stderr, "%s: WARNING: no information for key \"%s\"\n", me, key); |
315 |
|
|
return 0; |
316 |
|
|
} |
317 |
|
|
len = biffMsgStrlen(msg); |
318 |
|
|
len += 1; /* GLK forgets if the convention is that the caller allocates |
319 |
|
|
for one more to include '\0'; this is safer */ |
320 |
|
|
return len; |
321 |
|
|
} |
322 |
|
|
|
323 |
|
|
/* |
324 |
|
|
******** biffSetStr() |
325 |
|
|
** |
326 |
|
|
** for when you want to allocate the buffer for the biff string, this is |
327 |
|
|
** how you get the error message itself |
328 |
|
|
*/ |
329 |
|
|
void |
330 |
|
|
biffSetStr(char *str, const char *key) { |
331 |
|
|
static const char me[]="biffSetStr"; |
332 |
|
|
biffMsg *msg; |
333 |
|
|
|
334 |
|
|
if (!str) { |
335 |
|
|
fprintf(stderr, "%s: ERROR: got NULL buffer for \"%s\"\n", me, key); |
336 |
|
|
return; |
337 |
|
|
} |
338 |
|
|
|
339 |
|
|
_bmsgStart(); |
340 |
|
|
msg = _bmsgFind(key); |
341 |
|
|
if (!msg) { |
342 |
|
|
fprintf(stderr, "%s: WARNING: no information for key \"%s\"\n", me, key); |
343 |
|
|
return; |
344 |
|
|
} |
345 |
|
|
biffMsgStrSet(str, msg); |
346 |
|
|
|
347 |
|
|
return; |
348 |
|
|
} |
349 |
|
|
|
350 |
|
|
/* |
351 |
|
|
******** biffCheck() |
352 |
|
|
** |
353 |
|
|
** sees how many messages there are for a given key; |
354 |
|
|
** Note that this is just a simple wrapper around biffMsgErrNum |
355 |
|
|
*/ |
356 |
|
|
unsigned int |
357 |
|
|
biffCheck(const char *key) { |
358 |
|
|
|
359 |
|
|
_bmsgStart(); |
360 |
|
|
return biffMsgErrNum(_bmsgFind(key)); |
361 |
|
|
} |
362 |
|
|
|
363 |
|
|
/* |
364 |
|
|
******** biffDone() |
365 |
|
|
** |
366 |
|
|
** frees everything associated with given key, and shrinks list of keys, |
367 |
|
|
** and calls _bmsgFinish() if there are no keys left |
368 |
|
|
*/ |
369 |
|
|
void |
370 |
|
|
biffDone(const char *key) { |
371 |
|
|
static const char me[]="biffDone"; |
372 |
|
|
unsigned int idx; |
373 |
|
|
biffMsg *msg; |
374 |
|
|
|
375 |
|
50 |
_bmsgStart(); |
376 |
|
|
|
377 |
|
25 |
msg = _bmsgFind(key); |
378 |
✗✓ |
25 |
if (!msg) { |
379 |
|
|
fprintf(stderr, "%s: WARNING: no information for key \"%s\"\n", me, key); |
380 |
|
|
return; |
381 |
|
|
} |
382 |
|
25 |
idx = _bmsgFindIdx(msg); |
383 |
|
25 |
biffMsgNix(msg); |
384 |
✓✓ |
25 |
if (_bmsgNum > 1) { |
385 |
|
|
/* if we have more than one key in action, move the last biffMsg |
386 |
|
|
to the position that was just cleared up */ |
387 |
|
9 |
_bmsg[idx] = _bmsg[_bmsgNum-1]; |
388 |
|
9 |
} |
389 |
|
25 |
airArrayLenIncr(_bmsgArr, -1); |
390 |
|
|
/* if that was the last key, close shop */ |
391 |
✓✓ |
25 |
if (!_bmsgArr->len) { |
392 |
|
16 |
_bmsgFinish(); |
393 |
|
16 |
} |
394 |
|
|
|
395 |
|
25 |
return; |
396 |
|
25 |
} |
397 |
|
|
|
398 |
|
|
void |
399 |
|
|
biffMove(const char *destKey, const char *err, const char *srcKey) { |
400 |
|
|
static const char me[]="biffMove"; |
401 |
|
|
biffMsg *dest, *src; |
402 |
|
|
|
403 |
|
2 |
_bmsgStart(); |
404 |
|
1 |
dest = _bmsgAdd(destKey); |
405 |
|
1 |
src = _bmsgFind(srcKey); |
406 |
✗✓ |
1 |
if (!src) { |
407 |
|
|
fprintf(stderr, "%s: WARNING: key \"%s\" unknown\n", me, srcKey); |
408 |
|
|
return; |
409 |
|
|
} |
410 |
|
1 |
biffMsgMove(dest, src, err); |
411 |
|
1 |
return; |
412 |
|
1 |
} |
413 |
|
|
|
414 |
|
|
static void |
415 |
|
|
_biffMoveVL(const char *destKey, const char *srcKey, |
416 |
|
|
const char *errfmt, va_list args) { |
417 |
|
|
static const char me[]="biffMovev"; |
418 |
|
|
biffMsg *dest, *src; |
419 |
|
|
|
420 |
|
8 |
_bmsgStart(); |
421 |
|
4 |
dest = _bmsgAdd(destKey); |
422 |
|
4 |
src = _bmsgFind(srcKey); |
423 |
✗✓ |
4 |
if (!src) { |
424 |
|
|
fprintf(stderr, "%s: WARNING: key \"%s\" unknown\n", me, srcKey); |
425 |
|
|
return; |
426 |
|
|
} |
427 |
|
4 |
_biffMsgMoveVL(dest, src, errfmt, args); |
428 |
|
4 |
return; |
429 |
|
4 |
} |
430 |
|
|
|
431 |
|
|
void |
432 |
|
|
biffMovef(const char *destKey, const char *srcKey, |
433 |
|
|
const char *errfmt, ...) { |
434 |
|
8 |
va_list args; |
435 |
|
|
|
436 |
|
4 |
va_start(args, errfmt); |
437 |
|
4 |
_biffMoveVL(destKey, srcKey, errfmt, args); |
438 |
|
4 |
va_end(args); |
439 |
|
|
return; |
440 |
|
4 |
} |
441 |
|
|
|
442 |
|
|
char * |
443 |
|
|
biffGetDone(const char *key) { |
444 |
|
|
char *ret; |
445 |
|
|
|
446 |
|
44 |
_bmsgStart(); |
447 |
|
|
|
448 |
|
22 |
ret = biffGet(key); |
449 |
|
22 |
biffDone(key); /* will call _bmsgFinish if this is the last key */ |
450 |
|
|
|
451 |
|
22 |
return ret; |
452 |
|
|
} |
453 |
|
|
|
454 |
|
|
/* ---- BEGIN non-NrrdIO */ |
455 |
|
|
void |
456 |
|
|
biffSetStrDone(char *str, const char *key) { |
457 |
|
|
|
458 |
|
|
_bmsgStart(); |
459 |
|
|
|
460 |
|
|
biffSetStr(str, key); |
461 |
|
|
biffDone(key); /* will call _bmsgFinish if this is the last key */ |
462 |
|
|
|
463 |
|
|
return; |
464 |
|
|
} |
465 |
|
|
/* ---- END non-NrrdIO */ |
466 |
|
|
/* this is the end */ |