35#include <cxmessages.h>
41#define ASSERT(msg, x) const bool SBRM_##msg = x; assert(SBRM_##msg)
44#define HERE_SIG SBRM_PRIV_HERE_SIG
57static char const * g_catcher = NULL;
61void sbrm_destroy_and_nullify( __sbrm_entry_t * e )
64 case 'w': { void (*fp)(
void**) = e->dtor; fp(&e->o);
break; }
65 case 'v': { void (*fp)(
void*) = e->dtor; fp(e->o);
break; }
66 case 'p': {
void* (*fp)(
void*) = e->dtor; (
void)fp(e->o);
break; }
67 case 'i': { int (*fp)(
void*) = e->dtor; (
void)fp(e->o);
break; }
68 case 'f': { float (*fp)(
void*) = e->dtor; (
void)fp(e->o);
break; }
69 case 'd': { double(*fp)(
void*) = e->dtor; (
void)fp(e->o);
break; }
70 default: { ASSERT(dtor_return_type_is_well_defined,
false); };
77void * sbrm_cleanup( sbrm_registry * r,
void * target )
80 cpl_errorstate state = cpl_errorstate_get();
83 void * preserve = NULL;
86 if (target) r->rv = target;
89 for (
int i = r->avail; i < r->sz; ++i) {
90 __sbrm_entry_t * e = r->list + i;
93 ASSERT(report_this_error_to_technical_staff, e->dtor || !e->o);
103 if (!e->dtor || !e->o)
continue;
105 sbrm_destroy_and_nullify(e);
110 ASSERT(only_managed_objects_are_returned, found || !preserve);
116 ASSERT(dtors_do_not_set_errors, cpl_errorstate_is_equal(state));
123void sbrm_free( sbrm_registry * r,
void * target )
127 for (
int i = r->sz; i--; ) {
128 __sbrm_entry_t * e = r->list + i;
131 ASSERT(report_this_error_to_technical_staff, e->dtor || !e->o);
134 if (e != target)
continue;
138 ASSERT(uninitd_registry_slots_are_never_freed, e->dtor);
143 sbrm_destroy_and_nullify(e);
149 ASSERT(only_managed_objects_are_ever_freed, 0);
154__sbrm_void_wrapper_t sbrm_reset1( sbrm_registry * r,
void * target )
162void ** sbrm_reset2( sbrm_registry * r,
void * target )
170void * sbrm_set( sbrm_registry * r,
char fp,
void * dtor,
void * initval,
179 for (
int i = r->avail; i < r->sz; ++i) {
180 __sbrm_entry_t * e = r->list + i;
181 if (ident != e->ident)
continue;
187 ASSERT(registry_size_can_hold_all_managed_objects, r->avail);
189 r->list[--r->avail] = (__sbrm_entry_t){initval, fp, dtor, ident};
190 return r->list + r->avail;
197void sbrm_dump(
void (*messenger)(
const char *,
const char *, ...),
198 unsigned self,
unsigned first,
unsigned last )
200 const cpl_boolean is_reverse = first > last ? CPL_TRUE : CPL_FALSE;
201 const unsigned newest = is_reverse ? first : last;
202 const unsigned oldest = is_reverse ? last : first;
203 const char * revmsg = is_reverse ?
" in reverse order" :
"";
205 cx_assert( messenger != NULL );
206 cx_assert( oldest <= self );
207 cx_assert( newest >= self );
210 messenger(g_catcher,
"No error(s) to dump");
211 cx_assert( oldest == 0);
213 cx_assert( oldest > 0);
214 cx_assert( newest >= oldest);
217 messenger(g_catcher,
"Dumping all %u error(s)%s:", newest,
220 messenger(g_catcher,
"Dumping the %u most recent error(s) out "
221 "of a total of %u errors%s:", newest - oldest + 1,
224 cpl_msg_indent_more();
227 messenger(g_catcher,
"[%u/%u] '%s' (%u) at %s", self, newest,
228 cpl_error_get_message(), cpl_error_get_code(),
229 cpl_error_get_where());
231 if (self == last) cpl_msg_indent_less();
237void sbrm_dump_error(
unsigned self,
unsigned first,
unsigned last )
239 sbrm_dump(cpl_msg_error, self, first, last);
244void sbrm_dump_warn(
unsigned self,
unsigned first,
unsigned last )
246 sbrm_dump(cpl_msg_warning, self, first, last);
251void sbrm_dump_info(
unsigned self,
unsigned first,
unsigned last )
253 sbrm_dump(cpl_msg_info, self, first, last);
258void sbrm_dump_debug(
unsigned self,
unsigned first,
unsigned last )
260 sbrm_dump(cpl_msg_debug, self, first, last);
265void * sbrm_dumperr_action( sbrm_registry * r,
const bool ret, HERE_SIG,
266 void (*lvl)(
unsigned,
unsigned,
unsigned), cpl_error_code code,
267 const char * fmt, va_list vargs )
269 const cpl_error_code zcode = cpl_error_get_code();
270 const bool propagate = !code && zcode;
273 if (!code) code = zcode ? zcode : CPL_ERROR_UNSPECIFIED;
274 const bool extra = fmt && fmt[0] && (fmt[0] !=
' ' || fmt[1]);
275 char * msg = propagate ?
"propagated" :
"";
277 char * details = cpl_vsprintf(fmt, vargs);
278 msg = cpl_sprintf(
"%s%s(%s)", msg, msg[0] ?
" " :
"", details);
281 cpl_error_set_message_one_macro(func, code, file, line, msg);
282 if (extra) cpl_free(msg);
286 cpl_errorstate_dump(r->estate, 0, lvl);
289 if (ret)
return r->cleanup(r, NULL);
291 r->estate = cpl_errorstate_get();
297void * sbrm_abort( sbrm_registry * r, HERE_SIG,
const unsigned code,
298 const char * fmt, ... )
302 void * obj = sbrm_dumperr_action(
303 r,
true, func, file, line, sbrm_dump_error, code, fmt, args);
310void sbrm_warn( sbrm_registry * r, HERE_SIG,
const char * fmt, ... )
314 (void)sbrm_dumperr_action(
315 r,
false, func, file, line, sbrm_dump_warn, 0, fmt, args);
321void sbrm_info( sbrm_registry * r, HERE_SIG,
const char * fmt, ... )
325 (void)sbrm_dumperr_action(
326 r,
false, func, file, line, sbrm_dump_info, 0, fmt, args);
332void sbrm_debug( sbrm_registry * r, HERE_SIG,
const char * fmt, ...)
336 (void)sbrm_dumperr_action(
337 r,
false, func, file, line, sbrm_dump_debug, 0, fmt, args);
343void sbrm_rval( sbrm_registry * r,
void * target )
350void * sbrm_yank(
void * target )
352 __sbrm_entry_t * e = target;
360void * __sbrm_cp(
void * dest,
void * src,
size_t sz,
int release )
362 memcpy(dest, src, sz);
363 if (release) cpl_free(src);
368sbrm_registry * sbrm_init(
const int sz, HERE_SIG )
370 sbrm_registry * reg = SBRM_VALLOC(sbrm_registry, __sbrm_entry_t,
371 sz, sz, NULL, cpl_errorstate_get(),
372 sbrm_set, sbrm_reset1, sbrm_reset2,
373 sbrm_free, sbrm_cleanup,
374 sbrm_debug, sbrm_info, sbrm_warn, sbrm_abort,
378 for (
int i = 0; i < sz; ++i)
379 reg->list[i] = (__sbrm_entry_t){NULL,
'v', NULL, 0};
381 if (cpl_error_get_code()) sbrm_warn(reg, func, file, line,
382 "Error present at start of %s!", func);