/* * Configuration stuff. * * This code supports saving changes to the configuration file. * */ #include #include "v9t9.h" #include "v9t9_common.h" #include "command.h" #include "config.h" #define _L LOG_COMMANDS | LOG_INFO static OSHandle config; /* * Escape an outgoing quoted string */ char *escape(const char *s, int quote) { char *ret; char *ptr; if (!s) return xstrdup(""); ret = (char *)xmalloc(strlen(s)*2+1); ptr = ret; while (*s) { if (*s == '\\' || (quote == '\"' && *s == '\"') || (quote == '\'' && *s == '\'')) { *ptr++ = '\\'; } *ptr++ = *s++; } *ptr = 0; return ret; } static void cprintf(const char *format, ...) { va_list va; char tmp[256], *ptr; va_start(va, format); ptr = mvprintf(tmp, sizeof(tmp), format, va); if (OS_AppendHandle(&config, ptr, strlen(ptr)) != OS_NOERR) logger(_L | LOG_FATAL, "Out of memory for config file\n"); if (ptr != tmp) xfree(ptr); } static void dump_name(command_symbol *sym) { char *ptr = sym->name; int len = 0; while (ptr[len] && ptr[len] != '|') len++; cprintf("%.*s ", len, ptr); } static void dump_command(command_symbol *sym, bool session) { command_arg *arg; int iter = 0; int ret; // don't save certain active commands if (sym->flags & c_DONT_SAVE) return; // don't save machine state unless it's a session if ((sym->flags & c_SESSION_ONLY) && !session) return; // don't save state unless it's not a session if ((sym->flags & c_CONFIG_ONLY) && session) return; do { if ((sym->flags & c_DYNAMIC) && sym->action) { ret = sym->action(sym, csa_READ, iter); } else { ret = (iter == 0); } if (!ret) break; dump_name(sym); arg = sym->args; while (arg) { if (arg->type == ca_NUM) { int val; command_arg_read_num(arg, &val); if (strcmp(arg->name, "on|off") == 0 || strcmp(arg->name, "off|on") == 0) cprintf("%s ", val ? "on" : "off"); else if (arg->u.num.sz > 2) cprintf("%d ", val); else cprintf("0x%x ", arg->u.num.sz == 1 ? (val & 0xff) : arg->u.num.sz == 2 ? (val & 0xffff) : val); } else if (arg->type == ca_STRING) { char *str; command_arg_read_string(arg, &str); str = str ? escape(str, '\"') : 0L; cprintf("\"%s\" ", str ? str : ""); xfree(str); } else if (arg->type == ca_TOGGLE) { int val; command_arg_read_toggle(arg, &val); cprintf("%s ", val ? "on" : "off"); } else if (arg->type == ca_SPEC || arg->type == ca_PATHSPEC || arg->type == ca_NAMESPEC) { char *str; command_arg_read_spec(arg, &str); str = str ? escape(str, '\"') : 0L; cprintf("\"%s\" ", str ? str : ""); xfree(str); } else { logger(_L | LOG_FATAL, "Unhandled type in dump_command (%d)\n", arg->type); } arg = arg->next; } cprintf("\n"); iter++; } while (ret); } static void dump_symbol_table(command_symbol_table *table, bool session) { while (table) { command_symbol *sym; cprintf("\n[%s]\n", table->name); sym = table->list; while (sym) { dump_command(sym, session); sym = sym->next; } if (table->sub) dump_symbol_table(table->sub, session); table = table->next; } } int config_load_spec(const OSSpec *spec, bool session) { char path[OS_PATHSIZE]; int ret; bool sessionflag; OS_SpecToString2(spec, path); sessionflag = command_get_session_filter(); command_set_session_filter(session); ret = command_parse_file(path); command_set_session_filter(sessionflag); return ret; } int config_save_spec(const OSSpec *spec, bool session) { FILE *file; char *str; char path[OS_PATHSIZE]; OSSize sz; const char *filename = OS_NameSpecToString1(&spec->name); if (!filename || !*filename || strcmp(filename, "-") == 0) file = stdout; else { OS_SpecToString2(spec, path); file = fopen(path, "wt"); } if (!file) { logger(_L | LOG_ERROR | LOG_USER, "Cannot write to %s\n", path); return 0; } if (OS_NewHandle(0, &config) != OS_NOERR) logger(_L | LOG_FATAL, "Out of memory for config file\n"); fprintf(file, "#!%s %s\n", OS_SpecToString1(&v9t9_progspec), path); fprintf(file, "#\n" "# v9t9 configuration file\n" "#\n"); dump_symbol_table(universe, session); str = OS_LockHandle(&config); if (OS_GetHandleSize(&config, &sz) != OS_NOERR) sz = strlen(str); fwrite(str, sz, 1, file); OS_UnlockHandle(&config); if (file != stdout) fclose(file); #if defined(UNDER_UNIX) chmod(path, 0777); #endif return 1; } /* * Find a file in the given path, returning 1 for success, * or 0 for failure. If failed, 'spec' points to the file in the * first path element. */ int config_find_file(const char *filename, const char *path, OSSpec *spec) { OSError err; if (OS_GetFileNamePtr(filename) != filename && (err = OS_MakeFileSpec(filename, spec)) == OS_NOERR && OS_Status(spec) == OS_NOERR) { // found it return 1; } else if ((err = OS_FindFileInPath(filename, path, spec)) != OS_NOERR) { return 0; } else { return 1; } } int config_load_file(const char *path, const char *filename, bool session) { OSSpec spec; if (!config_find_file(filename, path, &spec)) return 0; return config_load_spec(&spec, session); } int config_save_file(const char *path, const char *filename, bool session) { OSSpec spec; config_find_file(filename, path, &spec); return config_save_spec(&spec, session); } DECL_SYMBOL_ACTION(save_config) { char *filename; int ret; command_arg_get_string(SYM_ARG_1st, &filename); ret = config_save_file(configspath, filename, false); if (!ret) { logger(_L|LOG_USER, "Could not save config file to '%s' in:\n%s\n", filename, configspath); } return ret; } DECL_SYMBOL_ACTION(load_config) { char *filename; int ret; command_arg_get_string(SYM_ARG_1st, &filename); ret = config_load_file(configspath, filename, false); if (!ret) { logger(_L|LOG_USER, "Could not find config file '%s' in:\n%s\n", filename, configspath); } return ret; } DECL_SYMBOL_ACTION(save_session) { char *filename; int ret; command_arg_get_string(SYM_ARG_1st, &filename); ret = config_save_file(sessionspath, filename, true); if (!ret) { logger(_L|LOG_USER, "Could not save session to '%s' in:\n%s\n", filename, sessionspath); } return ret; } DECL_SYMBOL_ACTION(load_session) { char *filename; int ret; command_arg_get_string(SYM_ARG_1st, &filename); ret = config_load_file(sessionspath, filename, true); if (!ret) { logger(_L|LOG_USER, "Could not find session file '%s' in:\n%s\n", filename, sessionspath); } return ret; }