home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / games / volume1 / rogue / part02 / machdep.c < prev    next >
C/C++ Source or Header  |  1987-05-12  |  15KB  |  539 lines

  1. /*
  2.  * machdep.c
  3.  *
  4.  * This source herein may be modified and/or distributed by anybody who
  5.  * so desires, with the following restrictions:
  6.  *    1.)  No portion of this notice shall be removed.
  7.  *    2.)  Credit shall not be taken for the creation of this source.
  8.  *    3.)  This code is not to be traded, sold, or used for personal
  9.  *         gain or profit.
  10.  *
  11.  */
  12.  
  13. /* Included in this file are all system dependent routines.  Extensive use
  14.  * of #ifdef's will be used to compile the appropriate code on each system:
  15.  *
  16.  *    UNIX:        all UNIX systems.
  17.  *    UNIX_BSD4_2: UNIX BSD 4.2 and later, UTEK, (4.1 BSD too?)
  18.  *    UNIX_SYS5:   UNIX system 5
  19.  *    UNIX_V7:     UNIX version 7
  20.  *
  21.  * All UNIX code should be included between the single "#ifdef UNIX" at the
  22.  * top of this file, and the "#endif UNIX" at the bottom.
  23.  * 
  24.  * To change a routine to include a new UNIX system, simply #ifdef the
  25.  * existing routine, as in the following example:
  26.  *
  27.  *   To make a routine compatible with UNIX system 5, change the first
  28.  *   function to the second:
  29.  *
  30.  *      md_function()
  31.  *      {
  32.  *         code;
  33.  *      }
  34.  *
  35.  *      md_function()
  36.  *      {
  37.  *      #ifdef UNIX_SYS5
  38.  *         sys5code;
  39.  *      #else
  40.  *         code;
  41.  *      #endif
  42.  *      }
  43.  *
  44.  * Appropriate variations of this are of course acceptible.
  45.  * The use of "#elseif" is discouraged because of non-portability.
  46.  * If the correct #define doesn't exist, "UNIX_SYS5" in this case, make it up
  47.  * and insert it in the list at the top of the file.  Alter the CFLAGS
  48.  * in you Makefile appropriately.
  49.  *
  50.  */
  51.  
  52. #ifdef UNIX
  53.  
  54. #include <stdio.h>
  55. #include <sgtty.h>
  56. #include <sys/file.h>
  57. #include <sys/types.h>
  58. #include <sys/stat.h>
  59. #include <sys/time.h>
  60. #include <signal.h>
  61. #include "rogue.h"
  62.  
  63. /* md_slurp:
  64.  *
  65.  * This routine throws away all keyboard input that has not
  66.  * yet been read.  It is used to get rid of input that the user may have
  67.  * typed-ahead.
  68.  *
  69.  * This function is not necessary, so it may be stubbed.  The might cause
  70.  * message-line output to flash by because the game has continued to read
  71.  * input without waiting for the user to read the message.  Not such a
  72.  * big deal.
  73.  */
  74.  
  75. md_slurp()
  76. {
  77. #ifdef UNIX_BSD4_2
  78.     long ln;
  79.     int i, n;
  80.     ioctl(0, FIONREAD, &ln);
  81.     n = (int) (stdin->_cnt + ln);
  82.  
  83.     for (i = 0; i < n; i++) {
  84.         (void) getchar();
  85.     }
  86. #endif UNIX_BSD4_2
  87. }
  88.  
  89. /* md_control_keyboard():
  90.  *
  91.  * This routine is much like md_cbreak_no_echo_nonl() above.  It sets up the
  92.  * keyboard for appropriate input.  Specifically, it prevents the tty driver
  93.  * from stealing characters.  For example, ^Y is needed as a command
  94.  * character, but the tty driver intercepts it for another purpose.  Any
  95.  * such behavior should be stopped.  This routine could be avoided if
  96.  * we used RAW mode instead of CBREAK.  But RAW mode does not allow the
  97.  * generation of keyboard signals, which the program uses.
  98.  *
  99.  * The parameter 'mode' when true, indicates that the keyboard should
  100.  * be set up to play rogue.  When false, it should be restored if
  101.  * necessary.
  102.  *
  103.  * This routine is not strictly necessary and may be stubbed.  This may
  104.  * cause certain command characters to be unavailable.
  105.  */
  106.  
  107. md_control_keybord(mode)
  108. short mode;
  109. {
  110.     static boolean called_before = 0;
  111.     static struct ltchars ltc_orig;
  112.     static struct tchars tc_orig;
  113.     struct ltchars ltc_temp;
  114.     struct tchars tc_temp;
  115.  
  116.     if (!called_before) {
  117.         called_before = 1;
  118.         ioctl(0, TIOCGETC, &tc_orig);
  119.         ioctl(0, TIOCGLTC, <c_orig);
  120.     }
  121.     ltc_temp = ltc_orig;
  122.     tc_temp = tc_orig;
  123.  
  124.     if (!mode) {
  125. #ifdef UNIX_BSD4_2
  126.         ltc_temp.t_suspc = ltc_temp.t_dsuspc = -1;
  127. #endif UNIX_BSD4_2
  128.         ltc_temp.t_rprntc = ltc_temp.t_flushc = -1;
  129.         ltc_temp.t_werasc = ltc_temp.t_lnextc = -1;
  130.         tc_temp.t_startc = tc_temp.t_stopc = -1;
  131.     }
  132.     ioctl(0, TIOCSETC, &tc_temp);
  133.     ioctl(0, TIOCSLTC, <c_temp);
  134. }
  135.  
  136. /* md_heed_signals():
  137.  *
  138.  * This routine tells the program to call particular routines when
  139.  * certain interrupts/events occur:
  140.  *
  141.  *      SIGINT: call onintr() to interrupt fight with monster or long rest.
  142.  *      SIGQUIT: call byebye() to check for game termination.
  143.  *      SIGHUP: call error_save() to save game when terminal hangs up.
  144.  *
  145.  *        On VMS, SIGINT and SIGQUIT correspond to ^C and ^Y.
  146.  *
  147.  * This routine is not strictly necessary and can be stubbed.  This will
  148.  * mean that the game cannot be interrupted properly with keyboard
  149.  * input, this is not usually critical.
  150.  */
  151.  
  152. md_heed_signals()
  153. {
  154.     signal(SIGINT, onintr);
  155.     signal(SIGQUIT, byebye);
  156.     signal(SIGHUP, error_save);
  157. }
  158.  
  159. /* md_ignore_signals():
  160.  *
  161.  * This routine tells the program to completely ignore the events mentioned
  162.  * in md_heed_signals() above.  The event handlers will later be turned on
  163.  * by a future call to md_heed_signals(), so md_heed_signals() and
  164.  * md_ignore_signals() need to work together.
  165.  *
  166.  * This function should be implemented or the user risks interrupting
  167.  * critical sections of code, which could cause score file, or saved-game
  168.  * file, corruption.
  169.  */
  170.  
  171. md_ignore_signals()
  172. {
  173.     signal(SIGQUIT, SIG_IGN);
  174.     signal(SIGINT, SIG_IGN);
  175.     signal(SIGHUP, SIG_IGN);
  176. }
  177.  
  178. /* md_get_file_id():
  179.  *
  180.  * This function returns an integer that uniquely identifies the specified
  181.  * file.  It need not check for the file's existence.  In UNIX, the inode
  182.  * number is used.
  183.  *
  184.  * This function need not be implemented.  To stub the routine, just make
  185.  * it return 0.  This will make the game less able to prevent users from
  186.  * modifying saved-game files.  This is probably no big deal.
  187.  */
  188.  
  189. int
  190. md_get_file_id(fname)
  191. char *fname;
  192. {
  193.     struct stat sbuf;
  194.  
  195.     if (stat(fname, &sbuf)) {
  196.         return(-1);
  197.     }
  198.     return((int) sbuf.st_ino);
  199. }
  200.  
  201. /* md_link_count():
  202.  *
  203.  * This routine returns the number of hard links to the specified file.
  204.  *
  205.  * This function is not strictly necessary.  On systems without hard links
  206.  * this routine can be stubbed by just returning 1.
  207.  */
  208.  
  209. int
  210. md_link_count(fname)
  211. char *fname;
  212. {
  213.     struct stat sbuf;
  214.  
  215.     stat(fname, &sbuf);
  216.     return((int) sbuf.st_nlink);
  217. }
  218.  
  219. /* md_gct(): (Get Current Time)
  220.  *
  221.  * This function returns the current year, month(1-12), day(1-31), hour(0-23),
  222.  * minute(0-59), and second(0-59).  This is used for identifying the time
  223.  * at which a game is saved.
  224.  *
  225.  * This function is not strictly necessary.  It can be stubbed by returing
  226.  * zeros instead of the correct year, month, etc.  If your operating
  227.  * system doesn't provide all of the time units requested here, then you
  228.  * can provide only those that it does, and return zeros for the others.
  229.  * If you cannot provide good time values, then users may be able to copy
  230.  * saved-game files and play them.  
  231.  */
  232.  
  233. md_gct(rt_buf)
  234. struct rogue_time *rt_buf;
  235. {
  236.     struct timeval tv;
  237.     struct timezone tzp;
  238.     struct tm *t;
  239.     long seconds;
  240.  
  241.     gettimeofday(&tv, &tzp);
  242.     seconds = (long) tv.tv_sec;
  243.     t = localtime(&seconds);
  244.  
  245.     rt_buf->year = t->tm_year;
  246.     rt_buf->month = t->tm_mon + 1;
  247.     rt_buf->day = t->tm_mday;
  248.     rt_buf->hour = t->tm_hour;
  249.     rt_buf->minute = t->tm_min;
  250.     rt_buf->second = t->tm_sec;
  251. }
  252.  
  253. /* md_gfmt: (Get File Modification Time)
  254.  *
  255.  * This routine returns a file's date of last modification in the same format
  256.  * as md_gct() above.
  257.  *
  258.  * This function is not strictly necessary.  It is used to see if saved-game
  259.  * files have been modified since they were saved.  If you have stubbed the
  260.  * routine md_gct() above by returning constant values, then you may do
  261.  * exactly the same here.
  262.  * Or if md_gct() is implemented correctly, but your system does not provide
  263.  * file modification dates, you may return some date far in the past so
  264.  * that the program will never know that a saved-game file being modified.  
  265.  * You may also do this if you wish to be able to restore games from
  266.  * saved-games that have been modified.
  267.  */
  268.  
  269. md_gfmt(fname, rt_buf)
  270. char *fname;
  271. struct rogue_time *rt_buf;
  272. {
  273.     struct stat sbuf;
  274.     long seconds;
  275.     struct tm *t;
  276.  
  277.     stat(fname, &sbuf);
  278.     seconds = (long) sbuf.st_mtime;
  279.     t = localtime(&seconds);
  280.  
  281.     rt_buf->year = t->tm_year;
  282.     rt_buf->month = t->tm_mon + 1;
  283.     rt_buf->day = t->tm_mday;
  284.     rt_buf->hour = t->tm_hour;
  285.     rt_buf->minute = t->tm_min;
  286.     rt_buf->second = t->tm_sec;
  287. }
  288.  
  289. /* md_df: (Delete File)
  290.  *
  291.  * This function deletes the specified file, and returns true (1) if the
  292.  * operation was successful.  This is used to delete saved-game files
  293.  * after restoring games from them.
  294.  *
  295.  * Again, this function is not strictly necessary, and can be stubbed
  296.  * by simply returning 1.  In this case, saved-game files will not be
  297.  * deleted and can be replayed.
  298.  */
  299.  
  300. boolean
  301. md_df(fname)
  302. char *fname;
  303. {
  304.     if (unlink(fname)) {
  305.         return(0);
  306.     }
  307.     return(1);
  308. }
  309.  
  310. /* md_gln: (Get login name)
  311.  *
  312.  * This routine returns the login name of the user.  This string is
  313.  * used mainly for identifying users in score files.
  314.  *
  315.  * A dummy string may be returned if you are unable to implement this
  316.  * function, but then the score file would only have one name in it.
  317.  */
  318.  
  319. char *
  320. md_gln()
  321. {
  322.     char *getlogin();
  323.     char *t;
  324.  
  325.     t = getlogin();
  326.     return(t);
  327. }
  328.  
  329. /* md_sleep:
  330.  *
  331.  * This routine causes the game to pause for the specified number of
  332.  * seconds.
  333.  *
  334.  * This routine is not necessary at all, and can be stubbed with no ill
  335.  * effects.
  336.  */
  337.  
  338. md_sleep(nsecs)
  339. int nsecs;
  340. {
  341.     (void) sleep(nsecs);
  342. }
  343.  
  344. /* md_getenv()
  345.  *
  346.  * This routine gets certain values from the user's environment.  These
  347.  * values are strings, and each string is identified by a name.  The names
  348.  * of the values needed, and their use, is as follows:
  349.  *
  350.  *   TERMCAP
  351.  *     The name of the users's termcap file, NOT the termcap entries
  352.  *     themselves.  This is used ONLY if the program is compiled with
  353.  *     CURSES defined (-DCURSES).  Even in this case, the program need
  354.  *     not find a string for TERMCAP.  If it does not, it will use the
  355.  *     default termcap file as returned by md_gdtcf();
  356.  *   TERM
  357.  *     The name of the users's terminal.  This is used ONLY if the program
  358.  *     is compiled with CURSES defined (-DCURSES).  In this case, the string
  359.  *     value for TERM must be found, or the routines in curses.c cannot
  360.  *     function, and the program will quit.
  361.  *   ROGUEOPTS
  362.  *     A string containing the various game options.  This need not be
  363.  *     defined.
  364.  *   HOME
  365.  *     The user's home directory.  This is only used when the user specifies
  366.  *     '~' as the first character of a saved-game file.  This string need
  367.  *     not be defined.
  368.  *
  369.  * If your system does not provide a means of searching for these values,
  370.  * you will have to do it yourself.  None of the values above really need
  371.  * to be defined except TERM when the program is compiled with CURSES
  372.  * defined.  In this case, as a bare minimum, you can check the 'name'
  373.  * parameter, and if it is "TERM" find the terminal name and return that,
  374.  * else return zero.  If the program is not compiled with CURSES, you can
  375.  * get by with simply always returning zero.  Returning zero indicates
  376.  * that their is no defined value for the given string.
  377.  */
  378.  
  379. char *
  380. md_getenv(name)
  381. char *name;
  382. {
  383.     char *value;
  384.     char *getenv();
  385.  
  386.     value = getenv(name);
  387.  
  388.     return(value);
  389. }
  390.  
  391. /* md_malloc()
  392.  *
  393.  * This routine allocates, and returns a pointer to, the specified number
  394.  * of bytes.  This routines absolutely MUST be implemented for your
  395.  * particular system or the program will not run at all.  Return zero
  396.  * when no more memory can be allocated.
  397.  */
  398.  
  399. char *
  400. md_malloc(n)
  401. int n;
  402. {
  403.     char *malloc();
  404.     char *t;
  405.  
  406.     t = malloc(n);
  407.     return(t);
  408. }
  409.  
  410. /* md_gseed() (Get Seed)
  411.  *
  412.  * This function returns a seed for the random number generator (RNG).  This
  413.  * seed causes the RNG to begin generating numbers at some point in it's
  414.  * sequence.  Without a random seed, the RNG will generate the same set
  415.  * of numbers, and every game will start out exactly the same way.  A good
  416.  * number to use is the process id, given by getpid() on most UNIX systems.
  417.  *
  418.  * You need to find some single random integer, such as:
  419.  *   process id.
  420.  *   current time (minutes + seconds) returned from md_gct(), if implemented.
  421.  *   
  422.  * It will not help to return "get_rand()" or "rand()" or the return value of
  423.  * any pseudo-RNG.  If you cannot a random number, you can just return 1,
  424.  * but this means you games will ALWAYS start the same way, and will play
  425.  * exactly the same way given the same input.
  426.  */
  427.  
  428. md_gseed()
  429. {
  430.     return(getpid());
  431. }
  432.  
  433. /* md_exit():
  434.  *
  435.  * This function causes the program to discontinue execution and exit.
  436.  * This function must be implemented or the program will continue to
  437.  * hang when it should quit.
  438.  */
  439.  
  440. md_exit(status)
  441. int status;
  442. {
  443.     exit(status);
  444. }
  445.  
  446. /* If you have a viable curses/termlib library, then use it and don't bother
  447.  * implementing the routines below.  And don't compile with -DCURSES.
  448.  */
  449.  
  450. #ifdef CURSES
  451.  
  452. /* md_cbreak_no_echo_nonl:
  453.  *
  454.  * This routine sets up some terminal characteristics.  The tty-driver
  455.  * must be told to:
  456.  *   1.)  Not echo input.
  457.  *   2.)  Transmit input characters immediately upon typing. (cbreak mode)
  458.  *   3.)  Move the cursor down one line, without changing column, and
  459.  *        without generating a carriage-return, when it
  460.  *        sees a line-feed.  This is only necessary if line-feed is ever
  461.  *        used in the termcap 'do' (cursor down) entry, in which case,
  462.  *        your system should must have a way of accomplishing this.
  463.  *
  464.  * When the parameter 'on' is true, the terminal is set up as specified
  465.  * above.  When this parameter is false, the terminal is restored to the
  466.  * original state.
  467.  *
  468.  * Raw mode should not to be used.  Keyboard signals/events/interrupts should
  469.  * be sent, although they are not strictly necessary.  See notes in
  470.  * md_heed_signals().
  471.  *
  472.  * This function must be implemented for rogue to run properly if the
  473.  * program is compiled with CURSES defined to use the enclosed curses
  474.  * emulation package.  If you are not using this, then this routine is
  475.  * totally unnecessary.
  476.  * 
  477.  * Notice that information is saved between calls.  This is used to
  478.  * restore the terminal to an initial saved state.
  479.  *
  480.  */
  481.  
  482. md_cbreak_no_echo_nonl(on)
  483. boolean on;
  484. {
  485.     static struct sgttyb tty_buf;
  486.     static int tty_save_flags;
  487.  
  488.     if (on) {
  489.         ioctl(0, TIOCGETP, &tty_buf);
  490.         tty_save_flags = tty_buf.sg_flags;
  491.         tty_buf.sg_flags |= CBREAK;
  492.         tty_buf.sg_flags &= ~(ECHO | CRMOD);    /* CRMOD: see note above */
  493.         ioctl(0, TIOCSETP, &tty_buf);
  494.     } else {
  495.         tty_buf.sg_flags = tty_save_flags;
  496.         ioctl(0, TIOCSETP, &tty_buf);
  497.     }
  498. }
  499.  
  500. /* md_gdtcf(): (Get Default Termcap File)
  501.  *
  502.  * This function is called ONLY when the program is compiled with CURSES
  503.  * defined.  If you use your system's curses/termlib library, this function
  504.  * won't be called.  On most UNIX systems, "/etc/termcap" suffices.
  505.  *
  506.  * If their is no such termcap file, then return 0, but in that case, you
  507.  * must have a TERMCAP file returned from md_getenv("TERMCAP").  The latter
  508.  * will override the value returned from md_gdtcf().  If the program is
  509.  * compiled with CURSES defined, and md_gdtcf() returns 0, and
  510.  * md_getenv("TERMCAP") returns 0, the program will have no terminal
  511.  * capability information and will quit.
  512.  */
  513.  
  514. char *
  515. md_gdtcf()
  516. {
  517.     return("/etc/termcap");
  518. }
  519.  
  520. /* md_tstp():
  521.  *
  522.  * This function puts the game to sleep and returns to the shell.  This
  523.  * only applies to UNIX 4.2 and 4.3.  For other systems, the routine should
  524.  * be provided as a do-nothing routine.  md_tstp() will only be referenced
  525.  * in the code when compiled with CURSES defined.
  526.  *
  527.  */
  528.  
  529. md_tstp()
  530. {
  531. #ifdef UNIX_BSD4_2
  532.     kill(0, SIGTSTP);
  533. #endif UNIX_BSD4_2
  534. }
  535.  
  536. #endif CURSES
  537.  
  538. #endif UNIX
  539.