summaryrefslogtreecommitdiff
path: root/pom.c
diff options
context:
space:
mode:
Diffstat (limited to 'pom.c')
-rw-r--r--pom.c53
1 files changed, 49 insertions, 4 deletions
diff --git a/pom.c b/pom.c
index fbbe6e0..1ed3c9b 100644
--- a/pom.c
+++ b/pom.c
@@ -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;
+}