fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
at master 727 lines 10 kB view raw
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}