/* This file is part of GSC Copyright (C) 2007 Sergey Poznyakoff This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 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. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include #include #include "xalloc.h" #include "gsc.h" /* Configuration file handling (general) */ static gsc_config_fun find_cfg_fun (struct gsc_config_keyword *kwtab, char *kw) { for (; kwtab->kw; kwtab++) if (strcmp (kwtab->kw, kw) == 0) break; return kwtab->handler; } ssize_t read_cont_line (gsc_config_file_t *file) { ssize_t rc; ssize_t len = rc; len = getline (&file->buf, &file->size, file->fp); file->line++; if (len <= 0) return len; if (file->buf[len-1] != '\n') return len; file->buf[--len] = 0; if (len > 0 && file->buf[len-1] == '\\') { size_t newsize = file->size; char *newbuf = x2realloc (NULL, &newsize); strcpy (newbuf, file->buf); do { rc = getline (&file->buf, &file->size, file->fp); if (rc <= 0) break; file->line++; if (file->buf[rc-1] == '\n') file->buf[--rc] = 0; newbuf[--len] = 0; len += rc; if (len + 1 > newsize) { newsize = len + 1; newbuf = x2realloc (newbuf, &newsize); } strcat (newbuf, file->buf); } while (rc > 0 && file->buf[rc-1] == '\\'); free (file->buf); file->buf = newbuf; file->size = newsize; } return len + 1; } void gsc_config_parse_block (gsc_config_file_t *file, void *data, struct gsc_config_keyword *kwtab, const char *end) { while (read_cont_line (file) > 0) { size_t len; char *p, *kw, *val = NULL; gsc_config_fun fun; for (p = file->buf; *p && isspace (*p); p++) ; if (*p == '#' || *p == 0) continue; len = strlen (p); for (;len > 0 && isspace (p[len-1]); len--) ; if (len > 0) p[len] = 0; else continue; kw = p; for (; *p && !isspace (*p); p++) ; if (*p) { *p++ = 0; for (; *p && isspace (*p); p++) ; val = p; } if (end && val == NULL && strcmp (kw, end) == 0) break; fun = find_cfg_fun (kwtab, kw); if (fun) { file->kwtab = kwtab; fun (file, kw, val, data); } else file->error_msg (file->file_name, file->line, "unrecognized line"); } } static void default_error_msg (const char *name, unsigned line, const char *fmt, ...) { va_list ap; fprintf (stderr, "%s:%u: ", name, line); va_start (ap, fmt); vfprintf (stderr, fmt, ap); va_end (ap); fputc ('\n', stderr); } gsc_config_status_t gsc_config_parse (const char *config_file, void (*errmsg) (const char *, unsigned, const char *, ...), struct gsc_config_keyword *kwh) { gsc_config_file_t file; struct stat st; if (stat (config_file, &st)) return gsc_config_open; file.fp = fopen (config_file, "r"); if (!file.fp) return gsc_config_open; file.buf = NULL; file.size = 0; file.line = 0; file.ino = st.st_ino; file.dev = st.st_dev; file.prev = NULL; file.file_name = config_file; file.error_msg = errmsg ? errmsg : default_error_msg; file.error_count = 0; gsc_config_parse_block (&file, NULL, kwh, NULL); free (file.buf); fclose (file.fp); return file.error_count ? gsc_config_error : gsc_config_success; }