commit - d4bc3969e0e863ce00f19586bb95bd95278f2542
commit + b222bed8e90c03020af831d291ffde61306aae5b
blob - f7c02d5842cc12348e0c0c6408373a0eec5a52af
blob + 457b677af8e441e0332985be02f0e4f845110887
--- Makefile.am
+++ Makefile.am
bin_PROGRAMS = xc
-xc_SOURCES = xc.c
+xc_SOURCES = list.c list.h \
+ xc.c
LDADD = $(LIBOBJS)
blob - /dev/null
blob + 036f6c920815db37b946b0504c1f18ad04a968fd (mode 644)
--- /dev/null
+++ list.c
+/*
+ * Copyright (c) 2021 Omar Polo <op@omarpolo.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Simplicistic list parser.
+ */
+
+#include "compat.h"
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "list.h"
+
+static int
+push_item(struct listhead *h, int type, char *str, int64_t num)
+{
+ struct item *i;
+
+ if ((i = calloc(1, sizeof(*i))) == NULL)
+ return -1;
+
+ switch (i->type = type) {
+ case ATOM_STRING:
+ case ATOM_SYMBOL:
+ case ATOM_KEYWORD:
+ i->v.str = str;
+ break;
+ case ATOM_NUMBER:
+ i->v.num = num;
+ break;
+ default:
+ /* unreachable */
+ abort();
+ }
+
+ SIMPLEQ_INSERT_TAIL(h, i, items);
+
+ return 0;
+}
+
+static int
+parse_keyword(char **line, struct listhead *h)
+{
+ char *start;
+
+ if (**line != ':')
+ return -1;
+ start = ++(*line);
+
+ while (**line != '\0' && !isspace(**line))
+ (*line)++;
+
+ **line = '\0';
+ return push_item(h, ATOM_KEYWORD, start, 0);
+}
+
+static int
+parse_symbol(char **line, struct listhead *h)
+{
+ char *start;
+
+ start = *line;
+
+ while (**line != '\0' && !isspace(**line))
+ (*line)++;
+
+ **line = '\0';
+ return push_item(h, ATOM_SYMBOL, start, 0);
+}
+
+static int
+parse_string(char **line, struct listhead *h)
+{
+ char *start;
+ int esc = 0;
+
+ if (**line != '\"')
+ return -1;
+
+ for (start = ++(*line); !esc && **line == '\"'; ++(*line)) {
+ if (**line == '\0')
+ return -1;
+ else if (esc)
+ esc = 0;
+ else if (**line == '\\')
+ esc = 1;
+ }
+
+ **line = '\0';
+
+ return push_item(h, ATOM_STRING, start, 0);
+}
+
+static int
+parse_number(char **line, struct listhead *h)
+{
+ char *end;
+ int64_t num;
+
+ if (!isdigit(**line))
+ return -1;
+
+ num = strtol(*line, &end, 0);
+ if (*end != '\0' && !isspace(*end))
+ return -1;
+ if (errno == ERANGE && (num == LONG_MAX || num == LONG_MIN))
+ return -1;
+
+ *line = end;
+ return push_item(h, ATOM_NUMBER, NULL, num);
+}
+
+int
+parse_list(char *line, struct listhead *h)
+{
+ char *end;
+
+ /*
+ * Make sure the string starts with `(' and ends with a `)',
+ * then remove those characters from the string and parse the
+ * content.
+ */
+
+ if (*line != '(')
+ return -1;
+ line++;
+
+ end = strchr(line, '\0');
+ if (*--end != ')')
+ return -1;
+ *end = '\0';
+
+ while (line < end) {
+ while (isspace(*line))
+ ++line;
+
+ switch (*line) {
+ case ':':
+ if (parse_keyword(&line, h) == -1)
+ return -1;
+ break;
+ case '\"':
+ if (parse_string(&line, h) == -1)
+ return -1;
+ break;
+ default:
+ if (isdigit(*line) && parse_number(&line, h) == -1)
+ return -1;
+ if (parse_symbol(&line, h) == -1)
+ return -1;
+ }
+ ++line;
+ }
+
+ return 0;
+}
+
+void
+free_list(struct listhead *h)
+{
+ struct item *i, *it;
+
+ SIMPLEQ_FOREACH_SAFE(i, h, items, it) {
+ free(i);
+ }
+}
+
+struct item *
+plist_get(struct listhead *h, const char *keyword)
+{
+ struct item *i;
+ int skip = 0;
+
+ SIMPLEQ_FOREACH(i, h, items) {
+ if (skip) {
+ skip = 0;
+ continue;
+ }
+
+ if (i->type == ATOM_KEYWORD &&
+ !strcmp(keyword, i->v.str))
+ return SIMPLEQ_NEXT(i, items);
+ }
+
+ return NULL;
+}
+
+void
+print_list(struct listhead *h, FILE *out)
+{
+ struct item *i;
+ int first = 1;
+
+ fprintf(out, "(");
+
+ SIMPLEQ_FOREACH(i, h, items) {
+ if (first)
+ first = 0;
+ else
+ fprintf(out, " ");
+
+ switch (i->type) {
+ case ATOM_STRING:
+ fprintf(out, "\"%s\"", i->v.str);
+ break;
+ case ATOM_SYMBOL:
+ fprintf(out, "%s", i->v.str);
+ break;
+ case ATOM_KEYWORD:
+ fprintf(out, ":%s", i->v.str);
+ break;
+ case ATOM_NUMBER:
+ fprintf(out, "%"PRIi64, i->v.num);
+ break;
+ default:
+ /* unreachable */
+ abort();
+ }
+ }
+
+ fprintf(out, ")\n");
+}
blob - /dev/null
blob + 5abb29aefbbacca08e45dd8a098a1e556ceba6dd (mode 644)
--- /dev/null
+++ list.h
+/*
+ * Copyright (c) 2021 Omar Polo <op@omarpolo.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef LIST_H
+#define LIST_H
+
+#include <sys/queue.h>
+
+#include <stdint.h>
+#include <stdio.h>
+
+enum atom_type {
+ ATOM_STRING,
+ ATOM_SYMBOL,
+ ATOM_KEYWORD,
+ ATOM_NUMBER,
+};
+
+SIMPLEQ_HEAD(listhead, item);
+
+struct item {
+ int type;
+ union {
+ char *str;
+ int64_t num;
+ } v;
+ SIMPLEQ_ENTRY(item) items;
+};
+
+int parse_list(char *, struct listhead *);
+void free_list(struct listhead *);
+struct item *plist_get(struct listhead *, const char *);
+void print_list(struct listhead *, FILE *);
+
+#endif