/***************************************************************************** * libini * *****************************************************************************/ /***************************************************************************** * File name: src/libini/read.c * * Created: 2001-08-24 by Hampa Hug * * Copyright: (C) 2001-2020 Hampa Hug * *****************************************************************************/ /***************************************************************************** * This program is free software. You can redistribute it and / or modify it * * under the terms of the GNU General Public License version 2 as published * * by the Free Software Foundation. * * * * This program is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY, without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General * * Public License for more details. * *****************************************************************************/ #include #include #include #include #include extern int ini_eval (scanner_t *scn, ini_sct_t *sct, ini_val_t *val); static int parse_section (scanner_t *scn, ini_sct_t *sct, char *buf); static void parse_error (scanner_t *scn, const char *text, int src) { char c; unsigned i; const char *name; if (scn->file != NULL) { name = scn->file->name; } else { name = NULL; } if (name == NULL) { name = ""; } fprintf (stderr, "%s:%lu: %s", name, scn->line + 1, text ); if (src) { fputs (": ", stderr); for (i = 0; i < 64; i++) { c = scn_get_chr (scn, i); if (c == 0) { fputs ("", stderr); break; } if ((c == 0x0d) || (c == 0x0a)) { fputs ("", stderr); break; } fputc (c, stderr); } } fputs ("\n", stderr); } static int skip_block (scanner_t *scn) { int c; unsigned cnt; cnt = 1; while ((c = scn_get_chr (scn, 0)) != 0) { scn_rmv_chr (scn, 1); if (c == '{') { cnt += 1; } else if (c == '}') { cnt -= 1; if (cnt == 0) { return (0); } } } return (1); } static int parse_block (scanner_t *scn, ini_sct_t *sct, char *buf, int skip) { if (scn_match (scn, "{") == 0) { return (1); } if (skip) { return (skip_block (scn)); } if (parse_section (scn, sct, buf)) { return (1); } if (scn_match (scn, "}") == 0) { return (1); } return (0); } static int parse_assign_undef (scanner_t *scn, ini_sct_t *sct, ini_val_t *tmp, const char *name) { ini_val_t *val; if (ini_eval (scn, sct, tmp)) { return (1); } if (tmp->type == INI_VAL_NONE) { return (1); } val = ini_get_val (sct, name, 0); if (val != NULL) { return (0); } val = ini_get_val (sct, name, 1); if (val == NULL) { return (1); } ini_val_copy (val, tmp); return (0); } static int parse_if (scanner_t *scn, ini_sct_t *sct, char *buf) { int done, skip; ini_val_t val; ini_val_init (&val, NULL); if (ini_eval (scn, sct, &val)) { ini_val_free (&val); return (1); } if ((val.type == INI_VAL_INT) && (val.val.u32 != 0)) { skip = 0; done = 1; } else if ((val.type == INI_VAL_STR) && (val.val.str[0] != 0)) { skip = 0; done = 1; } else { skip = 1; done = 0; } ini_val_free (&val); if (parse_block (scn, sct, buf, skip)) { return (1); } while (scn_match_ident (scn, "else")) { if (scn_match_ident (scn, "if")) { ini_val_init (&val, NULL); if (ini_eval (scn, sct, &val)) { ini_val_free (&val); return (1); } skip = 1; if (done == 0) { if ((val.type == INI_VAL_INT) && (val.val.u32 != 0)) { skip = 0; done = 1; } else if ((val.type == INI_VAL_STR) && (val.val.str[0] != 0)) { skip = 0; done = 1; } } ini_val_free (&val); if (parse_block (scn, sct, buf, skip)) { return (1); } } else { if (parse_block (scn, sct, buf, done)) { return (1); } break; } } return (0); } static int parse_include (scanner_t *scn, ini_sct_t *sct, char *buf, int rel) { int noerr; noerr = (scn_match (scn, "?") != 0); if (scn_match_string (scn, buf, 256) == 0) { return (1); } if (scn_add_file (scn, buf, NULL, 1, rel)) { if (noerr == 0) { parse_error (scn, "can't open include file:", 0); parse_error (scn, buf, 0); return (1); } } return (0); } static int parse_section (scanner_t *scn, ini_sct_t *sct, char *buf) { int r; ini_sct_t *sub; ini_val_t *val; while (1) { if (scn_match_name (scn, buf, 256) == 0) { return (0); } if (strcmp (buf, "section") == 0) { if (scn_match_name (scn, buf, 256) == 0) { return (1); } } if (scn_match (scn, "{")) { sub = ini_get_sct (sct, buf, 1); if (sub == NULL) { return (1); } if (parse_section (scn, sub, buf)) { return (1); } if (scn_match (scn, "}") == 0) { return (1); } } else if (scn_match (scn, "?=")) { ini_val_t tmp; ini_val_init (&tmp, NULL); r = parse_assign_undef (scn, sct, &tmp, buf); ini_val_free (&tmp); if (r) { return (1); } } else if (scn_match (scn, "=")) { val = ini_get_val (sct, buf, 1); if (val == NULL) { return (1); } if (ini_eval (scn, sct, val)) { return (1); } if (val->type == INI_VAL_NONE) { return (1); } } else if (strcmp (buf, "if") == 0) { if (parse_if (scn, sct, buf)) { return (1); } } else if (strcmp (buf, "include") == 0) { if (parse_include (scn, sct, buf, 0)) { return (1); } } else if (strcmp (buf, "rinclude") == 0) { if (parse_include (scn, sct, buf, 1)) { return (1); } } else { return (1); } scn_match (scn, ";"); } return (1); } int ini_read_str (ini_sct_t *sct, const char *str) { scanner_t scn; char buf[256]; scn_init (&scn); scn_set_str (&scn, str); if (parse_section (&scn, sct, buf)) { parse_error (&scn, "parse error before", 1); scn_free (&scn); return (1); } if (scn_get_chr (&scn, 0) != 0) { parse_error (&scn, "parse error before", 1); scn_free (&scn); return (1); } scn_free (&scn); return (0); } int ini_read_fp (ini_sct_t *sct, FILE *fp, const char *fname) { scanner_t scn; char buf[256]; scn_init (&scn); if (scn_add_file (&scn, fname, fp, 0, 0)) { ini_sct_del (sct); return (1); } if (parse_section (&scn, sct, buf)) { parse_error (&scn, "parse error before", 1); scn_free (&scn); return (1); } if (scn_get_chr (&scn, 0) != 0) { parse_error (&scn, "parse error before", 1); scn_free (&scn); return (1); } scn_free (&scn); return (0); } int ini_read (ini_sct_t *sct, const char *fname) { int r; FILE *fp; fp = fopen (fname, "rb"); if (fp == NULL) { return (1); } r = ini_read_fp (sct, fp, fname); fclose (fp); return (r); }