GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/air/mop.c Lines: 57 119 47.9 %
Date: 2017-05-26 Branches: 29 74 39.2 %

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 "air.h"
25
26
/*
27
learned: using these functions correctly to manage even simple
28
memory usage can be very tricky.
29
30
problem 0: even trying to write airMopPrint, I foolishly thought:
31
"print the string, then free it".  But the print callback clobbered
32
the free callback, because of the semantics of airMopAdd().  So,
33
I had to add _airMopAdd().
34
35
problem 1: debugging hest with purify, on case of hitting error after
36
parsing multiple variable parameter option of strings: so, I allocated
37
an array of strings (arrays), and registered all the strings with
38
airMopMem(), and registered the array itself also with airMopMem().
39
Again, got clobbered.  airSetNull(&((*vP)[0])) clobbered
40
airFree(*vP).  So, I gave up on using airMopMem() for the individual
41
elements, and am using simply airMopAdd(airFree).  The alternative
42
was to change the airMopAdd()s in airMopMem() to _airMopAdd()s, but
43
I didn't feel confident that this would be safe.
44
45
-----------  SO: as a result of all that:
46
47
airMopAdd() will no longer over-write a callback based on the pointer
48
It will only over-write the "when" of a (pointer,callback) pair, so that
49
you can't register multiple copies of a (pointer,callback) pair (regardless
50
of differences, if any, in "when").  Therefore, there will be AT MOST ONE
51
instance of a (pointer,callback) pair in a mop.
52
53
_airMopAdd() was nixed.
54
55
airMopSub() and airMopUnMem were created
56
57
*/
58
59
#define AIR_MOP_INCR 10
60
61
airArray *
62
airMopNew() {
63
64
7400
  return airArrayNew(NULL, NULL, sizeof(airMop), AIR_MOP_INCR);
65
}
66
67
/*
68
** except for allocation error, this always returns 0,
69
** to facilitate this weird idiom:
70
**
71
**   if (!(nmeasr = nrrdNew())
72
**       || airMopAdd(mop, nmeasr, (airMopper)nrrdNuke, airMopAlways)
73
**       || !(nsize = nrrdNew())
74
**       || airMopAdd(mop, nsize, (airMopper)nrrdNuke, airMopAlways)
75
**       || !(pair = AIR_CAST(ccpair *, calloc(pctx->CCNum, sizeof(ccpair))))
76
**       || airMopAdd(mop, pair, airFree, airMopAlways)) {
77
**
78
** GLK may regret this.
79
*/
80
int
81
airMopAdd(airArray *arr, void *ptr, airMopper mop, int when) {
82
  static const char me[]="airMopAdd";
83
  airMop *mops;
84
  unsigned int ii;
85
86
26332
  if (!arr) {
87
    return 0;
88
  }
89
90
13166
  mops = (airMop *)arr->data;
91
  /* first see if this is something we already set a callback for */
92
137406
  for (ii=0; ii<arr->len; ii++) {
93

55565
    if (mops[ii].ptr == ptr && mops[ii].mop == mop) {
94
1
      mops[ii].when = when;
95
      /* we're done */
96
1
      return 0;
97
    }
98
  }
99
  /* this is a new ptr */
100
13165
  ii = airArrayLenIncr(arr, 1);
101
13165
  if (!arr->data) {
102
    fprintf(stderr, "%s: PANIC: can't re-allocate mop array\n", me);
103
    return 1;
104
  }
105
13165
  mops = (airMop *)arr->data;
106
13165
  mops[ii].ptr = ptr;
107
13165
  mops[ii].mop = mop;
108
13165
  mops[ii].when = when;
109
13165
  return 0;
110
13166
}
111
112
void
113
airMopSub(airArray *arr, void *ptr, airMopper mop) {
114
  airMop *mops;
115
  unsigned int ii;
116
117
  if (!arr) {
118
    return;
119
  }
120
121
  mops = (airMop *)arr->data;
122
  /* first see if this is something we already set a callback for */
123
  for (ii=0; ii<arr->len; ii++) {
124
    if (mops[ii].ptr == ptr && mops[ii].mop == mop) {
125
      mops[ii].ptr = NULL;
126
      mops[ii].mop = NULL;
127
      mops[ii].when = airMopNever;
128
      return;
129
    }
130
  }
131
  /* else we've never seen this before, user is a moron */
132
  return;
133
}
134
135
void
136
airMopMem(airArray *arr, void *_ptrP, int when) {
137
  void **ptrP;
138
139
4578
  if (!(arr && _ptrP)) {
140
    return;
141
  }
142
143
2289
  ptrP = (void **)_ptrP;
144
2289
  airMopAdd(arr, ptrP, (airMopper)airSetNull, when);
145
2289
  airMopAdd(arr, *ptrP, airFree, when);
146
  /*
147
  printf("airMopMem(0x%p): will free() 0x%p\n",
148
         (void*)arr, (void*)(*ptrP));
149
  printf("airMopMem(0x%p): will set 0x%p to NULL\n",
150
         (void*)arr, (void*)ptrP);
151
  */
152
2289
  return;
153
2289
}
154
155
void
156
airMopUnMem(airArray *arr, void *_ptrP) {
157
  void **ptrP;
158
159
  if (!(arr && _ptrP)) {
160
    return;
161
  }
162
163
  ptrP = (void **)_ptrP;
164
  airMopSub(arr, ptrP, (airMopper)airSetNull);
165
  airMopSub(arr, *ptrP, airFree);
166
  return;
167
}
168
169
static void *
170
_airMopPrint(void *_str) {
171
  char *str;
172
173
  str = (char *)_str;
174
  if (str) {
175
    printf("%s\n", str);
176
  }
177
  return NULL;
178
}
179
180
void
181
airMopPrint(airArray *arr, const void *_str, int when) {
182
  char *copy;
183
184
  if (!(arr && _str))
185
    return;
186
187
  copy = airStrdup(AIR_CAST(const char*, _str));
188
  airMopAdd(arr, copy, airFree, airMopAlways);
189
  airMopAdd(arr, copy, _airMopPrint, when);
190
  return;
191
}
192
193
static const char
194
_airMopWhenStr[4][128] = {
195
  " never",
196
  " error",
197
  "  okay",
198
  "always",
199
};
200
201
/*
202
** This is to overcome the warning about
203
** "ISO C forbids conversion of function pointer to object pointer type";
204
** the result here is thus implementation-dependent
205
*/
206
typedef union {
207
  airMopper m;
208
  void *v;
209
} mvunion;
210
211
void
212
airMopDebug(airArray *arr) {
213
  airMop *mops;
214
  unsigned int ii;
215
  mvunion mvu;
216
217
  if (!arr)
218
    return;
219
220
  mops = (airMop *)arr->data;
221
  printf("airMopDebug: _________________________ mop stack for 0x%p:\n",
222
         AIR_VOIDP(arr));
223
  if (arr->len) {
224
    ii = arr->len;
225
    do {
226
      ii--;
227
      printf("%4u: ", ii);
228
      if (NULL == mops[ii].mop && NULL == mops[ii].ptr
229
          && airMopNever == mops[ii].when) {
230
        printf("no-op\n");
231
        continue;
232
      }
233
      /* else */
234
      printf("%s: ", _airMopWhenStr[mops[ii].when]);
235
      if (airFree == mops[ii].mop) {
236
        printf("airFree(0x%p)\n", AIR_VOIDP(mops[ii].ptr));
237
        continue;
238
      }
239
      if ((airMopper)airSetNull == mops[ii].mop) {
240
        printf("airSetNull(0x%p)\n", AIR_VOIDP(mops[ii].ptr));
241
        continue;
242
      }
243
      if (_airMopPrint == mops[ii].mop) {
244
        printf("_airMopPrint(\"%s\" == 0x%p)\n",
245
               AIR_CAST(char*, mops[ii].ptr), AIR_VOIDP(mops[ii].ptr));
246
        continue;
247
      }
248
      if ((airMopper)airFclose == mops[ii].mop) {
249
        printf("airFclose(0x%p)\n", AIR_VOIDP(mops[ii].ptr));
250
        continue;
251
      }
252
      /* else */
253
      mvu.m = mops[ii].mop;
254
      printf("0x%p(0x%p)\n", AIR_VOIDP(mvu.v), AIR_VOIDP(mops[ii].ptr));
255
    } while (ii);
256
  }
257
  printf("airMopDebug: ^^^^^^^^^^^^^^^^^^^^^^^^^\n");
258
}
259
260
void
261
airMopDone(airArray *arr, int error) {
262
  airMop *mops;
263
  unsigned int ii;
264
265
  /*
266
  printf("airMopDone(%p): hello, %s\n", (void*)arr, error ? "error" : "okay");
267
  */
268
7398
  if (arr) {
269
3699
    mops = (airMop *)arr->data;
270
3699
    if (arr->len) {
271
      ii = arr->len;
272
3097
      do {
273
13164
        ii--;
274
13164
        if (mops[ii].ptr
275
26306
            && (airMopAlways == mops[ii].when
276

20232
                || (airMopOnError == mops[ii].when && error)
277
6130
                || (airMopOnOkay == mops[ii].when && !error))) {
278
7060
          mops[ii].mop(mops[ii].ptr);
279
7060
        }
280
13164
      } while (ii);
281
    }
282
3699
    airArrayNuke(arr);
283
    /*
284
      printf("airMopDone(%p): done!\n", (void*)arr);
285
    */
286
3699
  }
287
  return;
288
3699
}
289
290
void
291
airMopError(airArray *arr) {
292
293
682
  airMopDone(arr, AIR_TRUE);
294
341
}
295
296
void
297
airMopOkay(airArray *arr) {
298
299
6716
  airMopDone(arr, AIR_FALSE);
300
3358
}
301
302
/* ---- BEGIN non-NrrdIO */
303
304
/*
305
** like airMopSub but calls the mopper first
306
*/
307
void
308
airMopSingleDone(airArray *arr, void *ptr, int error) {
309
  airMop *mops;
310
  unsigned int ii;
311
312

54
  if (!arr || !(arr->len)) {
313
    return;
314
  }
315
18
  mops = (airMop *)arr->data;
316
  ii = arr->len;
317
18
  do {
318
114
      ii--;
319
114
      if (ptr == mops[ii].ptr
320
132
          && (airMopAlways == mops[ii].when
321

18
              || (airMopOnError == mops[ii].when && error)
322
              || (airMopOnOkay == mops[ii].when && !error))) {
323
18
        mops[ii].mop(mops[ii].ptr);
324
18
        mops[ii].ptr = NULL;
325
18
        mops[ii].mop = NULL;
326
18
        mops[ii].when = airMopNever;
327
18
      }
328
114
  } while (ii);
329
18
  return;
330
18
}
331
332
void
333
airMopSingleError(airArray *arr, void *ptr) {
334
335
  airMopSingleDone(arr, ptr, AIR_TRUE);
336
}
337
338
void
339
airMopSingleOkay(airArray *arr, void *ptr) {
340
341
36
  airMopSingleDone(arr, ptr, AIR_FALSE);
342
18
}
343
344
/* ---- END non-NrrdIO */