home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / games / volume1 / rogue / patch3 / machdep.c < prev    next >
C/C++ Source or Header  |  1992-01-13  |  17KB  |  656 lines

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