home *** CD-ROM | disk | FTP | other *** search
/ Shareware Overload / ShartewareOverload.cdr / games / tinymud2.zip / GAME.C < prev    next >
C/C++ Source or Header  |  1990-09-02  |  14KB  |  696 lines

  1. #include "copyright.h"
  2.  
  3. #include <stdio.h>
  4. #include <ctype.h>
  5. #include <signal.h>
  6. #include <sys/wait.h>
  7. #include <time.h>
  8. #include <stdarg.h>
  9.     
  10. #include "db.h"
  11. #include "config.h"
  12. #include "interface.h"
  13. #include "match.h"
  14. #include "externs.h"
  15.  
  16. /* declarations */
  17. static const char *dumpfile = 0;
  18. static int epoch = 0;
  19. static int alarm_triggered = 0;
  20. static int alarm_block = 0;
  21.  
  22. static void fork_and_dump(void);
  23. void dump_database(void);
  24.  
  25. void do_dump(dbref player)
  26. {
  27.     if(Wizard(player)) {
  28.     alarm_triggered = 1;
  29.     notify(player, "Dumping...");
  30.     } else {
  31.     notify(player, "Sorry, you are in a no dumping zone.");
  32.     }
  33. }
  34.  
  35. void do_shutdown(dbref player)
  36. {
  37.     if(Wizard(player)) {
  38.     writelog("SHUTDOWN: by %s\n", unparse_object(player, player));
  39.     fflush(stderr);
  40.     shutdown_flag = 1;
  41.     } else {
  42.     notify(player, "Your delusions of grandeur have been duly noted.");
  43.     }
  44. }
  45.     
  46. /* should be void, but it's defined as int */
  47. static int alarm_handler(void)
  48. {
  49.     alarm_triggered = 1;
  50.     if(!alarm_block) {
  51.         fork_and_dump();
  52.     }
  53.     return 0;
  54. }
  55.  
  56. static void dump_database_internal(void)
  57. {
  58.     char tmpfile[2048];
  59.     FILE *f;
  60.  
  61.     sprintf(tmpfile, "%s.#%d#", dumpfile, epoch - 1);
  62.     unlink(tmpfile);        /* nuke our predecessor */
  63.  
  64.     sprintf(tmpfile, "%s.#%d#", dumpfile, epoch);
  65.  
  66.     if((f = fopen(tmpfile, "w")) != NULL) {
  67.     db_write(f);
  68.     fclose(f);
  69.     if(rename(tmpfile, dumpfile) < 0) perror(tmpfile);
  70.     } else {
  71.     perror(tmpfile);
  72.     }
  73. }
  74.  
  75. void panic(const char *message)
  76. {
  77.     char panicfile[2048];
  78.     FILE *f;
  79.     int i;
  80.  
  81.     writelog("PANIC: %s\n", message);
  82.  
  83.     /* turn off signals */
  84.     for(i = 0; i < NSIG; i++) {
  85.     signal(i, SIG_IGN);
  86.     }
  87.  
  88.     /* shut down interface */
  89.     emergency_shutdown();
  90.  
  91.     /* dump panic file */
  92.     sprintf(panicfile, "%s.PANIC", dumpfile);
  93.     if((f = fopen(panicfile, "w")) == NULL) {
  94.     perror("CANNOT OPEN PANIC FILE, YOU LOSE:");
  95. #ifndef NODUMPCORE
  96.     signal(SIGILL, SIG_DFL);
  97.     abort();
  98. #endif NODUMPCORE
  99.     _exit(135);
  100.     } else {
  101.     writelog("DUMPING: %s\n", panicfile);
  102.     db_write(f);
  103.     fclose(f);
  104.     writelog("DUMPING: %s (done)\n", panicfile);
  105. #ifndef NODUMPCORE
  106.     signal(SIGILL, SIG_DFL);
  107.     abort();
  108. #endif NODUMPCORE
  109.     _exit(136);
  110.     }
  111. }
  112.  
  113. void writelog(const char *fmt, ...)
  114. {
  115.     va_list list;
  116.     struct tm *tm;
  117.     long t;
  118.     char buffer[2048];
  119.  
  120.     va_start(list, fmt);
  121.     vsprintf(buffer, fmt, list);
  122.     t = time(NULL);
  123.     tm = localtime(&t);
  124.     fprintf(stderr, "%d/%02d %02d:%02d:%02d %s",
  125.         tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
  126.         buffer);
  127.     fflush(stderr);
  128.     va_end(list);
  129. }
  130.  
  131. void dump_database(void)
  132. {
  133.     epoch++;
  134.  
  135.     writelog("DUMPING: %s.#%d#\n", dumpfile, epoch);
  136.     dump_database_internal();
  137.     writelog("DUMPING: %s.#%d# (done)\n", dumpfile, epoch);
  138. }
  139.  
  140. static void fork_and_dump(void)
  141. {
  142.     int child;
  143.  
  144.     epoch++;
  145.  
  146.     writelog("CHECKPOINTING: %s.#%d#\n", dumpfile, epoch);
  147. #ifdef USE_VFORK
  148.     child = vfork();
  149. #else /* USE_VFORK */
  150.     child = fork();
  151. #endif /* USE_VFORK */
  152.     if(child == 0) {
  153.     /* in the child */
  154.     close(0);        /* get that file descriptor back */
  155.     dump_database_internal();
  156.     _exit(0);        /* !!! */
  157.     } else if(child < 0) {
  158.     perror("fork_and_dump: fork()");
  159.     }
  160.     
  161.     /* in the parent */
  162.     /* reset alarm */
  163.     alarm_triggered = 0;
  164.     alarm(DUMP_INTERVAL);
  165. }
  166.  
  167. static int reaper(void)
  168. {
  169.     union wait stat;
  170.  
  171.     while(wait3(&stat, WNOHANG, 0) > 0);
  172.     return 0;
  173. }
  174.  
  175. int init_game(const char *infile, const char *outfile)
  176. {
  177.    FILE *f;
  178.  
  179.    if((f = fopen(infile, "r")) == NULL) return -1;
  180.    
  181.    /* ok, read it in */
  182.    writelog("LOADING: %s\n", infile);
  183.    if(db_read(f) < 0) return -1;
  184.    writelog("LOADING: %s (done)\n", infile);
  185.  
  186.    /* everything ok */
  187.    fclose(f);
  188.  
  189.    /* initialize random number generator */
  190.    srandom(getpid());
  191.  
  192.    /* set up dumper */
  193.    if(dumpfile) free((void *) dumpfile);
  194.    dumpfile = alloc_string(outfile);
  195.    signal(SIGALRM, (void (*)) alarm_handler);
  196.    signal(SIGHUP, (void (*)) alarm_handler);
  197.    signal(SIGCHLD, (void (*)) reaper);
  198.    alarm_triggered = 0;
  199.    alarm(DUMP_INTERVAL);
  200.    
  201.    return 0;
  202. }
  203.  
  204. /* use this only in process_command */
  205. #define Matched(string) { if(!string_prefix((string), command)) goto bad; }
  206.  
  207. void process_command(dbref player, char *command)
  208. {
  209.     char *arg1;
  210.     char *arg2;
  211.     char *q;            /* utility */
  212.     char *p;            /* utility */
  213.  
  214.     char *index(char *, char);
  215.  
  216.     if(command == 0) abort();
  217.  
  218.     /* robustify player */
  219.     if(player < 0 || player >= db_top || Typeof(player) != TYPE_PLAYER) {
  220.     writelog("process_command: bad player %d\n", player);
  221.     return;
  222.     }
  223.  
  224. #ifdef LOG_COMMANDS
  225.     writelog("COMMAND from %s(%d) in %s(%d): %s\n",
  226.         db[player].name, player,
  227.         db[db[player].location].name, db[player].location,
  228.         command);
  229. #endif /* LOG_COMMANDS */
  230.  
  231.     /* eat leading whitespace */
  232.     while(*command && isspace(*command)) command++;
  233.  
  234.     /* eat extra white space */
  235.     q = p = command;
  236.     while(*p) {
  237.     /* scan over word */
  238.     while(*p && !isspace(*p)) *q++ = *p++;
  239.     /* smash spaces */
  240.     while(*p && isspace(*++p));
  241.     if(*p) *q++ = ' '; /* add a space to separate next word */
  242.     }
  243.     /* terminate */
  244.     *q = '\0';
  245.  
  246.     /* block dump to prevent db inconsistencies from showing up */
  247.     alarm_block = 1;
  248.  
  249.     /* check for single-character commands */
  250.     if(*command == SAY_TOKEN) {
  251.     do_say(player, command+1, NULL);
  252.     } else if(*command == POSE_TOKEN) {
  253.     do_pose(player, command+1, NULL);
  254.     } else if(can_move(player, command)) {
  255.     /* command is an exact match for an exit */
  256.     do_move(player, command);
  257.     } else {
  258.     /* parse arguments */
  259.  
  260.     /* find arg1 */
  261.     /* move over command word */
  262.     for(arg1 = command; *arg1 && !isspace(*arg1); arg1++);
  263.     /* truncate command */
  264.     if(*arg1) *arg1++ = '\0';
  265.  
  266.     /* move over spaces */
  267.     while(*arg1 && isspace(*arg1)) arg1++;
  268.  
  269.     /* find end of arg1, start of arg2 */
  270.     for(arg2 = arg1; *arg2 && *arg2 != ARG_DELIMITER; arg2++);
  271.  
  272.     /* truncate arg1 */
  273.     for(p = arg2 - 1; p >= arg1 && isspace(*p); p--) *p = '\0';
  274.  
  275.     /* go past delimiter if present */
  276.     if(*arg2) *arg2++ = '\0';
  277.     while(*arg2 && isspace(*arg2)) arg2++;
  278.  
  279.     switch(command[0]) {
  280.       case '@':
  281.         switch(command[1]) {
  282.           case 'b':
  283.           case 'B':
  284.               switch (command[2]) {
  285.           case 'o':
  286.           case 'O':
  287.             switch (command[3]) {
  288.               case 'o':
  289.               case 'O':    Matched("@boot");
  290.                 do_boot(player, arg1);
  291.                       break;
  292.               case 'b':
  293.               case 'B':    if(string_compare(command, "@bobble")) goto bad;
  294.                 do_bobble(player, arg1, arg2);
  295.                 break;
  296.              default:    goto bad;
  297.             }
  298.             break;
  299.           default: goto bad;
  300.         }
  301.         break;
  302.           case 'c':
  303.           case 'C':
  304.         /* chown, create */
  305.         switch(command[2]) {
  306.           case 'h':
  307.           case 'H':
  308.             Matched("@chown");
  309.             do_chown(player, arg1, arg2);
  310.             break;
  311. #ifdef RECYCLE
  312.           case 'o':
  313.           case 'O':
  314.             Matched("@count");
  315.             do_count(player, arg1);
  316.             break;
  317. #endif RECYCLE
  318.           case 'r':
  319.           case 'R':
  320.             Matched("@create");
  321.             do_create(player, arg1, atol(arg2));
  322.             break;
  323.           default:
  324.             goto bad;
  325.         }
  326.         break;
  327.           case 'd':
  328.           case 'D':
  329.         /* describe, dig, or dump */
  330.         switch(command[2]) {
  331.           case 'e':
  332.           case 'E':
  333.             Matched("@describe");
  334.             do_describe(player, arg1, arg2);
  335.             break;
  336.           case 'i':
  337.           case 'I':
  338.             Matched("@dig");
  339.             do_dig(player, arg1);
  340.             break;
  341.           case 'u':
  342.           case 'U':
  343.             Matched("@dump");
  344.             do_dump(player);
  345.             break;
  346.           default:
  347.             goto bad;
  348.         }
  349.         break;
  350.           case 'f':
  351.         /* fail, find, or force */
  352.         switch(command[2]) {
  353.           case 'a':
  354.           case 'A':
  355.             Matched("@fail");
  356.             do_fail(player, arg1, arg2);
  357.             break;
  358.           case 'i':
  359.           case 'I':
  360.             Matched("@find");
  361.             do_find(player, arg1);
  362.             break;
  363.           case 'o':
  364.           case 'O':
  365.             Matched("@force");
  366.             do_force(player, arg1, arg2);
  367.             break;
  368.           default:
  369.             goto bad;
  370.         }
  371.         break;
  372.           case 'l':
  373.           case 'L':
  374.         /* lock or link */
  375.         switch(command[2]) {
  376.           case 'i':
  377.           case 'I':
  378.             Matched("@link");
  379.             do_link(player, arg1, arg2);
  380.             break;
  381.           case 'o':
  382.           case 'O':
  383.             Matched("@lock");
  384.             do_lock(player, arg1, arg2);
  385.             break;
  386.           default:
  387.             goto bad;
  388.         }
  389.         break;
  390.           case 'm':
  391.           case 'M':
  392.               Matched("@mass_teleport");
  393.         do_mass_teleport(player, arg1);
  394.               break;
  395.           case 'n':
  396.           case 'N':
  397.         /* @name or @newpassword */
  398.         switch(command[2]) {
  399.           case 'a':
  400.           case 'A':
  401.             Matched("@name");
  402.             do_name(player, arg1, arg2);
  403.             break;
  404.           case 'e':
  405.             if(strcmp(command, "@newpassword")) goto bad;
  406.             do_newpassword(player, arg1, arg2);
  407.             break;
  408.           default:
  409.             goto bad;
  410.         }
  411.         break;
  412.           case 'o':
  413.           case 'O':
  414.         switch(command[2]) {
  415.           case 'f':
  416.           case 'F':
  417.             Matched("@ofail");
  418.             do_ofail(player, arg1, arg2);
  419.             break;
  420.           case 'p':
  421.           case 'P':
  422.             Matched("@open");
  423.             do_open(player, arg1, arg2);
  424.             break;
  425.           case 's':
  426.           case 'S':
  427.             Matched("@osuccess");
  428.             do_osuccess(player, arg1, arg2);
  429.             break;
  430.           case 'w':
  431.           case 'W':
  432.             Matched("@owned");
  433.             do_owned(player, arg1);
  434.             break;
  435.           default:
  436.             goto bad;
  437.         }
  438.         break;
  439.           case 'p':
  440.           case 'P':
  441.          switch(command[2]) {
  442.            case 'a':
  443.            case 'A':
  444.              Matched("@password");
  445.              do_password(player, arg1, arg2);
  446.              break;
  447. #ifdef REGISTRATION            
  448.            case 'c':
  449.            case 'C':
  450.              Matched("@pcreate");
  451.              do_pcreate(player, arg1, arg2);
  452.              break;
  453. #endif REGISTRATION
  454.               default: goto bad;
  455.          }
  456.         break;
  457. #ifdef RECYCLE
  458.           case 'r':
  459.           case 'R':
  460.               /* Recycle */
  461.         Matched("@recycle");
  462.         do_recycle(player, arg1);
  463.         break;
  464. #endif RECYCLE
  465.           case 's':
  466.           case 'S':
  467.         /* set, shutdown, success */
  468.         switch(command[2]) {
  469.           case 'e':
  470.           case 'E':
  471.             Matched("@set");
  472.             do_set(player, arg1, arg2);
  473.             break;
  474.           case 'h':
  475.             if(strcmp(command, "@shutdown")) goto bad;
  476.             do_shutdown(player);
  477.             break;
  478.           case 't':
  479.           case 'T':
  480.             Matched("@stats");
  481.             do_stats(player, arg1);
  482.             break;
  483.           case 'u':
  484.           case 'U':
  485.             Matched("@success");
  486.             do_success(player, arg1, arg2);
  487.             break;
  488.           default:
  489.             goto bad;
  490.         }
  491.         break;
  492.           case 't':
  493.           case 'T':
  494.         switch(command[2]) {
  495.           case 'e':
  496.           case 'E':
  497.             Matched("@teleport");
  498.             do_teleport(player, arg1, arg2);
  499.             break;
  500.           case 'o':
  501.           case 'O':
  502.             if(string_compare(command, "@toad")) goto bad;
  503.             do_bobble(player, arg1, arg2);
  504.             break;
  505.           default:
  506.             goto bad;
  507.         }
  508.         break;
  509.           case 'u':
  510.           case 'U':
  511.         if(string_prefix(command, "@unli")) {
  512.             Matched("@unlink");
  513.             do_unlink(player, arg1);
  514.         } else if(string_prefix(command, "@unlo")) {
  515.             Matched("@unlock");
  516.             do_unlock(player, arg1);
  517.         } else if(string_prefix(command, "@unb")) {
  518.             Matched("@unbobble");
  519.             do_unbobble(player, arg1, arg2);
  520.         } else if(string_prefix(command, "@unt")) {
  521.             Matched("@untoad");
  522.             do_unbobble(player, arg1, arg2);
  523.         } else {
  524.             goto bad;
  525.         }
  526.         break;
  527.           case 'w':
  528.         if(strcmp(command, "@wall")) goto bad;
  529.         do_wall(player, arg1, arg2);
  530.         break;
  531.           default:
  532.         goto bad;
  533.         }
  534.         break;
  535.       case 'd':
  536.       case 'D':
  537.         Matched("drop");
  538.         do_drop(player, arg1);
  539.         break;
  540.       case 'e':
  541.       case 'E':
  542.         if (command[1] == 'x' || command[1] == 'X') {
  543.         Matched("examine");
  544.         do_examine(player, arg1);
  545.         break;
  546.         } else {
  547.         goto bad;
  548.         }
  549.       case 'g':
  550.       case 'G':
  551.         /* get, give, go, or gripe */
  552.         switch(command[1]) {
  553.           case 'e':
  554.           case 'E':
  555.         Matched("get");
  556.         do_get(player, arg1);
  557.         break;
  558.           case 'i':
  559.           case 'I':
  560.         Matched("give");
  561.         do_give(player, arg1, atol(arg2));
  562.         break;
  563.           case 'o':
  564.           case 'O':
  565.         Matched("goto");
  566.         do_move(player, arg1);
  567.         break;
  568.           case 'r':
  569.           case 'R':
  570.         Matched("gripe");
  571.         do_gripe(player, arg1, arg2);
  572.         break;
  573.           default:
  574.         goto bad;
  575.         }
  576.         break;
  577.       case 'h':
  578.       case 'H':
  579.         Matched("help");
  580.         do_help(player);
  581.         break;
  582.       case 'i':
  583.       case 'I':
  584.         Matched("inventory");
  585.         do_inventory(player);
  586.         break;
  587.       case 'k':
  588.       case 'K':
  589.         Matched("kill");
  590.         do_kill(player, arg1, atol(arg2));
  591.         break;
  592.       case 'l':
  593.       case 'L':
  594.         Matched("look");
  595.         do_look_at(player, arg1);
  596.         break;
  597.       case 'm':
  598.       case 'M':
  599.         Matched("move");
  600.         do_move(player, arg1);
  601.         break;
  602.       case 'n':
  603.       case 'N':
  604.         /* news */
  605.         if(string_compare(command, "news")) goto bad;
  606.         do_news(player);
  607.         break;
  608.       case 'p':
  609.       case 'P':
  610.         Matched("page");
  611.         do_page(player, arg1, arg2);
  612.         break;
  613.       case 'r':
  614.       case 'R':
  615.         switch(command[1]) {
  616.           case 'e':
  617.           case 'E':
  618.         Matched("read"); /* undocumented alias for look at */
  619.         do_look_at(player, arg1);
  620.         break;
  621.           case 'o':
  622.           case 'O':
  623.         Matched("rob");
  624.         do_rob(player, arg1);
  625.         break;
  626.           default:
  627.         goto bad;
  628.         }
  629.         break;
  630.       case 's':
  631.       case 'S':
  632.         /* say, "score" */
  633.         switch(command[1]) {
  634.           case 'a':
  635.           case 'A':
  636.         Matched("say");
  637.         do_say(player, arg1, arg2);
  638.         break;
  639.           case 'c':
  640.           case 'C':
  641.         Matched("score");
  642.         do_score(player);
  643.         break;
  644.           default:
  645.         goto bad;
  646.         }
  647.         break;
  648.       case 't':
  649.       case 'T':
  650.         switch(command[1]) {
  651.           case 'a':
  652.           case 'A':
  653.         Matched("take");
  654.         do_get(player, arg1);
  655.         break;
  656.           case 'h':
  657.           case 'H':
  658.         Matched("throw");
  659.         do_drop(player, arg1);
  660.         break;
  661.           default:
  662.         goto bad;
  663.         }
  664.         break;
  665.       case 'w':
  666.       case 'W':
  667.         Matched("whisper");
  668.         do_whisper(player, arg1, arg2);
  669.         break;
  670.       default:
  671.       bad:
  672.         notify(player, "Huh?  (Type \"help\" for help.)");
  673. #ifdef LOG_FAILED_COMMANDS
  674.         if(!controls(player, db[player].location)) {
  675.         writelog("HUH from %s(%d) in %s(%d)[%s]: %s %s\n",
  676.             db[player].name, player,
  677.             db[db[player].location].name,
  678.             db[player].location,
  679.             db[db[db[player].location].owner].name,
  680.             command,
  681.             reconstruct_message(arg1, arg2));
  682.         }
  683. #endif /* LOG_FAILED_COMMANDS */
  684.         break;
  685.     }
  686.     }
  687.  
  688.     /* unblock alarms */
  689.     alarm_block = 0;
  690.     if(alarm_triggered) {
  691.     fork_and_dump();
  692.     }
  693. }
  694.  
  695. #undef Matched
  696.