/* This software is Copyright 1989, 1990, 1992, 1993 by various individuals. Please see the accompanying file COPYRIGHT for details. */ /* Routines for parsing arguments */ #include "db.h" #include "defs.h" #include "prims.h" #include "ctype.h" #include "match.h" #include "params.h" #include "config.h" #include "random.h" #include "externs.h" void init_match(dbref player, const char *name, int type, struct match_data *md) { md->exact_match = NOTHING; md->last_match = NOTHING; md->match_count = 0; md->exact_count = 0; md->match_who = player; md->match_name = name; md->check_keys = 0; md->preferred_type = type; md->longest_match = 0; md->match_args[0] = '\0'; } void init_match_check_keys(dbref player, const char *name, int type, struct match_data *md) { init_match(player,name,type,md); md->check_keys = 1; } static void choose_thing(struct match_data *md, dbref newthing) { if (newthing == NOTHING) return; if (md->exact_match == NOTHING) { md->exact_match = newthing; md->exact_count = 1; return; } if (md->preferred_type != NOTYPE) { if (Typeof(newthing) == md->preferred_type) { if (Typeof(md->exact_match) != md->preferred_type) { md->exact_match = newthing; md->exact_count = 1; return; } } else { if (Typeof(md->exact_match) == md->preferred_type) { return; } } } if (md->check_keys) { int hascur; int hasnew; hascur = (md->match_who != NOTHING) && could_doit(md->match_who,md->exact_match); hasnew = (md->match_who != NOTHING) && could_doit(md->match_who,newthing); if (hascur && !hasnew) return; if (hasnew && !hascur) { md->exact_match = newthing; md->exact_count = 1; } } md->exact_count ++; if (! rnd(md->exact_count)) md->exact_match = newthing; } void match_player(struct match_data *md) { dbref match; const char *p; if ( (*md->match_name == LOOKUP_TOKEN) && ( (md->match_who == NOTHING) || payfor(md->match_who,LOOKUP_COST,"match *name") ) ) { for (p=md->match_name+1;Cisspace(*p);p++) ; match = lookup_player(p); if (match != NOTHING) md->exact_match = match; } } /* returns nnn if name = #nnn, else NOTHING */ static dbref absolute_name(struct match_data *md) { dbref match; if(*(md -> match_name) == NUMBER_TOKEN) { match = parse_dbref((md -> match_name)+1); if(match < 0 || match >= db_top) return NOTHING; else return match; } else return NOTHING; } void match_absolute(struct match_data *md) { dbref match; if((match = absolute_name(md)) != NOTHING) { md -> exact_match = match; } } void match_me(struct match_data *md) { if ((md->match_who != NOTHING) && !string_compare(md->match_name,"me")) { md->exact_match = md->match_who; } } void match_here(struct match_data *md) { if ( (md->match_who != NOTHING) && !string_compare(md->match_name,"here") && (DBFETCH(md->match_who)->location != NOTHING) ) { md->exact_match = DBFETCH(md->match_who)->location; } } void match_home(struct match_data *md) { if (!string_compare(md -> match_name, "home")) md -> exact_match = HOME; } void match_builtin(struct match_data *md) { if (!string_compare(md->match_name,"builtin")) md->exact_match = BUILTIN; } static void match_list(dbref first, struct match_data *md) { dbref absolute; absolute = absolute_name(md); if ((md->match_who == NOTHING) || !controls(md->match_who,absolute)) { absolute = NOTHING; } DOLIST(first,first) { if (first == absolute) { md->exact_match = first; return; } else if (!string_compare(NAME(first),md->match_name)) { /* if there are multiple exact matches, randomly choose one */ choose_thing(md,first); } else if (string_match(NAME(first),md->match_name)) { md->last_match = first; md->match_count ++; } } } void match_possession(struct match_data *md) { match_list(DBFETCH(md->match_who)->contents,md); } void match_neighbor(struct match_data *md) { dbref loc; if (md->match_who != NOTHING) { loc = DBFETCH(md->match_who)->location; if (loc != NOTHING) match_list(DBFETCH(loc)->contents,md); } } /* * match_exits matches a list of exits, starting with 'first'. * It is will match exits of players, rooms, or things. */ void match_exits(dbref first, struct match_data *md) { dbref xit; dbref absolute; char *exitname; const char *p; int i; int exitprog; if (first == NOTHING) return; /* Easy fail match */ absolute = NOTHING; if (md->match_who != NOTHING) { if ((DBFETCH(md->match_who)->location) == NOTHING) return; absolute = absolute_name(md); /* parse #nnn entries */ if (!controls(md->match_who,absolute)) absolute = NOTHING; } DOLIST(xit,first) { if (xit == absolute) { md->exact_match = xit; for (p=md->match_name;*p&&(*p!=' ');p++); md->match_cmdlen = p - md->match_name; if (*p) strcpy(&md->match_args[0],p+1); else md->match_args[0] = '\0'; continue; } exitprog = 0; if (DBFETCH(xit)->sp.exit.dest) { for (i=0;isp.exit.ndest;i++) { if (Typeof((DBFETCH(xit)->sp.exit.dest)[i]) == TYPE_PROGRAM) { exitprog = 1; break; } } } exitname = NAME(xit); while (*exitname) /* for all exit aliases */ { for ( p=md->match_name; /* check out 1 alias */ *p && ( (FLAGS(xit) & EXACT) ? (*p == *exitname) : (DOWNCASE(*p) == DOWNCASE(*exitname)) ) && ((*exitname != EXIT_DELIMITER) || (FLAGS(xit) & FULLNAME)); p++,exitname++) ; /* did we get a match on this alias? */ if ( (*p == '\0') || ( exitprog && ( (*p == ' ') || (FLAGS(xit) & PREFIX) ) ) ) { /* make sure there's nothing afterwards */ while (Cisspace(*exitname)) exitname++; if ( (*exitname == '\0') || ( (*exitname == EXIT_DELIMITER) && !(FLAGS(xit) & FULLNAME) ) ) { /* we got a match on this alias */ if (p-md->match_name > md->longest_match) { md->exact_match = xit; md->longest_match = p - md->match_name; if ((*p == ' ') && !(FLAGS(xit) & PREFIX)) p ++; md->match_cmdlen = md->longest_match; strcpy(&md->match_args[0],p); } else if (p-md->match_name == md->longest_match) { choose_thing(md,xit); if (md->exact_match == xit) { if ((*p == ' ') && !(FLAGS(xit) & PREFIX)) p ++; strcpy(&md->match_args[0],p); } } goto next_exit; } } /* we didn't get it, go on to next alias */ while ( *exitname && ( (*exitname++ != EXIT_DELIMITER) || (FLAGS(xit) & FULLNAME) ) ) ; while (Cisspace(*exitname)) exitname++; } /* end of while alias string matches */ next_exit:; } } /* * match_room_exits * Matches exits and actions attached to player's current room. * Formerly 'match_exit'. */ void match_room_exits(dbref loc, struct match_data *md) { if (Typeof(loc) != TYPE_ROOM) return; if (DBFETCH(loc)->sp.room.exits != NOTHING) match_exits(DBFETCH(loc)->sp.room.exits,md); } /* * match_invobj_actions * matches actions attached to objects in inventory */ void match_invobj_actions(struct match_data *md) { dbref thing; if (md->match_who == NOTHING) return; if (DBFETCH(md->match_who)->contents == NOTHING) return; DOLIST(thing, DBFETCH(md->match_who)->contents) { if ( (Typeof(thing) == TYPE_THING) && (DBFETCH(thing)->sp.thing.actions != NOTHING) ) { match_exits(DBFETCH(thing)->sp.thing.actions,md); } } } /* * match_roomobj_actions * matches actions attached to objects in the room */ void match_roomobj_actions(struct match_data *md) { dbref thing; dbref loc; if (md->match_who == NOTHING) return; loc = DBFETCH(md->match_who)->location; if (loc == NOTHING) return; if (DBFETCH(loc)->contents == NOTHING) return; DOLIST(thing,DBFETCH(loc)->contents) { if ( (Typeof(thing) == TYPE_THING) && (DBFETCH(thing)->sp.thing.actions != NOTHING) ) { match_exits(DBFETCH(thing)->sp.thing.actions,md); } } } /* * match_player_actions * matches actions attached to player */ void match_player_actions(struct match_data *md) { if (md->match_who == NOTHING) return; if (Typeof(md->match_who) != TYPE_PLAYER) return; if (DBFETCH(md->match_who)->sp.player.actions == NOTHING) return; match_exits(DBFETCH(md->match_who)->sp.player.actions,md); } /* * match_all_exits * Matches actions on player, objects in room, objects in inventory, * and room actions/exits (in reverse order of priority order). */ void match_all_exits(struct match_data *md) { dbref loc; md->match_cmdlen = 0; md->match_args[0] = '\0'; loc = NOTHING; if (md->match_who != NOTHING) { loc = DBFETCH(md->match_who)->location; if (loc != NOTHING) match_room_exits(loc,md); } if (md->exact_match == NOTHING) match_invobj_actions(md); if (md->exact_match == NOTHING) match_roomobj_actions(md); if (md->exact_match == NOTHING) match_player_actions(md); if (loc != NOTHING) { while ( (md->exact_match == NOTHING) && ((loc=DBFETCH(loc)->location) != NOTHING) ) { match_room_exits(loc,md); } } if ( (md->exact_match == NOTHING) && ( (md->match_who == NOTHING) || Royalty(md->match_who) ) ) { match_absolute(md); } } void match_everything(struct match_data *md) { match_all_exits(md); match_neighbor(md); match_possession(md); match_me(md); match_here(md); match_absolute(md); match_player(md); } dbref match_result(struct match_data *md) { if (md->exact_match != NOTHING) return(md->exact_match); switch (md->match_count) { case 0: return(NOTHING); break; case 1: return(md->last_match); break; } return(AMBIGUOUS); } /* use this if you don't care about ambiguity */ dbref last_match_result(struct match_data *md) { if (md->exact_match != NOTHING) return(md->exact_match); return(md->last_match); } dbref noisy_match_result(struct match_data *md) { dbref match; match = match_result(md); switch (match) { case NOTHING: if (md->match_who != NOTHING) notify(md->match_who,NOMATCH_MESSAGE); return(NOTHING); break; case AMBIGUOUS: if (md->match_who != NOTHING) notify(md->match_who,AMBIGUOUS_MESSAGE); return(NOTHING); break; } return(match); } void match_rmatch(dbref arg1, struct match_data *md) { if (arg1 == NOTHING) return; switch (Typeof(arg1)) { case TYPE_PLAYER: match_list(DBFETCH(arg1)->contents,md); match_exits(DBFETCH(arg1)->sp.player.actions,md); break; case TYPE_ROOM: match_list(DBFETCH(arg1)->contents,md); match_exits(DBFETCH(arg1)->sp.room.exits,md); break; case TYPE_THING: match_exits(DBFETCH(arg1)->sp.thing.actions,md); break; } }