/* match.c */ /* Routines for parsing arguments */ #include "os.h" #include "copyright.h" #include "config.h" #include "db.h" #include "externs.h" #include "globals.h" #include "match.h" static dbref exact_match = NOTHING; /* holds result of exact match */ static int check_keys = 0; /* if non-zero, check for keys */ static dbref last_match = NOTHING; /* holds result of last match */ static int match_count; /* holds total number of inexact matches */ static dbref match_who; /* player who is being matched around */ static const char *match_name; /* name to match */ static int preferred_type = NOTYPE; /* preferred type */ #ifdef DO_GLOBALS static int global = 0; /* when 0 -- normal match */ /* 1 -- global match */ /* 2 -- remote match */ #endif char const *nomatch_message = "I don't see that here."; char const *ambiguous_message = "I don't know which one you mean!"; /* * check a list for objects that are prefix's for string, && are controlled * || link_ok */ dbref pref_match (dbref player, dbref list, const char *string) { dbref lmatch = NOTHING; unsigned int mlen = 0; while (list != NOTHING) { if (string_prefix (string, db[list].name) && ((Typeof (list) == TYPE_THING) && (db[list].flags & THING_PUPPET)) && controls (player, list)) { if (strlen (db[list].name) > mlen) { lmatch = list; mlen = strlen (db[list].name); } } list = db[list].next; } return (lmatch); } void init_match (dbref player, const char *name, int type) { exact_match = last_match = NOTHING; match_count = 0; match_who = player; match_name = name; check_keys = 0; preferred_type = type; #ifdef DO_GLOBALS global = NORMAL_MATCH; #endif } void init_match_check_keys (dbref player, const char *name, int type) { init_match (player, name, type); check_keys = 1; } #ifdef DO_GLOBALS void init_match_global (dbref player, const char *name, int type) { init_match (player, name, type); global = GLOBAL_MATCH; } void init_match_global_check_keys (dbref player, const char *name, int type) { init_match_global (player, name, type); check_keys = 1; } void init_match_remote (dbref location, const char *name, int type) { exact_match = last_match = NOTHING; match_count = 0; match_who = location; match_name = name; check_keys = 0; preferred_type = type; global = REMOTE_MATCH; } #endif static dbref choose_thing (dbref thing1, dbref thing2) { int has1; int has2; if (thing1 == NOTHING) { return thing2; } else if (thing2 == NOTHING) { return thing1; } if (preferred_type != NOTYPE) { if (Typeof (thing1) == preferred_type) { if (Typeof (thing2) != preferred_type) { return thing1; } } else if (Typeof (thing2) == preferred_type) { return thing2; } } if (check_keys) { has1 = could_doit (match_who, thing1); has2 = could_doit (match_who, thing2); if (has1 && !has2) { return thing1; } else if (has2 && !has1) { return thing2; } /* else fall through */ } return (OS_RAND () % 2 ? thing1 : thing2); } void match_player (void) { dbref match; const char *p; if (*match_name == LOOKUP_TOKEN) { for (p = match_name + 1; isspace ((int)*p); p++); if ((match = lookup_player (p)) != NOTHING) { exact_match = match; } } } /* returns nnn if name = #nnn, else NOTHING */ static dbref absolute_name (void) { dbref match; if (*match_name == NUMBER_TOKEN) { match = parse_dbref (match_name + 1); if (match < 0 || match >= db_top) { return NOTHING; } else { return match; } } else { return NOTHING; } } void match_absolute (void) { dbref match; if ((match = absolute_name ()) != NOTHING) { exact_match = match; } } void match_me (void) { if (!string_compare (match_name, "me")) { exact_match = match_who; } } void match_here (void) { if (!string_compare (match_name, "here") && db[match_who].location != NOTHING) { exact_match = db[match_who].location; } } static void match_list (dbref first) { dbref absolute; absolute = absolute_name (); if (!controls (match_who, absolute)) absolute = NOTHING; DOLIST (first, first) { Access (first); if (first == absolute) { exact_match = first; return; } else if (!string_compare (db[first].name, match_name)) { /* if there are multiple exact matches, randomly choose one */ exact_match = choose_thing (exact_match, first); } else if (string_match (db[first].name, match_name)) { last_match = first; match_count++; } } } void match_possession (void) { match_list (db[match_who].contents); } void match_neighbor (void) { dbref loc; if ((loc = db[match_who].location) != NOTHING) { match_list (db[loc].contents); } } #ifdef DO_GLOBALS void match_remote_contents (void) { if (match_who != NOTHING) match_list (db[match_who].contents); } #endif void match_container (void) { if (db[match_who].location != NOTHING) match_list (db[match_who].location); } void match_exit (void) { dbref loc; dbref exit; dbref absolute; const char *match; const char *p; #ifdef DO_GLOBALS switch (global) { case NORMAL_MATCH: loc = db[match_who].location; break; case GLOBAL_MATCH: loc = MASTER_ROOM; break; case REMOTE_MATCH: loc = match_who; break; default: loc = db[match_who].location; } #else loc = db[match_who].location; #endif if (loc != NOTHING) { if (Typeof (loc) != TYPE_ROOM) return; absolute = absolute_name (); if (!controls (match_who, absolute)) absolute = NOTHING; DOLIST (exit, db[loc].exits) { Access (exit); if (exit == absolute) { exact_match = exit; } else { match = db[exit].name; while (*match) { /* check out this one */ for (p = match_name; (*p && DOWNCASE (*p) == DOWNCASE (*match) && *match != EXIT_DELIMITER); p++, match++); /* did we get it? */ if (*p == '\0') { /* make sure there's nothing afterwards */ while (isspace ((int)*match)) match++; if (*match == '\0' || *match == EXIT_DELIMITER) { /* we got it */ exact_match = choose_thing (exact_match, exit); goto next_exit; /* got this match */ } } /* we didn't get it, find next match */ while (*match && *match++ != EXIT_DELIMITER); while (isspace ((int)*match)) match++; } } next_exit: ; } } } void match_everything (void) { match_exit (); match_neighbor (); match_possession (); match_me (); match_here (); match_absolute (); match_player (); } #ifdef DO_GLOBALS void match_remote (void) { match_exit (); match_remote_contents (); match_absolute (); match_player (); } #endif dbref match_result (void) { if (exact_match != NOTHING) { return exact_match; } else { switch (match_count) { case 0: return NOTHING; case 1: return last_match; default: return AMBIGUOUS; } } } /* use this if you don't care about ambiguity */ dbref last_match_result (void) { if (exact_match != NOTHING) { return exact_match; } else { return last_match; } } dbref noisy_match_result (void) { dbref match; switch (match = match_result ()) { case NOTHING: notify (match_who, nomatch_message); return NOTHING; case AMBIGUOUS: notify (match_who, ambiguous_message); return NOTHING; default: return match; } } dbref match_controlled (dbref player, const char *name) { dbref match; init_match (player, name, NOTYPE); match_everything (); match = noisy_match_result (); if (match != NOTHING && !controls (player, match)) { notify (player, "Permission denied."); return NOTHING; } else { return match; } }