/* ScummVM - Scumm Interpreter * Copyright (C) 2001 Ludvig Strigeus * Copyright (C) 2001/2002 The ScummVM project * * 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 2 * 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, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * $Header$ * */ #include #include #include "stdafx.h" #include "config-file.h" #include "scumm.h" #define MAXLINELEN 256 #define xfree(p) {if (p) free(p);} static char *ltrim(char *t) { for (; *t && (*t == ' '); t++); return t; } static char *rtrim(char *t) { int l; for (l = strlen(t) - 1; l; l--) { if (t[l] == ' ') { *t = 0; } else { return t; } } return t; } class hashconfig { public: hashconfig (const char *); ~hashconfig (); bool is_domain(const char *) const; const char *get(const char *) const; const char *set(const char *, const char *); const char *getdomain() const; void flush(FILE *) const; void rename(const char *); void merge(const hashconfig *); private: char *domain; char **keys, **values; int nkeys; }; hashconfig::hashconfig (const char *dom):domain(dom ? strdup(dom) : 0), keys(0), values(0), nkeys(0) { } hashconfig::~hashconfig () { xfree(domain); } bool hashconfig::is_domain(const char *d) const { return d && domain && !strcmp(d, domain); } const char *hashconfig::get(const char *key) const { int i; for (i = 0; i < nkeys; i++) { if (!strcmp(key, keys[i])) { return values[i]; } } return 0; } const char *hashconfig::set(const char *key, const char *value) { int i; for (i = 0; i < nkeys; i++) { if (!strcmp(key, keys[i])) { xfree(values[i]); return values[i] = value ? strdup(value) : 0; } } nkeys++; keys = (char **)realloc(keys, nkeys * sizeof(char *)); values = (char **)realloc(values, nkeys * sizeof(char *)); keys[nkeys - 1] = strdup(key); return values[nkeys - 1] = value ? strdup(value) : 0; } const char *hashconfig::getdomain() const { return domain; } void hashconfig::flush(FILE *cfg_file) const { int i; if (!domain) return; fprintf(cfg_file, "[%s]\n", domain); for (i = 0; i < nkeys; i++) { if (values[i]) { fprintf(cfg_file, "%s=%s\n", keys[i], values[i]); } } fprintf(cfg_file, "\n"); } void hashconfig::rename(const char *d) { xfree(domain); domain = d ? strdup(d) : 0; } void hashconfig::merge(const hashconfig *h) { int i; for (i = 0; i < h->nkeys; i++) { set(h->keys[i], h->values[i]); } } // The config-class itself. Config::Config (const char *cfg, const char *d) : filename(strdup(cfg)), domain(d ? strdup(d) : 0), hash(0), ndomains(0), willwrite(false) { FILE *cfg_file; char t[MAXLINELEN]; if (!(cfg_file = fopen(cfg, "r"))) { debug(1, "Unable to open configuration file: %s.\n", filename); } else { while (!feof(cfg_file)) { if (!fgets(t, MAXLINELEN, cfg_file)) continue; if (t[0] != '#') { if (t[0] == '[') { // It's a new domain which begins here. char *p = strchr(t, ']'); if (!p) { debug(1, "Config file buggy: no ] at the end of the domain name.\n"); } else { *p = 0; set_domain(t + 1); } } else { // It's a new key in the domain. if (!domain) { debug(1, "Config file buggy: we have a key without a domain first.\n"); } char *p = strchr(t, '\n'); if (p) *p = 0; p = strchr(t, '\r'); if (p) *p = 0; if (!(p = strchr(t, '='))) { if (strlen(t)) debug(1, "Config file buggy: there is junk: %s\n", t); } else { char *key, *value; *p = 0; key = ltrim(rtrim(t)); value = ltrim(p + 1); set(key, value); } } } } set_domain(d); fclose(cfg_file); } } Config::~Config () { int i; xfree(filename); xfree(domain); for (i = 0; i < ndomains; i++) { delete hash[i]; } xfree(hash); } const char *Config::get(const char *key, const char *d) const { int i; if (!d) d = domain; for (i = 0; i < ndomains; i++) { if (hash[i]->is_domain(d)) { return hash[i]->get(key); } } return 0; } const int Config::getInt(const char *key, int def, const char *d) const { const char *value = get(key, d); if (value) return atoi(value); return def; } const bool Config::getBool(const char *key, bool def, const char *d) const { const char *value = get(key, d); if (value) return !scumm_stricmp(value, "true"); return def; } const char *Config::set(const char *key, const char *value, const char *d) { int i; if (!d) d = domain; for (i = 0; i < ndomains; i++) { if (hash[i]->is_domain(d)) { return hash[i]->set(key, value); } } ndomains++; hash = (hashconfig **)realloc(hash, ndomains * sizeof(hashconfig *)); hash[ndomains - 1] = new hashconfig (d); return hash[ndomains - 1]->set(key, value); } const char *Config::set(const char *key, int value_i, const char *d) { char value[MAXLINELEN]; sprintf(value, "%i", value_i); return set(key, value, d); } const char *Config::set(const char *key, bool value_b, const char *d) { const char *value = value_b ? "true" : "false"; return set(key, value, d); } void Config::set_domain(const char *d) { int i; xfree(domain); domain = d ? strdup(d) : 0; for (i = 0; i < ndomains; i++) { if (hash[i]->is_domain(domain)) return; } ndomains++; hash = (hashconfig **)realloc(hash, ndomains * sizeof(hashconfig *)); hash[ndomains - 1] = new hashconfig (domain); } void Config::flush() const { FILE *cfg_file; int i; if (!willwrite) return; if (!(cfg_file = fopen(filename, "w"))) { debug(1, "Unable to write configuration file: %s.\n", filename); } else { for (i = 0; i < ndomains; i++) { hash[i]->flush(cfg_file); } fclose(cfg_file); } } void Config::rename_domain(const char *d) { int i, index = -1; for (i = 0; i < ndomains; i++) { if (hash[i]->is_domain(d)) { index = i; } } for (i = 0; i < ndomains; i++) { if (hash[i]->is_domain(domain)) { if (index >= 0) { hash[i]->merge(hash[index]); hash[index]->rename(0); rename_domain(d); } else { hash[i]->rename(d); set_domain(d); } } } } void Config::delete_domain(const char *d) { int i; for (i = 0; i < ndomains; i++) { if (hash[i]->is_domain(d)) { hash[i]->rename(0); } } } void Config::change_filename(const char *f) { xfree(filename); filename = f ? strdup(f) : 0; } void Config::merge_config(const Config *c) { int i, j; bool found; for (i = 0; i < c->ndomains; i++) { found = false; for (j = 0; j < ndomains; j++) { if (hash[j]->is_domain(c->hash[i]->getdomain())) { hash[j]->merge(c->hash[i]); found = true; break; } } if (!found) { ndomains++; hash = (hashconfig **)realloc(hash, ndomains * sizeof(hashconfig *)); hash[ndomains - 1] = new hashconfig (domain); hash[ndomains - 1]->merge(c->hash[i]); } } } void Config::set_writing(bool w) { willwrite = w; }