📄 config.cc
字号:
} // An option? (weirdness so we can have an empty line after =) else if (1 == sscanf (buf, "%[^=] =%n", name, &len) && buf[len-1] == '=') { int i, option_value; value = buf+len; while (isspace(*value)) value++; for (i = 0; option_table[i].name; i++) if (!strcasecmp (option_table[i].name, name)) { if (option_table[i].ptype == pt_string) setStringOption(option_table[i].option, value); else { if (option_table[i].ptype == pt_char) option_value = value[0]; else if ((1 != sscanf(value, "0x%x", &option_value)) && (1 != sscanf(value, "%d", &option_value))) error ("Malformed number: %s\n",value); setOption (option_table[i].option, option_value); } break; } if (!option_table[i].name) { // hmm, not found for (i = 0; obsolete_options[i]; i++) if (!strcasecmp(name, obsolete_options[i])) goto NEXT_LINE; error ("Unrecognized option in configuration file: %s", name); } } else if (!strcmp(keyword, "mud")) { if (1 != sscanf(rest, "%s {", name)) error ("Invalid MUD line: Must be MUD <mudname> {"); readMUD(fp, name); } else // mud data. or nothing. { match = sscanf (buf, " %512s %512s %d%n", mudname, hostname, &port, &count); if (match <= 0) continue; else if (match != 3) error ("Invalid line: You did not specify a valid configuration option, or you did\n" "not specify a full MUD definition (MUD name, hostname and port):\n%s\n", buf); if (1 != sscanf (buf + count, " %[^\n]", commands)) commands[0] = NUL; mud_list->insert ((last_mud = new MUD (mudname, hostname, port, &globalMUD, commands))); } NEXT_LINE: ; } fclose (fp);}// Parse this MUD command which can appear within a MUD { } section or in the old-style formatvoid Config::parseMUDLine(const char *keyword, const char *buf, MUD *mud) { char name[INPUT_SIZE], value[INPUT_SIZE]; if (!strcmp(keyword, "macro")) { if (2 != sscanf (buf, "%s %[^\n]", name, value)) error ("Invalid Macro format, must be Macro <key> <command>:\n%s\n", buf); int key = key_lookup(name); if (key < 0) error ("Unknown key in macro definition: %s", buf); mud->macro_list.insert(new Macro(key,value)); } else if (!strcmp(keyword, "alias")) { if (2 != sscanf (buf, "%s %[^\n]", name, value)) // alias? error ("Invalid Alias format, must be Alias <name> <commands>:\n%s\n", buf); mud->alias_list.insert(new Alias(name,value)); } else if (!strcmp(keyword, "action")) { String res; Action *ac = Action::parse(buf, res, Action::Trigger); if (!ac) error (res); mud->action_list.insert(ac); } else if (!strcmp(keyword, "subst")) { String res; Action *ac = Action::parse(buf, res, Action::Replacement); if (!ac) error (res); mud->action_list.insert(ac); } else error ("Uh, parsedMUDLine() called with invalid keyword %s?!", keyword);}// Read in the data about a MUDvoid Config::readMUD(FILE *fp, const char *mudname) { MUD *mud = new MUD(mudname, "", 0, &globalMUD); char buf[INPUT_SIZE], name[INPUT_SIZE]; char keyword[INPUT_SIZE]; char *nl; const char *s; bool done = false; int port; while ((fgets(buf, sizeof(buf), fp))) { if ((nl = strchr(buf, '\n'))) *nl = NUL; for (s = buf; *s && isspace(*s); s++) ; if (*s == '}') { done = true; break; } if (*s == '#' || !*s) continue; s = one_argument(s, keyword, true); if (!strcmp(keyword, "macro") || !strcmp(keyword, "alias") || !strcmp(keyword, "action") || !strcmp(keyword, "subst")) { parseMUDLine(keyword, s, mud); } else if (!strcmp(keyword, "host")) { if (2 != sscanf(s, "%s %d", name, &port)) error ("Invalid Host line in MUD %s definition: %s", mudname, s); mud->setHost(name, port); } else if (!strcmp(keyword, "inherit")) { MUD *parent = mud_list->find(s); if (!parent) error ("Parent MUD %s not found in MUD %s definition", s, mudname); mud->inherits = parent; } else if (!strcmp(keyword, "commands")) { mud->commands = s; } else error ("Invalid keyword %s within mud %s definition:\n%s\n", keyword, mudname, buf); } if (!done) error ("MUD entry %s was not propertly terminated with a }\n", mudname); mud_list->insert(mud);}MUD * Config::findMud (const char *name) { return mud_list->find(name);}static const char *type_to_string(ptype_t t) { switch (t) { case pt_int: return "<num>"; case pt_hex: return "<hex color>"; case pt_char: return "<char>"; case pt_bool: return "<0|1>"; default: return "<???>"; }}// Parse command line optionsint Config::parseOptions (int argc, char **argv) { int i,c; char option_string[max_option*2+1]; char *pc; // Build an option string based on the option_table for (pc = option_string, i = 0; option_table[i].opt_char; i++) { if (option_table[i].opt_char != '?') { *pc++ = option_table[i].opt_char; if (option_table[i].ptype == pt_int || option_table[i].ptype == pt_hex || option_table[i].ptype == pt_string) *pc++ = ':'; else if (option_table[i].ptype == pt_bool) { *pc++ = ':'; *pc++ = ':'; } } } *pc++ = '@'; *pc++ = ':'; *pc++ = 'x'; *pc++ = ':'; *pc = NUL; while( (c = getopt(argc,argv, option_string)) != EOF) { // Help requested or error ocurred, show options if (c == '?' || c == 'h') { fprintf (stderr, "\nmcl - my MUD client version %s\n" "Usage: mcl [options] [mud alias]\n\n", versionToString(VERSION) ); for (i = 0; option_table[i].opt_char; i++) if (option_table[i].opt_char != '?') { fprintf(stderr, "-%c%-10s\t%s", option_table[i].opt_char, type_to_string(option_table[i].ptype), option_table[i].description); if (option_table[i].ptype == pt_int) { fprintf(stderr, " (%d-%d)", option_table[i].min, option_table[i].max); } fprintf(stderr, "\n"); } exit (EXIT_FAILURE); } else if (c == '@') { // Recovering from alt-T extern int session_fd; session_fd = atoi(optarg); } else if (c == 'x') { // execute command interpreter.add(optarg); } else for (i = 0; option_table[i].opt_char; i++) if (option_table[i].opt_char == c) { if (option_table[i].ptype == pt_int) // Integer option setOption(option_table[i].option, atoi(optarg)); else if (option_table[i].ptype == pt_char) // char setOption(option_table[i].option, optarg[0]); else if (option_table[i].ptype == pt_string) setStringOption(option_table[i].option, optarg); else // Toggle (hmm, we don't even have any boolean options now? { if (optarg) setOption(option_table[i].option, atoi(optarg) ? true : false); else setOption(option_table[i].option, true); } break; } } // Validate options bool failed = false; for (i = 0; option_table[i].name; i++) if (getOption(option_table[i].option) > option_table[i].max) { fprintf (stderr, "Option '%s' has value %d (max is %d)\n", option_table[i].name, getOption(option_table[i].option), option_table[i].max); failed = true; } else if (getOption(option_table[i].option) < option_table[i].min) { fprintf (stderr, "Option '%s' has value %d (min is %d)\n", option_table[i].name, getOption(option_table[i].option), option_table[i].min); failed = true; } if (failed) error ("One or more options had values outside allowed range."); return optind;}// Load config. If fname == NULL, use ~/.mclrcConfig::Config (const char *fname) { // Set all config options to default values for (int i = 0; option_table[i].name; i++) setOption (option_table[i].option, option_table[i].default_value); // Move this later to a table once there is more than one string option setStringOption(opt_plugins, "perl"); setStringOption(opt_chat_download, Sprintf("%s/.mcl/downloads/", getenv("HOME"))); setStringOption(opt_chat_interfaces, "ppp0 eth0 lo"); Load(fname); String icon_file = getStringOption(opt_chat_icon); if (icon_file.len() && access(icon_file, R_OK) != 0) error ("Icon file %s was specified, but does not exist", ~icon_file);}// Save the configurationvoid Config::Save(const char *fname) { struct stat stat_buf; String name; if (fname == NULL) name = filename; else name = fname; // Check that there have been no modifications if (stat(name, &stat_buf) == 0 && stat_buf.st_mtime != save_time) fprintf(stderr, "Configuration file was NOT saved. It has been changed since it was last loaded!\n"); else { FILE *fp = fopen (name, "w"); if (!fp) return; fprintf (fp, "# mcl configuration file, generated by mcl v%s on %s\n", versionToString(VERSION), ctime(¤t_time)); for (int i = 0; option_table[i].name; i++) { if (option_table[i].ptype == pt_string) fprintf(fp, "# %s\n%s=%s\n\n", option_table[i].description, option_table[i].name, ~getStringOption(option_table[i].option)); else { if (!config->getOption(opt_nodefaults) || ( getOption(option_table[i].option) != option_table[i].default_value)) fprintf (fp, option_table[i].ptype == pt_hex ? "# %s\n%s=0x%02x\n\n" : option_table[i].ptype == pt_char ? "# %s\n%s=%c\n\n" : "# %s\n%s=%d\n\n", option_table[i].description, option_table[i].name, getOption(option_table[i].option)); } } globalMUD.write(fp, true); // Save all MUDs but those marked as temporary FOREACH(MUD*, mud, (*mud_list)) if (mud->name != "temp") { fprintf(fp, "\n"); mud->write(fp, false); } fclose (fp); }}Config::~Config() { if (!getOption(opt_readonly)) Save();}void Config::compileActions() { for (MUD* mud= mud_list->rewind(); mud; mud = mud_list->next()) if (strcmp(mud->name, "temp")) { // Actions FOREACH(Action*, action, mud->action_list) action->compile(); } FOREACH(Action*, action2, globalMUD.action_list) action2->compile(); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -