lima-1.0b5/
lima-1.0b5/driver/
lima-1.0b5/driver/ChangeLog.old/
lima-1.0b5/driver/Win32/
lima-1.0b5/driver/compat/
lima-1.0b5/driver/include/
lima-1.0b5/driver/testsuite/
lima-1.0b5/driver/testsuite/clone/
lima-1.0b5/driver/testsuite/command/
lima-1.0b5/driver/testsuite/data/
lima-1.0b5/driver/testsuite/etc/
lima-1.0b5/driver/testsuite/include/
lima-1.0b5/driver/testsuite/inherit/
lima-1.0b5/driver/testsuite/inherit/master/
lima-1.0b5/driver/testsuite/log/
lima-1.0b5/driver/testsuite/single/
lima-1.0b5/driver/testsuite/single/tests/compiler/
lima-1.0b5/driver/testsuite/single/tests/efuns/
lima-1.0b5/driver/testsuite/single/tests/operators/
lima-1.0b5/driver/testsuite/u/
lima-1.0b5/driver/tmp/
lima-1.0b5/etc/
lima-1.0b5/lib/WWW/help/
lima-1.0b5/lib/cmds/
lima-1.0b5/lib/cmds/create/
lima-1.0b5/lib/cmds/player/attic/
lima-1.0b5/lib/contrib/bboard/
lima-1.0b5/lib/contrib/boards/
lima-1.0b5/lib/contrib/marriage/
lima-1.0b5/lib/contrib/roommaker/
lima-1.0b5/lib/contrib/transient_effect/
lima-1.0b5/lib/daemons/channel/
lima-1.0b5/lib/daemons/imud/
lima-1.0b5/lib/data/
lima-1.0b5/lib/data/config/
lima-1.0b5/lib/data/links/
lima-1.0b5/lib/data/news/
lima-1.0b5/lib/data/players/
lima-1.0b5/lib/data/secure/
lima-1.0b5/lib/domains/
lima-1.0b5/lib/domains/std/2.4.5/maze1/
lima-1.0b5/lib/domains/std/2.4.5/npc/
lima-1.0b5/lib/domains/std/2.4.5/post_dir/
lima-1.0b5/lib/domains/std/2.4.5/sub/
lima-1.0b5/lib/domains/std/camera/
lima-1.0b5/lib/domains/std/config/
lima-1.0b5/lib/domains/std/cult/
lima-1.0b5/lib/domains/std/effects/
lima-1.0b5/lib/domains/std/misc/
lima-1.0b5/lib/domains/std/monsters/
lima-1.0b5/lib/domains/std/recorder/
lima-1.0b5/lib/domains/std/rooms/
lima-1.0b5/lib/domains/std/rooms/beach/
lima-1.0b5/lib/domains/std/rooms/labyrinth/
lima-1.0b5/lib/domains/std/school/
lima-1.0b5/lib/domains/std/school/O/
lima-1.0b5/lib/domains/std/spells/
lima-1.0b5/lib/domains/std/spells/stock-mage/
lima-1.0b5/lib/domains/std/spells/stock-priest/
lima-1.0b5/lib/help/
lima-1.0b5/lib/help/admin/
lima-1.0b5/lib/help/hints/General_Questions/
lima-1.0b5/lib/help/hints/Pirate_Quest/
lima-1.0b5/lib/help/player/
lima-1.0b5/lib/help/player/bin/
lima-1.0b5/lib/help/player/quests/
lima-1.0b5/lib/help/wizard/
lima-1.0b5/lib/help/wizard/coding/guilds/
lima-1.0b5/lib/help/wizard/coding/rooms/
lima-1.0b5/lib/help/wizard/lib/daemons/
lima-1.0b5/lib/help/wizard/lib/lfun/
lima-1.0b5/lib/help/wizard/lib/std/
lima-1.0b5/lib/help/wizard/mudos_doc/
lima-1.0b5/lib/help/wizard/mudos_doc/applies/
lima-1.0b5/lib/help/wizard/mudos_doc/applies/interactive/
lima-1.0b5/lib/help/wizard/mudos_doc/applies/parsing/
lima-1.0b5/lib/help/wizard/mudos_doc/concepts/
lima-1.0b5/lib/help/wizard/mudos_doc/driver/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/arrays/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/buffers/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/compile/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/filesystem/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/floats/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/functions/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/general/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/mappings/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/mixed/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/numbers/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/parsing/
lima-1.0b5/lib/help/wizard/mudos_doc/lpc/constructs/
lima-1.0b5/lib/help/wizard/mudos_doc/lpc/types/
lima-1.0b5/lib/include/driver/
lima-1.0b5/lib/log/
lima-1.0b5/lib/obj/admtool/
lima-1.0b5/lib/obj/admtool/internal/
lima-1.0b5/lib/obj/admtool/mudinfo/
lima-1.0b5/lib/obj/admtool/secure/
lima-1.0b5/lib/obj/secure/
lima-1.0b5/lib/obj/secure/cmd/
lima-1.0b5/lib/obj/secure/mailers/
lima-1.0b5/lib/obj/secure/shell/
lima-1.0b5/lib/obj/secure/shell/classes/
lima-1.0b5/lib/obj/tasktool/
lima-1.0b5/lib/obj/tasktool/internal/
lima-1.0b5/lib/open/
lima-1.0b5/lib/secure/
lima-1.0b5/lib/secure/cgi/
lima-1.0b5/lib/secure/modules/
lima-1.0b5/lib/secure/simul_efun/
lima-1.0b5/lib/std/adversary/
lima-1.0b5/lib/std/adversary/advancement/
lima-1.0b5/lib/std/adversary/armor/
lima-1.0b5/lib/std/adversary/blows/
lima-1.0b5/lib/std/adversary/death/
lima-1.0b5/lib/std/adversary/formula/
lima-1.0b5/lib/std/adversary/health/
lima-1.0b5/lib/std/adversary/pulse/
lima-1.0b5/lib/std/adversary/wield/
lima-1.0b5/lib/std/classes/event_info/
lima-1.0b5/lib/std/container/
lima-1.0b5/lib/std/living/
lima-1.0b5/lib/std/modules/contrib/
lima-1.0b5/lib/std/patterns/
lima-1.0b5/lib/std/race/
lima-1.0b5/lib/std/race/restricted/
lima-1.0b5/lib/std/room/
lima-1.0b5/lib/tmp/
lima-1.0b5/lib/trans/
lima-1.0b5/lib/trans/admincmds/
lima-1.0b5/lib/trans/obj/
lima-1.0b5/lib/wiz/
/* Do not remove the headers from this file! see /USAGE for more info. */

/* This will be converted to an inherited part of shells when:
 * 1) We have programatic security
 * 2) We have shared variables
 * (I guess that should hold for all daemons, though...)
 *  Someday might want to have cfile file and dir all accept string*'s in case people want to 
 *  use variables for them.  Right now, you can only use strings....
 */

//  cmd_d.c written by Rust (John Viega, rust@virginia.edu) for the Lima mudlib, July 1995.

#include <security.h>

#define PLURAL		1
#define	STR		2
#define	NUM		4

#define IS_PATH		8
#define IS_FILE 	16
#define IS_DIR		32
#define	IS_FNAME	64
#define IS_CFILE	128
#define IS_OBFILE	256

#define	FILE		(IS_PATH | IS_FILE)
#define DIR		(IS_PATH | IS_DIR)
#define CFILE		(IS_PATH | IS_FILE | IS_CFILE)
#define OBFILE		(IS_PATH | IS_FILE | IS_CFILE | IS_OBFILE)
#define FNAME		(IS_PATH | IS_FNAME)

#define	IS_OBJECT	512
#define	ONLY_USER	1024

#define OBJECT		(IS_OBJECT)
#define USER		(IS_OBJECT | ONLY_USER)

#define FILE_FLAGS (IS_PATH | IS_FILE | IS_DIR | IS_OBFILE | IS_FNAME)

inherit M_GLOB;
inherit M_REGEX;
inherit M_GETOPT;
inherit M_ACCESS;


private mixed parse_arg(int,string);

class proto_info
{
  string 	options;
  int *	prototype;
  int		first_optional_arg;
  string	proto_string;
}


private nosave mapping cmd_info = ([]);
private nosave mapping proto_info = ([]);

void create()
{
  set_privilege(1);
}

private void parse_verb_defs(string dir, string filecontents) 
{
  mapping	pathmap = ([]);
  string* 	lines = explode(filecontents,"\n");
  string* 	words;
  string 	line, cmd, item;
  int 	size, flags, error_flag, i;
  string	errors = "";

  foreach(line in lines)
  {
    words = split(line, "[ \t]+") - ({""," "});
    size = sizeof(words);
    if(!size || words[0][0] == '#')
      continue;
    cmd = words[0];
    if(!undefinedp(pathmap[cmd]))
      errors += sprintf("Warning: %s redefined.  Previous definition being clobbered.\n", cmd);
    pathmap[cmd] = new(class proto_info);
//### gross.
    ((class proto_info)pathmap[cmd])->proto_string = 
	    replace_string( replace_string( replace_string( replace_string 
							    (replace_string (replace_string( implode (words," "),
											     "num","number"), "str","string"), "obj", "object"), "fname", "filename"), 
					    "*", "(s)"), "cfile", "file");
    if(!(--size))
      continue;
    words = words[1..];
    if(words[0][0] == '-' && strlen(words[0]) > 1)
    {
      ((class proto_info)pathmap[cmd])->options = words[0][1..];
      if(!(--size))
      {
        errors += "Bad line: " + line +"\n";
        continue;
      }
      words = words[1..];
    }
    ((class proto_info)pathmap[cmd])->prototype = allocate(size);
    ((class proto_info)pathmap[cmd])->first_optional_arg = -1;
    for(i=0; i<size;i++)
    {
      flags = 0;
      if(words[i][0] == '[' && words[i][<1] == ']')
      {
        words[i] = words[i][1..<2];
        if(((class proto_info)pathmap[cmd])->first_optional_arg == -1)
         ((class proto_info)pathmap[cmd])->first_optional_arg = i;
      }
      if(words[i][<1] == '*')
      {
        flags |= PLURAL;
        words[i] = words[i][0..<2];
      }
      if(words[i] == "")
	    {
        errors += "Bad line: "+line + "\n";
        error_flag = 0;
        break;
      }
      foreach(item in explode(words[i],"|"))
        switch(item)
        {
          case "str":  flags |= STR; break;
          case "file": flags |= FILE; break;
          case "obfile": flags |= OBFILE; break;
          case "dir": flags |= DIR; break;
          case "obj": flags |= OBJECT; break;
          case "user": flags |= USER; break;
          case "fname": flags |= FNAME; break;
          case "num": flags |= NUM; break;
          case "cfile": flags |= CFILE; break;
          default:
            errors += "Bad line (invalid argument type): "+line + "\n";
            error_flag = 1;
            break;
        }
      if(error_flag)
        break;
      ((class proto_info)pathmap[cmd])->prototype[i] = flags;

    }
    if(error_flag)
    {
      error_flag = 0;
      continue;
    }
  }
  proto_info[dir] = pathmap;
  if(strlen(errors))
    NEWS_D->system_post(BUG_NEWSGROUP, "Bugs found by " + base_name(this_object()), errors);
}

private void cache_dir(string dir)
{
  string* files;
    
  if(dir[<1] != '/')
    dir += "/";

  if(is_file(dir+"Cmd_rules"))
    parse_verb_defs(dir, read_file(dir+"Cmd_rules"));
  files = get_dir(dir + "?*.c");
  if(!arrayp(files) || !sizeof(files))
    return;
  cmd_info[dir] = map(files, (: $1[0..<3] :));
}

varargs void cache(string* paths)
{
  if(!paths)
    paths = keys(cmd_info);
  map(paths,(:cache_dir:));
}

int is_command(object o)
{
  mixed ret;
    
  if(function_exists("call_main", o) != CMD)
    return 0;
  if ((ret = o->not_a_cmd()) && (ret == 1 || ret == file_name(o)))
    return 0;
  return 1;
}

// This one won't match commands not in your path.  For players, mainly...
varargs mixed find_cmd_in_path(string cmd, string* path)
{
  string dir;
  object o;

  foreach(dir in path)
  {
    if(dir[<1] != '/')
      dir += "/";
//Try adding this dir if we don't have it,
    if(!cmd_info[dir])
      cache_dir(dir);
//And if it's still not in the cache, this is a bogus path.
    if(!cmd_info[dir])
      continue;
    if(member_array(cmd, cmd_info[dir]) != -1 && 
        is_file(dir+cmd+".c") &&
        o = load_object(dir+cmd))
    { 
      if(!is_command(o))
        return -1;
      return ({ o, dir, cmd });
    }
  }

  return 0;
}

varargs mixed find_cmd(string cmd, string* path)
{
  object	o;
  string	dir, s;
    
  if (member_array('/', cmd) != -1)
  {
    s = evaluate_path(cmd);
    if(o = load_object(s))
    {
      if (is_command(o))
      {
        mixed tmp = split_path(s);
        dir = tmp[0];
        s = tmp[1];
        sscanf(s, "%s.c", s);
        if(!cmd_info[dir])
          cache_dir(dir);
        return ({o, dir, s });
      }
    }
  }
  return find_cmd_in_path(cmd, path);
}

mixed smart_arg_parsing(mixed argv, string* path, string *implode_info)
{
  mixed		resv;
  mixed		info;
  string 		cmd_name;
  string		this_path;
  object		cmd_obj;
  class proto_info	pstuff;
  string		USAGE;
  string		opstr;
  mapping		ops;
  int			argcounter;
  int			i;
  mixed 		expanded_arg;
  mixed		this_arg;
  int			plural;

  if (sizeof(argv) == 0)
    return -1;
    
  cmd_name = trim_spaces(argv[0]);
  if (member_array('/', cmd_name) != -1)
  {
    array matches = filter_array(glob(cmd_name + ".c"), (: is_file :));
    switch (sizeof(matches))
    {
      case 1:
        if ((cmd_obj = load_object(matches[0])) &&
            is_command(cmd_obj))
        {
          mixed tmp = split_path(matches[0]);
          this_path = tmp[0];
          cmd_name = tmp[1][0..<3];
        } else
          return 0;
        break;
      case 0:
        break;
      default:
        printf("Ambiguous expansion for %s.\n", cmd_name);
        return 1;
    }
  }
  if (!this_path)
  {
    info = find_cmd(cmd_name, path);
    if (intp(info))
      return info;
    cmd_obj = info[0];
    this_path = info[1];
    cmd_name = info[2];
  }

  if(undefinedp(proto_info[this_path]) || 
      undefinedp(pstuff=proto_info[this_path][cmd_name]))
  {
// no prototypes, so don't do no globbing or nothin'.
// In fact, just send back the raw string.
    if(sizeof(argv) > 1)
    {
// make it so that all non-strings are converted to strings, 
// since whatever command is going to be expecting a string.
      argv = map(argv, (: stringp($1) ? $1 : sprintf("%O",$1) :));
      return ({cmd_obj, ([]), implode_by_arr(argv[1..], implode_info) });
    }
    else
      return ({ cmd_obj, ([]), 0});
  }

// Remove "'s for:  "word1 word2"
  argv = map(argv, (: (stringp($1) && $1[0] == '"' && $1[<1] == '"') ? 
      $1[1..<2] : $1 :));
  USAGE = pstuff->proto_string;

  if(sizeof(argv) > 1)
  {
    argv = argv[1..];
    if((opstr = pstuff->options))
    {
      info = getopt(argv, opstr);
      if(!arrayp(info))
        return -2;
      argv = info[1];
      ops = info[0];
    }
  } else {
    argv = ({});
  }
  if(!ops) ops = ([]);

  argcounter = 0;
  resv = allocate(sizeof(pstuff->prototype));
  for(i=0; i<sizeof(pstuff->prototype); i++)
  {
    if(argcounter == sizeof(argv))
    {
      if(i >= pstuff->first_optional_arg && pstuff->first_optional_arg != -1)
        break;
      printf("Too few arguments.\nUsage: %s\n", USAGE);
      return 1;
    }
    expanded_arg = parse_arg(pstuff->prototype[i],argv[argcounter++]);
    if (intp(expanded_arg))
    {
// error
      switch (expanded_arg)
      {
        case -1:
          printf("Invalid argument: %O\nUsage: %s\n",
                  argv[argcounter-1], USAGE);
          break;
        case -2:
          printf("Vague argument: %O\nUsage: %s\n",
                  argv[argcounter-1], USAGE);
          break;
        case -3:
          printf("%s: No such file or directory.\n", argv[argcounter-1]);
          break;
      }
      return 1;
    }
    plural = pstuff->prototype[i] & PLURAL;
    this_arg = expanded_arg[0];
    resv[i] = expanded_arg[1];
    if(!plural)
    {
      if(sizeof(resv[i]) > 1)
      {
        printf("Vague argument: %s\nUsage: %s\n", argv[argcounter-1], USAGE);
        return 1;
      }
      resv[i] = resv[i][0];
      continue;
    }
    while (1)
    {
      if(argcounter == sizeof(argv))
        break;	
      expanded_arg = parse_arg(this_arg, argv[argcounter]);
      if(!arrayp(expanded_arg))
        break;
      if(sizeof(expanded_arg[1]) == 1 &&
           i+1 != sizeof(pstuff->prototype) &&
           !(pstuff->prototype[i+1]&PLURAL) &&
           (pstuff->prototype[i+1] & expanded_arg[0]) &&
           (argcounter + 1 == sizeof(argv) ||
           intp(parse_arg(pstuff->prototype[i+1], argv[argcounter+1]))))
        break;
      resv[i] += expanded_arg[1];
      argcounter++;
    }
  }
  if(argcounter != sizeof(argv))
  {
    if(pstuff->prototype[i-1] & PLURAL)
      printf("%s: not found.\n", argv[argcounter]);
    else
      printf("Too many arguments.\nUsage: %s\n",USAGE);
    return 1;
  }
  return ({ cmd_obj, ops, resv });
}

private mixed parse_arg(int this_arg, mixed argv)
{
  int		hits;
  mixed	untrimmed_argv;
  array	result = ({});
  array       string_result;
    
  untrimmed_argv = argv;

  if(stringp(argv))
  {
    argv = trim_spaces(argv);
    if (this_arg & IS_PATH)
    {
      string path = evaluate_path(argv);
      result = glob(path);
      if((this_arg & IS_CFILE) && ! (this_arg & IS_DIR))
        result = filter(result, (:!is_directory($1):));
      if (!sizeof(result) && (this_arg & IS_OBFILE))
      {
        object ob = get_object(argv);
        if (ob)
        {
          string bname = base_name(ob);
          if(is_file(bname + ".c"))
            result = ({ bname + ".c" });
          else
          {
            if(is_file(bname + ".scr"))
              result = ({bname + ".scr"});
          }
        }
      }
      if (!sizeof(result) && (this_arg & IS_CFILE))
      {
        int ix = strsrch(path, ".", -1);
        string extension = path[ix+1..];

        if(extension != "c" && extension != "scr")
        {
          result = glob(path + ".c") + glob(path + ".scr");
        }
      }

      if ((this_arg & IS_FILE) && !(this_arg & IS_DIR))
        result = filter(result, (: is_file :));

      if ((this_arg & IS_DIR) && !(this_arg & IS_FILE))
        result = filter(result, (: is_directory :));

      if (!sizeof(result) && (this_arg & IS_FNAME))
      {
        if (is_directory(base_path(path)))
          result = ({ path });
      }

      if (!sizeof(result))
        result = 0;
      else
      {
        result = ({ this_arg & FILE_FLAGS, result });
        hits++;
      }
    }

    if (this_arg & STR)
    {
      string_result = ({ STR, ({ untrimmed_argv }) });
      hits++;
    }
  }

  if (this_arg & IS_OBJECT)
  {
    object ob;

    if(stringp(argv))
      ob = get_object(argv);
    else if (objectp(argv))
      ob = argv;
    else
      ob = 0;

    if((this_arg & ONLY_USER) && ob && !ob->query_link())
      ob = 0;

    if(ob)
    {
      result = ({ this_arg & (IS_OBJECT | ONLY_USER), ({ ob }) });
      hits++;
    }
  }

  if (this_arg & NUM)
  {
    int tmp;
	
    if (intp(argv))
    {
      result = ({ NUM, ({ argv }) });
      hits++;
    }
    else if (sscanf(argv,"%d",tmp))
    {
      result = ({ NUM, ({ tmp }) });
      hits++;
    }
  }

  if(!hits)
  { 
    if (this_arg & IS_PATH)
      return -3;
    else
      return -1;
  }

  if (this_arg & STR)
  {
    if (hits == 1)
      result = string_result; // use string hit
    else
      hits--; // discard string hit
  }

  if(hits > 1)
    return -2;

  return result;
}