diff options
Diffstat (limited to 'pom.c')
-rw-r--r-- | pom.c | 53 |
1 files changed, 49 insertions, 4 deletions
@@ -1,7 +1,3 @@ -/* -TODO: -- get_list -*/ #include "pom.h" #include <stdio.h> // still needed for sprintf, even if POM_NO_STDIO is defined. @@ -1788,3 +1784,52 @@ pom_conf_get_bool_or_default(const pom_conf *conf, const char *key, bool *value_ return NULL; return value_str; } + +char ** +pom_conf_get_list(const pom_conf *conf, const char *key) { + check_conf(conf); + if (!key) fatal_error("NULL key passed to %s", __func__); + const char *value_str = pom_conf_get(conf, key); + if (!value_str) return NULL; + size_t max_entries = 1; // upper bound on # of entries + for (const char *p = value_str; *p; p++) + max_entries += *p == ','; + if (max_entries > SIZE_MAX / 16) { + // too many entries (avoid arithmetic overflow) + return NULL; + } + size_t bytes_needed = (max_entries+1) * sizeof (char *) + + strlen(value_str) + 1; + char **list = malloc(bytes_needed); + if (!list) return NULL; + char **entry = list; + char *strings = (char *)(list + max_entries+1); + const char *p = value_str; + while (true) { + while (strchr(" \t\n", *p)) p++; + const char *end = p; + char *out = *entry++ = strings; + for (; *end; end++) { + if (*end == '\\' && (end[1] == ',' || end[1] == '\\')) { + end++; + *out++ = *end; + } else if (*end == ',' || *end == '\0') { + break; + } else { + *out++ = *end; + } + } + *out = 0; + while (out > strings && strchr(" \t\n", out[-1])) + *--out = 0; + strings = out + 1; + if (*end == '\0') break; + p = end + 1; + } + // remove last entry if it's empty + if (entry > list && *entry[-1] == 0) { + entry[-1] = NULL; + } + *entry = NULL; + return list; +} |