fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
1/*****************************************************************************
2 * libini *
3 *****************************************************************************/
4
5/*****************************************************************************
6 * File name: src/libini/scanner.c *
7 * Created: 2000-12-18 by Hampa Hug <hampa@hampa.ch> *
8 * Copyright: (C) 2000-2024 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 <stdlib.h>
27#include <string.h>
28
29#include <libini/scanner.h>
30
31
32#ifdef PCE_HOST_WINDOWS
33#define scn_is_dir_sep(c) (((c) == '/') || ((c) == '\\'))
34#else
35#define scn_is_dir_sep(c) ((c) == PCE_DIR_SEP)
36#endif
37
38
39/*
40 * If name is an absolute path or base is NULL, return a copy of name.
41 * Otherwise return a copy of (directory name of base) + name.
42 */
43static
44char *scn_file_get_name (const char *base, const char *name)
45{
46 unsigned n1, n2;
47 char *ret;
48
49 if (scn_is_dir_sep (*name)) {
50 n1 = 0;
51 }
52#ifdef PCE_HOST_WINDOWS
53 else if ((name[0] != 0) && (name[1] == ':')) {
54 n1 = 0;
55 }
56#endif
57 else if (base != NULL) {
58 n1 = strlen (base);
59
60 while ((n1 > 0) && (base[n1 - 1] == PCE_DIR_SEP)) {
61 n1 -= 1;
62 }
63
64 while ((n1 > 0) && (base[n1 - 1] != PCE_DIR_SEP)) {
65 n1 -= 1;
66 }
67 }
68 else {
69 n1 = 0;
70 }
71
72 n2 = strlen (name);
73
74 ret = malloc (n1 + n2 + 1);
75
76 if (ret == NULL) {
77 return (NULL);
78 }
79
80 if (n1 > 0) {
81 memcpy (ret, base, n1);
82 }
83
84 memcpy (ret + n1, name, n2);
85
86 ret[n1 + n2] = 0;
87
88 return (ret);
89}
90
91static
92scn_file_t *scn_file_new (void)
93{
94 scn_file_t *scf;
95
96 scf = malloc (sizeof (scn_file_t));
97
98 if (scf == NULL) {
99 return (NULL);
100 }
101
102 scf->next = NULL;
103 scf->name = NULL;
104 scf->fp = NULL;
105 scf->del = 0;
106
107 return (scf);
108}
109
110static
111void scn_file_del (scn_file_t *scf)
112{
113 scn_file_t *tmp;
114
115 while (scf != NULL) {
116 tmp = scf;
117 scf = scf->next;
118
119 if (tmp->del) {
120 fclose (tmp->fp);
121 }
122
123 free (tmp->name);
124 free (tmp);
125 }
126}
127
128void scn_init (scanner_t *scn)
129{
130 scn->cnt = 0;
131
132 scn->line = 0;
133 scn->offset = 0;
134
135 scn->file = NULL;
136 scn->str = NULL;
137}
138
139void scn_free (scanner_t *scn)
140{
141 if (scn != NULL) {
142 scn_file_del (scn->file);
143 }
144}
145
146void scn_set_str (scanner_t *scn, const char *str)
147{
148 scn->str = str;
149}
150
151int scn_add_file (scanner_t *scn, const char *fname, FILE *fp, int del, int rel)
152{
153 char *name;
154 scn_file_t *scf;
155
156 scf = scn_file_new();
157
158 if (scf == NULL) {
159 return (1);
160 }
161
162 if ((scn->file == NULL) || (rel == 0)) {
163 name = scn_file_get_name (NULL, fname);
164 }
165 else {
166 name = scn_file_get_name (scn->file->name, fname);
167 }
168
169 if (scn->file != NULL) {
170 scn->file->line = scn->line;
171 scn->file->offset = scn->offset;
172 }
173
174 if (name == NULL) {
175 scn_file_del (scf);
176 return (1);
177 }
178
179 scf->name = name;
180
181 if (fp != NULL) {
182 scf->fp = fp;
183 }
184 else {
185 scf->fp = fopen (name, "r");
186 }
187
188 if (scf->fp == NULL) {
189 scn_file_del (scf);
190 return (1);
191 }
192
193 scf->del = (fp != NULL) && del;
194
195 scf->next = scn->file;
196 scn->file = scf;
197
198 scn->line = 0;
199 scn->offset = 0;
200
201 return (0);
202}
203
204static
205int scn_rmv_file (scanner_t *scn)
206{
207 scn_file_t *scf;
208
209 if (scn->file == NULL) {
210 return (0);
211 }
212
213 scf = scn->file;
214 scn->file = scn->file->next;
215 scf->next = NULL;
216
217 scn_file_del (scf);
218
219 if (scn->file != NULL) {
220 scn->line = scn->file->line;
221 scn->offset = scn->file->offset;
222 }
223
224 return (0);
225}
226
227static
228char scn_next_char (scanner_t *scn)
229{
230 int c;
231
232 if (scn->file != NULL) {
233 while (scn->file != NULL) {
234 c = fgetc (scn->file->fp);
235
236 if (c != EOF) {
237 return (c);
238 }
239
240 scn_rmv_file (scn);
241 }
242
243 return (0);
244 }
245
246 if (scn->str != NULL) {
247 if (scn->str[0] == 0) {
248 return (0);
249 }
250
251 c = scn->str[0];
252
253 scn->str += 1;
254
255 return (c);
256 }
257
258 return (0);
259}
260
261static
262void scn_process_char (scanner_t *scn, char c)
263{
264 if (c == 0) {
265 return;
266 }
267
268 scn->offset += 1;
269
270 if (c == 0x0d) {
271 scn->line += 1;
272 scn->nl = 1;
273 }
274 else if (c == 0x0a) {
275 if (scn->nl == 0) {
276 scn->line += 1;
277 }
278
279 scn->nl = 0;
280 }
281 else {
282 scn->nl = 0;
283 }
284}
285
286char scn_get_chr (scanner_t *scn, unsigned idx)
287{
288 if (idx >= SCN_BUF_MAX) {
289 return (0);
290 }
291
292 while (idx >= scn->cnt) {
293 scn->buf[scn->cnt] = scn_next_char (scn);
294
295 if (scn->buf[scn->cnt] == 0) {
296 return (0);
297 }
298
299 scn->cnt += 1;
300 }
301
302 return (scn->buf[idx]);
303}
304
305void scn_rmv_chr (scanner_t *scn, unsigned cnt)
306{
307 unsigned i;
308
309 if (cnt < scn->cnt) {
310 for (i = 0; i < cnt; i++) {
311 scn_process_char (scn, scn->buf[i]);
312 }
313
314 for (i = cnt; i < scn->cnt; i++) {
315 scn->buf[i - cnt] = scn->buf[i];
316 }
317
318 scn->cnt -= cnt;
319 }
320 else {
321 for (i = 0; i < scn->cnt; i++) {
322 scn_process_char (scn, scn->buf[i]);
323 }
324
325 cnt -= scn->cnt;
326
327 scn->cnt = 0;
328
329 while (cnt > 0) {
330 scn_process_char (scn, scn_next_char (scn));
331 cnt -= 1;
332 }
333 }
334}
335
336unsigned long scn_get_line (const scanner_t *scn)
337{
338 return (scn->line);
339}
340
341unsigned long scn_get_offset (const scanner_t *scn)
342{
343 return (scn->offset);
344}
345
346static
347int scn_is_space (char c)
348{
349 if ((c == ' ') || (c == '\t')) {
350 return (1);
351 }
352
353 if ((c == 0x0d) || (c == 0x0a)) {
354 return (1);
355 }
356
357 return (0);
358}
359
360static
361int scn_is_alpha (char c)
362{
363 if ((c >= 'a') && (c <= 'z')) {
364 return (1);
365 }
366
367 if ((c >= 'A') && (c <= 'Z')) {
368 return (1);
369 }
370
371 if (c == '_') {
372 return (1);
373 }
374
375 return (0);
376}
377
378static
379int scn_is_numeric (char c)
380{
381 if ((c >= '0') && (c <= '9')) {
382 return (1);
383 }
384
385 return (0);
386}
387
388static
389void scn_skip_line (scanner_t *scn)
390{
391 char c;
392
393 while (1) {
394 c = scn_get_chr (scn, 0);
395
396 if (c == 0) {
397 return;
398 }
399
400 scn_rmv_chr (scn, 1);
401
402 if (c == 0x0d) {
403 if (scn_get_chr (scn, 0) == 0x0a) {
404 scn_rmv_chr (scn, 1);
405 }
406
407 return;
408 }
409 else if (c == 0x0a) {
410 return;
411 }
412 }
413}
414
415static
416void scn_skip_comment (scanner_t *scn)
417{
418 unsigned level;
419 char buf[2];
420
421 level = 0;
422
423 buf[0] = 0;
424 buf[1] = 0;
425
426 while (1) {
427 buf[0] = buf[1];
428 buf[1] = scn_get_chr (scn, 0);
429
430 if (buf[1] == 0) {
431 return;
432 }
433
434 scn_rmv_chr (scn, 1);
435
436 if ((buf[0] == '*') && (buf[1] == '/')) {
437 if (level == 0) {
438 return;
439 }
440
441 buf[1] = 0;
442 level -= 1;
443 }
444 else if ((buf[0] == '/') && (buf[1] == '*')) {
445 buf[1] = 0;
446 level += 1;
447 }
448 }
449}
450
451int scn_match_space (scanner_t *scn)
452{
453 int r;
454 char c;
455
456 r = 0;
457
458 while (1) {
459 c = scn_get_chr (scn, 0);
460
461 if (scn_is_space (c)) {
462 scn_rmv_chr (scn, 1);
463 }
464 else if ((c == ';') || (c == '#')) {
465 scn_skip_line (scn);
466 }
467 else if ((c == '/') && (scn_get_chr (scn, 1) == '/')) {
468 scn_skip_line (scn);
469 }
470 else if ((c == '/') && (scn_get_chr (scn, 1) == '*')) {
471 scn_rmv_chr (scn, 2);
472 scn_skip_comment (scn);
473 }
474 else {
475 return (r);
476 }
477
478 r = 1;
479 }
480
481 return (1);
482}
483
484int scn_match_name (scanner_t *scn, char *str, unsigned max)
485{
486 unsigned i;
487 char c;
488
489 scn_match_space (scn);
490
491 c = scn_get_chr (scn, 0);
492
493 if ((scn_is_alpha (c) == 0) && (c != '$')) {
494 return (0);
495 }
496
497 i = 0;
498
499 while (i < max) {
500 str[i++] = c;
501
502 c = scn_get_chr (scn, i);
503
504 if (scn_is_alpha (c) || scn_is_numeric (c)) {
505 ;
506 }
507 else if (c == '.') {
508 ;
509 }
510 else if ((c == '[') || (c == ']')) {
511 ;
512 }
513 else if ((c == '+') && (i > 0) && (str[i - 1] == '[')) {
514 ;
515 }
516 else if ((c == '-') && (i > 0) && (str[i - 1] == '[')) {
517 ;
518 }
519 else {
520 break;
521 }
522 }
523
524 if (i >= max) {
525 return (0);
526 }
527
528 str[i] = 0;
529
530 scn_rmv_chr (scn, i);
531
532 return (1);
533
534}
535
536static
537int scn_get_hex (scanner_t *scn, char *val, unsigned idx)
538{
539 char c;
540 unsigned i, d, v;
541
542 v = 0;
543
544 for (i = 0; i < 2; i++) {
545 c = scn_get_chr (scn, idx + i);
546
547 if ((c >= '0') && (c <= '9')) {
548 d = c - '0';
549 }
550 else if ((c >= 'a') && (c <= 'f')) {
551 d = c - 'a' + 10;
552 }
553 else if ((c >= 'A') && (c <= 'F')) {
554 d = c - 'A' + 10;
555 }
556 else {
557 return (1);
558 }
559
560 v = 16 * v + d;
561 }
562
563 *val = (char) v;
564
565 return (0);
566}
567
568int scn_match_string (scanner_t *scn, char *str, unsigned max)
569{
570 char c;
571 unsigned i, j;
572
573 scn_match_space (scn);
574
575 c = scn_get_chr (scn, 0);
576
577 if (c != '"') {
578 return (0);
579 }
580
581 i = 1;
582 j = 0;
583
584 while (j < max) {
585 c = scn_get_chr (scn, i);
586
587 if (c == 0) {
588 return (1);
589 }
590
591 if (c == '\\') {
592 switch (scn_get_chr (scn, i + 1)) {
593 case 'a':
594 c = '\a';
595 i += 1;
596 break;
597
598 case 'b':
599 c = '\b';
600 i += 1;
601 break;
602
603 case 'f':
604 c = '\f';
605 i += 1;
606 break;
607
608 case 'n':
609 c = '\n';
610 i += 1;
611 break;
612
613 case 'r':
614 c = '\r';
615 i += 1;
616 break;
617
618 case 'v':
619 c = '\v';
620 i += 1;
621 break;
622
623 case '\\':
624 c = '\\';
625 i += 1;
626 break;
627
628 case '"':
629 c = '"';
630 i += 1;
631 break;
632
633 case 'x':
634 if (scn_get_hex (scn, &c, i + 2)) {
635 return (0);
636 }
637 i += 3;
638 break;
639 }
640 }
641 else if (c == '"') {
642 break;
643 }
644
645 str[j++] = c;
646
647 i += 1;
648 }
649
650 if (j >= max) {
651 return (0);
652 }
653
654 str[j] = 0;
655
656 scn_rmv_chr (scn, i + 1);
657
658 return (1);
659}
660
661int scn_peek (scanner_t *scn, const char *str)
662{
663 unsigned cnt;
664
665 scn_match_space (scn);
666
667 cnt = 0;
668
669 while (str[cnt] != 0) {
670 if (scn_get_chr (scn, cnt) != str[cnt]) {
671 return (0);
672 }
673
674 cnt += 1;
675 }
676
677 return (1);
678}
679
680int scn_match_ident (scanner_t *scn, const char *str)
681{
682 char c;
683 unsigned cnt;
684
685 scn_match_space (scn);
686
687 cnt = 0;
688
689 while (str[cnt] != 0) {
690 if (scn_get_chr (scn, cnt) != str[cnt]) {
691 return (0);
692 }
693
694 cnt += 1;
695 }
696
697 c = scn_get_chr (scn, cnt);
698
699 if (scn_is_alpha (c) || scn_is_numeric (c)) {
700 return (0);
701 }
702
703 scn_rmv_chr (scn, cnt);
704
705 return (1);
706}
707
708int scn_match (scanner_t *scn, const char *str)
709{
710 unsigned cnt;
711
712 scn_match_space (scn);
713
714 cnt = 0;
715
716 while (str[cnt] != 0) {
717 if (scn_get_chr (scn, cnt) != str[cnt]) {
718 return (0);
719 }
720
721 cnt += 1;
722 }
723
724 scn_rmv_chr (scn, cnt);
725
726 return (1);
727}