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