From 54d5c081eb48724bf8afdcb93b932c45723b782b Mon Sep 17 00:00:00 2001 From: Max Wash Date: Fri, 4 Jul 2025 15:38:42 +0100 Subject: [PATCH] substitute: implement an interface for performing variable reference substitution --- src/substitute.c | 104 +++++++++++++++++++++++++++++++++++++++++++++++ src/substitute.h | 25 ++++++++++++ 2 files changed, 129 insertions(+) create mode 100644 src/substitute.c create mode 100644 src/substitute.h diff --git a/src/substitute.c b/src/substitute.c new file mode 100644 index 0000000..dc92eeb --- /dev/null +++ b/src/substitute.c @@ -0,0 +1,104 @@ +#include "substitute.h" + +#define INVALID_INDEX ((size_t) - 1) + +enum ec3_status substitution_list_init(struct substitution_list *list) +{ + memset(list, 0x0, sizeof *list); + list->s_entries = b_dict_create(); + + return EC3_SUCCESS; +} + +enum ec3_status substitution_list_finish(struct substitution_list *list) +{ + b_dict_release(list->s_entries); + list->s_entries = NULL; + + return EC3_SUCCESS; +} + +enum ec3_status substitution_list_add_substitution( + struct substitution_list *list, + const char *find, + const char *replace_with) +{ + b_string *sub = b_string_create_from_cstr(replace_with); + b_status status = b_dict_put(list->s_entries, find, B_OBJECT(sub)); + b_string_release(sub); + + if (!B_OK(status)) { + return ec3_status_from_b_status( + status, + EC3_ERR_INTERNAL_FAILURE); + } + + return EC3_SUCCESS; +} + +static enum ec3_status perform_substitution( + struct substitution_list *list, + b_string *base, + size_t sub_start, + size_t sub_end) +{ + char sub[128]; + const char *s = b_string_ptr(base); + size_t sub_name_length = sub_end - sub_start - 2; + memcpy(sub, s + sub_start + 2, sub_name_length); + sub[sub_name_length] = '\0'; + + b_string *value = B_STRING(b_dict_at(list->s_entries, sub)); + if (value) { + b_string_replace( + base, + sub_start, + sub_end - sub_start + 1, + b_string_ptr(value)); + } else { + b_string_remove(base, sub_start, sub_end - sub_start + 1); + } + + return EC3_SUCCESS; +} + +enum ec3_status substitution_list_substitute( + struct substitution_list *list, + b_string *str) +{ + const char *s = b_string_ptr(str); + + size_t sub_start = INVALID_INDEX; + enum ec3_status status = EC3_SUCCESS; + + for (size_t i = 0; s[i]; i++) { + if (s[i] == '$' && s[i + 1] == '{') { + if (sub_start != INVALID_INDEX) { + status = EC3_ERR_BAD_FORMAT; + break; + } + + sub_start = i; + } else if (s[i] == '}') { + if (sub_start == INVALID_INDEX) { + status = EC3_ERR_BAD_FORMAT; + break; + } + + size_t sub_end = i; + status = perform_substitution( + list, + str, + sub_start, + sub_end); + if (status != EC3_SUCCESS) { + break; + } + + sub_start = INVALID_INDEX; + s = b_string_ptr(str); + } + } + + return status; +} diff --git a/src/substitute.h b/src/substitute.h new file mode 100644 index 0000000..2b15e9f --- /dev/null +++ b/src/substitute.h @@ -0,0 +1,25 @@ +#ifndef SUBSTITUTE_H_ +#define SUBSTITUTE_H_ + +#include "status.h" + +#include +#include + +struct substitution_list { + b_dict *s_entries; +}; + +extern enum ec3_status substitution_list_init(struct substitution_list *list); +extern enum ec3_status substitution_list_finish(struct substitution_list *list); + +extern enum ec3_status substitution_list_add_substitution( + struct substitution_list *list, + const char *find, + const char *replace_with); + +extern enum ec3_status substitution_list_substitute( + struct substitution_list *list, + b_string *str); + +#endif