dw_fluffos_v2/
dw_fluffos_v2/fluffos-2.9-ds2.05/
dw_fluffos_v2/fluffos-2.9-ds2.05/ChangeLog.old/
dw_fluffos_v2/fluffos-2.9-ds2.05/Win32/
dw_fluffos_v2/fluffos-2.9-ds2.05/compat/
dw_fluffos_v2/fluffos-2.9-ds2.05/compat/simuls/
dw_fluffos_v2/fluffos-2.9-ds2.05/include/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/clone/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/command/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/data/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/etc/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/include/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/inherit/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/inherit/master/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/log/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/single/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/single/tests/compiler/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/single/tests/efuns/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/single/tests/operators/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/u/
dw_fluffos_v2/fluffos-2.9-ds2.05/tmp/
dw_fluffos_v2/fluffos-2.9-ds2.05/windows/
dw_fluffos_v2/lib/
dw_fluffos_v2/lib/binaries/cmds/
dw_fluffos_v2/lib/binaries/cmds/creator/
dw_fluffos_v2/lib/binaries/cmds/living/
dw_fluffos_v2/lib/binaries/cmds/player/
dw_fluffos_v2/lib/binaries/d/admin/obj/
dw_fluffos_v2/lib/binaries/d/liaison/
dw_fluffos_v2/lib/binaries/global/virtual/
dw_fluffos_v2/lib/binaries/global/virtual/setup_compiler/
dw_fluffos_v2/lib/binaries/obj/handlers/autodoc/
dw_fluffos_v2/lib/binaries/obj/handlers/terrain_things/
dw_fluffos_v2/lib/binaries/obj/misc/
dw_fluffos_v2/lib/binaries/obj/misc/buckets/
dw_fluffos_v2/lib/binaries/obj/monster/
dw_fluffos_v2/lib/binaries/obj/reactions/
dw_fluffos_v2/lib/binaries/obj/reagents/
dw_fluffos_v2/lib/binaries/secure/cmds/creator/
dw_fluffos_v2/lib/binaries/secure/master/
dw_fluffos_v2/lib/binaries/std/
dw_fluffos_v2/lib/binaries/std/dom/
dw_fluffos_v2/lib/binaries/std/effects/object/
dw_fluffos_v2/lib/binaries/std/guilds/
dw_fluffos_v2/lib/binaries/std/languages/
dw_fluffos_v2/lib/binaries/std/races/
dw_fluffos_v2/lib/binaries/std/room/
dw_fluffos_v2/lib/binaries/std/room/basic/
dw_fluffos_v2/lib/binaries/std/shops/
dw_fluffos_v2/lib/binaries/std/shops/inherit/
dw_fluffos_v2/lib/binaries/www/
dw_fluffos_v2/lib/cmds/guild-race/
dw_fluffos_v2/lib/cmds/guild-race/crafts/
dw_fluffos_v2/lib/cmds/guild-race/other/
dw_fluffos_v2/lib/cmds/playtester/
dw_fluffos_v2/lib/cmds/playtester/senior/
dw_fluffos_v2/lib/d/admin/
dw_fluffos_v2/lib/d/admin/log/
dw_fluffos_v2/lib/d/admin/mapper/31-10-01/mapmaker/event/
dw_fluffos_v2/lib/d/admin/meetings/
dw_fluffos_v2/lib/d/admin/obj/
dw_fluffos_v2/lib/d/admin/room/we_care/
dw_fluffos_v2/lib/d/admin/save/
dw_fluffos_v2/lib/d/dist/
dw_fluffos_v2/lib/d/dist/mtf/
dw_fluffos_v2/lib/d/dist/pumpkin/
dw_fluffos_v2/lib/d/dist/pumpkin/chars/
dw_fluffos_v2/lib/d/dist/pumpkin/desert/
dw_fluffos_v2/lib/d/dist/pumpkin/gumboot/
dw_fluffos_v2/lib/d/dist/pumpkin/hospital/
dw_fluffos_v2/lib/d/dist/pumpkin/inherit/
dw_fluffos_v2/lib/d/dist/pumpkin/map/
dw_fluffos_v2/lib/d/dist/pumpkin/plain/
dw_fluffos_v2/lib/d/dist/pumpkin/pumpkin/
dw_fluffos_v2/lib/d/dist/pumpkin/save/
dw_fluffos_v2/lib/d/dist/pumpkin/squash/
dw_fluffos_v2/lib/d/dist/pumpkin/terrain/
dw_fluffos_v2/lib/d/dist/pumpkin/woods/
dw_fluffos_v2/lib/d/dist/start/
dw_fluffos_v2/lib/d/learning/TinyTown/buildings/
dw_fluffos_v2/lib/d/learning/TinyTown/map/
dw_fluffos_v2/lib/d/learning/TinyTown/roads/
dw_fluffos_v2/lib/d/learning/add_command/
dw_fluffos_v2/lib/d/learning/arms_and_weps/
dw_fluffos_v2/lib/d/learning/chars/
dw_fluffos_v2/lib/d/learning/cutnpaste/
dw_fluffos_v2/lib/d/learning/examples/npcs/
dw_fluffos_v2/lib/d/learning/examples/player_houses/npcs/
dw_fluffos_v2/lib/d/learning/examples/terrain_map/basic/
dw_fluffos_v2/lib/d/learning/functions/
dw_fluffos_v2/lib/d/learning/handlers/
dw_fluffos_v2/lib/d/learning/help_topics/npcs/
dw_fluffos_v2/lib/d/learning/help_topics/objects/
dw_fluffos_v2/lib/d/learning/help_topics/rcs_demo/
dw_fluffos_v2/lib/d/learning/help_topics/rooms/
dw_fluffos_v2/lib/d/learning/help_topics/rooms/crowd/
dw_fluffos_v2/lib/d/learning/help_topics/rooms/situations/
dw_fluffos_v2/lib/d/learning/items/
dw_fluffos_v2/lib/d/learning/save/
dw_fluffos_v2/lib/d/liaison/
dw_fluffos_v2/lib/d/liaison/NEWBIE/doc/
dw_fluffos_v2/lib/d/liaison/NEWBIE/save/oldlog/
dw_fluffos_v2/lib/db/
dw_fluffos_v2/lib/doc/
dw_fluffos_v2/lib/doc/creator/
dw_fluffos_v2/lib/doc/creator/autodoc/include/reaction/
dw_fluffos_v2/lib/doc/creator/autodoc/include/ritual_system/
dw_fluffos_v2/lib/doc/creator/autodoc/include/talker/
dw_fluffos_v2/lib/doc/creator/autodoc/include/terrain_map/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/baggage/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/clock/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/clothing/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/cont_save/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/corpse/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/money/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/monster/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/scabbard/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/service_provider/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/state_changer/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/wand/
dw_fluffos_v2/lib/doc/creator/autodoc/std/book_dir/
dw_fluffos_v2/lib/doc/creator/autodoc/std/key/
dw_fluffos_v2/lib/doc/creator/autodoc/std/learning/
dw_fluffos_v2/lib/doc/creator/autodoc/std/map/
dw_fluffos_v2/lib/doc/creator/autodoc/std/race/
dw_fluffos_v2/lib/doc/creator/autodoc/std/weapon_logic/
dw_fluffos_v2/lib/doc/creator/files/
dw_fluffos_v2/lib/doc/creator/policy/
dw_fluffos_v2/lib/doc/creator/room/
dw_fluffos_v2/lib/doc/effects/
dw_fluffos_v2/lib/doc/ideas/
dw_fluffos_v2/lib/doc/known_command/
dw_fluffos_v2/lib/doc/lpc/basic_manual/
dw_fluffos_v2/lib/doc/lpc/intermediate/
dw_fluffos_v2/lib/doc/new/add_command/
dw_fluffos_v2/lib/doc/new/handlers/
dw_fluffos_v2/lib/doc/new/living/
dw_fluffos_v2/lib/doc/new/living/race/
dw_fluffos_v2/lib/doc/new/living/spells/
dw_fluffos_v2/lib/doc/new/player/
dw_fluffos_v2/lib/doc/new/room/guild/
dw_fluffos_v2/lib/doc/new/room/outside/
dw_fluffos_v2/lib/doc/new/room/storeroom/
dw_fluffos_v2/lib/doc/object/
dw_fluffos_v2/lib/doc/playtesters/
dw_fluffos_v2/lib/doc/policy/
dw_fluffos_v2/lib/doc/weapons/
dw_fluffos_v2/lib/global/handlers/
dw_fluffos_v2/lib/global/virtual/setup_compiler/
dw_fluffos_v2/lib/include/
dw_fluffos_v2/lib/include/cmds/
dw_fluffos_v2/lib/include/effects/
dw_fluffos_v2/lib/include/npc/
dw_fluffos_v2/lib/include/shops/
dw_fluffos_v2/lib/net/daemon/chars/
dw_fluffos_v2/lib/net/inherit/
dw_fluffos_v2/lib/net/intermud3/
dw_fluffos_v2/lib/net/intermud3/services/
dw_fluffos_v2/lib/net/obj/
dw_fluffos_v2/lib/net/save/
dw_fluffos_v2/lib/net/smnmp/
dw_fluffos_v2/lib/net/snmp/
dw_fluffos_v2/lib/obj/amulets/
dw_fluffos_v2/lib/obj/b_day/
dw_fluffos_v2/lib/obj/examples/
dw_fluffos_v2/lib/obj/food/alcohol/
dw_fluffos_v2/lib/obj/food/chocolates/
dw_fluffos_v2/lib/obj/food/fruits/
dw_fluffos_v2/lib/obj/food/meat/
dw_fluffos_v2/lib/obj/food/nuts/
dw_fluffos_v2/lib/obj/food/seafood/
dw_fluffos_v2/lib/obj/food/vegetables/
dw_fluffos_v2/lib/obj/fungi/
dw_fluffos_v2/lib/obj/furnitures/artwork/
dw_fluffos_v2/lib/obj/furnitures/bathroom/
dw_fluffos_v2/lib/obj/furnitures/beds/
dw_fluffos_v2/lib/obj/furnitures/cabinets/
dw_fluffos_v2/lib/obj/furnitures/chairs/
dw_fluffos_v2/lib/obj/furnitures/chests/
dw_fluffos_v2/lib/obj/furnitures/clocks/
dw_fluffos_v2/lib/obj/furnitures/crockery/
dw_fluffos_v2/lib/obj/furnitures/cupboards/
dw_fluffos_v2/lib/obj/furnitures/cushions/
dw_fluffos_v2/lib/obj/furnitures/fake_plants/
dw_fluffos_v2/lib/obj/furnitures/lamps/
dw_fluffos_v2/lib/obj/furnitures/mirrors/
dw_fluffos_v2/lib/obj/furnitures/outdoor/
dw_fluffos_v2/lib/obj/furnitures/safes/
dw_fluffos_v2/lib/obj/furnitures/shelves/
dw_fluffos_v2/lib/obj/furnitures/sideboards/
dw_fluffos_v2/lib/obj/furnitures/sofas/
dw_fluffos_v2/lib/obj/furnitures/stoves/
dw_fluffos_v2/lib/obj/furnitures/tables/
dw_fluffos_v2/lib/obj/furnitures/wardrobes/
dw_fluffos_v2/lib/obj/handlers/
dw_fluffos_v2/lib/obj/handlers/autodoc/
dw_fluffos_v2/lib/obj/jewellery/anklets/
dw_fluffos_v2/lib/obj/jewellery/bracelets/
dw_fluffos_v2/lib/obj/jewellery/earrings/
dw_fluffos_v2/lib/obj/jewellery/misc/
dw_fluffos_v2/lib/obj/jewellery/necklaces/
dw_fluffos_v2/lib/obj/jewellery/rings/
dw_fluffos_v2/lib/obj/media/
dw_fluffos_v2/lib/obj/misc/buckets/
dw_fluffos_v2/lib/obj/misc/jars/
dw_fluffos_v2/lib/obj/misc/papers/
dw_fluffos_v2/lib/obj/misc/player_shop/
dw_fluffos_v2/lib/obj/misc/shops/
dw_fluffos_v2/lib/obj/misc/traps/
dw_fluffos_v2/lib/obj/monster/
dw_fluffos_v2/lib/obj/monster/godmother/
dw_fluffos_v2/lib/obj/monster/transport/
dw_fluffos_v2/lib/obj/plants/inherit/
dw_fluffos_v2/lib/obj/potions/
dw_fluffos_v2/lib/open/boards/
dw_fluffos_v2/lib/save/autodoc/
dw_fluffos_v2/lib/save/bank_accounts/
dw_fluffos_v2/lib/save/boards/frog/
dw_fluffos_v2/lib/save/books/bed_catalog/
dw_fluffos_v2/lib/save/creators/
dw_fluffos_v2/lib/save/mail/
dw_fluffos_v2/lib/save/mail/p/
dw_fluffos_v2/lib/save/soul/data/
dw_fluffos_v2/lib/save/tasks/
dw_fluffos_v2/lib/save/vaults/
dw_fluffos_v2/lib/secure/cmds/lord/
dw_fluffos_v2/lib/secure/config/
dw_fluffos_v2/lib/secure/items/
dw_fluffos_v2/lib/secure/player/
dw_fluffos_v2/lib/soul/
dw_fluffos_v2/lib/soul/i/
dw_fluffos_v2/lib/soul/j/
dw_fluffos_v2/lib/soul/k/
dw_fluffos_v2/lib/soul/o/
dw_fluffos_v2/lib/soul/q/
dw_fluffos_v2/lib/soul/to_approve/
dw_fluffos_v2/lib/soul/u/
dw_fluffos_v2/lib/soul/v/
dw_fluffos_v2/lib/soul/wish_list/
dw_fluffos_v2/lib/soul/y/
dw_fluffos_v2/lib/soul/z/
dw_fluffos_v2/lib/std/creator/
dw_fluffos_v2/lib/std/effects/
dw_fluffos_v2/lib/std/effects/attached/
dw_fluffos_v2/lib/std/effects/external/
dw_fluffos_v2/lib/std/effects/fighting/
dw_fluffos_v2/lib/std/effects/other/
dw_fluffos_v2/lib/std/environ/
dw_fluffos_v2/lib/std/guilds/
dw_fluffos_v2/lib/std/hospital/
dw_fluffos_v2/lib/std/house/
dw_fluffos_v2/lib/std/house/onebedhouse/
dw_fluffos_v2/lib/std/house/onebedhut/
dw_fluffos_v2/lib/std/house/tworoomflat/
dw_fluffos_v2/lib/std/languages/
dw_fluffos_v2/lib/std/liquids/
dw_fluffos_v2/lib/std/nationality/
dw_fluffos_v2/lib/std/nationality/accents/
dw_fluffos_v2/lib/std/nationality/accents/national/
dw_fluffos_v2/lib/std/nationality/accents/regional/
dw_fluffos_v2/lib/std/npc/goals/
dw_fluffos_v2/lib/std/npc/goals/basic/
dw_fluffos_v2/lib/std/npc/goals/misc/
dw_fluffos_v2/lib/std/npc/inherit/
dw_fluffos_v2/lib/std/npc/plans/
dw_fluffos_v2/lib/std/npc/plans/basic/
dw_fluffos_v2/lib/std/outsides/
dw_fluffos_v2/lib/std/races/shadows/
dw_fluffos_v2/lib/std/room/basic/topography/
dw_fluffos_v2/lib/std/room/controller/
dw_fluffos_v2/lib/std/room/controller/topography/
dw_fluffos_v2/lib/std/room/furniture/games/
dw_fluffos_v2/lib/std/room/furniture/inherit/
dw_fluffos_v2/lib/std/room/inherit/carriage/
dw_fluffos_v2/lib/std/room/inherit/topography/
dw_fluffos_v2/lib/std/room/punishments/
dw_fluffos_v2/lib/std/room/topography/area/
dw_fluffos_v2/lib/std/room/topography/iroom/
dw_fluffos_v2/lib/std/room/topography/milestone/
dw_fluffos_v2/lib/std/shadows/
dw_fluffos_v2/lib/std/shadows/attached/
dw_fluffos_v2/lib/std/shadows/curses/
dw_fluffos_v2/lib/std/shadows/disease/
dw_fluffos_v2/lib/std/shadows/fighting/
dw_fluffos_v2/lib/std/shadows/room/
dw_fluffos_v2/lib/std/shops/controllers/
dw_fluffos_v2/lib/std/shops/objs/
dw_fluffos_v2/lib/std/shops/player_shop/
dw_fluffos_v2/lib/std/shops/player_shop/office_code/
dw_fluffos_v2/lib/std/socket/
dw_fluffos_v2/lib/www/
dw_fluffos_v2/lib/www/external/autodoc/
dw_fluffos_v2/lib/www/external/java/telnet/Documentation/
dw_fluffos_v2/lib/www/external/java/telnet/Documentation/images/
dw_fluffos_v2/lib/www/external/java/telnet/examples/
dw_fluffos_v2/lib/www/external/java/telnet/tools/
dw_fluffos_v2/lib/www/pics/
dw_fluffos_v2/lib/www/secure/creator/
dw_fluffos_v2/lib/www/secure/editors/
dw_fluffos_v2/lib/www/secure/survey_results/
dw_fluffos_v2/win32/
/**
 * This is the object matching code.
 * It is based on some code by Scatter at Dawn Whispers, although this is
 * both cut down and extended from what scatter had written.
 * @changes 2000-04-20   Scatter    File created.
 * @changes 2000-05-20   Pinkfish   Adapted to Discworld
 */

/**** This documentation should go into a man page? ****

Object matching
---------------

Singular objects are matched if the text is a combination of an optional
ordinal, zero or more adjectives and a noun (e.g. 1st red womble.)

Plural objects are matched if the text is a combination of an optional
counter, zero or more adjectives and a plural noun (4 red wombles.) Plural
object tokens can also match combinations of singular and plural object
matches seperated by " & " or ", " or " and " strings. For example,
red womble, 3 purple wombles and the second green cabbage.

Possesives (his/her/its) are handled as if they were adjectives, since
their use matches adjectives. Objectives (him/her/it) are handled as
if they were nouns. A parsing context is used to maintain information
about which object these should apply to.

Matching specific objects to a text string is carried out using the
parse_match() apply with the objects, rather than within this parser -
the above behaviour is the intended one. It is down to the parse_match()
apply to carry out the above requirements (see below for apply details.)

*/

#include <obj_parser.h>

#if !efun_defined(query_multiple_short)
inherit "/secure/simul_efun/multiple_short";
#endif
#include <playtesters.h>

#ifdef DEBUG
#define TRACE(ARG) tell_creator("pinkfish", ARG + "\n")
#else
#define TRACE(ARG)
#endif

#define EVERY_NUM 18729487

private nosave mapping _ordinals;
private nosave mapping _counters;
private nosave mapping _fractions;

//
// These are defines from elesewhere in the simul_efun inherit tree.
// don't remove the living() stuff, it's needed on the clone!
void tell_creator(string player, string text, mixed arg ...);
#if !efun_defined(living)
int living (object);
#endif


//
// This is a predefinition for functions in here.
//
class obj_match match_objects_in_environments( string input, mixed env_list,
                                      int type, object player);

void create()
{
   _ordinals = ([
      "any" : 1,
      "a" : 1,
      "an" : 1,
      "the" : 1,
      "1st" : 1, "first" : 1,
      "2nd" : 2, "second" : 2,
      "3rd" : 3, "third" : 3,
      "4th" : 4, "fourth" : 4,
      "5th" : 5, "fifth" : 5,
      "6th" : 6, "sixth" : 6,
      "7th" : 7, "seventh" : 7,
      "8th" : 8, "eighth" : 8,
      "9th" : 9, "ninth" : 9,
      "10th" : 10, "tenth" : 10,
      "last" : -1
   ]);

   _counters = ([
      "1" : 1, "one" : 1,
      "2" : 2, "two" : 2,
      "3" : 3, "three" : 3,
      "4" : 4, "four" : 4,
      "5" : 5, "five" : 5,
      "6" : 6, "six" : 6,
      "7" : 7, "seven" : 7,
      "8" : 8, "eight" : 8,
      "9" : 9, "nine" : 9,
      "10" : 10, "ten" : 10,
      "11" : 11, "eleven" : 11,
      "12" : 12, "twelve" : 12,
      "13" : 13, "thirteen" : 13,
      "14" : 14, "fourteen" : 14,
      "15" : 15, "fifteen" : 15,
      "16" : 16, "sixteen" : 16,
      "17" : 17, "seventeen" : 17,
      "18" : 18, "eighteen" : 18,
      "19" : 19, "nineteen" : 19,
      "20" : 20, "twenty" : 20,
      "many" : 20,
      "every" : EVERY_NUM,
   ]);

   _fractions = ([
      "half" : ({ 1, 2 }),
      "quarter" : ({ 1, 4 }),
      "some" : ({ 1, 50 })
   ]);
}

private void fixup_context(object player,
                   object* objects,
                   class obj_match_context context) {
   if (!player || !sizeof(objects)) {
      return ;
   }
   //
   // Whoo!  Successful, setup the new context.
   //
   if (sizeof(objects) > 1) {
      context->plural = objects;
   } else if (living(objects[0]) && objects[0] != player) {
      if (objects[0]->query_male()) {
         context->him = objects[0];
      } else if (objects[0]->query_female() != 0) {
         context->her = objects[0];
      } else {
         context->it = objects[0];
      }
   } else {
      context->it = objects[0];
   }
   player->set_it_them(context);
} /* fixup_context() */

/*
 * Match objects to words...
 */

/**
 * Find an object in the given array that matches the given words.
 * This will only return a correct match if the entire string
 * matches.  If it gets a partial match then nothing will be
 * returned.  The return array is of the format:<br>
 * <pre>({ flag, class obj_match info })
 * </pre>
 * The flag can be one of:
 * <dd>
 * <dt>OBJ_PARSER_SUCCESS
 * <dd>Successfuly matched the objects.  the objects part of the class will
 * contain the matched objects.
 * <dt>OBJ_PARSER_NO_MATCH
 * <dd>No successful match.  The text bit of the omatch class will contain
 * the text that didn't match
 * <dt>OBJ_PARSER_AMBIGUOUS
 * <dd>An ambigous match is returned, this means 'frog' was referenced
 * when there was more than one frog.  The objects part of the class
 * has all the objects there were matched
 * <dt>OBJ_PARSER_BAD_FRACTION
 * <dd>The specified fracition was bad, the text bit of the class contains
 * the bad fraction.
 * <dt>OBJ_PARSER_FRACTION
 * <dd>Means that a fraction was attempted to be applied to multiple
 * objects.
 * <dt>OBJ_PARSER_TOO_DARK
 * <dd>Unable to match the specified object because it is too dark.
 * </dl>
 * @param input the input string to match
 * @param ob_list the object to list to match in
 * @param type we restrict the matching to certain groups of objects
 * @param player the person doing the lookup
 * @return an array of the format ({ flag, class obj_match info })
 */
class obj_match match_object_in_array( string input,
                     object *ob_list,
                     int type,
                     object player)
{
   object ob;
   object *singular_objects;
   object *plural_objects;
   object thing;
   string first_word;
   string rest;
   string *bits;
   string bit;
   string inside_match;
   string nick;
   int n;
   int ord;
   int random_item;
   int count;
   int *fraction;
   mixed *obj_info;
   class obj_match result;
   class obj_match omatch;
   class obj_match_context context;

   if (!player) {
      player = this_player();
   }

   input = lower_case(input);

   //
   // This is used for determining things like 'it', 'them' and 'him'
   // etc references.
   //
   if (player) {
      context = player->query_it_them();
   }
   if (!classp(context) || sizeof(context) != 9) {
      context = new(class obj_match_context);
      context->plural = ({ });
      if (player) {
         player->set_it_them(context);
      }
   }

   /* if we are working on a plural, then all the various ways of
    * combining things (e.g. "1st red womble and 4 elephants, 3 tins & pot" )
    * have to be standardised and then split and matched seperately.
    */


   //if( strsrch( input, " and " ) != -1 ) {
      //input = replace_string( input, " and ", ", " );
   //}

   TRACE( "            Processed input: " + input );

   omatch = new( class obj_match );
   omatch->text = input;
   omatch->objects = ({ });

   if( strsrch( input, "&" ) != -1 ) {
      //
      // This allows one, the other or both to match.
      //
      TRACE( "            Splitting input" );
      foreach( bit in explode(input, "&") - ({ "" }) )
      {
         result = match_object_in_array( bit, ob_list,
                                type, player);
         if( result->result == OBJ_PARSER_SUCCESS ) {
            omatch->objects |= result->objects;
         }
      }
      if (!sizeof(omatch->objects)) {
         omatch->text = input;
         omatch->result = OBJ_PARSER_NO_MATCH;
         return omatch;
      }
      fixup_context(player, omatch->objects, context);
      omatch->result = OBJ_PARSER_SUCCESS;
      return omatch;
   }

   if (!(type & OBJ_PARSER_TYPE_EXISTENCE) &&
       player && !player->query_property(OBJ_PARSER_USE_AND_AS_BREAK_PROP)) {
      input = replace_string(input, " and ", ",");
   }

   if( strsrch( input, "," ) != -1 )
   {
      TRACE( "            Splitting input" );
      foreach( bit in explode(input, ",") - ({ "" }) )
      {
         result = match_object_in_array( bit, ob_list,
                                type, player);
         if( result->result == OBJ_PARSER_SUCCESS ) {
            omatch->objects |= result->objects;
         } else if (!(type & OBJ_PARSER_TYPE_EXISTENCE)) {
            return result;
         }
      }
      fixup_context(player, omatch->objects, context);
      omatch->result = OBJ_PARSER_SUCCESS;
      return omatch;
   }

   //
   // Do a nickname lookup.
   //
   if (player) {
      nick = player->expand_nickname(input);
      if (nick && nick!="") {
        input = nick;
      }
   }

   //
   // xx in yy syntax.
   //
   if (!(type & OBJ_PARSER_TYPE_NO_NESTED)) {
      n = strsrch(input, " in ", -1);
      if (n == -1) {
         n = strsrch(input, " on ", -1);
      }
      if (n != -1) {
         inside_match = input[0..n - 1];
         input = input[n + 4..];
      } else {
         inside_match = 0;
      }
   }


   /* if we got to here, input is already split as necessary and
    * we are working on a fragment
    */

   n = strsrch( input, " " );
   ord = 0;

   if( n != -1 )
   {
      first_word = input[ 0 .. n - 1 ];
      rest = input[ n + 1 .. ];

      //
      // check for fractions.
      //
      fraction = _fractions[ first_word ];
      if (!fraction) {
         if (sscanf(first_word, "%d/%d", n, count) == 2) {
            if (n > count || n < 0 || count <= 0) {
               omatch = new( class obj_match );
               omatch->text = input;
               omatch->objects = ({ });
               omatch->result = OBJ_PARSER_BAD_FRACTION;
               return omatch;
            }
            fraction = ({ n, count });
         }
         count = 0;
      }
      if (fraction) {
         input = rest;
         if (input[0..2] == "of ") {
            input = input[3..];
         }
      }
      n = strsrch(input, " ");
   }

   if( n != -1 )
   {
      /* we have more than one word to match. The first word could be an ordinal
       * or a counter depending whether we are looking for a plural or a type.
       * This must be converted to a number to use later, and the word stripped
       * from the text to match. Example counter: "four coins", example ordinal:
       * "2nd coin"
       */

      first_word = input[ 0 .. n - 1 ];
      rest = input[ n + 1 .. ];

      ord = _ordinals[ first_word ];
      if( ord > 0 ) {
         input = rest;
      }

      if( !ord )
      {
         count = _counters[ first_word ];
         if( !count ) {
            sscanf( first_word, "%d", count );
         }

         if( count > 0 ) {
            input = rest;
         }

         if (!count) {
            //
            // Check for a number at the end...
            //
            n = strsrch( input, " ", -1);
            if (n != -1) {
               if (sscanf(input[n + 1..], "%d", ord) == 1) {
                  input = input[0..n-1];
               }
            }
         }
      }
      n = strsrch(input, " ");
   }

   if (n != -1 && input[0 .. n - 1] == "random") {
      if (ord) {
         random_item = ord;
      } else {
         random_item = 1;
      }
      count = EVERY_NUM;
      ord = 0;
      input = input[n + 1..];
   }

   omatch = new( class obj_match );
   omatch->text = input;
   omatch->objects = ({ });

   bits = explode(input, " ");
   if (!sizeof(bits)) {
      omatch->result = OBJ_PARSER_NO_MATCH;
   }

   context->ordinal = ord;
   context->number_included = count;
   context->ignore_rest = 0;
   context->fraction = fraction;

   /* if we are looking for a plural, try to match the segment to a
    * plural id first (even if we are looking for a plural, the
    * particular segment may be singular, consider "blue flowers and 1st ball")
    */

   singular_objects = ({ });
   plural_objects = ({ });


   /* check each object in the list, asking it how it matches the
    * text segment.
    * The parse_match method is assumed to handle noting the ordinal
    * and count stuff.
    */
   if (player) {
      ob_list = filter(ob_list, (: $1->query_visible($(player)) :));
   }
   foreach( ob in ob_list )
   {
      if (!inside_match && (type & OBJ_PARSER_TYPE_LIVING)) {
         if (!living(ob)) {
            continue;
         }
      }
      if (!inside_match && (type & OBJ_PARSER_TYPE_PLAYER)) {
         if (!userp(ob)) {
            continue;
         }
      }
      obj_info = ob->parse_match_object( bits, player, context );
      if (obj_info) {
         if (obj_info[OBJ_PARSER_MATCH_TYPE] & OBJ_PARSER_MATCH_PLURAL)
         {
            plural_objects += obj_info[OBJ_PARSER_OBJECTS];
         }
         if (obj_info[OBJ_PARSER_MATCH_TYPE] & OBJ_PARSER_MATCH_SINGULAR)
         {
            singular_objects += obj_info[OBJ_PARSER_OBJECTS];
         }
      }
      if (context->ignore_rest) {
         break;
      }
   }

   //
   // If we are looking for a singular, or we matched multiple singulars
   // and we did not specify which one.
   //
   if (sizeof(singular_objects) > 1 &&
       (!ord && !count)) {
      if (player && !player->query_property(OBJ_PARSER_AMBIGUOUS_PROP)) {
         omatch->objects = singular_objects;
         omatch->result = OBJ_PARSER_AMBIGUOUS;
         return omatch;
      }
      //
      // Strip it back to just one object.
      //
      if (!random_item) {
         singular_objects = singular_objects[0..0];
      } else {
         n = random(sizeof(singular_objects));
         singular_objects = singular_objects[n..n];
      }
   }

   if( !sizeof( singular_objects ) &&
       !sizeof( plural_objects))
   {
      /* nothing has matched the text. */
      TRACE( "            No matches" );
      omatch->result = OBJ_PARSER_NO_MATCH;
      return omatch;
   }

   if (type & OBJ_PARSER_TYPE_SLOPPY_MATCHING) {
      omatch->objects = singular_objects & plural_objects;
   } else if (random_item) {
      if (sizeof(plural_objects)) {
         omatch->objects = plural_objects;
      } else {
         omatch->objects = singular_objects;
      }
      n = random(sizeof(omatch->objects));
      omatch->objects = omatch->objects[n..n];
   } else if (ord || count == 1 || count == EVERY_NUM) {
      if (ord == -1) {
         omatch->objects = singular_objects[<1..<1];
      } else {
         omatch->objects = singular_objects;
      }
   } else if (count) {
      omatch->objects = plural_objects;
   } else {
      if (sizeof(plural_objects)) {
         omatch->objects = plural_objects;
      } else {
         omatch->objects = singular_objects;
      }
   }

   if (sizeof(omatch->objects) > 1 && fraction) {
      omatch->result = OBJ_PARSER_FRACTION;
      return omatch;
   }

   //
   // Check and see if we didn't match enough objects.
   //
   if (context->number_included && count != EVERY_NUM) {
      omatch->result = OBJ_PARSER_NOT_ENOUGH;
      return omatch;
   }

   //
   // If we are doing inside matches...  Try it here...
   //
   if (inside_match) {
      foreach (thing in omatch->objects) {
         if (!thing->can_find_match_recurse_into(player)) {
            omatch->objects -= ({ thing });
         }
      }
      if (sizeof(omatch->objects)) {
         result = match_objects_in_environments(inside_match,
                                             omatch->objects,
                                             type,
                                             player);
         omatch->objects = ({ });
         if (result->result == OBJ_PARSER_SUCCESS) {
            foreach (thing in result->objects) {
               if (environment(thing) &&
                   environment(thing)->can_find_match_reference_inside_object(thing, player)) {
                  omatch->objects += ({ thing });
               }
            }
         } else {
            result->text = inside_match + " in " + input;
            return result;
         }
      }
   }


   if( sizeof( omatch->objects ) == 0 )
   {
      /* matches have been removed */
      TRACE( "            No matches (living/visible elimination)" );
      omatch->result = OBJ_PARSER_NO_MATCH;
      return omatch;
   }

   fixup_context(player, omatch->objects, context);

   omatch->result = OBJ_PARSER_SUCCESS;
   return omatch;
} /* match_object_in_array() */

/**
 * Find an object in the given environments that match the given words.
 * This will only return a correct match if the entire string
 * matches.  If it gets a partial match then nothing will be
 * returned.  The return array is of the format:<br>
 * <pre>({ flag, class obj_match info })
 * </pre>
 * The flag can be one of:
 * <dd>
 * <dt>OBJ_PARSER_SUCCESS
 * <dd>Successfuly matched the objects.  the objects part of the class will
 * contain the matched objects.
 * <dt>OBJ_PARSER_NO_MATCH
 * <dd>No successful match.  The text bit of the omatch class will contain
 * the text that didn't match
 * <dt>OBJ_PARSER_AMBIGUOUS
 * <dd>An ambigous match is returned, this means 'frog' was referenced
 * when there was more than one frog.  The objects part of the class
 * has all the objects there were matched
 * <dt>OBJ_PARSER_BAD_FRACTION
 * <dd>The specified fracition was bad, the text bit of the class contains
 * the bad fraction.
 * <dt>OBJ_PARSER_FRACTION
 * <dd>Means that a fraction was attempted to be applied to multiple
 * objects.
 * <dt>OBJ_PARSER_TOO_DARK
 * <dd>Unable to match the specified object because it is too dark.
 * </dl>
 * @param input the input string to match
 * @param env_list the environments to get the objects from
 * @param singular force a singular match
 * @param player the person doing the lookup
 * @return an array of the format ({ flag, class obj_match info })
 */
class obj_match match_objects_in_environments( string input, mixed env_list,
                                      int type, object player)
{
   object* tmp_expanded;
   object* stuff;
   object ob;
   class obj_match omatch;

   if (!player) {
      player = this_player();
   }

/*
   if (!player || !PLAYTESTER_HAND->query_tester(player)) {
      stuff = find_match(input, env_list, player);
      omatch = new(class obj_match);
      omatch->text = input;
      omatch->objects = stuff;
      if (!sizeof(stuff)) {
         omatch->result = OBJ_PARSER_NO_MATCH;
      } else {
         omatch->result = OBJ_PARSER_SUCCESS;
      }
      return omatch;
   }
 */

   if (!pointerp(env_list)) {
      if (input == "all" &&
          env_list->query_is_room() &&
          player->check_dark(env_list->query_light())) {
         omatch = new( class obj_match );
         omatch->text = input;
         omatch->objects = ({ });
         omatch->result = OBJ_PARSER_TOO_DARK;
         return omatch;
      }

      tmp_expanded = env_list->find_inv_match(input,player);
   } else {
      tmp_expanded = ({ });
      foreach (ob in env_list) {
         if (!ob) {
            continue;
         }
         if (input == "all" &&
             ob->query_is_room() &&
             player->check_dark(ob->query_light())) {
            continue;
         }
         stuff = ob->find_inv_match(input,player);
         if (stuff && sizeof(stuff)) {
            tmp_expanded += stuff;
         }
      }
   }

   if (!sizeof(tmp_expanded)) {
      omatch = new( class obj_match );
      omatch->text = input;
      omatch->objects = ({ });
      omatch->result = OBJ_PARSER_NO_MATCH;
      return omatch;
   }
   return match_object_in_array(input, tmp_expanded, type,
                                player);
} /* match_objects_in_environment() */

/**
 * This method checks for existance of the specified objects.  It will
 * return any ambiguous matches as well as real matches.  This should only
 * be used in cases in the code where it is not nessessary to distinguish
 * between different objects of the same type.
 * @param input the input string to check
 * @param env_list the environments to check in
 * @param player the player to check with
 * @return the array of objects
 */
object* match_objects_for_existence(string input,
                                    object* env_list,
                                    object player) {
   class obj_match stuff;

   stuff = match_objects_in_environments(input, env_list,
                                         OBJ_PARSER_TYPE_EXISTENCE, player);
   switch (stuff->result) {
   case OBJ_PARSER_SUCCESS :
   case OBJ_PARSER_AMBIGUOUS :
      return stuff->objects;
   default :
      return ({ });
   }
} /* match_objects_for_existence() */

/**
 * This method returns the failed message for the specified
 * failed match string.
 * @param failed_match the return result from match_objects_*
 * @return the message to print when it gets an error
 */
string match_objects_failed_mess(class obj_match failed_match) {
   switch (failed_match->result) {
   case OBJ_PARSER_BAD_ENVIRONMENT :
      return "Cannot find \""+ failed_match->text +
                         "\" here, access is not allowed.\n";
   case OBJ_PARSER_NOT_LIVING :
      return "The objects \""+
             query_multiple_short(failed_match->objects) +
             "\" are not living.\n";
   case OBJ_PARSER_TOO_DARK :
      return "Cannot find \""+ failed_match->text +
             "\", it is too dark.\n";
   case OBJ_PARSER_NO_MATCH :
      return "Cannot find \""+ failed_match->text +
             "\", no match.\n";
   case OBJ_PARSER_BAD_FRACTION :
      return "The fraction \""+ failed_match->text +
             "\" is incorrectly specified.\n";
   case OBJ_PARSER_FRACTION :
      return "Can only reference a single object with a "
             "fraction, matched " +
             query_multiple_short(failed_match->objects) +
             " please be more specific.\n";
   case OBJ_PARSER_AMBIGUOUS :
      return "There are multiple matches for \"" + failed_match->text +
             "\".  See 'help parser' for more information on how to "
             "be more specific.\n";
   case OBJ_PARSER_NOT_ENOUGH :
      return "There are not enough \"" + failed_match->text +
             "\" to match as specified.\n";
   default :
      return "Unknow parser errror " + failed_match->result + ".\n";
   }
} /* setup_failed_mess() */