home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-387-Vol-3of3.iso / t / toaster.zip / Compat / simulate.c < prev    next >
C/C++ Source or Header  |  1992-03-09  |  90KB  |  3,547 lines

  1. #include <sys/types.h>
  2. #include <sys/stat.h>
  3. #include <sys/signal.h>
  4. #include <fcntl.h>
  5. #include <setjmp.h>
  6. #include <ctype.h>
  7. #include <string.h>
  8. #include <errno.h>
  9. #include <stdio.h>
  10. #include <memory.h>
  11. #if defined(sun)
  12. #include <alloca.h>
  13. #endif
  14. #include <ndir.h>
  15.  
  16. #include "lint.h"
  17. #include "config.h"
  18. #include "stdio.h"
  19. #include "lang.h"
  20. #include "interpret.h"
  21. #include "object.h"
  22. #include "sent.h"
  23. #include "wiz_list.h"
  24. #include "exec.h"
  25. #include "comm.h"
  26.  
  27. extern int errno;
  28. extern int comp_flag;
  29. extern char *init_file;
  30. char *inherit_file;
  31.  
  32. #if !defined(ultrix) && !defined(M_UNIX) && !defined(hpux) && !defined(sgi)
  33. extern int rename PROT((char *, char *));
  34. #endif
  35. extern int readlink PROT((char *, char *, int));
  36. extern int symlink PROT((char *, char *));
  37. #ifndef rindex
  38. extern char *rindex PROT((const char *, int));
  39. #endif
  40. #ifndef MSDOS
  41. extern int lstat PROT((char *, struct stat *));
  42. #else
  43. #define lstat stat
  44. #endif
  45. extern int fchmod PROT((int, int));     
  46. char *last_verb, *last_arg;
  47.  
  48. extern int special_parse PROT((char *)),
  49.     set_call PROT((struct object *, struct sentence *, int)),
  50.     legal_path PROT((char *));
  51.  
  52. void pre_compile PROT((char *)),
  53.     remove_interactive PROT((struct object *)),
  54.     add_light PROT((struct object *, int)),
  55.     add_action PROT((char *, char *, int)),
  56.     add_verb PROT((char *, int)),
  57.     print_local_commands(), ipc_remove(),
  58.     show_info_about PROT((char *, char *, struct interactive *)),
  59.     set_snoop PROT((struct object *, struct object *)),
  60.     print_lnode_status PROT((int)),
  61.     remove_all_players(), start_new_file PROT((FILE *)), end_new_file(),
  62.     move_or_destruct PROT((struct object *, struct object *)),
  63.     load_ob_from_swap PROT((struct object *)), dump_malloc_data(),
  64.     print_svalue PROT((struct svalue *)),
  65.     debug_message_value(),
  66.     destruct2();
  67.  
  68. extern int d_flag;
  69.  
  70. struct object *obj_list, *obj_list_destruct, *master_ob;
  71.  
  72. extern int current_line;
  73. extern struct wiz_list *back_bone_uid;
  74.  
  75. struct object *current_object;      /* The object interpreting a function. */
  76. struct object *command_giver;       /* Where the current command came from. */
  77. struct object *current_interactive; /* The user who caused this execution */
  78.  
  79. int num_parse_error;        /* Number of errors in the parser. */
  80.  
  81. void shutdowngame();
  82.  
  83. extern void flush_all_player_mess();
  84.  
  85. struct variable *find_status(str, must_find)
  86.     char *str;
  87.     int must_find;
  88. {
  89.     int i;
  90.  
  91.     for (i=0; i < current_object->prog->num_variables; i++) {
  92.     if (strcmp(current_object->prog->variable_names[i].name, str) == 0)
  93.         return ¤t_object->prog->variable_names[i];
  94.     }
  95.     if (!must_find)
  96.     return 0;
  97.     error("--Status %s not found in prog for %s\n", str,
  98.        current_object->name);
  99.     return 0;
  100. }
  101.  
  102. /*
  103.  * Give the correct uid and euid to a created object.
  104.  */
  105. int give_uid_to_object(ob)
  106.     struct object *ob;
  107. {
  108.     struct svalue *ret;
  109.     char *creator_name;
  110.     struct object *tmp_ob;
  111. #ifdef COMPAT_MODE
  112.     char wiz_name[100];
  113. #endif
  114.  
  115.     if (master_ob == 0)
  116.     tmp_ob = ob;
  117.     else {
  118.      assert_master_ob_loaded();
  119.     tmp_ob = master_ob;
  120.     }
  121.     
  122. #ifdef COMPAT_MODE
  123.     /* Is this object wizard defined ? */
  124.     if (sscanf(ob->name, "players/%s", wiz_name) == 1) {
  125.     char *np;
  126.     np = strchr(wiz_name, '/');
  127.     if (np)
  128.         *np = '\0';
  129.     ob->user = add_name(wiz_name);
  130.     } else {
  131.     ob->user = 0;
  132.     }
  133.     ob->eff_user = ob->user;    /* Initial state */
  134.     return 1;
  135. #else
  136.  
  137.     if (!current_object || !current_object->user) {
  138.     /*
  139.      * Only for the master and void object. Note that
  140.      * back_bone_uid is not defined when master.c is being loaded.
  141.      */
  142.     ob->user = add_name("NONAME");
  143.     ob->eff_user = 0;
  144.     return 1;
  145.     }
  146.  
  147.     /*
  148.      * Ask master.c who the creator of this object is.
  149.      */
  150.     push_constant_string(ob->name);
  151.     ret = apply("creator_file", tmp_ob, 1);
  152.     if (!ret)
  153.     error("No function 'creator_file' in master.c!\n");
  154.     if (ret->type != T_STRING) {
  155.     struct svalue arg;
  156.     /* This can be the case for objects in /ftp and /open. */
  157.     arg.type = T_OBJECT;
  158.     arg.u.ob = ob;
  159.     destruct_object(&arg, 0);
  160.     error("Illegal object to load.\n");
  161.     }
  162.     creator_name = ret->u.string;
  163.     /*
  164.      * Now we are sure that we have a creator name.
  165.      * Do not call apply() again, because creator_name will be lost !
  166.      */
  167.     if (strcmp(current_object->user->name, creator_name) == 0) {
  168.     /* 
  169.      * The loaded object has the same uid as the loader.
  170.      */
  171.     ob->user = current_object->eff_user;
  172.     ob->eff_user = current_object->eff_user;
  173.     return 1;
  174.     }
  175.  
  176.     if (strcmp(back_bone_uid->name, creator_name) == 0) {
  177.     /*
  178.      * The object is loaded from backbone. This is trusted, so we
  179.      * let it inherit the value of eff_user.
  180.      */
  181.     ob->user = current_object->eff_user;
  182.     ob->eff_user = current_object->eff_user;
  183.     return 1;
  184.     }
  185.  
  186.     /*
  187.      * The object is not loaded from backbone, nor from 
  188.      * from the loading objects path. That should be an object
  189.      * defined by another wizard. It can't be trusted, so we give it the
  190.      * same uid as the creator. Also give it eff_user 0, which means that
  191.      * player 'a' can't use objects from player 'b' to load new objects nor
  192.      * modify files owned by player 'b'.
  193.      *
  194.      * If this effect is wanted, player 'b' must let his object do
  195.      * 'seteuid()' to himself. That is the case for most rooms.
  196.      */
  197.     ob->user = add_name(creator_name);
  198.     ob->eff_user = (struct wiz_list *)0;
  199.     return 1;
  200. #endif /* COMPAT_MODE */
  201. }
  202.  
  203. /*
  204.  * Load an object definition from file. If the object wants to inherit
  205.  * from an object that is not loaded, discard all, load the inherited object,
  206.  * and reload again.
  207.  *
  208.  *
  209.  * In mudlib3.0 when loading inherited objects, their reset() is not called.
  210.  *
  211.  * Save the command_giver, because reset() in the new object might change
  212.  * it.
  213.  */
  214. struct object *load_object(lname, dont_reset)
  215.     char *lname;
  216.     int dont_reset;
  217. {
  218.     FILE *f;
  219.     extern int total_lines;
  220.     extern int approved_object;
  221.  
  222.     struct object *ob, *save_command_giver = command_giver;
  223.     extern struct program *prog;
  224.     extern char *current_file;
  225. #ifdef LEX_lexical
  226.     char *current_i_file;
  227.     struct stat i_st;
  228. #endif
  229.     struct stat c_st;
  230.     int name_length;
  231.     char real_name[200], name[200];
  232.  
  233. #ifndef COMPAT_MODE
  234.     if (current_object && current_object->eff_user == 0)
  235.        error("Can't load objects when no effective user.\n");
  236. #endif
  237.     /* Truncate possible .c in the object name. */
  238.     /* Remove leading '/' if any. */
  239.     while(lname[0] == '/')
  240.     lname++;
  241.     strncpy(name, lname, sizeof(name));
  242.     name[sizeof(name)-1] = 0;
  243.     name_length = strlen(name);
  244.     if (name_length > sizeof name - 4)
  245.     name_length = sizeof name - 4;
  246.     name[name_length] = '\0';
  247.     if (name[name_length-2] == '.' && name[name_length-1] == 'c') {
  248.     name[name_length-2] = '\0';
  249.     name_length -= 2;
  250.     }
  251.     /*
  252.      * First check that the c-file exists.
  253.      */
  254.     (void)strcpy(real_name, name);
  255.     (void)strcat(real_name, ".c");
  256.     if (stat(real_name, &c_st) == -1) {
  257.     fprintf(stderr, "Could not load descr for %s\n", real_name);
  258.     error("Failed to load file.\n");
  259.     return 0;
  260.     }
  261.     /*
  262.      * Check if it's a legal name.
  263.      */
  264.     if (!legal_path(real_name)) {
  265.     fprintf(stderr, "Illegal pathname: %s\n", real_name);
  266.     error("Illegal path name.\n");
  267.     return 0;
  268.     }
  269.  
  270. #ifdef LEX_lexical
  271.     real_name[name_length+1] = 'i';
  272.     if (stat(real_name, &i_st) == -1 || i_st.st_mtime < c_st.st_mtime) {
  273.        real_name[name_length+1] = 'c';
  274.        pre_compile(name);
  275.        real_name[name_length+1] = 'i';
  276.     }
  277.     if (stat(real_name, &i_st) == -1 || i_st.st_mtime < c_st.st_mtime) {
  278.        if (command_giver)
  279.           add_message("Failed to compile the new file.\n");
  280.     }
  281.     current_i_file = real_name;
  282. #endif
  283.     if (comp_flag)
  284.     fprintf(stderr, " compiling %s ...", real_name);
  285.     f = fopen(real_name, "r");
  286.     if (f == 0) {
  287.     perror(real_name);
  288.     error("Could not read the file.\n");
  289.     }
  290.     start_new_file(f);
  291.     current_file = string_copy(real_name);    /* This one is freed below */
  292.  
  293. #ifdef LEX_lexical
  294.     current_line = 0;
  295.     num_parse_error = 0;
  296. #endif
  297.     compile_file();
  298.     end_new_file();
  299.     if (comp_flag)
  300.         fprintf(stderr, " done\n");
  301.     update_compile_av(total_lines);
  302.     total_lines = 0;
  303.     (void)fclose(f);
  304.  
  305. #ifdef LEX_lexical
  306.     unlink(current_i_file);
  307. #endif
  308.  
  309.     free(current_file);
  310.     current_file = 0;
  311.     /* Sorry, can't handle objects without programs yet. */
  312.     if (inherit_file == 0 && (num_parse_error > 0 || prog == 0)) {
  313.     if (prog)
  314.         free_prog(prog, 1);
  315.     if (num_parse_error == 0 && prog == 0)
  316.         error("No program in object !\n");
  317.     error("Error in loading object\n");
  318.     }
  319.     /*
  320.      * This is an iterative process. If this object wants to inherit an
  321.      * unloaded object, then discard current object, load the object to be
  322.      * inherited and reload the current object again. The global variable
  323.      * "inherit_file" will be set by lang.y to point to a file name.
  324.      */
  325.     if (inherit_file) {
  326.     char *tmp = inherit_file;
  327.     if (prog) {
  328.         free_prog(prog, 1);
  329.         prog = 0;
  330.     }
  331.     if (strcmp(inherit_file, name) == 0) {
  332.         free(inherit_file);
  333.         inherit_file = 0;
  334.         error("Illegal to inherit self.\n");
  335.     }
  336.     inherit_file = 0;
  337. #ifdef MUDLIB3_NEED
  338. #ifdef COMPAT_MODE
  339.         load_object(tmp, 0);
  340. #else
  341.         load_object(tmp, 1);
  342. #endif
  343. #else
  344.     load_object(tmp, 0);
  345. #endif
  346.     free(tmp);
  347.     ob = load_object(name, dont_reset);
  348.     return ob;
  349.     }
  350.     ob = get_empty_object(prog->num_variables);
  351.     /*
  352.      * Can we approve of this object ?
  353.      */
  354.     if (approved_object || strcmp(prog->name, "std/object.c") == 0)
  355.     ob->flags |= O_APPROVED;
  356.     ob->name = string_copy(name);    /* Shared string is no good here */
  357.     add_ref(ob, "load_object");
  358.     ob->prog = prog;
  359.     ob->next_all = obj_list;
  360.     obj_list = ob;
  361.     enter_object_hash(ob);    /* add name to fast object lookup table */
  362.     if (give_uid_to_object(ob) && !dont_reset)
  363.        reset_object(ob, 0);
  364.     if (!(ob->flags & O_DESTRUCTED) && function_exists("clean_up",ob) ) {
  365.     ob->flags |= O_WILL_CLEAN_UP;
  366.     }
  367.     command_giver = save_command_giver;
  368.     if (d_flag > 1 && ob)
  369.     debug_message("--%s loaded\n", ob->name);
  370.     return ob;
  371. }
  372.  
  373. struct object *previous_ob;
  374.  
  375. char *make_new_name(str)
  376.     char *str;
  377. {
  378.     static int i;
  379.     char *p = xalloc(strlen(str) + 10);
  380.  
  381.     (void)sprintf(p, "%s#%d", str, i);
  382.     i++;
  383.     return p;
  384. }
  385.     
  386.  
  387. /*
  388.  * Save the command_giver, because reset() in the new object might change
  389.  * it.
  390.  */
  391. struct object *clone_object(str1)
  392.     char *str1;
  393. {
  394.     struct object *ob, *new_ob;
  395.     struct object *save_command_giver = command_giver;
  396.  
  397. #ifndef COMPAT_MODE
  398.     if (current_object && current_object->eff_user == 0)
  399.        error("Illegal to call clone_object() with no effective user.\n"); 
  400. #endif
  401.     ob = find_object(str1);
  402.     if (ob == 0 || ob->super || (ob->flags & O_CLONE))
  403.     error("Cloning a bad object!\n");
  404.     
  405.     /* We do not want the heart beat to be running for unused copied objects */
  406.  
  407.     if (ob->flags & O_HEART_BEAT) 
  408.     (void)set_heart_beat(ob, 0);
  409.     new_ob = get_empty_object(ob->prog->num_variables);
  410.     new_ob->name = make_new_name(ob->name);
  411.     new_ob->flags |= O_CLONE | ob->flags & ( O_APPROVED | O_WILL_CLEAN_UP ) ;
  412. #if 0
  413.       if (ob->flags & O_APPROVED)
  414.       new_ob->flags |= O_APPROVED;
  415. #endif
  416.     add_ref(new_ob, "clone_object");
  417.     new_ob->prog = ob->prog;
  418.     reference_prog(ob->prog, "clone_object");
  419. #ifdef COMPAT_MODE
  420.     if (current_object && current_object->user && !ob->user)
  421.         new_ob->user = current_object->user;
  422.     else
  423.         new_ob->user = ob->user;        /* Possibly a null pointer */
  424.     new_ob->eff_user = new_ob->user;
  425. #else
  426.     if (!current_object)
  427.           fatal("clone_object() from no current_object!\n");
  428.     give_uid_to_object(new_ob);
  429. #endif
  430.     new_ob->next_all = obj_list;
  431.     obj_list = new_ob;
  432.     enter_object_hash(new_ob);    /* Add name to fast object lookup table */
  433.     reset_object(new_ob, 0); 
  434.     command_giver = save_command_giver;
  435.     /* Never know what can happen ! :-( */
  436.     if (new_ob->flags & O_DESTRUCTED)
  437.     return 0;
  438.     return new_ob;
  439. }
  440.  
  441. struct object *environment(arg)
  442.     struct svalue *arg;
  443. {
  444.     struct object *ob = current_object;
  445.  
  446.     if (arg && arg->type == T_OBJECT)
  447.     ob = arg->u.ob;
  448.     else if (arg && arg->type == T_STRING)
  449.     ob = find_object2(arg->u.string);
  450.     if (ob == 0 || ob->super == 0 || (ob->flags & O_DESTRUCTED))
  451.     return 0;
  452.     if (ob->flags & O_DESTRUCTED)
  453.     error("environment() of destructed object.\n");
  454.     return ob->super;
  455. }
  456.  
  457. /*
  458.  * Execute a command for an object. Copy the command into a
  459.  * new buffer, because 'parse_command()' can modify the command.
  460.  * If the object is not current object, static functions will not
  461.  * be executed. This will prevent forcing players to do illegal things.
  462.  *
  463.  * Return cost of the command executed if success (> 0).
  464.  * When failure, return 0.
  465.  */
  466. int command_for_object(str, ob)
  467.     char *str;
  468.     struct object *ob;
  469. {
  470.     char buff[1001];
  471.     extern int eval_cost;
  472.     int save_eval_cost = eval_cost - 1000;
  473.  
  474.     if (strlen(str) > sizeof(buff) - 1)
  475.     error("Too long command.\n");
  476.     if (ob == 0)
  477.     ob = current_object;
  478.     else if (ob->flags & O_DESTRUCTED)
  479.     return 0;
  480.     strncpy(buff, str, sizeof buff);
  481.     buff[sizeof(buff)-1] = 0;
  482.     if (parse_command(buff, ob, ob!=current_object))
  483.     return eval_cost - save_eval_cost;
  484.     else
  485.     return 0;
  486. }
  487.  
  488. /*
  489.  * To find if an object is present, we have to look in two inventory
  490.  * lists. The first list is the inventory of the current object.
  491.  * The second list is all things that have the same ->super as
  492.  * current_object.
  493.  * Also test the environment.
  494.  * If the second argument 'ob' is non zero, only search in the
  495.  * inventory of 'ob'. The argument 'ob' will be mandatory, later.
  496.  */
  497.  
  498. static struct object *object_present2 PROT((char *, struct object *));
  499.  
  500. struct object *object_present(v, ob)
  501.     struct svalue *v;
  502.     struct object *ob;
  503. {
  504.     struct svalue *ret;
  505.     struct object *ret_ob;
  506.     int specific = 0;
  507.  
  508.     if (ob == 0)
  509.     ob = current_object;
  510.     else
  511.     specific = 1;
  512.     if (ob->flags & O_DESTRUCTED)
  513.     return 0;
  514.     if (v->type == T_OBJECT) {
  515.     if (specific) {
  516.         if (v->u.ob->super == ob)
  517.         return v->u.ob;
  518.         else
  519.         return 0;
  520.     }
  521.     if (v->u.ob->super == ob ||
  522.         (v->u.ob->super == ob->super && ob->super != 0))
  523.         return v->u.ob;
  524.     return 0;
  525.     }
  526.     ret_ob = object_present2(v->u.string, ob->contains);
  527.     if (ret_ob)
  528.     return ret_ob;
  529.     if (specific)
  530.     return 0;
  531.     if (ob->super) {
  532.     push_string(v->u.string, STRING_CONSTANT);
  533.     ret = apply("id", ob->super, 1);
  534.     if (ob->super->flags & O_DESTRUCTED)
  535.         return 0;
  536.     if (ret && !(ret->type == T_NUMBER && ret->u.number == 0))
  537.         return ob->super;
  538.     return object_present2(v->u.string, ob->super->contains);
  539.     }
  540.     return 0;
  541. }
  542.  
  543. static struct object *object_present2(str, ob)
  544.     char *str;
  545.     struct object *ob;
  546. {
  547.     struct svalue *ret;
  548.     char *p;
  549.     int count = 0, length;
  550.     char *item;
  551.  
  552.     item = string_copy(str);
  553.     length = strlen(item);
  554.     p = item + length - 1;
  555.     if (*p >= '0' && *p <= '9') {
  556.     while(p > item && *p >= '0' && *p <= '9')
  557.         p--;
  558.     if (p > item && *p == ' ') {
  559.         count = atoi(p+1) - 1;
  560.         *p = '\0';
  561.         length = p - item;    /* This is never used again ! */
  562.     }
  563.     }
  564.     for (; ob; ob = ob->next_inv) {
  565.     push_string(item, STRING_CONSTANT);
  566.     ret = apply("id", ob, 1);
  567.     if (ob->flags & O_DESTRUCTED) {
  568.         free(item);
  569.         return 0;
  570.     }
  571.     if (ret == 0 || (ret->type == T_NUMBER && ret->u.number == 0))
  572.         continue;
  573.     if (count-- > 0)
  574.         continue;
  575.     free(item);
  576.     return ob;
  577.     }
  578.     free(item);
  579.     return 0;
  580. }
  581.  
  582. /* KLUDGE KLUDGE KLUDGE KLUDGE KLUDGE      */
  583. /* ALL THIS TO AVOID 1 BYTE PER OBJECT     */
  584. /* not used very often however -- Raistlin */
  585.  
  586. struct destructor_stack
  587. {
  588.    struct object *element;
  589.    struct destructor_stack *next;
  590. } *d_stack = NULL;
  591.  
  592. static struct object *top_of_stack() 
  593.    if (!d_stack) 
  594.       return NULL; 
  595.    else 
  596.       return d_stack->element; 
  597. }
  598.  
  599. /* cleans up things, just in case of errors... */
  600. static void clean_stack()
  601. {
  602.    struct destructor_stack *current, *previous=NULL;
  603.  
  604.    current = d_stack;
  605.    while(current)
  606.    {
  607.       struct destructor_stack *next;
  608.  
  609.       next = current->next;
  610.       if (current->element->flags&O_DESTRUCTED)
  611.       {
  612.          if (!previous)  d_stack = current->next;
  613.          else previous->next = current->next;
  614.          free((char *)current);
  615.       }
  616.       else 
  617.          previous = current;
  618.       current = next;
  619.    }
  620. }
  621.  
  622. static void push_destructor(ob)
  623. struct object *ob;
  624. {
  625.    struct destructor_stack *new;
  626.    new = (struct destructor_stack *) xalloc(sizeof(struct destructor_stack));
  627.    new->element = ob;
  628.    new->next = NULL;
  629.    if (d_stack)
  630.       new->next = d_stack;
  631.    d_stack = new;
  632.    clean_stack();   
  633. }
  634.  
  635. static struct object *pop_destructor()
  636. {
  637.    struct destructor_stack *popped;
  638.    struct object *ob;
  639.    popped = d_stack;
  640.    d_stack = d_stack->next;
  641.    ob = popped->element;
  642.    free((char *)popped);
  643.    clean_stack();
  644.    return ob;
  645. }
  646.  
  647. static int test_stack(ob)
  648. struct object *ob;
  649. {
  650.    struct destructor_stack *current = d_stack;
  651.    while(current)
  652.    {
  653.       if (current->element == ob) return 1;
  654.       current = current->next;
  655.    }
  656.    return 0;
  657. }
  658.  
  659. /*
  660.  * Remove an object. It is first moved into the destruct list, and
  661.  * not really destructed until later. (see destruct2()).
  662.  */
  663. void destruct_object(v, really)
  664.     struct svalue *v;
  665.     int really;
  666. {
  667.     struct object *ob, *super;
  668.     struct object **pp;
  669.     int removed;
  670.  
  671.     if (v->type == T_OBJECT)
  672.     ob = v->u.ob;
  673.     else {
  674.     ob = find_object2(v->u.string);
  675.     if (ob == 0)
  676.         error("destruct_object: Could not find %s\n", v->u.string);
  677.     }
  678.     if (ob->flags & O_DESTRUCTED)
  679.     return;
  680.     if (ob->flags & O_SWAPPED)
  681.         load_ob_from_swap(ob);
  682.     remove_object_from_stack(ob);
  683. /* 
  684.  * Added 4/26/91 -- Raistlin.  destructor() is called on destructed objects 
  685.  *
  686.  * This means that the object is already in the process of being destructed 
  687.  * and another destructor (or it's own) tried to destruct it. 
  688.  * The "really" flag means "Don't call the destructor", in case of error 
  689.  */
  690.     if (!really && test_stack(ob)) return;
  691.     if (!really && function_exists("destructor", ob))
  692.     {
  693.        push_destructor(ob);
  694.        (void)apply("destructor", ob, 0);
  695.        pop_destructor(); 
  696.     } 
  697.  
  698.     /*
  699.      * If this is the first object being shadowed by another object, then
  700.      * destruct the whole list of shadows.
  701.      */
  702.     if (ob->shadowed && !ob->shadowing) {
  703.     struct svalue svp;
  704.     struct object *ob2;
  705.  
  706.     svp.type = T_OBJECT;
  707.     for (ob2 = ob->shadowed; ob2; ) {
  708.         svp.u.ob = ob2;
  709.         ob2 = ob2->shadowed;
  710.         svp.u.ob->shadowed = 0;
  711.         svp.u.ob->shadowing = 0;
  712.         destruct_object(&svp, 0);
  713.     }
  714.     }
  715.     /*
  716.      * The chain of shadows is a double linked list. Take care to update
  717.      * it correctly.
  718.      */
  719.     if (ob->shadowed)
  720.     ob->shadowed->shadowing = ob->shadowing;
  721.     if (ob->shadowing)
  722.     ob->shadowing->shadowed = ob->shadowed;
  723.     ob->shadowed = ob->shadowing = 0;
  724.  
  725.     if (d_flag > 1)
  726.     debug_message("Destruct object %s (ref %d)\n", ob->name, ob->ref);
  727.     super = ob->super;
  728. #ifdef COMPAT_MODE
  729.     if (super) {
  730.     struct svalue *weight;
  731.     /* Call exit in current room, if player or npc not in mudlib 3.0 */
  732.     if((ob->flags & O_ENABLE_COMMANDS)) {
  733.         push_object(ob, "destruct_object");
  734.         (void)apply("exit",super,1);
  735.     }
  736.     weight = apply("query_weight", ob, 0);
  737.     if (weight && weight->type == T_NUMBER) {
  738.         push_number(-weight->u.number);
  739.         (void)apply("add_weight", super, 1);
  740.     }
  741.     }
  742. #endif
  743.     if (super == 0)
  744.     {
  745.     struct svalue svp;
  746.     svp.type = T_OBJECT;
  747.     while(ob->contains) {
  748.         svp.u.ob = ob->contains;
  749.         push_object(ob->contains, "destruct");
  750.         /*
  751.          * An errer here will not leave destruct() in an inconsistant
  752.              * stage.
  753.          */
  754.         apply_master_ob("destruct_environment_of", 1);
  755.         if (svp.u.ob == ob->contains)
  756.            destruct_object(&svp, 0);
  757.     }
  758.     }
  759.     else
  760.         while(ob->contains)
  761.         move_or_destruct(ob->contains, super);
  762.     if ( ob->interactive ) {
  763.     struct object *save=command_giver;
  764.  
  765.     command_giver=ob;
  766.     if (ob->interactive->ed_buffer) {
  767.         extern void save_ed_buffer();
  768.  
  769.         save_ed_buffer();
  770.     }
  771.     flush_all_player_mess();
  772.     command_giver=save;
  773.     }
  774.     set_heart_beat(ob, 0);
  775.     /*
  776.      * Remove us out of this current room (if any).
  777.      * Remove all sentences defined by this object from all objects here.
  778.      */
  779.     if (ob->super) {
  780.     if (ob->super->flags & O_ENABLE_COMMANDS)
  781.         remove_sent(ob, ob->super);
  782.     add_light(ob->super, - ob->total_light);
  783.     for (pp = &ob->super->contains; *pp;) {
  784.         if ((*pp)->flags & O_ENABLE_COMMANDS)
  785.         remove_sent(ob, *pp);
  786.         if (*pp != ob)
  787.         pp = &(*pp)->next_inv;
  788.         else
  789.         *pp = (*pp)->next_inv;
  790.     }
  791.     }
  792.     /*
  793.      * Now remove us out of the list of all objects.
  794.      * This must be done last, because an error in the above code would
  795.      * halt execution.
  796.      */
  797.     removed = 0;
  798.     /*
  799.      * If any of the calls above (move_or_destruct) caused a call 
  800.      * to the efun destruct, then this object will already be destructed
  801.      * and removed from the list, so everything after this for loop will
  802.      * already have been done, so we can just return here.
  803.      */
  804.     if (ob->flags & O_DESTRUCTED)
  805.         return;
  806.     else
  807.        for (pp = &obj_list; *pp; pp = &(*pp)->next_all) {
  808.     if (*pp != ob)
  809.         continue;
  810.     *pp = (*pp)->next_all;
  811.     removed = 1;
  812.     remove_object_hash(ob);
  813.     break;
  814.     }
  815.     if (!removed)
  816.         fatal("Failed to delete object.\n"); 
  817.     if (ob->living_name)
  818.     remove_living_name(ob);
  819.     ob->super = 0;
  820.     ob->next_inv = 0;
  821.     ob->contains = 0;
  822.     ob->flags &= ~O_ENABLE_COMMANDS;
  823.     ob->next_all = obj_list_destruct;
  824.     obj_list_destruct = ob;
  825.     ob->flags |= O_DESTRUCTED;
  826. }
  827.  
  828. /*
  829.  * This one is called when no program is executing.
  830.  * The super pointer is still maintained.
  831.  */
  832. void destruct2(ob)
  833.     struct object *ob;
  834. {
  835.     if (d_flag > 1) {
  836.     debug_message("Destruct-2 object %s (ref %d)\n", ob->name, ob->ref);
  837.     }
  838.     if (ob->interactive)
  839.     remove_interactive(ob);
  840.     /*
  841.      * We must deallocate variables here, not in 'free_object()'.
  842.      * That is because one of the local variables may point to this object,
  843.      * and deallocation of this pointer will also decrease the reference
  844.      * count of this object. Otherwise, an object with a variable pointing
  845.      * to itself, would never be freed.
  846.      * Just in case the program in this object would continue to
  847.      * execute, change string and object variables into the number 0.
  848.      */
  849.     if (ob->prog->num_variables > 0) {
  850.     /*
  851.      * Deallocate variables in this object.
  852.      * The space of the variables are not deallocated until
  853.      * the object structure is freed in free_object().
  854.      */
  855.     int i;
  856.     for (i=0; i<ob->prog->num_variables; i++) {
  857.         free_svalue(&ob->variables[i], "destruct_object");
  858.         ob->variables[i].type = T_NUMBER;
  859.         ob->variables[i].u.number = 0;
  860.     }
  861.     }
  862.     free_object(ob, "destruct_object");
  863. }
  864.  
  865. #ifdef F_CREATE_WIZARD
  866. /*
  867.  * This is the efun create_wizard(). Create a home dir for a wizard,
  868.  * and other files he may want.
  869.  *
  870.  * The real job is done by the master.c object, so the call could as well
  871.  * have been done to it directly. But, this function remains for
  872.  * compatibility.
  873.  *
  874.  * It should be replaced by a function in simul_efun.c !
  875.  */
  876. char *create_wizard(owner, domain)
  877.     char *owner;
  878.     char *domain;
  879. {
  880.     struct svalue *ret;
  881. #if 0
  882.     struct stat st;
  883.     char cmd[200], lbuf[128];
  884.     static char name[200], name2[200];
  885.     FILE *f;
  886.     struct object *owner_obj;
  887. #endif
  888.  
  889.     /* 
  890.      * Let the master object do the job.
  891.      */
  892.     push_constant_string(owner);
  893.     push_constant_string(domain);
  894.     push_object(current_object, "create_wizard");
  895.     ret = apply_master_ob("master_create_wizard", 3);
  896.     if (ret && ret->type == T_STRING)
  897.         return ret->u.string;
  898.     return 0;
  899. #if 0
  900.     fprintf(stderr, "c_w called with %s and %s from %s\n",
  901.     owner, domain ? domain : "without domain", current_object->name);
  902.     /*
  903.      * Verify that it is a valid call of create_wizard(). This is done
  904.      * by a function in master.c. It will take the calling object as
  905.      * argument, and must return a non-zero value.
  906.      */
  907.     push_object(current_object, "create_wizard");
  908.     ret = apply_master_ob("verify_create_wizard", 1);
  909.     if (ret == 0)
  910.     error("No wizards allowed ! (because no verify_create_wizard() in master.c)\n");
  911.     if (ret->type == T_NUMBER && ret->u.number == 0)
  912.     error("Illegal use of create_wizard() !\n");
  913.  
  914.     /*
  915.      * Even if the object that called create_wizard() is trusted, we won't
  916.      * allow it to use funny names for the owner.
  917.      */
  918.     if (!legal_path(owner))
  919.     error("Bad name to create_wizard: %s\n", owner);
  920.     owner_obj = find_living_object(owner, 1);
  921.     if (owner_obj == 0) {
  922.     fprintf(stderr,
  923.         "create_wizard: Could not find living object %s.\n", owner);
  924.     return 0;
  925.     }
  926.     (void)sprintf(name, "%s/%s", PLAYER_DIR, owner);
  927.     if(domain) {
  928.     (void)sprintf(name2, "%s/%s/%s", DOMAIN_DIR, domain, owner);
  929.     fprintf(stderr, "name = %s, name2 =  %s\n", name, name2);
  930.     if (stat(name, &st) == 0) {
  931.         if((st.st_mode & S_IFMT) == S_IFDIR) {
  932.         rename(name, name2);
  933.         }
  934.     } else {
  935.         if (mkdir(name2, 0777) == -1) {
  936.         perror(name);
  937.         error("Could not mkdir %s\n", name2);
  938.         }
  939.     }
  940.     } else {
  941.     if (stat(name, &st) == 0)
  942.         error("Player %s already has a castle!\n", owner);
  943.  
  944.     else
  945.         if (mkdir(name, 0777) == -1) {
  946.         perror(name);
  947.         error("Could not mkdir %s\n", name);
  948.         }
  949.     }
  950.  
  951.     /* add castle */
  952.     if(domain) {
  953.     (void)sprintf(name, "%s/%s/common/domain.c", DOMAIN_DIR, domain);
  954.     } else {
  955.     (void)sprintf(name, "%s/%s/%s", PLAYER_DIR, owner, "castle.c");
  956.     }
  957.     if(stat(name, &st) == 0) {
  958.     fprintf(stderr, "castle file %s already exists.\n", name);
  959.     } else {
  960.     f = fopen(name, "w");
  961.     if (f == NULL)
  962.         error("Could not create a castle file %s!\n", name);
  963.     (void)fprintf(f, "#define NAME \"%s\"\n", domain ? domain : owner);
  964. #ifdef CASTLE_ROOM
  965.     (void)fprintf(f, "#define DEST \"%s\"\n", CASTLE_ROOM);
  966. #else
  967.         (void)fprintf(f, "#define DEST \"%s\"\n", current_object->super->name);
  968. #endif
  969.     (void)fclose(f);
  970.     (void)sprintf(cmd, "cat %s >> %s", DEFAULT_CASTLE, name);
  971.     (void)system(cmd);
  972.     }
  973.  
  974. #ifdef COMPAT_MODE
  975.     f = fopen(init_file, "a");
  976.     if (f == NULL)
  977.         error("Could not add the new castle to the %s\n", init_file);
  978.     (void)fprintf(f, "%s\n", name);
  979.     (void)fclose(f);
  980. #endif
  981.     return name;
  982. #endif
  983. }
  984. #endif F_CREATE_WIZARD
  985.  
  986. /*
  987.  * A message from an object will reach
  988.  * all objects in the inventory,
  989.  * all objects in the same environment and
  990.  * the surrounding object.
  991.  * Non interactive objects gets no messages.
  992.  *
  993.  * There are two cases to take care of. If this routine is called from
  994.  * a player (indirectly), then the message goes to all in his
  995.  * environment. Otherwise, the message goes to all in the current_object's
  996.  * environment (as the case when called from a heart_beat()).
  997.  *
  998.  * If there is a second argument 'avoid_ob', then do not send the message
  999.  * to that object.
  1000.  */
  1001.  
  1002. #if 0
  1003. void say(v, avoid_ob)
  1004.     struct svalue *v;
  1005.     struct object *avoid_ob;
  1006. {
  1007.     struct object *ob, *save_command_giver = command_giver;
  1008.     struct object *origin;
  1009.     char buff[257];
  1010.  
  1011.     if (current_object->flags & O_ENABLE_COMMANDS)
  1012.     command_giver = current_object;
  1013.     else if (current_object->shadowing)
  1014.     command_giver = current_object->shadowing;
  1015.     if (command_giver)
  1016.     origin = command_giver;
  1017.     else
  1018.     origin = current_object;
  1019.     switch(v->type) {
  1020.     case T_STRING:
  1021.     strncpy(buff, v->u.string, sizeof buff);
  1022.     buff[sizeof buff - 1] = '\0';
  1023.     break;
  1024.     case T_OBJECT:
  1025.     strncpy(buff, v->u.ob->name, sizeof buff);
  1026.     buff[sizeof buff - 1] = '\0';
  1027.     break;
  1028.     case T_NUMBER:
  1029.     sprintf(buff, "%d", v->u.number);
  1030.     break;
  1031.     default:
  1032.     error("Invalid argument %d to say()\n", v->type);
  1033.     }
  1034.     buff[sizeof buff - 1] = 0;
  1035.     for (ob = origin->contains; ob; ob = ob->next_inv) 
  1036.     {
  1037.     struct object *save_again;
  1038.     if (ob->interactive == 0) 
  1039.         {
  1040.         if ((ob->flags & O_ENABLE_COMMANDS) && ob != command_giver &&
  1041.         ob != avoid_ob)
  1042.         tell_npc(ob, buff);
  1043.         if (ob->flags & O_DESTRUCTED)
  1044.         break;
  1045.         continue;
  1046.     }
  1047.     if (ob == save_command_giver || ob == avoid_ob)
  1048.         continue;
  1049.     save_again = command_giver;
  1050.     command_giver = ob;
  1051.     add_message("%s", buff);
  1052.     command_giver = save_again;
  1053.     }
  1054.     if (origin->super) 
  1055.     {
  1056.     if (origin->super->interactive && origin != command_giver &&
  1057.         origin->super != avoid_ob) 
  1058.         {
  1059.         command_giver = origin->super;
  1060.         add_message("%s", buff);
  1061.     } 
  1062.         else if (origin->super->interactive == 0 && 
  1063.                  origin->super != avoid_ob &&
  1064.         (origin->super->flags & O_ENABLE_COMMANDS) &&
  1065.          ob != command_giver) 
  1066.         tell_npc(origin->super, buff);
  1067.  
  1068.     for (ob = origin->super->contains; ob; ob = ob->next_inv) 
  1069.         {
  1070.         struct object *save_again;
  1071.         if (ob == avoid_ob)
  1072.         continue;
  1073.         if (ob->interactive == 0) 
  1074.         {
  1075.         if ((ob->flags & O_ENABLE_COMMANDS) && ob != command_giver)
  1076.             tell_npc(ob, buff);
  1077.         if (ob->interactive)
  1078.             break;
  1079.         continue;
  1080.         }
  1081.         if (ob == command_giver)
  1082.         continue;
  1083.         save_again = command_giver;
  1084.         command_giver = ob;
  1085.         add_message("%s", buff);
  1086.         command_giver = save_again;
  1087.     }
  1088.     }
  1089.     command_giver = save_command_giver;
  1090. }
  1091. #else
  1092.  
  1093. void say(v, avoid)
  1094.     struct svalue *v;
  1095.     struct vector *avoid;
  1096. {
  1097.     extern struct vector *order_alist PROT((struct vector *));
  1098.     struct vector *vtmpp;
  1099.     static struct vector vtmp = { 1, 1,
  1100. #ifdef DEBUG
  1101.     1,
  1102. #endif
  1103.     (struct wiz_list *)NULL,
  1104.     { { T_POINTER } }
  1105.     };
  1106.  
  1107.     extern int assoc PROT((struct svalue *key, struct vector *));
  1108.     struct object *ob, *save_command_giver = command_giver;
  1109.     struct object *origin;
  1110.     char buff[256];
  1111. #define INITAL_MAX_RECIPIENTS 20
  1112.     int max_recipients = INITAL_MAX_RECIPIENTS;
  1113.     struct object *first_recipients[INITAL_MAX_RECIPIENTS];
  1114.     struct object **recipients = first_recipients;
  1115.     struct object **curr_recipient = first_recipients;
  1116.     struct object **last_recipients =
  1117.     &first_recipients[INITAL_MAX_RECIPIENTS-1];
  1118.  
  1119.     struct object *save_again;
  1120.     static struct svalue stmp = { T_OBJECT };
  1121.  
  1122.     if (current_object->flags & O_ENABLE_COMMANDS)
  1123.     command_giver = current_object;
  1124.     else if (current_object->shadowing)
  1125.     command_giver = current_object->shadowing;
  1126.     if (command_giver) {
  1127.     origin = command_giver;
  1128.         if (avoid->item[0].type == T_NUMBER) {
  1129.             avoid->item[0].type = T_OBJECT;
  1130.             avoid->item[0].u.ob = command_giver;
  1131.             add_ref(command_giver, "ass to var");
  1132.         }
  1133.     } else
  1134.     origin = current_object;
  1135.     vtmp.item[0].u.vec = avoid;
  1136.     vtmpp = order_alist(&vtmp);
  1137.     avoid = vtmpp->item[0].u.vec;
  1138.     if (ob = origin->super) {
  1139.     if (ob->flags & O_ENABLE_COMMANDS || ob->interactive) {
  1140.         *curr_recipient++ = ob;
  1141.     }
  1142.     for (ob = origin->super->contains; ob; ob = ob->next_inv) {
  1143.             if (ob->flags & O_ENABLE_COMMANDS || ob->interactive) {
  1144.                 if (curr_recipient >= last_recipients) {
  1145.                     max_recipients <<= 1;
  1146.                     curr_recipient = (struct object **)
  1147.               alloca(max_recipients * sizeof(struct object *));
  1148.                     memcpy((char*)curr_recipient, (char*)recipients,
  1149.                       max_recipients * sizeof(struct object *)>>1);
  1150.                     recipients = curr_recipient;
  1151.                     last_recipients = &recipients[max_recipients-1];
  1152.                 }
  1153.                 *curr_recipient++ = ob;
  1154.             }
  1155.     }
  1156.     }
  1157.     for (ob = origin->contains; ob; ob = ob->next_inv) {
  1158.     if (ob->flags & O_ENABLE_COMMANDS || ob->interactive) {
  1159.         if (curr_recipient >= last_recipients) {
  1160.         max_recipients <<= 1;
  1161.         curr_recipient = (struct object **)alloca(max_recipients);
  1162.         memcpy((char*)curr_recipient, (char*)recipients,
  1163.           max_recipients * sizeof(struct object *)>>1);
  1164.         recipients = curr_recipient;
  1165.         last_recipients = &recipients[max_recipients-1];
  1166.         }
  1167.         *curr_recipient++ = ob;
  1168.     }
  1169.     }
  1170.     *curr_recipient = (struct object *)0;
  1171.     switch(v->type) {
  1172.     case T_STRING:
  1173.     strncpy(buff, v->u.string, sizeof buff);
  1174.     buff[sizeof buff - 1] = '\0';
  1175.     break;
  1176.     case T_OBJECT:
  1177.     strncpy(buff, v->u.ob->name, sizeof buff);
  1178.     buff[sizeof buff - 1] = '\0';
  1179.     break;
  1180.     case T_NUMBER:
  1181.     sprintf(buff, "%d", v->u.number);
  1182.     break;
  1183.     case T_POINTER:
  1184.     for (curr_recipient = recipients; ob = *curr_recipient++; ) {
  1185.         extern void push_vector PROT((struct vector *));
  1186.  
  1187.         if (ob->flags & O_DESTRUCTED) continue;
  1188.         stmp.u.ob = ob;
  1189.         if (assoc(&stmp, avoid) >= 0) continue;
  1190.         push_vector(v->u.vec);
  1191.         push_object(command_giver, "say");
  1192.         apply("catch_msg", ob, 2);
  1193.     }
  1194.     break;
  1195.     default:
  1196.     error("Invalid argument %d to say()\n", v->type);
  1197.     }
  1198.     save_again = command_giver;
  1199.     for (curr_recipient = recipients; ob = *curr_recipient++; ) {
  1200.         if (ob->flags & O_DESTRUCTED) continue;
  1201.     stmp.u.ob = ob;
  1202.     if (assoc(&stmp, avoid) >= 0) continue;
  1203.     if (ob->interactive == 0) {
  1204.         tell_npc(ob, buff);
  1205.         continue;
  1206.     }
  1207.     command_giver = ob;
  1208.     add_message("%s", buff);
  1209.     command_giver = save_again;
  1210.     }
  1211.     free_vector(vtmpp);
  1212.     command_giver = save_command_giver;
  1213. }
  1214. #endif
  1215.  
  1216. /*
  1217.  * Send a message to all objects inside an object.
  1218.  * Non interactive objects gets no messages.
  1219.  * Compare with say().
  1220.  */
  1221.  
  1222. void tell_room(room, v, avoid)
  1223.     struct object *room;
  1224.     struct svalue *v;
  1225.     struct vector *avoid; /* has to be in alist order */
  1226. {
  1227.     struct object *ob, *save_command_giver = command_giver;
  1228.     char buff[257];
  1229.  
  1230.     switch(v->type) {
  1231.     case T_STRING:
  1232.     strncpy(buff, v->u.string, sizeof buff);
  1233.     buff[sizeof buff - 1] = '\0';
  1234.     break;
  1235.     case T_OBJECT:
  1236.     strncpy(buff, v->u.ob->name, sizeof buff);
  1237.     buff[sizeof buff - 1] = '\0';
  1238.     break;
  1239.     case T_NUMBER:
  1240.     sprintf(buff, "%d", v->u.number);
  1241.     break;
  1242.     default:
  1243.     error("Invalid argument %d to tell_room()\n", v->type);
  1244.     }
  1245.     buff[sizeof buff - 1] = 0;
  1246.     for (ob = room->contains; ob; ob = ob->next_inv) {
  1247.         int assoc PROT((struct svalue *key, struct vector *));
  1248.     static struct svalue stmp = { T_OBJECT, } ;
  1249.  
  1250.     stmp.u.ob = ob;
  1251.     if (assoc(&stmp, avoid) >= 0) continue;
  1252.     if (ob->interactive == 0) {
  1253.         if (ob->flags & O_ENABLE_COMMANDS) {
  1254.         /*
  1255.          * We want the monster code to have a correct this_player()
  1256.          */
  1257.         command_giver = save_command_giver;
  1258.         tell_npc(ob, buff);
  1259.         }
  1260.         if (ob->flags & O_DESTRUCTED)
  1261.         break;
  1262.         continue;
  1263.     }
  1264.     command_giver = ob;
  1265.     add_message("%s", buff);
  1266.     }
  1267.     command_giver = save_command_giver;
  1268. }
  1269.  
  1270. void shout_string(str)
  1271.     char *str;
  1272. {
  1273.     struct object *ob, *save_command_giver = command_giver;
  1274.     int emergency = 0, i;
  1275.     extern int num_player;
  1276. #ifdef LOG_SHOUT
  1277.     FILE *f = 0;
  1278. #endif
  1279.     char *p;
  1280.  
  1281.     if (str[0] == '!') { emergency = 1; }
  1282.     str = string_copy(str+emergency);
  1283.  
  1284. #ifdef LOG_SHOUT
  1285.     if (command_giver) {
  1286.     struct svalue *v = 0;
  1287.     v = apply("query_real_name", command_giver, 0);
  1288.     if (v && v->type == T_STRING)
  1289.         p = v->u.string;
  1290.     } else if (current_object && current_object->user)
  1291.     p = current_object->user->name;
  1292.     if (p)
  1293.     f = fopen("log/SHOUTS", "a");
  1294.     if (f) {
  1295.     fprintf(f, "%s: %s\n", p, str);
  1296.     fclose(f);
  1297.     }
  1298. #endif
  1299. #if 0
  1300.     for (ob = obj_list; ob; ob = ob->next_all) {
  1301.         struct svalue *ret;
  1302.     if (!ob->interactive || ob == save_command_giver || !ob->super)
  1303.         continue;
  1304.         push_object(ob, "shout_string");
  1305.         ret = apply_master_ob("valid_shout", 1);
  1306.         if (!emergency && (!ret || ret->type != T_NUMBER || ret->u.number == 0))
  1307.             continue;
  1308.     command_giver = ob;
  1309.     add_message("%s", str);
  1310.     }
  1311. #endif
  1312.     for (i = 0; i < num_player; ++i)
  1313.     {
  1314.        struct svalue *ret;
  1315.       
  1316.        ob = get_interactive_object(i);
  1317.        if (!ob->interactive || ob == save_command_giver || !ob->super)
  1318.           continue;
  1319.  
  1320.        ret = 0;
  1321.        if (!emergency)
  1322.        {
  1323.           push_object(ob, "shout_string");
  1324.           ret = apply_master_ob("valid_shout", 1);
  1325.           if (ret && ret->type == T_NUMBER && ret->u.number == 0)
  1326.              continue;
  1327.        }
  1328.        command_giver = ob;
  1329.        add_message("%s", str);
  1330.     } 
  1331.     command_giver = save_command_giver;
  1332.     free(str);
  1333. }
  1334.  
  1335. struct object *first_inventory(arg)
  1336.     struct svalue *arg;
  1337. {
  1338.     struct object *ob;
  1339.  
  1340.     if (arg->type == T_STRING)
  1341.     ob = find_object(arg->u.string);
  1342.     else
  1343.     ob = arg->u.ob;
  1344.     if (ob == 0)
  1345.     error("No object to first_inventory()");
  1346.     if (ob->contains == 0)
  1347.     return 0;
  1348.     return ob->contains;
  1349. }
  1350.  
  1351. /*
  1352.  * This will enable an object to use commands normally only
  1353.  * accessible by interactive players.
  1354.  * Also check if the player is a wizard. Wizards must not affect the
  1355.  * value of the wizlist ranking.
  1356.  */
  1357.  
  1358. void enable_commands(num)
  1359.     int num;
  1360. {
  1361.     if (current_object->flags & O_DESTRUCTED)
  1362.     return;
  1363.     if (d_flag > 1) {
  1364.     debug_message("Enable commands %s (ref %d)\n",
  1365.         current_object->name, current_object->ref);
  1366.     }
  1367.     if (num) {
  1368.     current_object->flags |= O_ENABLE_COMMANDS;
  1369.     command_giver = current_object;
  1370.     } else {
  1371.     current_object->flags &= ~O_ENABLE_COMMANDS;
  1372.     command_giver = 0;
  1373.     }
  1374. }
  1375.  
  1376. /*
  1377.  * Set up a function in this object to be called with the next
  1378.  * user input string.
  1379.  */
  1380. int input_to(fun, flag)
  1381.     char *fun;
  1382.     int flag;
  1383. {
  1384.     struct sentence *s;
  1385.  
  1386.     if (!command_giver || command_giver->flags & O_DESTRUCTED)
  1387.     return 0;
  1388.     s = alloc_sentence();
  1389.     if (set_call(command_giver, s, flag)) {
  1390.     s->function = make_shared_string(fun);
  1391.     s->ob = current_object;
  1392.     add_ref(current_object, "input_to");
  1393.     return 1;
  1394.     }
  1395.     free_sentence(s);
  1396.     return 0;
  1397. }
  1398.  
  1399. #define MAX_LINES 50
  1400. #define MAXLSCOLUMNS 6
  1401.  
  1402. struct entry { 
  1403.    int len;
  1404.    int size;
  1405.    char file[34];
  1406. };
  1407.  
  1408. int pstrcmp(p1, p2)
  1409.     char **p1, **p2;
  1410. {
  1411.     return strcmp(((struct entry *)p1)->file,((struct entry *)p2)->file);
  1412. }
  1413.  
  1414. /*
  1415.  * List files in a directory. The standard 'ls' could be used, but
  1416.  * it takes too much time.
  1417.  * Prepared for flag decoding.
  1418.  *
  1419.  * Look at the the last component of the path name. It is a regular
  1420.  * expression, select only matching files.
  1421.  *
  1422.  * All .i files and '.' and '..' are only listed if they match the regexp.
  1423.  */
  1424.  
  1425. void list_files(path)
  1426. char *path;
  1427. {
  1428.    DIR *dirp;
  1429.    struct direct *de;
  1430.    struct stat st;
  1431.    char regexp[80], *p, path2[150];
  1432.    int do_match = 0;
  1433.    struct entry name[MAXLSCOLUMNS*MAX_LINES];
  1434. /*
  1435.    struct entry *nbuf;
  1436. */
  1437.    int colwidth[MAXLSCOLUMNS];
  1438.    char *fname;
  1439.    int num, i, j, k, ncols, npercol, max, total, size;
  1440.    
  1441.    if (!path)
  1442.       path = ".";
  1443. #ifdef COMPAT_MODE
  1444.    path = check_file_name(path, 0);
  1445. #else
  1446.    path = check_valid_path(path, current_object->eff_user,
  1447.                   "list_files", 0);
  1448. #endif
  1449.    if (path  ==  0)
  1450.       return;
  1451.    strncpy(path2, path, sizeof path2);
  1452.    path2[sizeof path2 - 1] = '\0';
  1453.    if(path2[0]==0) 
  1454.      strcpy(path2, "./");
  1455.    p = path2 + strlen(path2) - 2;
  1456.    if (p  >=  path2 && p[0]  ==  '/' && p[1]  ==  '.')
  1457.       p[0] = '\0';
  1458.    if (stat(path2, &st)  ==  -1) 
  1459.    {
  1460.       /* Either the directory does not exist, or it is a regexp
  1461.        * file name. Strip of the last component.
  1462.        */
  1463.       p = strrchr(path2, '/');
  1464.       if (p  ==  0 || p[1]  ==  '\0')
  1465.      return;
  1466.       strncpy(regexp, p+1, sizeof regexp);
  1467.       regexp[sizeof regexp - 1] = '\0';
  1468.       *p = '\0';
  1469.       do_match = 1;
  1470.    }
  1471.    dirp = opendir(path2);
  1472.    if (dirp  ==  0) 
  1473.    {
  1474.       add_message("No such directory '%s'\n", path2);
  1475.       return;
  1476.    }
  1477.    num = 0;
  1478.    total = 0;
  1479.    if (path[0]) strcat(path2,"/");
  1480.    i = strlen(path2);
  1481.    fname = &path2[i];
  1482.    i = sizeof(path2) - i - 1;
  1483. /*
  1484.    nbuf = (struct entry *)xalloc((sizeof(struct entry))*MAXLSCOLUMNS*MAX_LINES);
  1485.    
  1486.    for (j=0; j<MAXLSCOLUMNS*MAX_LINES; j++)
  1487.       name[j] = nbuf+j;
  1488. */
  1489.    
  1490.    for(de = readdir(dirp); (de && num<(MAXLSCOLUMNS*MAX_LINES)); 
  1491.        de = readdir(dirp)) 
  1492.    {
  1493.       if (!do_match && (strcmp(de-> d_name, ".")  ==  0 ||
  1494.             strcmp(de-> d_name, "..")  ==  0))
  1495.      continue;
  1496.       if (do_match && !match_string(regexp, de-> d_name))
  1497.      continue;
  1498.       strncpy(fname, de-> d_name, i);
  1499.       j = 0;
  1500.       if (stat(path2, &st) != -1) 
  1501.       {
  1502.      size = (int)st.st_size / 1024 + ((int)st.st_size % 1024  >  0);
  1503.      total += size;
  1504.      if (S_IFDIR & st.st_mode) j = 1;
  1505.       }
  1506.       else size=0;
  1507.       strncpy(name[num].file, de->d_name, sizeof(name[num].file));
  1508.       name[num].file[sizeof(name[num].file)-1]=0;
  1509.       name[num].len = (int) (de-> d_namlen+j);
  1510.       name[num].size = (int) size;
  1511.       if (j)
  1512.      strcat(name[num].file,"/");
  1513.       num++;
  1514.    }
  1515.    closedir(dirp);
  1516.    
  1517.    if (num == 0) 
  1518.    {
  1519.       add_message(do_match?"No matching files.\n":"No files.\n");
  1520. /*
  1521.       free(nbuf);
  1522. */
  1523.       return;
  1524.    }
  1525.    
  1526.    /* Sort the names. */
  1527.    qsort((char *)name, num, sizeof (struct entry), pstrcmp);
  1528.    
  1529.    ncols = num/(num/MAXLSCOLUMNS+(num%MAXLSCOLUMNS > 0))+
  1530.            ((num%(num/MAXLSCOLUMNS+(num%MAXLSCOLUMNS > 0))) > 0);
  1531.    while (1) 
  1532.    {
  1533.       npercol = num / ncols + (num % ncols  >  0);        
  1534.       for (j=0; j<ncols; j++) 
  1535.       {
  1536.      max = 0;
  1537.      for (i=j*npercol; i<(j+1)*npercol && i<num; i++) 
  1538.         if (name[i].len  >  max)
  1539.            max=name[i].len;
  1540.      colwidth[j] = max+6;
  1541.       }
  1542.       for (i=0, max=0; i<ncols; i++)
  1543.      max+=colwidth[i];
  1544.       if (max<79)
  1545.      break;
  1546.       ncols--;
  1547.       if (ncols<1) 
  1548.       {
  1549.      ncols=1;
  1550.      npercol=num;
  1551.      break;
  1552.       }
  1553.    }
  1554.    
  1555.    for (i=1; i < ncols; i++)
  1556.       colwidth[i]+=colwidth[i-1];
  1557.    
  1558.    add_message("Total %d\n", total);
  1559.    
  1560.    max = 0; i = 0; j = 0;
  1561.    strcpy(path2,
  1562.       "                                                                                ");
  1563.    while (max < num) 
  1564.    {
  1565.       k = (i * npercol) + j;
  1566.       if (i >= ncols) 
  1567.       {
  1568.      j++; i=0;
  1569.      add_message("%s\n", path2);
  1570.      strcpy(path2,
  1571.         "                                                                                ");
  1572.      continue;
  1573.       }            
  1574.       if (k < num) 
  1575.       {
  1576.      if (name[k].size > 9999)
  1577.         sprintf(&path2[(i > 0 ? colwidth[i - 1] : 0)],
  1578.             "BIG! %s ", name[k].file);
  1579.      else
  1580.         sprintf(&path2[(i > 0 ? colwidth[i-1] : 0)],
  1581.             "%4d %s ",
  1582.             name[k].size,
  1583.             name[k].file);
  1584.             if ((i + 1) * npercol + j < num)
  1585.                path2[(i > 0 ? colwidth[i - 1] : 0) +
  1586.                  6 + name[k].len]=' ';
  1587.      max++;
  1588.       }
  1589.       i++;    
  1590.    }
  1591.    add_message("%s\n", path2);
  1592.    if (num == MAXLSCOLUMNS * MAX_LINES)
  1593.       add_message("***Too many files, listing truncated***\n");
  1594. /*
  1595.    free(nbuf);
  1596. */
  1597. }
  1598.  
  1599. int fstrcmp(a, b)
  1600. char **a, **b;
  1601. {
  1602.    return strcmp((char *)a, (char *)b);
  1603. }
  1604.  
  1605. struct vector *get_files(path)
  1606. char *path;
  1607. {
  1608.    DIR *dirp;
  1609.    struct direct *de;
  1610.    struct stat st;
  1611.    char regexp[80], *p, path2[150], *fname;
  1612.    char name[MAX_ARRAY_SIZE][34];/*dunno where 34 comes from, but they use it */
  1613.    int do_match = 0;
  1614.    int num, i, j;
  1615.    struct vector *ret;
  1616.    
  1617.    if (!path)
  1618.       path = ".";
  1619. #ifdef COMPAT_MODE
  1620.    path = check_file_name(path, 0);
  1621. #else
  1622.    path = check_valid_path(path, current_object->eff_user, 
  1623.                   "files", 0);
  1624. #endif
  1625.    if (path  ==  0)
  1626.       return 0;
  1627.    strncpy(path2, path, sizeof path2);
  1628.    path2[sizeof path2 - 1] = '\0';
  1629.    p = path2 + strlen(path2) - 2;
  1630.    if (p  >=  path2 && p[0]  ==  '/' && p[1]  ==  '.')
  1631.       p[0] = '\0';
  1632.    if (stat(path2, &st)  ==  -1) 
  1633.    {
  1634.       /* Either the directory does not exist, or it is a regexp
  1635.        * file name. Strip of the last component.
  1636.        */
  1637.       p = strrchr(path2, '/');
  1638.       if (p  ==  0 || p[1]  ==  '\0')
  1639.      return 0;
  1640.       strncpy(regexp, p+1, sizeof regexp);
  1641.       regexp[sizeof regexp - 1] = '\0';
  1642.       *p = '\0';
  1643.       do_match = 1;
  1644.    }
  1645.    dirp = opendir(path2);
  1646.    if (dirp  ==  0) 
  1647.       return 0;
  1648.    num = 0;
  1649.    if (path[0]) strcat(path2,"/");
  1650.    i = strlen(path2);
  1651.    fname = path2+i;
  1652.    i = sizeof(path2) - i - 1;
  1653.    
  1654.    for(de = readdir(dirp); de; de = readdir(dirp)) 
  1655.    {
  1656.       if (!do_match && (strcmp(de-> d_name, ".")  ==  0 ||
  1657.             strcmp(de-> d_name, "..")  ==  0))
  1658.      continue;
  1659.       if (do_match && !match_string(regexp, de-> d_name))
  1660.      continue;
  1661.       j = 0;
  1662.       strncpy(fname, de-> d_name, i);
  1663.       if (stat(path2, &st) != -1) 
  1664.          if (S_IFDIR & st.st_mode) j = 1;
  1665.       strncpy(name[num], de->d_name, sizeof name[num]);
  1666.       name[num][sizeof(name[num])-1] = 0;
  1667.       if (j)
  1668.      strcat(name[num],"/");
  1669.       num++;
  1670.    }
  1671.    closedir(dirp);
  1672.    
  1673.    /* Sort the names. */
  1674.    if (num)
  1675.       qsort((char *)name, num, sizeof name[0], fstrcmp);
  1676.    
  1677.    ret = allocate_array(num);
  1678.    for (i=0; i<num; ++i)
  1679.    {
  1680.       ret->item[i].type = T_STRING;
  1681.       ret->item[i].u.string = make_shared_string(name[i]);
  1682.       ret->item[i].string_type = STRING_SHARED;
  1683.    }
  1684.    return ret;
  1685.  
  1686. /*
  1687.  * List files in directory. This function do same as standard list_files
  1688.  * but instead writing files right away to player this returns an array
  1689.  * containing those files. Actually most of code is copied from list_files()
  1690.  * function.
  1691.  * Differenceies with list_files:
  1692.  *
  1693.  *   - file_list("/w"); returns ({ "w" })
  1694.  *
  1695.  *   - file_list("/w/"); and file_list("/w/."); return contents of directory
  1696.  *     "/w"
  1697.  *
  1698.  *   - file_list("/");, file_list("."); and file_list("/."); return contents
  1699.  *     of directory "/"
  1700.  */
  1701. struct vector *get_dir(path)
  1702.     char *path;
  1703. {
  1704.     struct vector *v;
  1705.     int i, count = 0;
  1706.     DIR *dirp;
  1707.     int namelen, do_match = 0;
  1708.     struct direct *de;
  1709.     struct stat st;
  1710.     char *temppath;
  1711.     char *p;
  1712.     char *regexp = 0;
  1713.  
  1714.     if (!path)
  1715.     return 0;
  1716.  
  1717. #ifdef COMPAT_MODE
  1718.     path = check_file_name(path, 0);
  1719. #else
  1720.     path = check_valid_path(path, current_object->eff_user, "get_dir", 0);
  1721. #endif
  1722.  
  1723.     if (path == 0)
  1724.     return 0;
  1725.  
  1726.     /*
  1727.      * We need to modify the returned path, and thus to make a
  1728.      * writeable copy.
  1729.      * The path "" needs 2 bytes to store ".\0".
  1730.      */
  1731.     temppath = (char *)alloca(strlen(path)+2);
  1732.     if (strlen(path)<2) {
  1733.     temppath[0]=path[0]?path[0]:'.';
  1734.     temppath[1]='\000';
  1735.     p = temppath;
  1736.     } else {
  1737.     strcpy(temppath, path);
  1738.     /*
  1739.      * If path ends with '/' or "/." remove it
  1740.      */
  1741.     if ((p = strrchr(temppath, '/')) == 0)
  1742.         p = temppath;
  1743.     if (p[0] == '/' && p[1] == '.' && p[2] == '\0' || 
  1744.         p[0] == '/' && p[1] == '\0')
  1745.         *p = '\0';
  1746.     }
  1747.  
  1748.     if (stat(temppath, &st) < 0) {
  1749.     if (*p == '\0')
  1750.         return 0;
  1751.     regexp = (char *)alloca(strlen(p)+2);
  1752.     if (p != temppath) {
  1753.         strcpy(regexp, p + 1);
  1754.         *p = '\0';
  1755.     } else {
  1756.         strcpy(regexp, p);
  1757.         strcpy(temppath, ".");
  1758.     }
  1759.     do_match = 1;
  1760.     } else if (*p != '\0' && strcmp(temppath, ".")) {
  1761.     if (*p == '/' && *(p + 1) != '\0')
  1762.         p++;
  1763.     v = allocate_array(1);
  1764.     v->item[0].type = T_STRING;
  1765.     v->item[0].string_type = STRING_MALLOC;
  1766.     v->item[0].u.string = string_copy(p);
  1767.     return v;
  1768.     }
  1769.  
  1770.     if ((dirp = opendir(temppath)) == 0)
  1771.     return 0;
  1772.  
  1773.     /*
  1774.      *  Count files
  1775.      */
  1776.     for (de = readdir(dirp); de; de = readdir(dirp)) {
  1777.     namelen = de->d_namlen;
  1778.     if (!do_match && (strcmp(de->d_name, ".") == 0 ||
  1779.               strcmp(de->d_name, "..") == 0))
  1780.         continue;
  1781.     if (do_match && !match_string(regexp, de->d_name))
  1782.         continue;
  1783.     count++;
  1784.     if ( count >= MAX_ARRAY_SIZE)
  1785.         break;
  1786.     }
  1787.     /*
  1788.      * Make array and put files on it.
  1789.      */
  1790.     v = allocate_array(count);
  1791.     if (count == 0) {
  1792.     /* This is the easy case :-) */
  1793.     closedir(dirp);
  1794.     return v;
  1795.     }
  1796.     rewinddir(dirp);
  1797.     for(i = 0, de = readdir(dirp); i < count; de = readdir(dirp)) {
  1798.     namelen = de->d_namlen;
  1799.     if (!do_match && (strcmp(de->d_name, ".") == 0 ||
  1800.               strcmp(de->d_name, "..") == 0))
  1801.         continue;
  1802.     if (do_match && !match_string(regexp, de->d_name))
  1803.         continue;
  1804.     de->d_name[namelen] = '\0';
  1805.     v->item[i].type = T_STRING;
  1806.     v->item[i].string_type = STRING_MALLOC;
  1807.     v->item[i].u.string = string_copy(de->d_name);
  1808.     i++;
  1809.     }
  1810.     closedir(dirp);
  1811.     /* Sort the names. */
  1812.     qsort((char *)v->item, count, sizeof v->item[0], pstrcmp);
  1813.     return v;
  1814. }
  1815.  
  1816. int tail(path)
  1817.     char *path;
  1818. {
  1819.     char buff[1000];
  1820.     FILE *f;
  1821.     struct stat st;
  1822.     int offset;
  1823.  
  1824. #ifdef COMPAT_MODE
  1825.     path = check_file_name(path, 0);
  1826. #else
  1827.     path = check_valid_path(path, current_object->eff_user, "tail", 0);
  1828. #endif
  1829.     if (path == 0)
  1830.         return 0;
  1831.     f = fopen(path, "r");
  1832.     if (f == 0)
  1833.     return 0;
  1834.     if (fstat(fileno(f), &st) == -1)
  1835.     error("Could not stat an open file.\n");
  1836.     offset = st.st_size - 54 * 20;
  1837.     if (offset < 0)
  1838.     offset = 0;
  1839.     if (fseek(f, offset, 0) == -1)
  1840.     fatal("Could not seek.\n");
  1841.     /* Throw away the first incomplete line. */
  1842.     if (offset > 0)
  1843.     (void)fgets(buff, sizeof buff, f);
  1844.     while(fgets(buff, sizeof buff, f)) {
  1845.     add_message("%s", buff);
  1846.     }
  1847.     fclose(f);
  1848.     return 1;
  1849. }
  1850.  
  1851.  
  1852. int print_file(path, start, len)
  1853.     char *path;
  1854.     int start, len;
  1855. {
  1856.     char buff[1000];
  1857.     FILE *f;
  1858.     int i, num_read = 0;;
  1859.  
  1860.     if (len < 0)
  1861.     return -1;
  1862. #ifdef COMPAT_MODE
  1863.     path = check_file_name(path, 0);
  1864. #else
  1865.     path = check_valid_path(path, current_object->eff_user, 
  1866.                 "print_file", 0);
  1867. #endif
  1868.     if (path == 0)
  1869.         return -1;
  1870.     f = fopen(path, "r");
  1871.     if (f == 0)
  1872.     return -1;
  1873.     if (start < 0) {
  1874.     int lines = 0;
  1875.  
  1876.     while (fgets(buff, sizeof buff, f) != 0)
  1877.         lines++;
  1878.     rewind(f);
  1879.     start = lines - len + 1;
  1880.     }
  1881.     for (i = 1; i < start; i++) {
  1882.     if (fgets(buff, sizeof buff, f) == 0)
  1883.         break;
  1884.     }
  1885.     if (!len || len > MAX_LINES)
  1886.     len = MAX_LINES;
  1887.     for (i = 0; i < len; i++) {
  1888.     if (fgets(buff, sizeof buff, f) == 0)
  1889.         break;
  1890.         buff[sizeof buff - 1] = 0;
  1891.     num_read++;
  1892.     add_message("%s", buff);
  1893.     }
  1894.     if (i == MAX_LINES)
  1895.     add_message("*****TRUNCATED*****\n");
  1896.     fclose(f);
  1897.     return num_read;
  1898. }
  1899.  
  1900. int remove_file(path)
  1901.     char *path;
  1902. {
  1903. #ifdef COMPAT_MODE
  1904.     path = check_file_name(path, 1);
  1905. #else
  1906.     path = check_valid_path(path, current_object->eff_user,
  1907.                   "remove_file", 1);
  1908. #endif
  1909.     if (path == 0)
  1910.         return 0;
  1911.     if (unlink(path) == -1)
  1912.        return 0;
  1913.     return 1;
  1914. }
  1915.  
  1916. void log_file(file, str)
  1917.     char *file, *str;
  1918. {
  1919.     FILE *f;
  1920.     char file_name[100];
  1921.     struct stat st;
  1922.  
  1923.     sprintf(file_name, "/log/%s", file);
  1924. #ifdef COMPAT_MODE
  1925.     if (strchr(file, '/') || file[0] == '.' || strlen(file) > 30
  1926. #ifdef MSDOS
  1927.         || !valid_msdos(file)
  1928. #endif
  1929.         )
  1930.           error("Illegal file name to log_file(%s)\n", file);
  1931. #else
  1932.     if (!check_valid_path(file_name, current_object->eff_user, 
  1933.             "log_file", 1))
  1934.           return;
  1935. #endif
  1936.     if (stat(file_name+1, &st) != -1 && st.st_size > MAX_LOG_SIZE) {
  1937.       char file_name2[sizeof file_name + 4];
  1938.     sprintf(file_name2, "%s.old", file_name+1);
  1939.     rename(file_name+1, file_name2);    /* No panic if failure */
  1940.     }
  1941.     f = fopen(file_name+1, "a");    /* Skip leading '/' */
  1942.     if (f == 0)
  1943.     return;
  1944.     fwrite(str, strlen(str), 1, f);
  1945.     fclose(f);
  1946. }
  1947.  
  1948. void
  1949. print_svalue(arg)
  1950.     struct svalue *arg;
  1951. {
  1952.     if (arg == 0)
  1953.     add_message("<NULL>");
  1954.     else if (arg->type == T_STRING) {
  1955.     if (strlen(arg->u.string) > 9500)    /* Not pretty */
  1956.         error("Too long string.\n");
  1957.     /* Strings sent to monsters are now delivered */
  1958.     if (command_giver && (command_giver->flags & O_ENABLE_COMMANDS) &&
  1959.               !command_giver->interactive)
  1960.         tell_npc(command_giver, arg->u.string);
  1961.     else
  1962.         add_message("%s", arg->u.string);
  1963.     } else if (arg->type == T_OBJECT)
  1964.     add_message("OBJ(%s)", arg->u.ob->name);
  1965.     else if (arg->type == T_NUMBER)
  1966.     add_message("%d", arg->u.number);
  1967.     else if (arg->type == T_POINTER)
  1968.     add_message("<ARRAY>");
  1969.     else
  1970.     add_message("<UNKNOWN>");
  1971. }
  1972.  
  1973. void do_write(arg)
  1974.     struct svalue *arg;
  1975. {
  1976.     struct object *save_command_giver = command_giver;
  1977.     if (command_giver == 0 && current_object->shadowing)
  1978.        command_giver = current_object;
  1979.     if (command_giver)
  1980.     while (command_giver->shadowing)
  1981.         command_giver = command_giver->shadowing;
  1982.     print_svalue(arg);
  1983.     command_giver = save_command_giver;
  1984. }
  1985.  
  1986. /* Find an object. If not loaded, load it ! */
  1987.  
  1988. struct object *find_object(str)
  1989.     char *str;
  1990. {
  1991.     struct object *ob;
  1992.  
  1993.     /* Remove leading '/' if any. */
  1994.     while(str[0] == '/')
  1995.     str++;
  1996.     ob = find_object2(str);
  1997.     if (ob)
  1998.     return ob;
  1999.     ob = load_object(str, 0);
  2000.     if (ob->flags & O_DESTRUCTED)        /* *sigh* */
  2001.        return 0;
  2002.     if (ob && ob->flags & O_SWAPPED)
  2003.     load_ob_from_swap(ob);
  2004.     return ob;
  2005. }
  2006.  
  2007. /* Look for a loaded object. Return 0 if non found. */
  2008. struct object *find_object2(str)
  2009.     char *str;
  2010. {
  2011.     register struct object *ob;
  2012.     register int length;
  2013.  
  2014.     /* Remove leading '/' if any. */
  2015.     while(str[0] == '/')
  2016.     str++;
  2017.     /* Truncate possible .c in the object name. */
  2018.     length = strlen(str);
  2019.     if (str[length-2] == '.' && str[length-1] == 'c') {
  2020.     /* A new writreable copy of the name is needed. */
  2021.     char *p;
  2022.     p = (char *)alloca(strlen(str)+1);
  2023.     strcpy(p, str);
  2024.     str = p;
  2025.     str[length-2] = '\0';
  2026.     }
  2027.     if (ob = lookup_object_hash(str)) {
  2028.     if (ob->flags & O_SWAPPED)
  2029.         load_ob_from_swap(ob);
  2030.     return ob;
  2031.     }
  2032.     return 0;
  2033. }
  2034.  
  2035. #if 0
  2036.  
  2037. void apply_command(com)
  2038.     char *com;
  2039. {
  2040.     struct value *ret;
  2041.  
  2042.     if (command_giver == 0)
  2043.     error("command_giver == 0 !\n");
  2044.     ret = apply(com, command_giver->super, 0);
  2045.     if (ret != 0) {
  2046.     add_message("Result:");
  2047.     if (ret->type == T_STRING)
  2048.         add_message("%s\n", ret->u.string);
  2049.     if (ret->type == T_NUMBER)
  2050.         add_message("%d\n", ret->u.number);
  2051.     } else {
  2052.     add_message("Error apply_command: function %s not found.\n", com);
  2053.     }
  2054. }
  2055. #endif /* 0 */
  2056.  
  2057.  
  2058. /*
  2059.  * Transfer an object.
  2060.  * The object has to be taken from one inventory list and added to another.
  2061.  * The main work is to update all command definitions, depending on what is
  2062.  * living or not. Note that all objects in the same inventory are affected.
  2063.  */
  2064. void move_object(item, dest)
  2065.     struct object *item, *dest;
  2066. {
  2067.     struct object **pp, *ob, *next_ob;
  2068.     struct object *save_cmd = command_giver;
  2069.     extern int current_time;
  2070.  
  2071. #ifndef COMPAT_MODE
  2072.     if (item != current_object)
  2073.     error("Illegal to move other object than this_object()\n");
  2074. #endif
  2075.     /* Recursive moves are not allowed. */
  2076.     for (ob = dest; ob; ob = ob->super)
  2077.     if (ob == item)
  2078.             return; 
  2079.     if (item->shadowing)
  2080.         error("Can't move an object that is shadowing.\n");
  2081. #if 0 /* Not now /Lars */
  2082.     /*
  2083.      * Objects must have inherited std/object if they are to be allowed to
  2084.      * be moved.
  2085.      */
  2086. #ifndef COMPAT_MODE
  2087.     if (!(item->flags & O_APPROVED) ||
  2088.             !(dest->flags & O_APPROVED)) {
  2089.     error("Trying to move object where src or dest not inherit std/object\n");
  2090.     return;
  2091.     }
  2092. #endif
  2093. #endif
  2094.     /* if it's past due for a reset, reset the object immediately */
  2095.     /* else mark it to be reset.  Set command_giver to zero to    */
  2096.     /* simulate a normal reset, where there is no command_giver   */
  2097.     /* also, reset the eval_cost, since this shouldn't add to the */
  2098.     /* current execution thread's eval_cost                       */
  2099. #ifdef COMPAT_MODE
  2100.     {
  2101.        extern int eval_cost;
  2102.        if (item->next_reset < current_time)
  2103.        {
  2104.           struct object *s = command_giver;
  2105.           int save = eval_cost;
  2106.           eval_cost = 0;
  2107.           command_giver = 0;
  2108.           reset_object(item, 1);
  2109.           command_giver = s;
  2110.           eval_cost = save;
  2111.           if (item->flags & O_DESTRUCTED)
  2112.              return;
  2113.        }
  2114.        else
  2115.           item->flags &= ~O_RESET_STATE;
  2116.  
  2117.        if (dest->next_reset < current_time)
  2118.        {
  2119.           struct object *s = command_giver;
  2120.           int save = eval_cost;
  2121.           eval_cost = 0;
  2122.           command_giver = 0;
  2123.           reset_object(dest, 1);
  2124.           eval_cost = save;
  2125.           command_giver = s;
  2126.           if (dest->flags & O_DESTRUCTED)
  2127.              return;
  2128.        }
  2129.        else
  2130.           dest->flags &= ~O_RESET_STATE;
  2131.     }
  2132. #endif
  2133.     add_light(dest, item->total_light);
  2134.     if (item->super) {
  2135.     int okey = 0;
  2136.         
  2137.     if (item->flags & O_ENABLE_COMMANDS) {
  2138. #ifdef COMPAT_MODE
  2139.         command_giver = item;
  2140.         push_object(item, "move_object");
  2141.         (void)apply("exit", item->super, 1);
  2142.         if (item->flags & O_DESTRUCTED || dest->flags & O_DESTRUCTED)
  2143.             return;    /* Give up */
  2144. #endif
  2145.         remove_sent(item->super, item);
  2146.     }
  2147.     if (item->super->flags & O_ENABLE_COMMANDS)
  2148.         remove_sent(item, item->super);
  2149.     add_light(item->super, - item->total_light);
  2150.     for (pp = &item->super->contains; *pp;) {
  2151.         if (*pp != item) {
  2152.         if ((*pp)->flags & O_ENABLE_COMMANDS) 
  2153.             remove_sent(item, *pp);
  2154.         if (item->flags & O_ENABLE_COMMANDS) 
  2155.             remove_sent(*pp, item);
  2156.         pp = &(*pp)->next_inv;
  2157.         continue;
  2158.         }
  2159.         *pp = item->next_inv;
  2160.         okey = 1;
  2161.     }
  2162.     if (!okey)
  2163.         fatal("Failed to find object %s in super list of %s.\n",
  2164.           item->name, item->super->name);
  2165.     }
  2166.     item->next_inv = dest->contains;
  2167.     dest->contains = item;
  2168.     item->super = dest;
  2169.     /*
  2170.      * Setup the new commands. The order is very important, as commands
  2171.      * in the room should override commands defined by the room.
  2172.      * Beware that init() in the room may have moved 'item' !
  2173.      *
  2174.      * The call of init() should really be done by the object itself
  2175.      * (except in the -o mode). It might be too slow, though :-(
  2176.      */
  2177.     if (item->flags & O_ENABLE_COMMANDS) {
  2178.     command_giver = item;
  2179.     (void)apply("init", dest, 0);
  2180.     if ((dest->flags & O_DESTRUCTED) || item->super != dest) {
  2181.         command_giver = save_cmd; /* marion */
  2182.         return;
  2183.     }
  2184.     }
  2185.     /*
  2186.      * Run init of the item once for every present player, and
  2187.      * for the environment (which can be a player).
  2188.      */
  2189.     for (ob = dest->contains; ob; ob=next_ob) {
  2190.     next_ob = ob->next_inv;
  2191.     if (ob == item)
  2192.         continue;
  2193.     if (ob->flags & O_DESTRUCTED)
  2194.             continue;
  2195. #if 0 /* Raistlin */
  2196.         error("An object was destructed at call of init()\n");
  2197. #endif
  2198.     if (ob->flags & O_ENABLE_COMMANDS) {
  2199.         command_giver = ob;
  2200.         (void)apply("init", item, 0);
  2201.         if (dest != item->super) {
  2202.         command_giver = save_cmd; /* marion */
  2203.         return;
  2204.         }
  2205.     }
  2206.     if (item->flags & O_DESTRUCTED) /* marion */
  2207.         error("The object to be moved was destructed at call of init()\n");
  2208.     if (item->flags & O_ENABLE_COMMANDS) {
  2209.         command_giver = item;
  2210.         (void)apply("init", ob, 0);
  2211.         if (dest != item->super) {
  2212.         command_giver = save_cmd; /* marion */
  2213.         return;
  2214.         }
  2215.     }
  2216.     }
  2217.     if (dest->flags & O_DESTRUCTED) /* marion */
  2218.     error("The destination to move to was destructed at call of init()\n");
  2219.     if (dest->flags & O_ENABLE_COMMANDS) {
  2220.     command_giver = dest;
  2221.     (void)apply("init", item, 0);
  2222.     }
  2223.     command_giver = save_cmd;
  2224. }
  2225.  
  2226. /*
  2227.  * Every object as a count of number of light sources it contains.
  2228.  * Update this.
  2229.  */
  2230.  
  2231. void add_light(p, n)
  2232.     struct object *p;
  2233.     int n;
  2234. {
  2235.     if (n == 0)
  2236.     return;
  2237.     p->total_light += n;
  2238.     if (p->super)
  2239.     add_light(p->super, n);
  2240. }
  2241.  
  2242. struct sentence *sent_free = 0;
  2243. int tot_alloc_sentence;
  2244.  
  2245. struct sentence *alloc_sentence() {
  2246.     struct sentence *p;
  2247.     if (sent_free == 0) {
  2248.     p = (struct sentence *)xalloc(sizeof *p);
  2249.         tot_alloc_sentence++;
  2250.     } else {
  2251.     p = sent_free;
  2252.     sent_free = sent_free->next;
  2253.     }
  2254. /*
  2255.     p = (struct sentence *)xalloc(sizeof(struct sentence));
  2256.     tot_alloc_sentence++;
  2257. */
  2258.     p->verb = 0;
  2259.     p->ob = 0;
  2260.     p->function = 0;
  2261.     p->next = 0;
  2262.     p->short_verb = 0;
  2263.     p->no_space = 0;
  2264.     return p;
  2265. }
  2266.  
  2267. #ifdef DEALLOCATE_MEMORY_AT_SHUTDOWN
  2268. void free_all_sent() {
  2269.     struct sentence *p;
  2270.     for (;sent_free; sent_free = p) {
  2271.     p = sent_free->next;
  2272.     free((char *)sent_free);
  2273.     }
  2274. }
  2275. #endif
  2276.  
  2277. void free_sentence(p)
  2278.     struct sentence *p;
  2279. {
  2280.     if (p->function)
  2281.     free_string(p->function);
  2282.     if (p->verb)
  2283.     free_string(p->verb);
  2284. /*
  2285.     memset((char *)p, '\0', sizeof(struct sentence));
  2286.     free((char *)p);
  2287.     tot_alloc_sentence--;
  2288. */
  2289.     p->verb = 0;
  2290.     p->function = 0;
  2291.     p->ob = 0;
  2292.     p->next = sent_free;
  2293.     sent_free = p;
  2294. }
  2295.  
  2296. compress_spaces(buff)
  2297. char *buff;
  2298. {
  2299.    char *p, *q;
  2300.    
  2301.    p = buff;
  2302.    while(isspace(*p)) p++;
  2303.    strcpy(buff, p);
  2304.    p = buff;
  2305.    while (*p)
  2306.    {
  2307.       if (isspace(*p) && *p != ' ') *p = ' ';
  2308.       if (isspace(*p) && isspace(*(p+1)))
  2309.       {
  2310.          q = ++p;
  2311.          while (isspace(*q)) ++q;
  2312.          strcpy(p, q);
  2313.       }
  2314.       else
  2315.          ++p;
  2316.    }
  2317. }
  2318.        
  2319.  
  2320. /*
  2321.  * Find the sentence for a command from the player.
  2322.  * Return success status.
  2323.  */
  2324. int player_parser(buff)
  2325.     char *buff;
  2326. {
  2327.     struct sentence *s;
  2328.     char *p;
  2329.     int length;
  2330.     struct object *save_current_object = current_object;
  2331.     char verb_copy[100], verb_arg[1000];
  2332.  
  2333.     if (d_flag > 1)
  2334.     debug_message("cmd [%s]: %s\n", command_giver->name, buff);
  2335. #if 0
  2336.     /* strip trailing spaces. */
  2337.     compress_spaces(buff);
  2338. #endif /* not used yet */
  2339.     for (p = buff + strlen(buff) - 1; p >= buff; p--) {
  2340.     if (*p != ' ')
  2341.         break;
  2342.     *p = '\0';
  2343.     }
  2344.     if (buff[0] == '\0')
  2345.     return 0;
  2346.     if (special_parse(buff))
  2347.     return 1;
  2348.     p = strchr(buff, ' ');
  2349.     if (p == 0)
  2350.     length = strlen(buff);
  2351.     else
  2352.     length = p - buff;
  2353.     clear_notify();
  2354.     for (s=command_giver->sent; s; s = s->next) {
  2355.     struct svalue *ret;
  2356.         struct object *command_object;
  2357.     int len;
  2358.     
  2359.     if (s->verb == 0)
  2360.         error("An 'action' did something, but returned 0 or had an undefined verb.\n");
  2361.     len = strlen(s->verb);
  2362.         if (s->no_space) {
  2363.             if (strncmp(buff, s->verb, len) != 0)
  2364.                continue;
  2365.         }
  2366.     else if (s->short_verb) {
  2367. #ifdef OLD_ADD_ACTION
  2368.             if (strncmp(buff, s->verb, len))
  2369. #else
  2370.             if (length < s->short_verb || strncmp(buff, s->verb, length) != 0)
  2371. #endif
  2372.         continue;
  2373.     } else {
  2374.         if (len != length) continue;
  2375.         if (strncmp(buff, s->verb, length) != 0)
  2376.         continue;
  2377.     }
  2378.     /*
  2379.      * Now we have found a special sentence !
  2380.      */
  2381.     if (d_flag > 1)
  2382.         debug_message("Local command %s on %s\n", s->function, s->ob->name);
  2383.         if (!s->no_space)
  2384.        if (length < sizeof verb_copy)
  2385.            len = length;
  2386.        else
  2387.            len = sizeof verb_copy - 1;
  2388.     strncpy(verb_copy, buff, len);
  2389.     verb_copy[len] = '\0';
  2390.     last_verb = verb_copy;
  2391.     /*
  2392.      * If the function is static and not defined by current object,
  2393.      * then it will fail. If this is called directly from player input,
  2394.      * then we set current_object so that static functions are allowed.
  2395.      */
  2396. #ifndef COMMAND_STATIC
  2397.     if (current_object == 0)  
  2398. #endif
  2399.         current_object = s->ob;
  2400.         command_object = s->ob;
  2401.     if (s->no_space) {
  2402.            push_constant_string(&buff[strlen(s->verb)]);
  2403.            strncpy(verb_arg, buff+strlen(s->verb), sizeof verb_arg -1);
  2404.            verb_arg[sizeof verb_arg - 1] = 0;
  2405.            last_arg = verb_arg;
  2406.            ret = apply(s->function, s->ob, 1);
  2407.         }
  2408.         else if (buff[length] == ' ') {
  2409.            push_constant_string(&buff[length+1]);
  2410.            strncpy(verb_arg, buff+length+1, sizeof verb_arg -1);
  2411.            verb_arg[sizeof verb_arg - 1] = 0;
  2412.            last_arg = verb_arg;
  2413.            ret = apply(s->function, s->ob, 1);
  2414.         } else {
  2415.            last_arg = 0;
  2416.            ret = apply(s->function, s->ob, 0);
  2417.     }
  2418.     if (current_object->flags & O_DESTRUCTED)
  2419.         {
  2420.             if (!command_giver)
  2421.                 return 1;
  2422.         s = command_giver->sent;    /* Restart :-( */
  2423.         }
  2424.         current_object = save_current_object;
  2425.     last_verb = 0;
  2426.         last_arg = 0;
  2427.     /* If we get fail from the call, it was wrong second argument. */
  2428.     if (ret && ret->type == T_NUMBER && ret->u.number == 0)
  2429.         continue;
  2430.     if (s && command_object->user && command_giver->interactive &&
  2431.         !(command_giver->flags & O_IS_WIZARD)) 
  2432.         command_object->user->score++;
  2433.     if (ret == 0)
  2434.         add_message("Error: function %s not found.\n", s->function);
  2435.     break;
  2436.     }
  2437.     if (s == 0) {
  2438.     notify_no_command();
  2439.     return 0;
  2440.     }
  2441.     return 1;
  2442. }
  2443.  
  2444. /*
  2445.  * Associate a command with function in this object.
  2446.  * The optional second argument is the command name. If the command name
  2447.  * is not given here, it should be given with add_verb().
  2448.  *
  2449.  * The optinal third argument is a flag that will state that the verb should
  2450.  * only match against leading characters.
  2451.  *
  2452.  * The object must be near the command giver, so that we ensure that the
  2453.  * sentence is removed when the command giver leaves.
  2454.  */
  2455. void add_action(str, cmd, flag)
  2456.     char *str, *cmd;
  2457.     int flag;
  2458. {
  2459.     struct sentence *p;
  2460.     struct object *ob;
  2461.  
  2462.     if (str[0] == ':')
  2463.     error("Illegal function name: %s\n", str);
  2464.     if (current_object->flags & O_DESTRUCTED)
  2465.     return;
  2466.     ob = current_object;
  2467.     while (ob->shadowing) 
  2468.         ob = ob->shadowing;
  2469.     if (command_giver == 0 || (command_giver->flags & O_DESTRUCTED))
  2470.     return;
  2471.     if (ob != command_giver && ob->super != command_giver &&
  2472.     ob->super != command_giver->super && ob != command_giver->super)
  2473.       error("add_action from object that was not present.\n");
  2474.     if (d_flag > 1)
  2475.     debug_message("--Add action %s\n", str);
  2476. #ifdef COMPAT_MODE
  2477.     if (strcmp(str, "exit") == 0)
  2478.     error("Illegal to define a command to the exit() function.\n");
  2479. #endif
  2480.     p = alloc_sentence();
  2481.     p->function = make_shared_string(str);
  2482.     p->ob = ob;
  2483.     p->next = command_giver->sent;
  2484.     p->short_verb = flag;
  2485.     p->no_space = 0;
  2486.     if (cmd)
  2487.     p->verb = make_shared_string(cmd);
  2488.     else
  2489.     p->verb = 0;
  2490.     command_giver->sent = p;
  2491. }
  2492.  
  2493. void add_verb(str, no_space)
  2494.     char *str;
  2495.     int no_space;
  2496. {
  2497.     if (command_giver == 0 || (command_giver->flags & O_DESTRUCTED))
  2498.     return;
  2499.     if (command_giver->sent == 0)
  2500.     error("No add_action().\n");
  2501.     if (command_giver->sent->verb != 0)
  2502.     error("Tried to set verb again.\n");
  2503.     command_giver->sent->verb = make_shared_string(str);
  2504.     command_giver->sent->no_space = no_space;
  2505.     if (d_flag > 1)
  2506.     debug_message("--Adding verb %s to action %s\n", str,
  2507.         command_giver->sent->function);
  2508. }
  2509.  
  2510. /*
  2511.  * Remove all commands (sentences) defined by object 'ob' in object
  2512.  * 'player'. 
  2513.  */
  2514. void remove_sent(ob, player)
  2515. struct object *ob, *player;
  2516. {
  2517.    struct sentence **s;
  2518.  
  2519.    for (s = &player->sent; *s;) 
  2520.    {
  2521.       struct sentence *tmp;
  2522.  
  2523.       if ((*s)->ob == ob) 
  2524.       {
  2525.          if (d_flag > 1)
  2526.             debug_message("--Unlinking sentence %s\n", (*s)->function);
  2527.          tmp = *s;
  2528.          *s = tmp->next;
  2529.          free_sentence(tmp);
  2530.       } 
  2531.       else
  2532.          s = &((*s)->next);
  2533.    }
  2534. }
  2535.  
  2536. char debug_parse_buff[51]; /* Used for debugging */
  2537.  
  2538. /*
  2539.  * Hard coded commands, that will be available to all players. They can not
  2540.  * be redefined, so the command name should be something obscure, not likely
  2541.  * to be used in the game.
  2542.  */
  2543. int special_parse(buff)
  2544.     char *buff;
  2545. {
  2546.     int verbose = 0;
  2547.     strncpy(debug_parse_buff, buff, sizeof debug_parse_buff-1);
  2548.     debug_parse_buff[sizeof debug_parse_buff - 1] = 0;
  2549.     if (strcmp(buff, "malloc") == 0) {
  2550. #if defined(MALLOC_malloc) || defined(MALLOC_smalloc)
  2551.     dump_malloc_data();
  2552. #endif
  2553. #ifdef MALLOC_gmalloc
  2554.     add_message("Using Gnu malloc.\n");
  2555. #endif
  2556. #ifdef MALLOC_sysmalloc
  2557.     add_message("Using system malloc.\n");
  2558. #endif
  2559.     return 1;
  2560.     }
  2561.     if (strcmp(buff, "dumpallobj") == 0) {
  2562.         dumpstat();
  2563.     return 1;
  2564.     }
  2565. #if defined(MALLOC_malloc) || defined(MALLOC_smalloc)
  2566.     if (strcmp(buff, "debugmalloc") == 0) {
  2567.     extern int debugmalloc;
  2568.     debugmalloc = !debugmalloc;
  2569.     if (debugmalloc)
  2570.         add_message("On.\n");
  2571.     else
  2572.         add_message("Off.\n");
  2573.     return 1;
  2574.     }
  2575. #endif
  2576.     if (strcmp(buff, "status") == 0 || 
  2577.         (strcmp(buff, "status tables") == 0 && (verbose = 1))) {
  2578.     int tot, res;
  2579.     extern int tot_alloc_sentence, tot_alloc_object,
  2580.            num_swapped, total_bytes_swapped, reserved_area,
  2581.                    num_arrays, total_array_size, total_object_size;
  2582.     extern int total_num_prog_blocks, total_prog_block_size;
  2583. #ifdef COMM_STAT
  2584.     extern int add_message_calls,inet_packets,inet_volume;
  2585. #endif
  2586.  
  2587.         if (reserved_area)
  2588.         res = RESERVED_SIZE;
  2589.     else
  2590.         res = 0; 
  2591. #ifdef COMM_STAT
  2592.         if (verbose)
  2593.        add_message(
  2594.       "Calls to add_message: %d    Packets: %d    Average packet size: %f\n", 
  2595.             add_message_calls, inet_packets, (float)inet_volume/inet_packets);
  2596. #endif
  2597.         if (!verbose)
  2598.         {
  2599.        add_message("Sentences:   %5d %7d\n", tot_alloc_sentence, 
  2600.         tot_alloc_sentence * sizeof (struct sentence)); 
  2601.        add_message("Objects:     %5d %7d\n",
  2602.             tot_alloc_object, total_object_size);
  2603.            add_message("Arrays:      %5d %7d\n", num_arrays, total_array_size);
  2604.        add_message("Prog blocks: %5d %7d (%d swapped, %d Kbyte)\n", 
  2605.                     total_num_prog_blocks, total_prog_block_size,
  2606.                     num_swapped, total_bytes_swapped / 1024);
  2607.        add_message("Memory reserved:    %7d\n", res);
  2608.         }
  2609.     /* status_lnodes_matched(); */
  2610.         if (verbose)
  2611.        stat_living_objects();
  2612.     tot =           total_prog_block_size +
  2613.                show_otable_status(verbose) +
  2614.                heart_beat_status(verbose) +
  2615.                add_string_status(verbose) +
  2616.                print_call_out_usage(verbose) +
  2617.                total_array_size +
  2618.                            total_object_size +
  2619.                res;
  2620.         if (!verbose)
  2621.         {
  2622.             add_message("\t\t\t\t\t --------\n");
  2623.             add_message("Total:\t\t\t\t\t %8d\n", tot);
  2624.         }
  2625.     return 1;
  2626.     }
  2627. #ifdef NEED_DIRECTIONS
  2628.     if (strcmp(buff, "e") == 0) {
  2629.     (void)strcpy(buff, "east");
  2630.     return 0;
  2631.     }
  2632.     if (strcmp(buff, "w") == 0) {
  2633.     (void)strcpy(buff, "west");
  2634.     return 0;
  2635.     }
  2636.     if (strcmp(buff, "s") == 0) {
  2637.     (void)strcpy(buff, "south");
  2638.     return 0;
  2639.     }
  2640.     if (strcmp(buff, "n") == 0) {
  2641.     (void)strcpy(buff, "north");
  2642.     return 0;
  2643.     }
  2644.     if (strcmp(buff, "d") == 0) {
  2645.     (void)strcpy(buff, "down");
  2646.     return 0;
  2647.     }
  2648.     if (strcmp(buff, "u") == 0) {
  2649.     (void)strcpy(buff, "up");
  2650.     return 0;
  2651.     }
  2652.     if (strcmp(buff, "nw") == 0) {
  2653.     (void)strcpy(buff, "northwest");
  2654.     return 0;
  2655.     }
  2656.     if (strcmp(buff, "ne") == 0) {
  2657.     (void)strcpy(buff, "northeast");
  2658.     return 0;
  2659.     }
  2660.     if (strcmp(buff, "sw") == 0) {
  2661.     (void)strcpy(buff, "southwest");
  2662.     return 0;
  2663.     }
  2664.     if (strcmp(buff, "se") == 0) {
  2665.     (void)strcpy(buff, "southeast");
  2666.     return 0;
  2667.     }
  2668. #endif
  2669.     return 0;
  2670. }
  2671.  
  2672. void print_local_commands() {
  2673.     struct sentence *s;
  2674.  
  2675.     add_message("Current local commands:\n");
  2676.     for (s = command_giver->sent; s; s = s->next)
  2677.     add_message("%s ", s->verb);
  2678.     add_message("\n");
  2679. }
  2680.  
  2681. /*VARARGS1*/
  2682. void fatal(fmt, a, b, c, d, e, f, g, h)
  2683.     char *fmt;
  2684.     int a, b, c, d, e, f, g, h;
  2685. {
  2686.     static int in_fatal = 0;
  2687.     /* Prevent double fatal. */
  2688.     if (in_fatal)
  2689.     abort();
  2690.     in_fatal = 1;
  2691.     (void)fprintf(stderr, fmt, a, b, c, d, e, f, g, h);
  2692.     fflush(stderr);
  2693.     if (current_object)
  2694.     (void)fprintf(stderr, "Current object was %s\n",
  2695.               current_object->name);
  2696.     debug_message(fmt, a, b, c, d, e, f, g, h);
  2697.     if (current_object)
  2698.     debug_message("Current object was %s\n", current_object->name);
  2699.     debug_message("Dump of variables:\n");
  2700. #if defined(DEBUG) && defined(TRACE_CODE)
  2701.     (void)dump_trace(1);
  2702. #else
  2703.     (void)dump_trace();
  2704. #endif
  2705.     abort();
  2706. }
  2707.  
  2708. int num_error = 0;
  2709.  
  2710. /*
  2711.  * Error() has been "fixed" so that users can catch and throw them.
  2712.  * To catch them nicely, we really have to provide decent error information.
  2713.  * Hence, all errors that are to be caught
  2714.  * (error_recovery_context_exists == 2) construct a string containing
  2715.  * the error message, which is returned as the
  2716.  * thrown value.  Users can throw their own error values however they choose.
  2717.  */
  2718.  
  2719. /*
  2720.  * This is here because throw constructs its own return value; we dont
  2721.  * want to replace it with the system's error string.
  2722.  */
  2723.  
  2724. void throw_error() {
  2725.     extern int error_recovery_context_exists;
  2726.     extern jmp_buf error_recovery_context;
  2727.     if (error_recovery_context_exists > 1) {
  2728.     longjmp(error_recovery_context, 1);
  2729.     fatal("Throw_error failed!");
  2730.     }
  2731.     error("Throw with no catch.\n");
  2732. }
  2733.  
  2734. static char emsg_buf[2000];
  2735.  
  2736. /*VARARGS1*/
  2737. void error(fmt, a, b, c, d, e, f, g, h)
  2738.     char *fmt;
  2739.     int a, b, c, d, e, f, g, h;
  2740. {
  2741.     extern int error_recovery_context_exists;
  2742.     extern jmp_buf error_recovery_context;
  2743.     extern struct object *current_heart_beat;
  2744.     extern struct svalue catch_value;
  2745.     char *object_name;
  2746.  
  2747.     sprintf(emsg_buf+1, fmt, a, b, c, d, e, f, g, h);
  2748.     emsg_buf[0] = '*';    /* all system errors get a * at the start */
  2749.  
  2750.     if (error_recovery_context_exists > 1) { /* user catches this error */
  2751.     struct svalue v;
  2752.     v.type = T_STRING;
  2753.     v.u.string = emsg_buf;
  2754.     v.string_type = STRING_MALLOC;    /* Always reallocate */
  2755.     assign_svalue(&catch_value, &v);
  2756.        longjmp(error_recovery_context, 1);
  2757.        fatal("Catch() longjump failed");
  2758.     }
  2759.     num_error++;
  2760.     if (num_error > 1)
  2761.     error("Too many simultaneous errors.\n");
  2762.     debug_message("%s", emsg_buf+1);
  2763.     if (current_object) {
  2764.     debug_message("Current object was %s, line %d\n",
  2765.               current_object->name, current_line);
  2766.     save_error(emsg_buf, current_object->name, current_line);
  2767.     }
  2768. #if defined(DEBUG) && defined(TRACE_CODE)
  2769.     object_name = dump_trace(1);
  2770. #else
  2771.     object_name = dump_trace();
  2772. #endif
  2773.     fflush(stdout);
  2774.     if (object_name) {
  2775.     struct object *ob;
  2776.     ob = find_object2(object_name);
  2777.     if (!ob) {
  2778.         if (command_giver)
  2779.         add_message("error when executing program in destroyed object %s\n",
  2780.                 object_name);
  2781.         debug_message("error when executing program in destroyed object %s\n",
  2782.             object_name);
  2783.     }
  2784.     }
  2785.     if (command_giver && command_giver->interactive) {
  2786.     struct svalue *v = 0;
  2787.  
  2788.     num_error--;
  2789.     /* 
  2790.      * The stack must be brought in a usable state. After the
  2791.      * call to reset_machine(), all arguments to error() are invalid,
  2792.      * and may not be used any more. The reason is that some strings
  2793.      * may have been on the stack machine stack, and has been deallocated.
  2794.      */
  2795.     reset_machine (0);
  2796.     push_constant_string("error messages");
  2797.     v = apply_master_ob("query_player_level", 1);
  2798.     num_error++;
  2799.     if (v && v->u.number != 0) {
  2800.         add_message("%s", emsg_buf+1);
  2801.         if (current_object)
  2802.         add_message("program: %s, object: %s line %d\n",
  2803.                 current_prog ? current_prog->name : "",
  2804.                 current_object->name,
  2805.                 get_line_number_if_any());
  2806.     } else {
  2807.         add_message("Your sensitive mind notices a wrongness in the fabric of space.\n");
  2808.     }
  2809.     }
  2810.     if (current_heart_beat) {
  2811.     set_heart_beat(current_heart_beat, 0);
  2812.     debug_message("Heart beat in %s turned off.\n",
  2813.               current_heart_beat->name);
  2814.     if (current_heart_beat->interactive) {
  2815.         struct object *save_cmd = command_giver;
  2816.         command_giver = current_heart_beat;
  2817.         add_message("Game driver tells you: You have no heart beat !\n");
  2818.         command_giver = save_cmd;
  2819.     }
  2820.     current_heart_beat = 0;
  2821.     }
  2822.     num_error--;
  2823.     if (error_recovery_context_exists)
  2824.     longjmp(error_recovery_context, 1);
  2825.     abort();
  2826. }
  2827.  
  2828. /*
  2829.  * Check that it is an legal path. No '..' are allowed.
  2830.  */
  2831. int legal_path(path)
  2832.     char *path;
  2833. {
  2834.     char *p;
  2835.  
  2836.     if (path == NULL || strchr(path, ' '))
  2837.     return 0;
  2838.     if (path[0] == '/')
  2839.         return 0;
  2840. #ifdef MSDOS
  2841.     if (!valid_msdos(path)) return(0);
  2842. #endif
  2843.     for(p = strchr(path, '.'); p; p = strchr(p+1, '.')) {
  2844.     if (p[1] == '.')
  2845.         return 0;
  2846.     }
  2847.     for (p=strchr(path, '/'); p; p = strchr(p+1, '/')) 
  2848.        if (p[1] == '/') return 0;
  2849.     return 1;
  2850. }
  2851.  
  2852. /*
  2853.  * There is an error in a specific file. Ask the game driver to log the
  2854.  * message somewhere.
  2855.  */
  2856. void smart_log(error_file, line, what)
  2857.      char *error_file, *what;
  2858.      int line;
  2859. {
  2860.     char buff[500];
  2861.  
  2862.     if (error_file == 0)
  2863.     return;
  2864.     if (strlen(what) + strlen(error_file) > sizeof(buff) - 100)
  2865.        what = "...[too long error message]...";
  2866.     if (strlen(what) + strlen(error_file) > sizeof(buff) - 100)
  2867.        error_file = "...[too long file name]...";
  2868.     sprintf(buff, "%s line %d:%s\n", error_file, line, what);
  2869.     push_constant_string(error_file);
  2870.     push_constant_string(buff);
  2871.     apply_master_ob("log_error", 2);
  2872. }
  2873.  
  2874.  
  2875. /*
  2876.  * Check that a file name is valid for read or write.
  2877.  * Also change the name as if the current directory was at the players
  2878.  * own directory.
  2879.  * This is done by functions in the player object.
  2880.  *
  2881.  * The master object (master.c) always have permissions to access
  2882.  * any file in the mudlib hierarchy, but only inside the mudlib.
  2883.  *
  2884.  * WARNING: The string returned will (mostly) be deallocated at next
  2885.  * call of apply().
  2886.  */
  2887. #ifdef COMPAT_MODE
  2888. char debug_check_file[50];
  2889.  
  2890. char *check_file_name(file, writeflg)
  2891. char *file;
  2892. int writeflg;
  2893. {
  2894.    struct svalue *ret;
  2895.    struct object *stuff = command_giver;
  2896.    char *str;
  2897.    
  2898.    if (current_object == master_ob)
  2899.    {
  2900.       /* Master object can read/write anywhere */
  2901.       if (file[0] == '/')
  2902.      str = file+1;
  2903.       else
  2904.      str = file;
  2905.    }
  2906.    else 
  2907.    {  
  2908.       if (!stuff)
  2909.      stuff = find_object("room/church");
  2910.       if (!stuff)
  2911.       {
  2912.      char *temp;
  2913.      struct object *ob;
  2914.      ob=(command_giver?command_giver:current_object);
  2915.      if (!ob) return 0;
  2916.      if (!legal_path(file)) return 0;
  2917.      if (ob->user) 
  2918.      {
  2919.         int tl;
  2920.         tl = strlen(ob->user->name) + 10;
  2921.         temp=(char *)xalloc(tl);
  2922.         strcpy(temp,"players/");
  2923.         strcat(temp,ob->user->name);
  2924.         strcat(temp,"/");
  2925.         if (strncmp(file, temp, tl-1)==0 ||
  2926.         strncmp(file, "open/", 5)==0 ||
  2927.         (!strchr(file, '/') && !writeflg))
  2928.         { 
  2929.            free(temp); 
  2930.            return file; 
  2931.         }
  2932.         else
  2933.         { 
  2934.            free(temp); 
  2935.            return 0; 
  2936.         }
  2937.      }
  2938.      else if (strncmp(ob->name, "open/", 5) == 0 &&
  2939.                   strncmp(file, "open/", 5) == 0)
  2940.         return file;
  2941.      else if (strncmp(ob->name, "obj/", 4) == 0||
  2942.                   strncmp(ob->name, "room/",5) == 0)
  2943.         return file;
  2944.      else return 0;
  2945.       }
  2946.       /*
  2947.        * We don't have to free the string in ret. This is done
  2948.        * by the garbage collection.
  2949.        */
  2950.       else
  2951.       {
  2952.          push_constant_string(file);
  2953.           if (writeflg)
  2954.              ret = apply("valid_write", stuff, 1);
  2955.          else
  2956.          ret = apply("valid_read",  stuff, 1);
  2957.          if (stuff->flags&O_DESTRUCTED)
  2958.         return 0;
  2959.          if (!ret || ret->type != T_STRING) 
  2960.      {
  2961.         add_message("Bad file name %s.\n", file?file:"<null>");
  2962.         return 0;
  2963.          }
  2964.          str = ret->u.string;
  2965.       } 
  2966.    }
  2967.    strncpy(debug_check_file, str, sizeof debug_check_file);
  2968.    debug_check_file[sizeof debug_check_file- 1] = 0;
  2969.    if (!legal_path(str)) 
  2970.    {
  2971.       add_message("Illegal path: %s\n", str?str:"<null>");
  2972.       return 0;
  2973.    }
  2974.    if (str[0] == '\0')
  2975.        return ".";
  2976.    return str;
  2977. }
  2978. #else
  2979.  
  2980. /*
  2981.  * Check that a path to a file is valid for read or write.
  2982.  * This is done by functions in the master object.
  2983.  * The path is always treated as an absolute path, and is returned without
  2984.  * a leading '/'.
  2985.  * If the path was '/', then '.' is returned.
  2986.  * The returned string may or may not be residing inside the argument 'path',
  2987.  * so don't deallocate arg 'path' until the returned result is used no longer.
  2988.  * Otherwise, the returned path is temporarily allocated by apply(), which
  2989.  * means it will be dealocated at next apply().
  2990.  */
  2991. char *check_valid_path(path, eff_user, call_fun, writeflg)
  2992.     char *path;
  2993.     struct wiz_list *eff_user;
  2994.     char *call_fun;
  2995.     int writeflg;
  2996. {
  2997.     struct svalue *v;
  2998.  
  2999.     if (eff_user == 0)
  3000.     return 0;
  3001.     push_string(make_shared_string(path), STRING_SHARED);/**MALLOC**/
  3002.     push_string(eff_user->name, STRING_CONSTANT);
  3003.     push_string(call_fun, STRING_CONSTANT);
  3004.     if (writeflg)
  3005.     v = apply_master_ob("valid_write", 3);
  3006.     else
  3007.     v = apply_master_ob("valid_read", 3);
  3008.     if (v && v->type == T_NUMBER && v->u.number == 0)
  3009.     return 0;
  3010.     if (path[0] == '/')
  3011.        path++;
  3012.     if (legal_path(path)) 
  3013.         return path;
  3014.     else
  3015.         return 0;
  3016. }
  3017. #endif
  3018.  
  3019. /*
  3020.  * This one is called from HUP.
  3021.  */
  3022. int game_is_being_shut_down;
  3023.  
  3024. #ifndef _AIX
  3025. void startshutdowngame() {
  3026.     (void)signal(SIGHUP, startshutdowngame);
  3027.     game_is_being_shut_down = 1;
  3028. }
  3029. #else
  3030. void startshutdowngame(int arg) {
  3031.     game_is_being_shut_down = 1;
  3032. }
  3033. #endif
  3034.  
  3035. /*
  3036.  * This one is called from the command "shutdown".
  3037.  * We don't call it directly from HUP, because it is dangerous when being
  3038.  * in an interrupt.
  3039.  */
  3040. void shutdowngame() {
  3041.     shout_string("Game driver shouts: LPmud shutting down immediately.\n");
  3042.     save_wiz_file();
  3043.     ipc_remove();
  3044.     remove_all_players();
  3045.     unlink_swap_file();
  3046. #ifdef DEALLOCATE_MEMORY_AT_SHUTDOWN
  3047.     remove_all_objects();
  3048.     free_all_sent();
  3049.     free_all_call_outs();
  3050.     remove_wiz_list();
  3051.     dump_malloc_data();
  3052. #endif
  3053. #ifdef OPCPROF
  3054.     opcdump();
  3055. #endif
  3056.     exit(0);
  3057. }
  3058.  
  3059. /*
  3060.  * Transfer an object from an object to an object.
  3061.  * Call add_weight(), drop(), get(), prevent_insert(), add_weight(),
  3062.  * and can_put_and_get() where needed.
  3063.  * Return 0 on success, and special code on failure:
  3064.  *
  3065.  * 1: To heavy for destination.
  3066.  * 2: Can't be dropped.
  3067.  * 3: Can't take it out of it's container.
  3068.  * 4: The object can't be inserted into bags etc.
  3069.  * 5: The destination doesn't allow insertions of objects.
  3070.  * 6: The object can't be picked up.
  3071.  */
  3072. #ifdef F_TRANSFER
  3073. int transfer_object(ob, to)
  3074.     struct object *ob, *to;
  3075. {
  3076.     struct svalue *v_weight, *ret;
  3077.     int weight;
  3078.     struct object *from = ob->super;
  3079.  
  3080.     /*
  3081.      * Get the weight of the object
  3082.      */
  3083. #ifndef COMPAT_MODE
  3084.     error("transfer() not allowed.\n");
  3085. #endif
  3086.     if (ob->shadowing)
  3087.         error("transfer: cannot move object that is shadowing.\n");
  3088.     v_weight = apply("query_weight", ob, 0);
  3089.     if (v_weight && v_weight->type != T_NUMBER)
  3090.     error("Bad type the weight of object in transfer()\n");
  3091.     weight = 0;
  3092.     if (v_weight)
  3093.     weight = v_weight->u.number;
  3094.     if (ob->flags & O_DESTRUCTED)
  3095.     return 3;
  3096.     /*
  3097.      * If the original place of the object is a living object,
  3098.      * then we must call drop() to check that the object can be dropped.
  3099.      */
  3100.     if (from && (from->flags & O_ENABLE_COMMANDS)) {
  3101.     ret = apply("drop", ob, 0);
  3102.     if (ret && (ret->type != T_NUMBER || ret->u.number != 0))
  3103.         return 2;
  3104.     /* This shold not happen, but we can not trust LPC hackers. :-) */
  3105.     if (ob->flags & O_DESTRUCTED)
  3106.         return 2;
  3107.     }
  3108.     /*
  3109.      * If 'from' is not a room and not a player, check that we may
  3110.      * remove things out of it.
  3111.      */
  3112.     if (from && from->super && !(from->flags & O_ENABLE_COMMANDS)) {
  3113.     ret = apply("can_put_and_get", from, 0);
  3114.     if (!ret || (ret->type != T_NUMBER && ret->u.number != 1) ||
  3115.       (from->flags & O_DESTRUCTED))
  3116.         return 3;
  3117.     }
  3118.     /*
  3119.      * If the destination is not a room, and not a player,
  3120.      * Then we must test 'prevent_insert', and 'can_put_and_get'.
  3121.      */
  3122.     if (to->super && !(to->flags & O_ENABLE_COMMANDS)) {
  3123.     ret = apply("prevent_insert", ob, 0);
  3124.     if (ret && (ret->type != T_NUMBER || ret->u.number != 0))
  3125.         return 4;
  3126.     ret = apply("can_put_and_get", to, 0);
  3127.     if (!ret || (ret->type != T_NUMBER && ret->type != 0) ||
  3128.       (to->flags & O_DESTRUCTED) || (ob->flags & O_DESTRUCTED))
  3129.         return 5;
  3130.     }
  3131.     /*
  3132.      * If the destination is a player, check that he can pick it up.
  3133.      */
  3134.     if (to->flags & O_ENABLE_COMMANDS) {
  3135.     ret = apply("get", ob, 0);
  3136.     if (!ret || (ret->type == T_NUMBER && ret->u.number == 0) ||
  3137.       (ob->flags & O_DESTRUCTED))
  3138.         return 6;
  3139.     }
  3140.     /*
  3141.      * If it is not a room, correct the total weight in the destination.
  3142.      */
  3143.     if (to->super && weight) {
  3144.     /*
  3145.      * Check if the destination can carry that much.
  3146.      */
  3147.     push_number(weight);
  3148.         ret = 0;
  3149.     ret = apply("add_weight", to, 1);
  3150.     if (ret && ret->type == T_NUMBER && ret->u.number == 0)
  3151.         return 1;
  3152.     if (to->flags & O_DESTRUCTED)
  3153.         return 1;
  3154.     }
  3155.     /*
  3156.      * If it is not a room, correct the weight in the 'from' object.
  3157.      */
  3158.     if (from && from->super && weight) {
  3159.     push_number(-weight);
  3160.     (void)apply("add_weight", from, 1);
  3161.         if (from->flags & O_DESTRUCTED)
  3162.            return 1;
  3163.     }
  3164.     move_object(ob, to);
  3165.     return 0;
  3166. }
  3167. #endif /* F_TRANSFER */
  3168.  
  3169. /*
  3170.  * Move or destruct one object.
  3171.  */
  3172. void move_or_destruct(what, to)
  3173.     struct object *what, *to;
  3174. {
  3175.     int res;
  3176.     struct svalue v;
  3177.  
  3178. #ifdef COMPAT_MODE
  3179.     res = transfer_object(what, to);
  3180.     if (res == 0 || (what->flags & O_DESTRUCTED))
  3181.         return;
  3182.     if (res == 1 || res == 4 || res == 5) {
  3183.         if (to->super) {
  3184.              move_or_destruct(what, to->super);
  3185.              return;
  3186.         }
  3187.     }
  3188. #else
  3189.     {
  3190.     struct svalue *svp;
  3191.     push_object(to, "move_or_destruct");
  3192.         push_number(1);
  3193.     svp = apply("move", what, 2);
  3194.     if (svp && svp->type == T_NUMBER && svp->u.number == 0)
  3195.         return;
  3196.     if (what->flags & O_DESTRUCTED)
  3197.         return;
  3198.     }
  3199. #endif
  3200.     
  3201.     v.type = T_OBJECT;
  3202.     v.u.ob = what;
  3203.     destruct_object(&v, 0);
  3204. }
  3205.  
  3206. /*
  3207.  * Call this one when there is only little memory left. It will start
  3208.  * Armageddon.
  3209.  */
  3210. void slow_shut_down(minutes)
  3211.     int minutes;
  3212. {
  3213.     struct object *ob;
  3214.  
  3215.     /*
  3216.      * Swap out objects, and free some memory.
  3217.      */
  3218.     ob = find_object("obj/shut");
  3219.     if (!ob) {
  3220.     struct object *save_current = current_object,
  3221.                   *save_command = command_giver;
  3222.     command_giver = 0;
  3223.     current_object = 0;
  3224.     shout_string("Game driver shouts: Out of memory.\n");
  3225.     command_giver = save_command;
  3226.     current_object = save_current;
  3227. #ifndef _AIX
  3228.     startshutdowngame();
  3229. #else
  3230.         startshutdowngame(1);
  3231. #endif
  3232.     return;
  3233.     }
  3234.     shout_string("Game driver shouts: The memory is getting low !\n");
  3235.     push_number(minutes);
  3236.     (void)apply("shut", ob, 1);
  3237. }
  3238.  
  3239. int match_string(match, str)
  3240.     char *match, *str;
  3241. {
  3242.     int i;
  3243.  
  3244.  again:
  3245.     if (*str == '\0' && *match == '\0')
  3246.     return 1;
  3247.     switch(*match) {
  3248.     case '?':
  3249.     if (*str == '\0')
  3250.         return 0;
  3251.     str++;
  3252.     match++;
  3253.     goto again;
  3254.     case '*':
  3255.     match++;
  3256.     if (*match == '\0')
  3257.         return 1;
  3258.     for (i=0; str[i] != '\0'; i++)
  3259.         if (match_string(match, str+i))
  3260.         return 1;
  3261.     return 0;
  3262.     case '\0':
  3263.     return 0;
  3264.     case '\\':
  3265.     match++;
  3266.     if (*match == '\0')
  3267.         return 0;
  3268.     /* Fall through ! */
  3269.     default:
  3270.     if (*match == *str) {
  3271.         match++;
  3272.         str++;
  3273.         goto again;
  3274.     }
  3275.     return 0;
  3276.     }
  3277. }
  3278.  
  3279. /*
  3280.  * Credits for some of the code below goes to Free Software Foundation
  3281.  * Copyright (C) 1990 Free Software Foundation, Inc.
  3282.  * See the GNU General Public License for more details.
  3283.  */
  3284. #ifndef S_ISDIR
  3285. #define    S_ISDIR(m)    (((m)&S_IFMT) == S_IFDIR)
  3286. #endif
  3287.  
  3288. #ifndef S_ISREG
  3289. #define    S_ISREG(m)    (((m)&S_IFMT) == S_IFREG)
  3290. #endif
  3291.  
  3292. int
  3293. isdir (path)
  3294.      char *path;
  3295. {
  3296.   struct stat stats;
  3297.  
  3298.   return stat (path, &stats) == 0 && S_ISDIR (stats.st_mode);
  3299. }
  3300.  
  3301. void
  3302. strip_trailing_slashes (path)
  3303.      char *path;
  3304. {
  3305.   int last;
  3306.  
  3307.   last = strlen (path) - 1;
  3308.   while (last > 0 && path[last] == '/')
  3309.     path[last--] = '\0';
  3310. }
  3311.  
  3312. struct stat to_stats, from_stats;
  3313.  
  3314. int
  3315. copy (from, to)
  3316.      char *from, *to;
  3317. {
  3318.   int ifd;
  3319.   int ofd;
  3320.   char buf[1024 * 8];
  3321.   int len;            /* Number of bytes read into `buf'. */
  3322.   
  3323.   if (!S_ISREG (from_stats.st_mode))
  3324.     {
  3325.       error ("cannot move `%s' across filesystems: Not a regular file\n", from);
  3326.       return 1;
  3327.     }
  3328.   
  3329.   if (unlink (to) && errno != ENOENT)
  3330.     {
  3331.       error ("cannot remove `%s'\n", to);
  3332.       return 1;
  3333.     }
  3334.  
  3335.   ifd = open (from, O_RDONLY, 0);
  3336.   if (ifd < 0)
  3337.     {
  3338.       error ("%s: open failed\n", from);
  3339.       return errno;
  3340.     }
  3341.   ofd = open (to, O_WRONLY | O_CREAT | O_TRUNC, 0600);
  3342.   if (ofd < 0)
  3343.     {
  3344.       error ("%s: open failed\n", to);
  3345.       close (ifd);
  3346.       return 1;
  3347.     }
  3348. #ifndef FCHMOD_MISSING
  3349.   if (fchmod (ofd, from_stats.st_mode & 0777))
  3350.     {
  3351.       error ("%s: fchmod failed\n", to);
  3352.       close (ifd);
  3353.       close (ofd);
  3354.       unlink (to);
  3355.       return 1;
  3356.     }
  3357. #endif
  3358.   
  3359.   while ((len = read (ifd, buf, sizeof (buf))) > 0)
  3360.     {
  3361.       int wrote = 0;
  3362.       char *bp = buf;
  3363.       
  3364.       do
  3365.     {
  3366.       wrote = write (ofd, bp, len);
  3367.       if (wrote < 0)
  3368.         {
  3369.           error ("%s: write failed\n", to);
  3370.           close (ifd);
  3371.           close (ofd);
  3372.           unlink (to);
  3373.           return 1;
  3374.         }
  3375.       bp += wrote;
  3376.       len -= wrote;
  3377.     } while (len > 0);
  3378.     }
  3379.   if (len < 0)
  3380.     {
  3381.       error ("%s: read failed\n", from);
  3382.       close (ifd);
  3383.       close (ofd);
  3384.       unlink (to);
  3385.       return 1;
  3386.     }
  3387.  
  3388.   if (close (ifd) < 0)
  3389.     {
  3390.       error ("%s: close failed", from);
  3391.       close (ofd);
  3392.       return 1;
  3393.     }
  3394.   if (close (ofd) < 0)
  3395.     {
  3396.       error ("%s: close failed", to);
  3397.       return 1;
  3398.     }
  3399.   
  3400. #ifdef FCHMOD_MISSING
  3401.   if (chmod (to, from_stats.st_mode & 0777))
  3402.     {
  3403.       error ("%s: chmod failed\n", to);
  3404.       return 1;
  3405.     }
  3406. #endif
  3407.  
  3408.   return 0;
  3409. }
  3410.  
  3411. #if 0
  3412. /* Move FROM onto TO.  Handles cross-filesystem moves.
  3413.    If TO is a directory, FROM must be also.
  3414.    Return 0 if successful, 1 if an error occurred.  */
  3415.  
  3416. int
  3417. do_move (from, to)
  3418.      char *from;
  3419.      char *to;
  3420. {
  3421.   if (lstat (from, &from_stats) != 0)
  3422.       return 0;
  3423.  
  3424.   if (lstat (to, &to_stats) == 0)
  3425.     {
  3426. #ifndef MSDOS
  3427.       if (from_stats.st_dev == to_stats.st_dev
  3428.       && from_stats.st_ino == to_stats.st_ino)
  3429. #else
  3430.       if (same_file(from,  to))
  3431. #endif
  3432.       return 0;
  3433.  
  3434.       if (S_ISDIR (to_stats.st_mode))
  3435.       return 0;
  3436.  
  3437.     }
  3438.   else if (errno != ENOENT)
  3439.       return 0;
  3440. #ifdef SYSV
  3441.   if (isdir(from)) {
  3442.       char cmd_buf[100];
  3443.       sprintf(cmd_buf, "/usr/lib/mv_dir %s %s", from, to);
  3444.       return system(cmd_buf);
  3445.   } else
  3446. #endif /* SYSV */      
  3447.   if (rename (from, to) == 0)
  3448.     {
  3449.       return 1;
  3450.     }
  3451.  
  3452.   if (errno != EXDEV)
  3453.       return 0;
  3454.  
  3455.   /* rename failed on cross-filesystem link.  Copy the file instead. */
  3456.  
  3457.   if (copy (from, to))
  3458.       return 0;
  3459.   
  3460.   if (unlink (from))
  3461.       return 0;
  3462.  
  3463.   return 1;
  3464. }
  3465.     
  3466. /*
  3467.  * do_rename is used by the efun rename. It is basically a combination
  3468.  * of the unix system call rename and the unix command mv. Please shoot
  3469.  * the people at ATT who made Sys V.
  3470.  */
  3471.  
  3472. #ifdef F_RENAME
  3473. int
  3474. do_rename(fr, t)
  3475.     char *fr, *t;
  3476. {
  3477.     char *from, *to;
  3478.     
  3479.     from = check_valid_path(fr, current_object->eff_user, "do_rename", 1);
  3480.     if(!from)
  3481.     return 1;
  3482.     to = check_valid_path(t, current_object->eff_user, "do_rename", 1);
  3483.     if(!to)
  3484.     return 1;
  3485.     if(!strlen(to) && !strcmp(t, "/")) {
  3486.     to = (char *)alloca(3);
  3487.     sprintf(to, "./");
  3488.     }
  3489.     strip_trailing_slashes (from);
  3490.     if (isdir (to))
  3491.     {
  3492.         /* Target is a directory; build full target filename. */
  3493.         char *cp;
  3494.         char *newto;
  3495.         
  3496.         cp = strrchr (from, '/');
  3497.         if (cp)
  3498.         cp++;
  3499.         else
  3500.         cp = from;
  3501.         
  3502.         newto = (char *) alloca (strlen (to) + 1 + strlen (cp) + 1);
  3503.         sprintf (newto, "%s/%s", to, cp);
  3504.         return do_move (from, newto);
  3505.     }
  3506.     else
  3507.     return do_move (from, to);
  3508. }
  3509.  
  3510. #endif
  3511.  
  3512. #ifdef LEX_lexical
  3513. void pre_compile(str)
  3514.     char *str;
  3515. {
  3516.     char *c_name, *i_name, buff[1000];
  3517.     FILE *f;
  3518.  
  3519.     if(!legal_path(str))
  3520.     error("Illegal attempt to access %s\n",str);
  3521.     i_name = xalloc(strlen(str)+3);
  3522.     (void)strcpy(i_name, str);
  3523.     (void)strcat(i_name, ".i");
  3524.     c_name = (char *)xalloc(strlen(str)+3);
  3525.     (void)strcpy(c_name, str);
  3526.     (void)strcat(c_name, ".c");
  3527.     sprintf(buff, "%s %s %s", PRE_COMPILE, c_name, i_name);
  3528.     f = (FILE *)vpopen(buff, "r");
  3529.     if (f == 0) {
  3530.     error("Unable to invoke precompiler!\n");
  3531.     alarm(0);
  3532.     }
  3533.     while(1) {
  3534.     if (fgets(buff, sizeof buff, f) == 0)
  3535.         break;
  3536.     add_message("%s", buff);
  3537.     }
  3538.     vpclose(f);
  3539.     free((char *)c_name);
  3540.     free((char *)i_name);
  3541. }
  3542. #endif
  3543. #endif /* F_RENAME */
  3544.  
  3545.