/* command.c */ #include "copyright.h" #include "config.h" #include <stdio.h> #include <ctype.h> #include "teeny.h" #include "match.h" /* * The command parser for TeenyMUD. Command names are stored in a table, * along with the corresponding routine to execute and the number of * arguments (0, 1, or 2) required by the command. * * All command functions must be of type voidfunc. */ struct commands { char *name; voidfunc (*function)(); int nargs; }; typedef struct commands CMDS; /* Forward declarations for the table. Most are extern. */ extern voidfunc do_drop(); extern voidfunc do_examine(); extern voidfunc do_finger(); extern voidfunc do_go(); extern voidfunc do_gripe(); extern voidfunc do_help(); extern voidfunc do_home(); extern voidfunc do_inventory(); extern voidfunc do_kill(); extern voidfunc do_look(); extern voidfunc do_news(); extern voidfunc do_page(); extern voidfunc do_poll(); extern voidfunc do_pose(); extern voidfunc do_say(); extern voidfunc do_take(); extern voidfunc do_whisper(); extern voidfunc do_boot(); extern voidfunc do_chownall(); extern voidfunc do_chown(); extern voidfunc do_create(); extern voidfunc do_dig(); extern voidfunc do_dump(); voidfunc do_descstr(); #ifdef DROP_FIELDS voidfunc do_dropstr(); #endif /*DROP_FIELDS*/ #ifdef EDIT extern voidfunc do_edit(); #endif /*EDIT*/ voidfunc do_efind(); voidfunc do_failstr(); extern voidfunc do_force(); extern voidfunc do_find(); voidfunc do_genderstr(); extern voidfunc do_lock(); extern voidfunc do_link(); voidfunc do_namestr(); extern voidfunc do_newpassword(); voidfunc do_oarrive(); #ifdef DROP_FIELDS voidfunc do_odropstr(); #endif /*DROP_FIELDS*/ voidfunc do_ofailstr(); voidfunc do_oleave(); extern voidfunc do_open(); voidfunc do_osucstr(); extern voidfunc do_owned(); extern voidfunc do_password(); extern voidfunc do_pcreate(); extern voidfunc do_purge(); extern voidfunc do_recycle(); extern voidfunc do_set(); extern voidfunc do_shutdown(); extern voidfunc do_stats(); voidfunc do_sucstr(); extern voidfunc do_teleport(); extern voidfunc do_textdump(); extern voidfunc do_toad(); extern voidfunc do_unlink(); extern voidfunc do_unlock(); extern voidfunc do_version(); extern voidfunc do_wall(); /* * The tables themselves. Regular and 'At' commands are kept in seperate * tables for speed. Note that a function _always_ gets the * 'player' variable passed to it, even when it's in the table as having * no arguments. */ static CMDS cmds[] = { /* drop */ { "drop", do_drop, 1 }, { "dro", do_drop, 1 }, { "dr", do_drop, 1 }, { "d", do_drop, 1 }, /* examine */ { "examine", do_examine, 1 }, { "examin", do_examine, 1 }, { "exami", do_examine, 1 }, { "exam", do_examine, 1 }, { "exa", do_examine, 1 }, { "ex", do_examine, 1 }, { "e", do_examine, 1 }, /* finger */ { FINGER_COMMAND, do_finger, 1}, /* get */ { "get", do_take, 1 }, { "ge", do_take, 1 }, /* go */ { "go", do_go, 1 }, /* gripe */ { "gripe", do_gripe, 1 }, { "grip", do_gripe, 1 }, { "gri", do_gripe, 1 }, { "gr", do_gripe, 1 }, /* help */ #ifdef HELPSYSTEM { "help", do_help, 1 }, #else { "help", do_help, 0 }, #endif /*HELPSYSTEM*/ /* home */ { "home", do_home, 0 }, /* inventory */ { "inventory", do_inventory, 0 }, { "inventor", do_inventory, 0 }, { "invento", do_inventory, 0 }, { "invent", do_inventory, 0 }, { "inven", do_inventory, 0 }, { "inve", do_inventory, 0 }, { "inv", do_inventory, 0 }, { "in", do_inventory, 0 }, { "i", do_inventory, 0 }, /* kill */ { "kill", do_kill, 1 }, { "kil", do_kill, 1 }, { "ki", do_kill, 1 }, { "k", do_kill, 1 }, /* look */ { "look", do_look, 1 }, { "loo", do_look, 1 }, { "lo", do_look, 1 }, { "l", do_look, 1 }, /* move */ { "move", do_go, 1 }, { "mov", do_go, 1 }, { "mo", do_go, 1 }, { "m", do_go, 1 }, /* news */ #ifdef NEWSSYSTEM { "news", do_news, 1 }, #else { "news", do_news, 0 }, #endif /*NEWSSYSTEM*/ /* page */ { "page", do_page, 2 }, { "pag", do_page, 2 }, { "pa", do_page, 2 }, { "p", do_page, 2 }, /* pose */ { "pose", do_pose, 1 }, { "pos", do_pose, 1 }, { "po", do_pose, 1 }, /* read */ { "read", do_look, 1 }, { "rea", do_look, 1 }, { "re", do_look, 1 }, { "r", do_look, 1 }, /* say */ { "say", do_say, 1 }, { "sa", do_say, 1 }, /* take */ { "take", do_take, 1 }, { "tak", do_take, 1 }, { "ta", do_take, 1 }, /* throw */ { "throw", do_drop, 1 }, { "thro", do_drop, 1 }, { "thr", do_drop, 1 }, { "th", do_drop, 1 }, /* whisper */ { "whisper", do_whisper, 2 }, { "whispe", do_whisper, 2 }, { "whisp", do_whisper, 2 }, { "whis", do_whisper, 2 }, { "whi", do_whisper, 2 }, { "wh", do_whisper, 2 }, { "w", do_whisper, 2 }, { NULL, NULL, 0 } }; static CMDS atcmds[] = { /* @boot */ { "boot", do_boot, 1 }, /* @chownall */ { "chownall", do_chownall, 2 }, /* @chown */ { "chown", do_chown, 2 }, { "chow", do_chown, 2 }, { "cho", do_chown, 2 }, { "ch", do_chown, 2 }, /* @create */ { "create", do_create, 1 }, { "creat", do_create, 1 }, { "crea", do_create, 1 }, { "cre", do_create, 1 }, { "cr", do_create, 1 }, /* @dig */ { "dig", do_dig, 1 }, { "di", do_dig, 1 }, /* @dump */ { "dump", do_dump, 0 }, /* @describe */ { "describe", do_descstr, 2 }, { "describ", do_descstr, 2 }, { "descri", do_descstr, 2 }, { "descr", do_descstr, 2 }, { "desc", do_descstr, 2 }, { "des", do_descstr, 2 }, { "de", do_descstr, 2 }, #ifdef DROP_FIELDS /* @drop */ { "drop", do_dropstr, 2 }, { "dro", do_dropstr, 2 }, { "dr", do_dropstr, 2 }, #endif /*DROP_FIELDS*/ #ifdef EDIT /* @edit */ { "edit", do_edit, 2 }, { "edi", do_edit, 2 }, { "ed", do_edit, 2 }, #endif /*EDIT*/ /* @efind */ { "efind", do_efind, 0 }, { "efin", do_efind, 0 }, { "efi", do_efind, 0 }, { "ef", do_efind, 0 }, /* @fail */ { "fail", do_failstr, 2 }, { "fai", do_failstr, 2 }, { "fa", do_failstr, 2 }, /* @force */ { "force", do_force, 2 }, { "forc", do_force, 2 }, { "for", do_force, 2 }, { "fo", do_force, 2 }, /* @find */ { "find", do_find, 2 }, { "fin", do_find, 2 }, { "fi", do_find, 2 }, /* @gender */ { "gender", do_genderstr, 2 }, { "gende", do_genderstr, 2 }, { "gend", do_genderstr, 2 }, { "gen", do_genderstr, 2 }, { "ge", do_genderstr, 2 }, /* @gripe */ { "gripe", do_gripe, 1 }, { "grip", do_gripe, 1 }, { "gri", do_gripe, 1 }, { "gr", do_gripe, 1 }, /* @lock */ { "lock", do_lock, 2 }, { "loc", do_lock, 2 }, { "lo", do_lock, 2 }, /* @link */ { "link", do_link, 2 }, { "lin", do_link, 2 }, { "li", do_link, 2 }, /* @name */ { "name", do_namestr, 2 }, { "nam", do_namestr, 2 }, { "na", do_namestr, 2 }, /* @newpassword */ { "newpassword", do_newpassword, 2 }, /* @oarrive */ { "oarrive", do_oarrive, 2 }, { "oarriv", do_oarrive, 2 }, { "oarri", do_oarrive, 2 }, { "oarr", do_oarrive, 2 }, { "oar", do_oarrive, 2 }, { "oa", do_oarrive, 2 }, #ifdef DROP_FIELDS /* @odrop */ { "odrop", do_odropstr, 2 }, { "odro", do_odropstr, 2 }, { "odr", do_odropstr, 2 }, { "od", do_odropstr, 2 }, #endif /*DROP_FIELDS*/ /* @ofail */ { "ofail", do_ofailstr, 2 }, { "ofai", do_ofailstr, 2 }, { "ofa", do_ofailstr, 2 }, { "of", do_ofailstr, 2 }, /* @oleave */ { "oleave", do_oleave, 2 }, { "oleav", do_oleave, 2 }, { "olea", do_oleave, 2 }, { "ole", do_oleave, 2 }, { "ol", do_oleave, 2 }, /* @open */ { "open", do_open, 2 }, { "ope", do_open, 2 }, { "op", do_open, 2 }, /* @osuccess */ { "osuccess", do_osucstr, 2 }, { "osucces", do_osucstr, 2 }, { "osucce", do_osucstr, 2 }, { "osucc", do_osucstr, 2 }, { "osuc", do_osucstr, 2 }, { "osu", do_osucstr, 2 }, { "os", do_osucstr, 2 }, /* @owned */ { "owned", do_owned, 2 }, { "owne", do_owned, 2 }, { "own", do_owned, 2 }, { "ow", do_owned, 2 }, /* @password */ { "password", do_password, 2 }, /* @pcreate */ { "pcreate", do_pcreate, 2 }, { "pcreat", do_pcreate, 2 }, { "pcrea", do_pcreate, 2 }, { "pcre", do_pcreate, 2 }, { "pcr", do_pcreate, 2 }, { "pc", do_pcreate, 2 }, /* @poll */ { "poll", do_poll, 1 }, { "pol", do_poll, 1 }, { "po", do_poll, 1 }, /* @purge */ { "purge", do_purge, 1 }, /* @recycle */ { "recycle", do_recycle, 1 }, { "recycl", do_recycle, 1 }, { "recyc", do_recycle, 1 }, { "recy", do_recycle, 1 }, { "rec", do_recycle, 1 }, /* @set */ { "set", do_set, 2 }, /* @sex */ { "sex", do_genderstr, 2 }, /* @shutdown */ { "shutdown", do_shutdown, 0 }, { "shutdow", do_shutdown, 0 }, { "shutdo", do_shutdown, 0 }, { "shutd", do_shutdown, 0 }, { "shut", do_shutdown, 0 }, { "shu", do_shutdown, 0 }, { "sh", do_shutdown, 0 }, /* @stats */ { "stats", do_stats, 1 }, { "stat", do_stats, 1 }, { "sta", do_stats, 1 }, { "st", do_stats, 1 }, /* @success */ { "success", do_sucstr, 2 }, { "succes", do_sucstr, 2 }, { "succe", do_sucstr, 2 }, { "succ", do_sucstr, 2 }, { "suc", do_sucstr, 2 }, { "su", do_sucstr, 2 }, /* @teleport */ { "teleport", do_teleport, 2 }, { "telepor", do_teleport, 2 }, { "telepo", do_teleport, 2 }, { "telep", do_teleport, 2 }, { "tele", do_teleport, 2 }, { "tel", do_teleport, 2 }, { "te", do_teleport, 2 }, /* @textdump */ { "textdump", do_textdump, 1 }, /* @toad */ { "toad", do_toad, 2 }, /* @unlink */ { "unlink", do_unlink, 1 }, { "unlin", do_unlink, 1 }, { "unli", do_unlink, 1 }, /* @unlock */ { "unlock", do_unlock, 1 }, { "unloc", do_unlock, 1 }, { "unlo", do_unlock, 1 }, /* @version */ { "version", do_version, 0 }, { "versio", do_version, 0 }, { "versi", do_version, 0 }, { "vers", do_version, 0 }, { "ver", do_version, 0 }, { "ve", do_version, 0 }, { "v", do_version, 0 }, /* @wall */ { "wall", do_wall, 1 }, { NULL, NULL, 0 } }; static void handle_at_cmd(); static int handle_exit_cmd(); static int cmdcmp(); /* A macro to instantly parse the command, given suitably set up pointers */ #define Parse {if(first != NULL) first_end[1] = '\0';} void handle_cmd(player, cmd) int player; char *cmd; { char *first; /* First char of arg 1*/ char *first_end; /* Terminate arg 1 at first_end[1] */ char *second; /* Same deal */ char *p; CMDS *fp; lock_cache(); /* Lock up the cache so things stay in memory */ #ifdef LOGCOMMANDS { char *x, *y, z; if(get_str_elt(player, NAME, &x) != -1){ for(y = x; y && *y && *y != ' '; y++); z = *y; *y = '\0'; log_command("COMMAND [%s(#%d)]: %s\n", x, player, cmd); *y = z; } else log_command("COMMAND [???(#%d)]: %s\n", player, cmd); } #endif /*LOGCOMMANDS*/ if(cmd[0] == '\"'){ do_say(player, cmd + 1); if(mudstat() != DUMPING) unlock_cache(); return; } if(cmd[0] == ':'){ do_pose(player, cmd + 1); if(mudstat() != DUMPING) unlock_cache(); return; } if(cmd[0] != '@'){ if(handle_exit_cmd(player, cmd)){ if(mudstat() != DUMPING) unlock_cache(); cache_trim(); return; } } /* Smash the command up, prepare to parse out args if required */ first = second = first_end = NULL; p = cmd; while(!isspace(*p) && *p) p++; /* Skip over the command */ first = p; while(isspace(*p) && *p) p++; /* Skip to arg 1 */ *first = '\0'; if(!(*p)){ /* There is no arg 1 */ first = NULL; goto parse; } first = p; while((*p != '=') && *p) p++; /* Skip to end of arg 1 */ first_end = p-1; /* Not the terminator, last char */ if(!(*p)) goto parse; /* Back first_end up. We don't like trailing whitespace */ while(isspace(*first_end)) first_end--; p++; /* Skip the '=' */ while(isspace(*p) && *p) p++; /* Skip to arg 2 */ if(!(*p)) goto parse; second = p; while(*p) p++; /* Skip to end of arg 2 */ p--; while(isspace(*p)) p--; /* Back up over trailing whitespace. */ p[1] = '\0'; /* Go to it */ parse: if(cmd[0] == '@'){ handle_at_cmd(cmd+1, player, first, first_end, second); return; } for(fp = cmds; fp->name && !cmdcmp(fp, cmd); fp++); if(fp->name){ switch(fp->nargs){ case 0: fp->function(player); break; case 1: fp->function(player, first); break; case 2: Parse; fp->function(player, first, second); break; default: log_error("handle_cmd: function %s has a bad argument number\n", fp->name); do_huh(player); } if(mudstat() != DUMPING) unlock_cache(); cache_trim(); } else { do_huh(player); if(mudstat() != DUMPING) unlock_cache(); cache_trim(); } } static void handle_at_cmd(cmd, player, first, first_end, second) char *cmd; int player; char *first, *first_end, *second; { CMDS *fp; for(fp = atcmds; fp->name && !cmdcmp(fp, cmd); fp++); if(fp->name){ switch(fp->nargs){ case 0: fp->function(player); break; case 1: fp->function(player, first); break; case 2: Parse; fp->function(player, first, second); break; default: log_error("handle_at_cmd: function %s has a bad argument number\n", fp->name); do_huh(player); } if(mudstat() != DUMPING) unlock_cache(); cache_trim(); } else { if(!handle_exit_cmd(player, cmd)) do_huh(player); if(mudstat() != DUMPING) unlock_cache(); cache_trim(); } } static int handle_exit_cmd(player, cmd) int player; char *cmd; { struct match *exlist; int here, list, count; /* Is this an exit? If so, cope with it. */ if(get_int_elt(player, LOC, &here) == -1){ log_error("handle_exit_cmd: bad location ref on player %d\n", player); return 0; } if(get_int_elt(here, EXITS, &list) == -1){ log_error("handle_exit_cmd: bad exit list on object %d\n", here); return 0; } if((exlist = match_exits(cmd, list, &count)) != NULL){ /* Ok. We have a list of exits. Cope with 'em. */ do_go_attempt(player, here, exlist); return 1; } else return 0; } #undef Parse static int cmdcmp(fp, cmd) register CMDS *fp; register char *cmd; { return(!strncasecmp(fp->name, cmd, strlen(fp->name)) && ((!cmd[strlen(fp->name)]) || isspace(cmd[strlen(fp->name)]))); } /* Dummy commands follow. */ voidfunc do_efind(player) int player; { notify_player(player, "@efind: Try \"@find <name> = exit\".\r\n"); } voidfunc do_descstr(player, s1, s2) int player; char *s1, *s2; { do_set_string(player, s1, s2, DESC); } voidfunc do_failstr(player, s1, s2) int player; char *s1, *s2; { do_set_string(player, s1, s2, FAIL); } voidfunc do_genderstr(player, s1, s2) int player; char *s1, *s2; { do_set_string(player, s1, s2, GENDER); } voidfunc do_namestr(player, s1, s2) int player; char *s1, *s2; { do_set_string(player, s1, s2, NAME); } voidfunc do_ofailstr(player, s1, s2) int player; char *s1, *s2; { do_set_string(player, s1, s2, OFAIL); } voidfunc do_osucstr(player, s1, s2) int player; char *s1, *s2; { do_set_string(player, s1, s2, OSUC); } voidfunc do_sucstr(player, s1, s2) int player; char *s1, *s2; { do_set_string(player, s1, s2, SUC); } #ifdef DROP_FIELDS voidfunc do_dropstr(player, s1, s2) int player; char *s1, *s2; { do_set_string(player, s1, s2, DROP); } voidfunc do_odropstr(player, s1, s2) int player; char *s1, *s2; { do_set_string(player, s1, s2, ODROP); } #endif /*DROP_FIELDS*/ voidfunc do_oarrive(player, s1, s2) int player; char *s1, *s2; { do_set_string(player, s1, s2, OARRIVE); } voidfunc do_oleave(player, s1, s2) int player; char *s1, *s2; { do_set_string(player, s1, s2, OLEAVE); }