diff --git a/src/hammer.c b/src/hammer.c index dba530e66762b5e6dfccdc42ea63fbc7ed1e7300..2d34f9e041ea189e1ed39159e28135c35f539b50 100644 --- a/src/hammer.c +++ b/src/hammer.c @@ -139,6 +139,136 @@ void h_free_backend_with_params(HParserBackendWithParams *be_with_params) { } } +/* + * Internal function to query name or descriptive text; the logic is + * the same in both cases. + */ + +static const char * h_get_string_for_backend( + HParserBackend be, int description) { + /* + * For names, failure to resolve should return null - those are + * cases we can't look up by name either. Human readable descriptions + * should have human-readable error strings + */ + const char *text = description ? "this is a bug!" : NULL; + const char **ptr; + + if (be >= PB_MIN && be <= PB_MAX) { + /* the invalid backend is special */ + if (be == PB_INVALID) { + text = description ? "invalid backend" : NULL; + } else { + if (backends[be] != backends[PB_INVALID]) { + /* Point to the name or description */ + ptr = description ? + &(backends[be]->backend_description) : + &(backends[be]->backend_short_name); + /* See if the backend knows how to describe itself */ + if (*ptr != NULL) { + text = *ptr; + } else { + /* nope */ + text = description ? "no description available" : NULL; + } + } else { + /* + * This is the case for backends which weren't compiled into this + * library. + */ + text = description ? "unsupported backend" : NULL; + } + } + } else { + text = description ? "bad backend number" : NULL; + } + + return text; +} + +/* Return an identifying name for this backend */ + +const char * h_get_name_for_backend(HParserBackend be) { + /* + * call h_get_string_for_backend(), 0 indicates name + * rather than description requested + */ + return h_get_string_for_backend(be, 0); +} + +/* + * Return some human-readable descriptive text for this backend + */ + +const char * h_get_descriptive_text_for_backend(HParserBackend be) { + /* + * call h_get_string_for_backend(), 1 indicates a + * description is requested. + */ + return h_get_string_for_backend(be, 1); +} + +/* + * Internal function to query name or descriptive text for a backend with + * params; the logic is the same in both cases. + */ + +static char * h_get_string_for_backend_with_params__m(HAllocator *mm__, + HParserBackendWithParams *be_with_params, int description) { + char *text = NULL; + const char *generic_text = NULL; + HParserBackend be = PB_INVALID; + char * (**text_getter_func)(HAllocator *mm__, + HParserBackend be, + void *params) = NULL; + + + if (mm__ == NULL || be_with_params == NULL) goto done; + + /* check if we can compute custom text with params for this backend */ + be = be_with_params->backend; + if (be >= PB_MIN && be <= PB_MAX && be != PB_INVALID && + backends[be] != backends[PB_INVALID]) { + text_getter_func = description ? + &(backends[be]->get_description_with_params) : + &(backends[be]->get_short_name_with_params); + + if (*text_getter_func != NULL) { + text = (*text_getter_func)(mm__, be, + be_with_params->params); + } + } + + /* got it? */ + if (!text) { + /* fall back to the generic descriptive text */ + generic_text = h_get_string_for_backend(be, description); + if (generic_text) { + text = h_new(char, strlen(generic_text) + 1); + strncpy(text, generic_text, strlen(generic_text) + 1); + } + } + + done: + return text; +} + +/* + * Allocate and return some human-readable descriptive text for this backend + * with parameters. The caller is responsible for freeing the result. + */ + +char * h_get_descriptive_text_for_backend_with_params__m(HAllocator *mm__, + HParserBackendWithParams *be_with_params) { + return h_get_string_for_backend_with_params__m(mm__, be_with_params, 1); +} + +char * h_get_descriptive_text_for_backend_with_params( + HParserBackendWithParams *be_with_params) { + return h_get_descriptive_text_for_backend_with_params__m( + &system_allocator, 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 e838720af187b28fec6eae03790cd627067a747d..687592943102c30bd9794a00f20784a5017b9bb1 100644 --- a/src/hammer.h +++ b/src/hammer.h @@ -306,6 +306,40 @@ HAMMER_FN_DECL(HParserBackendWithParams *, h_copy_backend_with_params, void h_free_backend_with_params(HParserBackendWithParams *be_with_params); +/** + * Get a name string for a backend; this is constant per backend and so + * need not be freed; it will resolve to the backend under + * h_get_backend_by_name(). + */ + +const char * h_get_name_for_backend(HParserBackend be); + +/** + * Get a name string for a backend with parameters; it is the caller's + * responsibility to free it later. This will resolve to the same + * backend and parameters under h_get_backend_with_params_by_name(). + */ + +HAMMER_FN_DECL(char *, h_get_name_for_backend_with_params, + HParserBackendWithParams *be_with_params); + +/** + * Get a human-readable descriptive string for a backend; this is constant + * per backend and so need not be freed. + */ + +const char * h_get_descriptive_text_for_backend(HParserBackend be); + +/** + * Get a human-readable descriptive string for a backend with params; it is + * the caller's responsibility to free it later. Sorry, but it's allowed + * to depend on the params and putting keeping the buffer elsewhere and + * replacing it on the next call wouldn't be thread-safe. + */ + +HAMMER_FN_DECL(char *, h_get_descriptive_text_for_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 1ed77e7a021269d4d764af35c4af32a5aa9f2e6f..4fc9eb989ebd40e44f62ef3b90c164984b1e69da 100644 --- a/src/internal.h +++ b/src/internal.h @@ -252,6 +252,16 @@ typedef struct HParserBackendVTable_ { * void ** and returning a status code (0 indicates success). */ int (*copy_params)(HAllocator *mm__, void **out, void *in); + + /* Description/name handling */ + const char *backend_short_name; + const char *backend_description; + char * (*get_description_with_params)(HAllocator *mm__, + HParserBackend be, + void *params); + char * (*get_short_name_with_params)(HAllocator *mm__, + HParserBackend be, + void *params); } HParserBackendVTable;