1 #include <stdlib.h>
2 #include <string.h>
3 #include <ctype.h>
4 #include "options.h"
5 
6 struct sect sect_hd = {""};
7 
to_integer(const char * str,int n)8 static int to_integer(const char *str, int n)
9 {
10 	int i = *str=='-';
11 	if (str[i]>'0' && str[i]<='9') {
12 		i++;
13 		for (; i<n; i++)
14 			if (!isdigit(str[i]))
15 				return 0;
16 		return atoi(str);
17 	}
18 	return 0;
19 }
20 
strtoval(char * str,union val * val)21 int strtoval(char *str, union val *val)
22 {
23 	int n;
24 	while (isspace(*str))
25 		str++;
26 	n = strlen(str);
27 	while (n && isspace(str[n-1]))
28 		n--;
29 	val->integ = 0;
30 	if (n==1 && *str=='0')
31 		return 0;
32 	if (n >= 4) {
33 		str[n] = '\0';
34 		val->p = str;
35 		return 2;
36 	}
37 	if ((val->integ = to_integer(str, n)) != 0) {
38 		return 0;
39 	}
40 	strncpy(val->str, str, 4);
41 	if (n && n<4)
42 		val->str[n] = '\0';
43 	return 1;
44 }
45 
getsect(const char * name,struct sect ** prev)46 static struct sect *getsect(const char *name, struct sect **prev)
47 {
48 	struct sect *s = &sect_hd;
49 	if (!name[0])
50 		return s;
51 	while (s->next) {
52 		if (!strcmp(name, s->next->name)) {
53 			if (prev)
54 				*prev = s;
55 			return s->next;
56 		}
57 		s = s->next;
58 	}
59 	return NULL;
60 }
61 
addsect(const char * name)62 struct sect *addsect(const char *name)
63 {
64 	struct sect *s = getsect(name, NULL);
65 	if (!s) {
66 		s = malloc(sizeof(struct sect));
67 		strcpy(s->name, name);
68 		s->opts = NULL;
69 		s->next = sect_hd.next;
70 		sect_hd.next = s;
71 	}
72 	return s;
73 }
74 
newopt(const char * key,union val val,int tp)75 static struct option *newopt(const char *key, union val val, int tp)
76 {
77 	struct option *o;
78 	int n = sizeof(struct option) + strlen(key) - 2;
79 	int m = 0;
80 	char *p;
81 	if (tp == 1 && val.str[3])
82 		m = 5;
83 	if (tp == 2)
84 		m = strlen(val.p)+1;
85 	o = malloc(n+m);
86 	o->val = val;
87 	if (m) {
88 		p = (char *) o;
89 		p += n;
90 		if (tp == 2) {
91 			strncpy(o->val.str, val.p, 4);
92 			strcpy(p, val.p);
93 		} else {
94 			memcpy(p, val.str, 4);
95 			p[4] = '\0';
96 		}
97 		tp = 1;
98 	}
99 	o->tp_key[0] = tp;
100 	strcpy(opt_key(o), key);
101 	return o;
102 }
103 
addopt(const char * key,union val val,int tp,struct sect * sect)104 void addopt(const char *key, union val val, int tp, struct sect *sect)
105 {
106 	struct option *o = newopt(key, val, tp);
107 	if (!sect)
108 		sect = &sect_hd;
109 	o->next = sect->opts;
110 	sect->opts = o;
111 }
112 
getoptions(const char * sect_name)113 struct option *getoptions(const char *sect_name)
114 {
115 	struct sect *s = getsect(sect_name, NULL);
116 	if (s)
117 		return s->opts;
118 	return NULL;
119 }
120 
121 /* getopt might be declared in stdio.h */
get_opt(const char * sect_name,const char * key)122 static struct option *get_opt(const char *sect_name, const char *key)
123 {
124 	struct option *o = getoptions(sect_name);
125 	while (o) {
126 		if (!strcmp(key, opt_key(o)))
127 			return o;
128 		o = o->next;
129 	}
130 	return NULL;
131 }
132 
getopt_int(const char * sect_name,const char * key)133 int getopt_int(const char *sect_name, const char *key)
134 {
135 	struct option *o = get_opt(sect_name, key);
136 	if (o) {
137 		const char *s = opt_longstr(o);
138 		if (s) {
139 			int d = to_integer(s, strlen(s));
140 			if (d != 0)
141 				return d;
142 		}
143 		return o->val.integ;
144 	}
145 	return 0;
146 }
147 
getopt_str(const char * sect_name,const char * key)148 char *getopt_str(const char *sect_name, const char *key)
149 {
150 	struct option *o = get_opt(sect_name, key);
151 	if (o)
152 		return opt_longstr(o);
153 	return NULL;
154 }
155 
opt_longstr(struct option * o)156 char *opt_longstr(struct option *o)
157 {
158 	if (opt_isint(o))
159 		return NULL;
160 	if (!o->val.str[3])
161 		return o->val.str;
162 	return (char *) o + (sizeof(struct option) + strlen(opt_key(o)) - 2);
163 }
164 
rmopt(const char * key,struct option * o)165 static void rmopt(const char *key, struct option *o)
166 {
167 	struct option *p;
168 	while (o->next) {
169 		if (!strcmp(key, opt_key(o->next))) {
170 			p = o->next;
171 			o->next = p->next;
172 			free(p);
173 		} else
174 			o = o->next;
175 	}
176 }
177 
setoption(const char * sect_name,const char * key,union val val,int tp)178 void setoption(const char *sect_name, const char *key, union val val, int tp)
179 {
180 	struct sect *s = addsect(sect_name);
181 	struct option *o;
182 	if (tp==0 || tp==1 && !val.str[3]) {
183 		o = s->opts;
184 		while (o) {
185 			if (!strcmp(key, opt_key(o))) {
186 				o->val = val;
187 				o->tp_key[0] = tp;
188 				rmopt(key, o);
189 				return;
190 			}
191 			o = o->next;
192 		}
193 	}
194 	addopt(key, val, tp, s);
195 	rmopt(key, s->opts);
196 }
197 
unsetoption(const char * sect_name,const char * key)198 void unsetoption(const char *sect_name, const char *key)
199 {
200 	struct sect *s = getsect(sect_name, NULL);
201 	struct option *o;
202 	if (!s || !s->opts)
203 		return;
204 	o = s->opts;
205 	if (!strcmp(key, opt_key(o))) {
206 		s->opts = o->next;
207 		free(o);
208 	} else
209 		rmopt(key, o);
210 }
211 
freeoptions(const char * sect_name)212 void freeoptions(const char *sect_name)
213 {
214 	struct sect *s, *p;
215 	struct option *o;
216 	if (sect_name[0]) {
217 		s = getsect(sect_name, &p);
218 		if (!s)
219 			return;
220 		p->next = s->next;
221 	} else {
222 		while (sect_hd.next)
223 			freeoptions(sect_hd.next->name);
224 		s = &sect_hd;
225 	}
226 	while (o = s->opts) {
227 		s->opts = o->next;
228 		free(o);
229 	}
230 	if (sect_name[0])
231 		free(s);
232 	else
233 		s->opts = NULL;
234 }
235