/* -*- LPC -*- */ /* * $Locker: $ * $Id: command.c,v 1.16 2003/06/09 19:22:31 pinkfish Exp $ */ /* /daemon/command.c * from the Nightmare IVr1 Object Library * a new commands daemon, much faster than the old * created by Descartes of Borg 940119 * Hacked for Discworld by Turrican 9-11-95 */ #include <command.h> #include <user_parser.h> private nosave mapping Commands, Cache; private nosave string *Paths, *GRCommands; private nosave string last_verb, last_args, found_cmd, found_args; void eventRehash(string *paths); void create() { seteuid(getuid()); Commands = ([]); Cache = ([ ]); GRCommands = ({}); Paths = ({}); eventRehash( ({ DIR_PLAYER_CMDS, DIR_CREATOR_CMDS, DIR_SECURE_CREATOR_CMDS, DIR_LORD_CMDS, DIR_LIVING_CMDS, DIR_GUILD_CMDS, DIR_PLAYTESTER_CMDS }) ); } /* create() */ void eventGuildRaceRehash() { string *paths, path; paths = ({ DIR_GUILD_CMDS }); paths += map(filter(unguarded((: get_dir, DIR_GUILD_CMDS + "/", -1 :)), (: $1[1] == -2 :)), (: DIR_GUILD_CMDS + "/" + $1[0] :)); GRCommands = ({ }); foreach (path in paths) { string *files, cmd; files = map(unguarded((: get_dir, path + "/*.c" :)), (: $1[0..<3] :)); GRCommands += files; foreach(cmd in files) { if (pointerp(Commands[cmd])) { Commands[cmd] += ({ path }); } else { Commands[cmd] = ({ path }); } } Paths = uniq_array(Paths + ({ path })); } } /* eventGuildRaceRehash() */ void eventRehash(mixed paths) { string path; // Clear the cache since rehashing the paths may affect the results. Cache = ([ ]); if (stringp(paths)) { paths = ({ paths }); } else if (!pointerp(paths)) { return; } foreach(path in paths) { string file; if ( path[<1..<1] == "/" ) continue; if (file_size(path) != -2) continue; if (path == DIR_GUILD_CMDS) { eventGuildRaceRehash(); continue; } foreach (file in unguarded((: get_dir, path + "/*.c" :))) { string cmd; cmd = file[0..<3]; if (pointerp(Commands[cmd])) { Commands[cmd] += ({ path }); } else { Commands[cmd] = ({ path }); } } Paths = uniq_array(Paths + ({ path })); } } /* eventRehash() */ void HandleCommandLine(class command cmd) { string args = cmd->args; int i; string* bits; //args = replace_string(args, "%^", " "); /* if (strsrch("%^", args)) { bits = explode("f" + args, "%^"); for (i = 1; i < sizeof(bits); i += 2) { bits[i] += "USER_"; } bits[0] = bits[0][1..]; args = implode(bits, "%^"); } */ if ((i = strsrch(args, " ")) != -1) { cmd->verb = args[0..i-1]; cmd->args = args[i+1..]; } else { cmd->verb = args; cmd->args = (string)0; } } /* HandleCommandLine() */ int strncmp(string s1, string s2, int len) { return strcmp(s1[0..len-1], s2[0..len-1]); } /* strncmp() */ int HandleStars(class command cmd) { int i; int no_cache; string file, *files; // No point continuing! if(cmd->verb == "END_ALIAS") return 0; // This function gets called a hell of a lot of times. It gets called // 4 times for _each_ command. So, lets remember some common results and // not do all that searching over and over again. // exactly the same as last time. if(last_verb == cmd->verb && last_args == cmd->args) { cmd->verb = found_cmd; if(stringp(found_args)) { cmd->args = found_args; } return 1; } // check common patterns (can't do ones that end in _. if(Cache[cmd->verb]) { if(stringp(Cache[cmd->verb][1])) cmd->args = Cache[cmd->verb][1]; cmd->verb = Cache[cmd->verb][0]; return 1; } if (Commands[cmd->verb]) { /* Yippiee ! No searching needed ! */ return 1; } /* Darn. Need to search for shortcuts. */ files = keys(Commands); files = filter(files, (: (int)$1[0] == $(cmd)->verb[0] :)); foreach (file in files) { string tmpverb, tmpargs = 0, tmpfile = 0; int len, length; if ((i = strsrch(file, "_")) == -1) continue; tmpfile = (string)delete(file, i, 1); len = strlen(tmpfile); if (i == len) { tmpargs = cmd->verb[i..]+(cmd->args?(strlen(cmd->verb) == i?"":" ") + cmd->args:""); tmpverb = cmd->verb[0..i-1]; if (strncmp(tmpfile, tmpverb, len) != 0) { continue; } no_cache = 1; } else { length = strlen(cmd->verb); if ((length > len) || (length < i)) continue; if (strncmp(cmd->verb, tmpfile, length) != 0) continue; } /* Yay! Found a match! */ if (!no_cache) { Cache[cmd->verb] = ({ file, tmpargs }); } last_verb = cmd->verb; last_args = cmd->args; cmd->verb = file; if (stringp(tmpargs)) cmd->args = tmpargs; found_cmd = cmd->verb; found_args = tmpargs; return 1; } return 0; } /* HandleStars() */ int GetCommand(class command cmd, string *path) { string *tmp; int i; if (!stringp(cmd->args)) { return 0; } tmp = (path & Paths); if (sizeof(tmp = path - tmp)) { eventRehash(tmp); } HandleCommandLine(cmd); if (HandleStars(cmd) && Commands[cmd->verb] && sizeof(tmp = (path & (string *)Commands[cmd->verb]))) { cmd->file = sprintf("%s/%s", tmp[0], cmd->verb); cmd->filepart = cmd->verb; if ((i = strsrch(cmd->verb, "_")) != -1) { cmd->verb = (string)delete(cmd->verb, i, 1); } if (cmd->args && cmd->args == "") { cmd->args = (string)0; } if ((cmd->file)->query_patterns()) { return 0; } return 1; } return 0; } /* GetCommand() */ mixed ReturnPatterns(class command cmd, string *path) { mixed *q_patterns; mixed *r_patterns; mixed *stuff; mixed *tmp; mixed *ret_patterns; int i, j; string fname; tmp = (path & Paths); tmp = path - tmp; if (sizeof(tmp)) { eventRehash(tmp); } if (HandleStars(cmd) && Commands[cmd->verb]) { tmp = (path & (string *)Commands[cmd->verb]); if (tmp) { ret_patterns = ({ }); foreach (fname in tmp) { cmd->file = sprintf("%s/%s", fname, cmd->verb); //if ((i = strsrch(cmd->verb, "_")) != -1) { //cmd->verb = (string)delete(cmd->verb, i, 1); //} q_patterns = (cmd->file)->query_patterns(); if (!q_patterns) { return 0; } r_patterns = ({ }); for (i = 0; i < sizeof(q_patterns); i += 2) { if (q_patterns[i+1] && !functionp(q_patterns[i+1])) { continue; } stuff = (mixed *)PATTERN_OB->query_pattern(q_patterns[i]); j = 0; while (j < sizeof(r_patterns) && r_patterns[j][PATTERN_WEIGHT] >= stuff[0]) { j++; } r_patterns = r_patterns[0..j-1] + ({ ({ stuff[0], q_patterns[i], 0, find_object(cmd->file), q_patterns[i+1] }) }) + r_patterns[j..]; } ret_patterns += r_patterns; } return ret_patterns; } } return 0; } /* ReturnPatterns() */ mixed *GetCommandPatterns(string cmd_name, string *path) { class command cmd; mixed *stuff; cmd = new(class command); cmd->verb = cmd_name; cmd->args = 0; stuff = ReturnPatterns(cmd, path); return stuff; } /* GetCommandPatterns() */ varargs string *GetCommands(string path) { string *paths, *tmp; string cmd; if (!path) { return keys(Commands); } tmp = ({ }); foreach (cmd, paths in Commands) { if (member_array(path, paths) != -1) { tmp += ({ cmd }); } } return tmp; } /* GetCommands() */ varargs string *GetPaths(string cmd) { if (cmd) { string *paths; class command tmp; if (sizeof(paths = Commands[cmd])) { return paths; } tmp = new(class command, verb : cmd); if (HandleStars(tmp)) { return Commands[tmp->verb]; } else { return 0; } } return Paths; } /* GetPaths() */ int IsGRCommand(string cmd) { if (member_array(cmd, GRCommands) != -1) { return 1; } else { class command tmp = new(class command, verb : cmd); if (HandleStars(tmp)) { return (member_array(tmp->verb, GRCommands) != -1); } } } /* IsGRCommand() */