Skip to content

Commit b113bba

Browse files
committed
Created little config parser
An odd start, but a start nonetheless
0 parents  commit b113bba

File tree

2 files changed

+265
-0
lines changed

2 files changed

+265
-0
lines changed

emu/cfg.c

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
#include "cfg.h"
2+
3+
#include <stdlib.h>
4+
#include <errno.h>
5+
#include <string.h>
6+
#include <stdio.h>
7+
8+
9+
static int cfg_buffer(cfg_t *cfg, char c) {
10+
// Amortize double
11+
if (cfg->blen == cfg->bsize) {
12+
size_t nsize = cfg->bsize * 2;
13+
char *nbuf = malloc(nsize);
14+
if (!nbuf) {
15+
return -ENOMEM;
16+
}
17+
18+
memcpy(nbuf, cfg->buf, cfg->bsize);
19+
free(cfg->buf);
20+
cfg->buf = nbuf;
21+
cfg->bsize = nsize;
22+
}
23+
24+
cfg->buf[cfg->blen] = c;
25+
cfg->blen += 1;
26+
return 0;
27+
}
28+
29+
static int cfg_attr(cfg_t *cfg, unsigned key, unsigned val) {
30+
// Amortize double
31+
if (cfg->len == cfg->size) {
32+
size_t nsize = cfg->size * 2;
33+
struct cfg_attr *nattrs = malloc(nsize*sizeof(struct cfg_attr));
34+
if (!nattrs) {
35+
return -ENOMEM;
36+
}
37+
38+
memcpy(nattrs, cfg->attrs, cfg->size*sizeof(struct cfg_attr));
39+
free(cfg->attrs);
40+
cfg->attrs = nattrs;
41+
cfg->size = nsize;
42+
}
43+
44+
// Keep attrs sorted for binary search
45+
unsigned i = 0;
46+
while (i < cfg->len &&
47+
strcmp(&cfg->buf[key],
48+
&cfg->buf[cfg->attrs[i].key]) > 0) {
49+
i += 1;
50+
}
51+
52+
memmove(&cfg->attrs[i+1], &cfg->attrs[i],
53+
(cfg->size - i)*sizeof(struct cfg_attr));
54+
cfg->attrs[i].key = key;
55+
cfg->attrs[i].val = val;
56+
cfg->len += 1;
57+
return 0;
58+
}
59+
60+
static bool cfg_match(FILE *f, const char *matches) {
61+
char c = getc(f);
62+
ungetc(c, f);
63+
64+
for (int i = 0; matches[i]; i++) {
65+
if (c == matches[i]) {
66+
return true;
67+
}
68+
}
69+
70+
return false;
71+
}
72+
73+
int cfg_create(cfg_t *cfg, const char *filename) {
74+
// start with some initial space
75+
cfg->len = 0;
76+
cfg->size = 4;
77+
cfg->attrs = malloc(cfg->size*sizeof(struct cfg_attr));
78+
79+
cfg->blen = 0;
80+
cfg->bsize = 16;
81+
cfg->buf = malloc(cfg->size);
82+
83+
FILE *f = fopen(filename, "r");
84+
if (!f) {
85+
return -errno;
86+
}
87+
88+
while (!feof(f)) {
89+
int err;
90+
91+
while (cfg_match(f, " \t\v\f")) {
92+
fgetc(f);
93+
}
94+
95+
if (!cfg_match(f, "#\r\n")) {
96+
unsigned key = cfg->blen;
97+
while (!cfg_match(f, " \t\v\f:#") && !feof(f)) {
98+
if ((err = cfg_buffer(cfg, fgetc(f)))) {
99+
return err;
100+
}
101+
}
102+
if ((err = cfg_buffer(cfg, 0))) {
103+
return err;
104+
}
105+
106+
while (cfg_match(f, " \t\v\f")) {
107+
fgetc(f);
108+
}
109+
110+
if (cfg_match(f, ":")) {
111+
fgetc(f);
112+
while (cfg_match(f, " \t\v\f")) {
113+
fgetc(f);
114+
}
115+
116+
unsigned val = cfg->blen;
117+
while (!cfg_match(f, " \t\v\f#\r\n") && !feof(f)) {
118+
if ((err = cfg_buffer(cfg, fgetc(f)))) {
119+
return err;
120+
}
121+
}
122+
if ((err = cfg_buffer(cfg, 0))) {
123+
return err;
124+
}
125+
126+
if ((err = cfg_attr(cfg, key, val))) {
127+
return err;
128+
}
129+
} else {
130+
cfg->blen = key;
131+
}
132+
}
133+
134+
while (!cfg_match(f, "\r\n") && !feof(f)) {
135+
fgetc(f);
136+
}
137+
fgetc(f);
138+
}
139+
140+
return 0;
141+
}
142+
143+
void cfg_destroy(cfg_t *cfg) {
144+
free(cfg->attrs);
145+
}
146+
147+
bool cfg_has(cfg_t *cfg, const char *key) {
148+
return cfg_get(cfg, key, 0);
149+
}
150+
151+
const char *cfg_get(cfg_t *cfg, const char *key, const char *def) {
152+
// binary search for attribute
153+
int lo = 0;
154+
int hi = cfg->len-1;
155+
156+
while (lo <= hi) {
157+
int i = (hi + lo) / 2;
158+
int cmp = strcmp(key, &cfg->buf[cfg->attrs[i].key]);
159+
if (cmp == 0) {
160+
return &cfg->buf[cfg->attrs[i].val];
161+
} else if (cmp < 0) {
162+
hi = i-1;
163+
} else {
164+
lo = i+1;
165+
}
166+
}
167+
168+
return def;
169+
}
170+
171+
ssize_t cfg_geti(cfg_t *cfg, const char *key, ssize_t def) {
172+
const char *val = cfg_get(cfg, key, 0);
173+
if (!val) {
174+
return def;
175+
}
176+
177+
char *end;
178+
ssize_t res = strtoll(val, &end, 0);
179+
return (end == val) ? def : res;
180+
}
181+
182+
size_t cfg_getu(cfg_t *cfg, const char *key, size_t def) {
183+
const char *val = cfg_get(cfg, key, 0);
184+
if (!val) {
185+
return def;
186+
}
187+
188+
char *end;
189+
size_t res = strtoull(val, &end, 0);
190+
return (end == val) ? def : res;
191+
}

emu/cfg.h

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
* Simple config parser
3+
*
4+
* Copyright (c) 2016 Christopher Haster
5+
* Distributed under the MIT license
6+
*/
7+
#ifndef CFG_H
8+
#define CFG_H
9+
10+
#include <stddef.h>
11+
#include <stdbool.h>
12+
#include <unistd.h>
13+
14+
// This is a simple parser for config files
15+
//
16+
// The cfg file format is dumb simple. Attributes are
17+
// key value pairs separated by a single colon. Delimited
18+
// by comments (#) and newlines (\r\n) and trims
19+
// whitespace ( \t\v\f)
20+
//
21+
// Here's an example file
22+
// # Here is a dump example
23+
// looky: it's_an_attribute
24+
// hey_look: another_attribute
25+
//
26+
// huh: yeah_that's_basically_it # basically it
27+
28+
// Internal config structure
29+
typedef struct cfg {
30+
size_t len;
31+
size_t size;
32+
33+
size_t blen;
34+
size_t bsize;
35+
char *buf;
36+
37+
struct cfg_attr {
38+
unsigned key;
39+
unsigned val;
40+
} *attrs;
41+
} cfg_t;
42+
43+
44+
45+
// Creates a cfg object and reads in the cfg file from the filename
46+
//
47+
// If the cfg_read fails, returns a negative value from the underlying
48+
// stdio functions
49+
int cfg_create(cfg_t *cfg, const char *filename);
50+
51+
// Destroys the cfg object and frees any used memory
52+
void cfg_destroy(cfg_t *cfg);
53+
54+
// Checks if a cfg attribute exists
55+
bool cfg_has(cfg_t *cfg, const char *key);
56+
57+
// Retrieves a cfg attribute as a null-terminated string
58+
//
59+
// If the attribute does not exist, returns the string passed as def
60+
const char *cfg_get(cfg_t *cfg, const char *key, const char *def);
61+
62+
// Retrieves a cfg attribute parsed as an int
63+
//
64+
// If the attribute does not exist or can't be parsed, returns the
65+
// integer passed as def
66+
ssize_t cfg_geti(cfg_t *cfg, const char *name, ssize_t def);
67+
68+
// Retrieves a cfg attribute parsed as an unsigned int
69+
//
70+
// If the attribute does not exist or can't be parsed, returns the
71+
// integer passed as def
72+
size_t cfg_getu(cfg_t *cfg, const char *name, size_t def);
73+
74+
#endif

0 commit comments

Comments
 (0)