/* * prefs.cpp - Preferences handling * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include #include #include #include #include "sysdeps.h" #include "sys.h" #include "prefs.h" // Prefs items are stored in a linked list of these nodes struct prefs_node { prefs_node *next; const char *name; prefs_type type; void *data; }; // List of prefs nodes static prefs_node *the_prefs = NULL; // Prototypes static const prefs_desc *find_prefs_desc(const char *name); /* * Initialize preferences */ void PrefsInit(const char *vmdir, int &argc, char **&argv) { // Set defaults AddPrefsDefaults(); AddPlatformPrefsDefaults(); // Load preferences from settings file LoadPrefs(vmdir); // Override prefs with command line options for (int i=1; i= argc) { fprintf(stderr, "Option '%s' must be followed by a value\n", option); continue; } const char *value = argv[i]; argv[i] = NULL; // Add/replace prefs item switch (d->type) { case TYPE_STRING: if (d->multiple) PrefsAddString(keyword, value); else PrefsReplaceString(keyword, value); break; case TYPE_BOOLEAN: { if (!strcmp(value, "true") || !strcmp(value, "on") || !strcmp(value, "yes")) PrefsReplaceBool(keyword, true); else if (!strcmp(value, "false") || !strcmp(value, "off") || !strcmp(value, "no")) PrefsReplaceBool(keyword, false); else fprintf(stderr, "Value for option '%s' must be 'true' or 'false'\n", option); break; } case TYPE_INT32: PrefsReplaceInt32(keyword, atoi(value)); break; default: break; } } // Remove processed arguments for (int i=1; i i) { k -= i; for (int j=i+k; jnext; free((void *)p->name); free(p->data); delete p; p = next; } the_prefs = NULL; } /* * Print preferences options help */ static void print_options(const prefs_desc *list) { while (list->type != TYPE_END) { if (list->help) { const char *typestr, *defstr; char numstr[32]; switch (list->type) { case TYPE_STRING: typestr = "STRING"; defstr = PrefsFindString(list->name); if (defstr == NULL) defstr = "none"; break; case TYPE_BOOLEAN: typestr = "BOOL"; if (PrefsFindBool(list->name)) defstr = "true"; else defstr = "false"; break; case TYPE_INT32: typestr = "NUMBER"; sprintf(numstr, "%d", PrefsFindInt32(list->name)); defstr = numstr; break; default: typestr = ""; defstr = "none"; break; } printf(" --%s %s\n %s [default=%s]\n", list->name, typestr, list->help, defstr); } list++; } } void PrefsPrintUsage(void) { printf("\nGeneral options:\n"); print_options(common_prefs_items); printf("\nPlatform-specific options:\n"); print_options(platform_prefs_items); printf("\nBoolean options are specified as '--OPTION true|on|yes' or\n'--OPTION false|off|no'.\n"); } /* * Find preferences descriptor by keyword */ static const prefs_desc *find_prefs_desc(const char *name, const prefs_desc *list) { while (list->type != TYPE_ANY) { if (strcmp(list->name, name) == 0) return list; list++; } return NULL; } static const prefs_desc *find_prefs_desc(const char *name) { const prefs_desc *d = find_prefs_desc(name, common_prefs_items); if (d == NULL) d = find_prefs_desc(name, platform_prefs_items); return d; } /* * Set prefs items */ static void add_data(const char *name, prefs_type type, void *data, int size) { void *d = malloc(size); if (d == NULL) return; memcpy(d, data, size); prefs_node *p = new prefs_node; p->next = 0; p->name = strdup(name); p->type = type; p->data = d; if (the_prefs) { prefs_node *prev = the_prefs; while (prev->next) prev = prev->next; prev->next = p; } else the_prefs = p; } void PrefsAddString(const char *name, const char *s) { add_data(name, TYPE_STRING, (void *)s, strlen(s) + 1); } void PrefsAddBool(const char *name, bool b) { add_data(name, TYPE_BOOLEAN, &b, sizeof(bool)); } void PrefsAddInt32(const char *name, int32 val) { add_data(name, TYPE_INT32, &val, sizeof(int32)); } /* * Replace prefs items */ static prefs_node *find_node(const char *name, prefs_type type, int index = 0) { prefs_node *p = the_prefs; int i = 0; while (p) { if ((type == TYPE_ANY || p->type == type) && !strcmp(p->name, name)) { if (i == index) return p; else i++; } p = p->next; } return NULL; } void PrefsReplaceString(const char *name, const char *s, int index) { prefs_node *p = find_node(name, TYPE_STRING, index); if (p) { free(p->data); p->data = strdup(s); } else add_data(name, TYPE_STRING, (void *)s, strlen(s) + 1); } void PrefsReplaceBool(const char *name, bool b) { prefs_node *p = find_node(name, TYPE_BOOLEAN); if (p) *(bool *)(p->data) = b; else add_data(name, TYPE_BOOLEAN, &b, sizeof(bool)); } void PrefsReplaceInt32(const char *name, int32 val) { prefs_node *p = find_node(name, TYPE_INT32); if (p) *(int32 *)(p->data) = val; else add_data(name, TYPE_INT32, &val, sizeof(int32)); } /* * Get prefs items */ const char *PrefsFindString(const char *name, int index) { prefs_node *p = find_node(name, TYPE_STRING, index); if (p) return (char *)(p->data); else return NULL; } extern "C" const char *PrefsFindStringC(const char *name, int index) { return PrefsFindString(name, index); } bool PrefsFindBool(const char *name) { prefs_node *p = find_node(name, TYPE_BOOLEAN, 0); if (p) return *(bool *)(p->data); else return false; } int32 PrefsFindInt32(const char *name) { prefs_node *p = find_node(name, TYPE_INT32, 0); if (p) return *(int32 *)(p->data); else return 0; } /* * Remove prefs items */ void PrefsRemoveItem(const char *name, int index) { prefs_node *p = find_node(name, TYPE_ANY, index); if (p) { free((void *)p->name); free(p->data); prefs_node *q = the_prefs; if (q == p) { the_prefs = NULL; delete p; return; } while (q) { if (q->next == p) { q->next = p->next; delete p; return; } q = q->next; } } } /* * Load prefs from stream (utility function for LoadPrefs() implementation) */ void LoadPrefsFromStream(FILE *f) { char line[256]; while(fgets(line, sizeof(line), f)) { // Remove newline, if present int len = strlen(line); if (len > 0 && line[len-1] == '\n') { line[len-1] = '\0'; len--; } if (len == 0) continue; // Comments begin with "#" or ";" if (line[0] == '#' || line[0] == ';') continue; // Terminate string after keyword char *p = line; while (*p && !isspace(*p)) p++; if (*p != '\0') *p++ = 0; // Skip whitespace until value while (*p && isspace(*p)) p++; char *keyword = line; char *value = p; int32 i = atol(value); // Look for keyword first in prefs item list const prefs_desc *desc = find_prefs_desc(keyword); if (desc == NULL) { printf("WARNING: Unknown preferences keyword '%s'\n", keyword); continue; } // Add item to prefs switch (desc->type) { case TYPE_STRING: if (desc->multiple) PrefsAddString(keyword, value); else PrefsReplaceString(keyword, value); break; case TYPE_BOOLEAN: PrefsReplaceBool(keyword, !strcmp(value, "true")); break; case TYPE_INT32: PrefsReplaceInt32(keyword, i); break; default: break; } } } /* * Save settings to stream (utility function for SavePrefs() implementation) */ static void write_prefs(FILE *f, const prefs_desc *list) { while (list->type != TYPE_ANY) { switch (list->type) { case TYPE_STRING: { int index = 0; const char *str; while ((str = PrefsFindString(list->name, index++)) != NULL) fprintf(f, "%s %s\n", list->name, str); break; } case TYPE_BOOLEAN: fprintf(f, "%s %s\n", list->name, PrefsFindBool(list->name) ? "true" : "false"); break; case TYPE_INT32: fprintf(f, "%s %d\n", list->name, PrefsFindInt32(list->name)); break; default: break; } list++; } } void SavePrefsToStream(FILE *f) { write_prefs(f, common_prefs_items); write_prefs(f, platform_prefs_items); }