==> src/catalog_toml.c <==1/* Line probes of program.toml, one per grep/sed of build-programs.sh. */
2#include "mesh/catalog_toml.h"
3
4#include <stdint.h>
5#include <string.h>
6
7/* Calls f on each line (without its newline) until it returns true. */
8static bool each_line(const char *t, bool (*f)(const char *l, size_t n, void *u), void *u) {
9 while (*t) {
10 const char *e = strchr(t, '\n');
11 size_t n = e ? (size_t)(e - t) : strlen(t);
12 if (f(t, n, u)) return true;
13 if (!e) break;
14 t = e + 1;
15 }
16 return false;
17}
18
19static size_t skip_spaces(const char *l, size_t i, size_t n) {
20 while (i < n && l[i] == ' ') i++;
21 return i;
22}
23
24typedef struct {
25 char *out;
26 size_t cap;
27} name_q;
28
29static bool name_line(const char *l, size_t n, void *u) {
30 name_q *q = u;
31 if (n < 4 || memcmp(l, "name", 4) != 0) return false;
32 size_t i = skip_spaces(l, 4, n);
33 if (i >= n || l[i] != '=') return false;
34 i = skip_spaces(l, i + 1, n);
35 if (i >= n || l[i] != '"') return false;
36 /* sed's greedy .* up to the last '"' of the line, which must end it. */
37 if (l[n - 1] != '"' || n - 1 <= i) return false;
38 size_t len = n - 1 - (i + 1);
39 if (len + 1 > q->cap) return false;
40 memcpy(q->out, l + i + 1, len);
41 q->out[len] = 0;
42 return true;
43}
44
45bool mesh_catalog_toml_name(const char *text, char *out, size_t cap) {
46 name_q q = {out, cap};
47 return each_line(text, name_line, &q);
48}
49
50static bool starts(const char *l, size_t n, const char *p) {
51 size_t k = strlen(p);
52 return n >= k && memcmp(l, p, k) == 0;
53}
54
55static bool backends_line(const char *l, size_t n, void *u) {
56 (void)u;
57 return starts(l, n, "backends");
58}
59bool mesh_catalog_toml_has_backends(const char *text) { return each_line(text, backends_line, NULL); }
60
61/* '^backends *= *\[ *"native" *\]' (the line may go on after the ']'). */
62static bool native_line(const char *l, size_t n, void *u) {
63 (void)u;
64 if (!starts(l, n, "backends")) return false;
65 size_t i = skip_spaces(l, 8, n);
66 if (i >= n || l[i] != '=') return false;
67 i = skip_spaces(l, i + 1, n);
68 if (i >= n || l[i] != '[') return false;
69 i = skip_spaces(l, i + 1, n);
70 if (n - i < 8 || memcmp(l + i, "\"native\"", 8) != 0) return false;
71 i = skip_spaces(l, i + 8, n);
72 return i < n && l[i] == ']';
73}
74bool mesh_catalog_toml_native(const char *text) { return each_line(text, native_line, NULL); }
75
76static bool backend_line(const char *l, size_t n, void *u) {
77 const char *want = u;
78 if (!starts(l, n, "backends")) return false;
79 size_t i = skip_spaces(l, 8, n);
80 if (i >= n || l[i] != '=') return false;
81 size_t k = strlen(want);
82 for (size_t j = i + 1; j + k + 2 <= n; j++)
83 if (l[j] == '"' && memcmp(l + j + 1, want, k) == 0 && l[j + 1 + k] == '"') return true;
84 return false;
85}
86bool mesh_catalog_toml_backend(const char *text, const char *b) { return each_line(text, backend_line, (void *)(uintptr_t)b); }
87
88typedef struct {
89 const char *key;
90 char *out;
91 size_t cap, len;
92 bool found;
93} comment_q;
94
95static bool comment_line(const char *l, size_t n, void *u) {
96 comment_q *q = u;
97 size_t k = strlen(q->key);
98 if (n < 4 + k || l[0] != '#' || l[1] != ' ' || memcmp(l + 2, q->key, k) != 0 || l[2 + k] != ':') return false;
99 size_t i = skip_spaces(l, 3 + k, n);
100 size_t len = n - i;
101 if (q->found && q->len + 1 < q->cap) q->out[q->len++] = '\n';
102 if (q->len + len + 1 > q->cap) len = q->cap - q->len - 1;
103 memcpy(q->out + q->len, l + i, len);
104 q->len += len;
105 q->out[q->len] = 0;
106 q->found = true;
107 return false;
108}
109
110bool mesh_catalog_toml_comment(const char *text, const char *key, char *out, size_t cap) {
111 if (cap == 0) return false;
112 comment_q q = {key, out, cap, 0, false};
113 out[0] = 0;
114 each_line(text, comment_line, &q);
115 return q.found;
116}