summaryrefslogtreecommitdiff
path: root/pom.c
diff options
context:
space:
mode:
authorpommicket <pommicket@gmail.com>2025-09-11 16:40:04 -0400
committerpommicket <pommicket@gmail.com>2025-09-11 16:40:47 -0400
commitec9cf4ef9b4ff2a16172e72adf5fca2a94ba3009 (patch)
tree0dfcd4d1bb36b26804d773b6a4c053e5ac4969d9 /pom.c
parent06b3634741718a264bef03ee7b38455a2482bb24 (diff)
Start libpom implementation
Diffstat (limited to 'pom.c')
-rw-r--r--pom.c172
1 files changed, 172 insertions, 0 deletions
diff --git a/pom.c b/pom.c
index 4d53705..135e0d9 100644
--- a/pom.c
+++ b/pom.c
@@ -1,5 +1,24 @@
#include "pom.h"
+#include <stdio.h> // still needed for sprintf, even if POM_NO_STDIO is defined.
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include <inttypes.h>
+
+#if __GNUC__ >= 6
+#define ATTRIBUTE_PRINTF(fmt, args) __attribute__ ((format(printf, fmt, args)))
+#else
+#define ATTRIBUTE_PRINTF(fmt, args)
+#endif
+#if _MSC_VER >= 1600
+#define PRINTF_FORMAT_STRING _Printf_format_string_
+#else
+#define PRINTF_FORMAT_STRING
+#endif
+
struct pom_error {
const pom_error *next;
const char *file;
@@ -7,22 +26,175 @@ struct pom_error {
const char *message;
};
+struct main_conf;
+
+struct pom_conf {
+ struct main_conf *main;
+ size_t prefix_len;
+ const struct conf_item *items;
+ size_t items_count;
+};
+
+struct conf_items {
+ const char *key;
+ const char *value;
+ const pom_conf *section;
+};
+
+struct main_conf {
+ struct conf_item *items;
+ size_t items_count;
+};
+
+#ifdef POM_NO_STDIO
+#define fatal_error(...) abort()
+#else
+// fatal_error should only be called when the API is misused
+// (e.g. `NULL` argument that shouldn't be `NULL`).
+static void fatal_error(PRINTF_FORMAT_STRING const char *fmt, ...) ATTRIBUTE_PRINTF(1, 2);
+static void
+fatal_error(const char *fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+ abort();
+}
+#endif
+
+// Make an error with no next-error.
+static pom_error *make_error(PRINTF_FORMAT_STRING const char *file, uint64_t line, const char *fmt, ...) ATTRIBUTE_PRINTF(3, 4);
+static pom_error *
+make_error(const char *file, uint64_t line, const char *fmt, ...) {
+ va_list args, args_copy;
+ va_start(args, fmt);
+ va_copy(args_copy, args);
+ bool bad_fmt = false;
+ int len = vsnprintf(NULL, 0, fmt, args);
+ if (len < 0 || len > INT_MAX - sizeof(pom_error) - 1) {
+ // Should probably never happen? Who knows though.
+ // In this case, we just use fmt as the error message.
+ bad_fmt = true;
+ len = strlen(fmt);
+ }
+ pom_error *err = malloc(sizeof(pom_error) + len + 1);
+ if (err) {
+ char *message = (char *)(err + 1);
+ if (bad_fmt) {
+ strcpy(message, fmt);
+ } else {
+ vsnprintf(message, len + 1, fmt, args);
+ }
+ err->file = file;
+ err->line = line;
+ err->message = message;
+ err->next = NULL;
+ }
+ return err;
+}
+
const pom_error *
pom_error_next(const pom_error *error) {
+ if (!error) return NULL;
return error->next;
}
const char *
pom_error_file(const pom_error *error) {
+ if (!error)
+ fatal_error("%s called with NULL argument", __func__);
return error->file;
}
uint64_t
pom_error_line(const pom_error *error) {
+ if (!error)
+ fatal_error("%s called with NULL argument", __func__);
return error->line;
}
const char *
pom_error_message(const pom_error *error) {
+ if (!error)
+ fatal_error("%s called with NULL argument", __func__);
return error->message;
}
+
+#ifndef POM_NO_STDIO
+void
+pom_error_print(const pom_error *error) {
+ if (!error) {
+ fprintf(stderr, "No error.\n");
+ return;
+ }
+ fprintf(stderr, "Error:\n");
+ for (; error; error = pom_error_next(error)) {
+ fprintf(stderr, "%s:%" PRIu64 ": %s\n", error->file, error->line, error->message);
+ }
+}
+#endif
+
+pom_conf *
+pom_load(const char *filename,
+ size_t (*read_func)(void *userdata, char *buf, size_t len),
+ void *userdata, pom_error **error) {
+ if (!filename)
+ fatal_error("%s called with NULL file name", __func__);
+ if (!read_func)
+ fatal_error("%s called with NULL read function", __func__);
+ // TODO
+ if (error) *error = NULL;
+ return NULL;
+}
+
+static size_t
+read_string(void *vpstring, char *buf, size_t len) {
+ const char **pstring = vpstring;
+ const char *string = *pstring;
+ size_t i;
+ for (i = 0; i < len; i++, string++) {
+ if (*string == 0) break;
+ buf[i] = *string;
+ }
+ *pstring = string;
+ return i;
+}
+
+pom_conf *
+pom_load_string(const char *filename, const char *string, pom_error **error) {
+ return pom_load(filename, read_string, &string, error);
+}
+
+#ifndef POM_NO_STDIO
+static size_t
+read_file(void *file, char *buf, size_t len) {
+ return fread(buf, 1, len, file);
+}
+
+pom_conf *
+pom_load_file(const char *filename, FILE *file, pom_error **error) {
+ if (!filename)
+ fatal_error("%s called with NULL file name", __func__);
+ if (!file)
+ fatal_error("%s called with NULL file", __func__);
+ return pom_load(filename, read_file, file, error);
+}
+
+pom_conf *
+pom_load_path(const char *path, pom_error **error) {
+ if (!path)
+ fatal_error("%s called with NULL file name", __func__);
+ FILE *fp = fopen(path, "rb");
+ if (!fp) {
+ if (error) {
+ const char *message = strerror(errno);
+ *error = make_error(path, 1, "Couldn't open file: %s", message);
+ }
+ return NULL;
+ }
+ pom_conf *conf = pom_load_file(path, fp, error);
+ fclose(fp);
+ return conf;
+}
+#endif