fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
1/*****************************************************************************
2 * libini *
3 *****************************************************************************/
4
5/*****************************************************************************
6 * File name: src/libini/read.c *
7 * Created: 2001-08-24 by Hampa Hug <hampa@hampa.ch> *
8 * Copyright: (C) 2001-2020 Hampa Hug <hampa@hampa.ch> *
9 *****************************************************************************/
10
11/*****************************************************************************
12 * This program is free software. You can redistribute it and / or modify it *
13 * under the terms of the GNU General Public License version 2 as published *
14 * by the Free Software Foundation. *
15 * *
16 * This program is distributed in the hope that it will be useful, but *
17 * WITHOUT ANY WARRANTY, without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General *
19 * Public License for more details. *
20 *****************************************************************************/
21
22
23#include <config.h>
24
25#include <stdio.h>
26#include <string.h>
27
28#include <libini/libini.h>
29#include <libini/scanner.h>
30
31
32extern int ini_eval (scanner_t *scn, ini_sct_t *sct, ini_val_t *val);
33
34static int parse_section (scanner_t *scn, ini_sct_t *sct, char *buf);
35
36
37static
38void parse_error (scanner_t *scn, const char *text, int src)
39{
40 char c;
41 unsigned i;
42 const char *name;
43
44 if (scn->file != NULL) {
45 name = scn->file->name;
46 }
47 else {
48 name = NULL;
49 }
50
51 if (name == NULL) {
52 name = "<none>";
53 }
54
55 fprintf (stderr, "%s:%lu: %s",
56 name, scn->line + 1, text
57 );
58
59 if (src) {
60 fputs (": ", stderr);
61
62 for (i = 0; i < 64; i++) {
63 c = scn_get_chr (scn, i);
64
65 if (c == 0) {
66 fputs ("<eof>", stderr);
67 break;
68 }
69
70 if ((c == 0x0d) || (c == 0x0a)) {
71 fputs ("<nl>", stderr);
72 break;
73 }
74
75 fputc (c, stderr);
76 }
77 }
78
79 fputs ("\n", stderr);
80}
81
82static
83int skip_block (scanner_t *scn)
84{
85 int c;
86 unsigned cnt;
87
88 cnt = 1;
89
90 while ((c = scn_get_chr (scn, 0)) != 0) {
91 scn_rmv_chr (scn, 1);
92
93 if (c == '{') {
94 cnt += 1;
95 }
96 else if (c == '}') {
97 cnt -= 1;
98
99 if (cnt == 0) {
100 return (0);
101 }
102 }
103 }
104
105 return (1);
106}
107
108static
109int parse_block (scanner_t *scn, ini_sct_t *sct, char *buf, int skip)
110{
111 if (scn_match (scn, "{") == 0) {
112 return (1);
113 }
114
115 if (skip) {
116 return (skip_block (scn));
117 }
118
119 if (parse_section (scn, sct, buf)) {
120 return (1);
121 }
122
123 if (scn_match (scn, "}") == 0) {
124 return (1);
125 }
126
127 return (0);
128}
129
130static
131int parse_assign_undef (scanner_t *scn, ini_sct_t *sct, ini_val_t *tmp, const char *name)
132{
133 ini_val_t *val;
134
135 if (ini_eval (scn, sct, tmp)) {
136 return (1);
137 }
138
139 if (tmp->type == INI_VAL_NONE) {
140 return (1);
141 }
142
143 val = ini_get_val (sct, name, 0);
144
145 if (val != NULL) {
146 return (0);
147 }
148
149 val = ini_get_val (sct, name, 1);
150
151 if (val == NULL) {
152 return (1);
153 }
154
155 ini_val_copy (val, tmp);
156
157 return (0);
158}
159
160static
161int parse_if (scanner_t *scn, ini_sct_t *sct, char *buf)
162{
163 int done, skip;
164 ini_val_t val;
165
166 ini_val_init (&val, NULL);
167
168 if (ini_eval (scn, sct, &val)) {
169 ini_val_free (&val);
170 return (1);
171 }
172
173 if ((val.type == INI_VAL_INT) && (val.val.u32 != 0)) {
174 skip = 0;
175 done = 1;
176 }
177 else if ((val.type == INI_VAL_STR) && (val.val.str[0] != 0)) {
178 skip = 0;
179 done = 1;
180 }
181 else {
182 skip = 1;
183 done = 0;
184 }
185
186 ini_val_free (&val);
187
188 if (parse_block (scn, sct, buf, skip)) {
189 return (1);
190 }
191
192 while (scn_match_ident (scn, "else")) {
193 if (scn_match_ident (scn, "if")) {
194 ini_val_init (&val, NULL);
195
196 if (ini_eval (scn, sct, &val)) {
197 ini_val_free (&val);
198 return (1);
199 }
200
201 skip = 1;
202
203 if (done == 0) {
204 if ((val.type == INI_VAL_INT) && (val.val.u32 != 0)) {
205 skip = 0;
206 done = 1;
207 }
208 else if ((val.type == INI_VAL_STR) && (val.val.str[0] != 0)) {
209 skip = 0;
210 done = 1;
211 }
212 }
213
214 ini_val_free (&val);
215
216 if (parse_block (scn, sct, buf, skip)) {
217 return (1);
218 }
219 }
220 else {
221 if (parse_block (scn, sct, buf, done)) {
222 return (1);
223 }
224
225 break;
226 }
227 }
228
229 return (0);
230}
231
232static
233int parse_include (scanner_t *scn, ini_sct_t *sct, char *buf, int rel)
234{
235 int noerr;
236
237 noerr = (scn_match (scn, "?") != 0);
238
239 if (scn_match_string (scn, buf, 256) == 0) {
240 return (1);
241 }
242
243 if (scn_add_file (scn, buf, NULL, 1, rel)) {
244 if (noerr == 0) {
245 parse_error (scn, "can't open include file:", 0);
246 parse_error (scn, buf, 0);
247 return (1);
248 }
249 }
250
251 return (0);
252}
253
254static
255int parse_section (scanner_t *scn, ini_sct_t *sct, char *buf)
256{
257 int r;
258 ini_sct_t *sub;
259 ini_val_t *val;
260
261 while (1) {
262 if (scn_match_name (scn, buf, 256) == 0) {
263 return (0);
264 }
265
266 if (strcmp (buf, "section") == 0) {
267 if (scn_match_name (scn, buf, 256) == 0) {
268 return (1);
269 }
270 }
271
272 if (scn_match (scn, "{")) {
273 sub = ini_get_sct (sct, buf, 1);
274
275 if (sub == NULL) {
276 return (1);
277 }
278
279 if (parse_section (scn, sub, buf)) {
280 return (1);
281 }
282
283 if (scn_match (scn, "}") == 0) {
284 return (1);
285 }
286 }
287 else if (scn_match (scn, "?=")) {
288 ini_val_t tmp;
289
290 ini_val_init (&tmp, NULL);
291
292 r = parse_assign_undef (scn, sct, &tmp, buf);
293
294 ini_val_free (&tmp);
295
296 if (r) {
297 return (1);
298 }
299 }
300 else if (scn_match (scn, "=")) {
301 val = ini_get_val (sct, buf, 1);
302
303 if (val == NULL) {
304 return (1);
305 }
306
307 if (ini_eval (scn, sct, val)) {
308 return (1);
309 }
310
311 if (val->type == INI_VAL_NONE) {
312 return (1);
313 }
314 }
315 else if (strcmp (buf, "if") == 0) {
316 if (parse_if (scn, sct, buf)) {
317 return (1);
318 }
319 }
320 else if (strcmp (buf, "include") == 0) {
321 if (parse_include (scn, sct, buf, 0)) {
322 return (1);
323 }
324 }
325 else if (strcmp (buf, "rinclude") == 0) {
326 if (parse_include (scn, sct, buf, 1)) {
327 return (1);
328 }
329 }
330 else {
331 return (1);
332 }
333
334 scn_match (scn, ";");
335 }
336
337 return (1);
338}
339
340int ini_read_str (ini_sct_t *sct, const char *str)
341{
342 scanner_t scn;
343 char buf[256];
344
345 scn_init (&scn);
346 scn_set_str (&scn, str);
347
348 if (parse_section (&scn, sct, buf)) {
349 parse_error (&scn, "parse error before", 1);
350 scn_free (&scn);
351 return (1);
352 }
353
354 if (scn_get_chr (&scn, 0) != 0) {
355 parse_error (&scn, "parse error before", 1);
356 scn_free (&scn);
357 return (1);
358 }
359
360 scn_free (&scn);
361
362 return (0);
363}
364
365int ini_read_fp (ini_sct_t *sct, FILE *fp, const char *fname)
366{
367 scanner_t scn;
368 char buf[256];
369
370 scn_init (&scn);
371
372 if (scn_add_file (&scn, fname, fp, 0, 0)) {
373 ini_sct_del (sct);
374 return (1);
375 }
376
377 if (parse_section (&scn, sct, buf)) {
378 parse_error (&scn, "parse error before", 1);
379 scn_free (&scn);
380 return (1);
381 }
382
383 if (scn_get_chr (&scn, 0) != 0) {
384 parse_error (&scn, "parse error before", 1);
385 scn_free (&scn);
386 return (1);
387 }
388
389 scn_free (&scn);
390
391 return (0);
392}
393
394int ini_read (ini_sct_t *sct, const char *fname)
395{
396 int r;
397 FILE *fp;
398
399 fp = fopen (fname, "rb");
400
401 if (fp == NULL) {
402 return (1);
403 }
404
405 r = ini_read_fp (sct, fp, fname);
406
407 fclose (fp);
408
409 return (r);
410}