GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/biff/biffbiff.c Lines: 95 144 66.0 %
Date: 2017-05-26 Branches: 29 52 55.8 %

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 "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 */