substitute: implement an interface for performing variable reference substitution

This commit is contained in:
2025-07-04 15:38:42 +01:00
parent 265b4ba574
commit 54d5c081eb
2 changed files with 129 additions and 0 deletions

104
src/substitute.c Normal file
View File

@@ -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;
}

25
src/substitute.h Normal file
View File

@@ -0,0 +1,25 @@
#ifndef SUBSTITUTE_H_
#define SUBSTITUTE_H_
#include "status.h"
#include <blue/object/dict.h>
#include <blue/object/string.h>
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