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