From a3cf50388fde97242175c45b92c76dc6bc8ff620 Mon Sep 17 00:00:00 2001 From: Andrea Shepard <andrea@persephoneslair.org> Date: Sun, 7 May 2017 22:47:05 +0000 Subject: [PATCH] Add copy/free params mechanism --- src/hammer.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/hammer.h | 29 +++++++++++++++++++++ src/internal.h | 14 ++++++++++ 3 files changed, 112 insertions(+) diff --git a/src/hammer.c b/src/hammer.c index 44ff2e66..c72c59fb 100644 --- a/src/hammer.c +++ b/src/hammer.c @@ -55,6 +55,75 @@ HParserBackend h_get_default_backend(void) { return h_get_default_backend__int(); } +/* + * Copy an HParserBackendWithParams, using the backend-supplied copy + * method. + */ + +HParserBackendWithParams * h_copy_backend_with_params( + HParserBackendWithParams *be_with_params) { + return h_copy_backend_with_params__m(&system_allocator, be_with_params); +} + +HParserBackendWithParams * h_copy_backend_with_params__m(HAllocator *mm__, + HParserBackendWithParams *be_with_params) { + HParserBackendWithParams *r = NULL; + int s; + + if (be_with_params && be_with_params->backend >= PB_MIN && + be_with_params->backend <= PB_MAX) { + if (mm__ == NULL) { + /* use the allocator from the input */ + mm__ = be_with_params->mm__; + } + + /* got an allocator? */ + if (mm__) { + r = h_new(HParserBackendWithParams, 1); + if (r) { + r->mm__ = mm__; + r->backend = be_with_params->backend; + if (backends[be_with_params->backend]->copy_params) { + s = backends[be_with_params->backend]->copy_params(mm__, + &(r->params), be_with_params->params); + if (s != 0) { + /* copy_params() failed */ + h_free(r); + r = NULL; + } + } else { + /* else just ignore it and set it to NULL */ + r->params = NULL; + } + } + /* else fail out */ + } + /* else give up and return NULL */ + } + /* else return NULL, nothing to copy */ + + return r; +} + +/* Free this HParserBackendWithParams, and free the params too */ + +void h_free_backend_with_params(HParserBackendWithParams *be_with_params) { + HAllocator *mm__ = &system_allocator; + + if (be_with_params) { + if (be_with_params->mm__) mm__ = be_with_params->mm__; + + if (h_is_backend_available(be_with_params->backend)) { + if (backends[be_with_params->backend]->free_params) { + backends[be_with_params->backend]-> + free_params(be_with_params->mm__, be_with_params->params); + } + } + + h_free(be_with_params); + } +} + #define DEFAULT_ENDIANNESS (BIT_BIG_ENDIAN | BYTE_BIG_ENDIAN) HParseResult* h_parse(const HParser* parser, const uint8_t* input, size_t length) { diff --git a/src/hammer.h b/src/hammer.h index a9ace572..e838720a 100644 --- a/src/hammer.h +++ b/src/hammer.h @@ -54,6 +54,20 @@ typedef enum HParserBackend_ { PB_MAX = PB_GLR } HParserBackend; +typedef struct HParserBackendWithParams_ { + /* The backend */ + HParserBackend backend; + /* + * Backend-specific parameters - if this needs to be freed, the backend + * should provide a free_params method in its vtable; currently no backends + * do this - PB_PACKRAT and PB_REGULAR take no params, and PB_LLk, PB_LALR + * and PB_GLR take an integer cast to void * + */ + void *params; + /* Allocator to use to free this (and the params if necessary) */ + HAllocator *mm__; +} HParserBackendWithParams; + typedef enum HTokenType_ { // Before you change the explicit values of these, think of the poor bindings ;_; TT_INVALID = 0, @@ -277,6 +291,21 @@ int h_is_backend_available(HParserBackend backend); HParserBackend h_get_default_backend(void); +/** + * Copy a backend+params, using the backend-supplied copy method; the + * allocator used is the one passed in, or call the __m version with + * a NULL allocator to use the one from the source HParserBackendWithParams + */ + +HAMMER_FN_DECL(HParserBackendWithParams *, h_copy_backend_with_params, + HParserBackendWithParams *be_with_params); + +/** + * Free a backend+params + */ + +void h_free_backend_with_params(HParserBackendWithParams *be_with_params); + /** * Top-level function to call a parser that has been built over some * piece of input (of known size). diff --git a/src/internal.h b/src/internal.h index 51898bf0..22407cca 100644 --- a/src/internal.h +++ b/src/internal.h @@ -238,6 +238,20 @@ typedef struct HParserBackendVTable_ { HParseResult *(*parse_finish)(HSuspendedParser *s); // parse_finish must free s->backend_state. // parse_finish will not be called before parse_chunk reports done. + + /* The backend knows how to free its params */ + void (*free_params)(HAllocator *mm__, void *p); + /* + * ..and how to copy them + * + * Since the backend params need not actually be an allocated object, + * (and in fact no current backends use this, although it is permissible), + * but might (as in PB_GLR) be some numeric constant cast to void * which + * copy_params() should just pass through, we can't use returning NULL + * to signal allocation failure. Hence, passing the result out in a + * void ** and returning a status code (0 indicates success). + */ + int (*copy_params)(HAllocator *mm__, void **out, void *in); } HParserBackendVTable; -- GitLab