home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / EFFO / pd8.lzh / SRC / io.c < prev    next >
Text File  |  1990-03-25  |  11KB  |  443 lines

  1. /* this file (in principle) contains all the device-dependent code for
  2.  * handling screen movement and reading the keyboard. public routines are:
  3.  *   c_pos(r,c), c_erase(), c_eol();
  4.  *   chk_char(), read_char(), read_line (buf, max); and
  5.  *   byetty().
  6.  * N.B. we assume output may be performed by printf(), putchar() and
  7.  *   fputs(stdout). since these are buffered we flush first in read_char().
  8.  */
  9.  
  10. /* explanation of various conditional #define options:
  11.  * UNIX: uses termcap for screen management.
  12.  *   USE_NDELAY: does non-blocking tty reads with fcntl(O_NDELAY); otherwise
  13.  *     this is done with ioctl(..,FIONREAD..). Use which ever works on your
  14.  *     system.
  15.  * TURBO_C: compiles for Turbo C 2.0. I'm told it works for Lattice and
  16.  *     Microsoft too.
  17.  *   USE_ANSISYS: default PC cursor control uses direct BIOS calls (thanks to
  18.  *     Mr. Doug McDonald). If your PC does not work with this, however, add
  19.  *     "device ANSI.SYS" to your config.sys file and build ephem with
  20.  *     USE_ANSISYS.
  21.  */
  22.  
  23. /* #define UNIX */
  24. /* #define USE_NDELAY */
  25. /* #define TURBO_C */
  26. /* #define USE_ANSISYS */
  27.  
  28. #include <stdio.h>
  29. #include "screen.h"
  30.  
  31. #if defined(UNIX) | defined(OSK)
  32.  
  33. #ifdef UNIX
  34. #  include <sgtty.h>
  35. #  include <signal.h>
  36. #  ifdef USE_NDELAY
  37. #    include <fcntl.h>
  38. #  endif
  39. #endif
  40. #ifdef OSK
  41. #  include <sgstat.h>
  42. char *UP,*BC;
  43. #endif
  44.  
  45. extern char *tgoto();
  46. static char *cm, *ce, *cl, *kl, *kr, *ku, *kd; /* curses sequences */
  47. static int tloaded;
  48. static int ttysetup;
  49. #ifdef UNIX
  50.   static struct sgttyb orig_sgtty;
  51. #endif
  52. #ifdef OSK
  53.   static struct sgbuf sg_buf;
  54. #endif
  55.  
  56. /* move cursor to row, col, 1-based.
  57.  * we assume this also moves a visible cursor to this location.
  58.  */
  59. c_pos (r, c)
  60. int r, c;
  61. {
  62.         if (!tloaded) tload();
  63.         fputs (tgoto (cm, c-1, r-1), stdout);
  64. }
  65.  
  66. /* erase entire screen. */
  67. c_erase()
  68. {
  69.         if (!tloaded) tload();
  70.         fputs (cl, stdout);
  71. }
  72.  
  73. /* erase to end of line */
  74. c_eol()
  75. {
  76.         if (!tloaded) tload();
  77.         fputs (ce, stdout);
  78. }
  79.  
  80. #ifdef USE_NDELAY
  81. static char sav_char;   /* one character read-ahead for chk_char() */
  82. #endif
  83.  
  84. /* return 0 if there is a char that may be read without blocking, else -1 */
  85. chk_char()
  86. {
  87. #ifndef OSK
  88. #ifdef USE_NDELAY
  89.         if (!ttysetup) setuptty();
  90.         if (sav_char)
  91.             return (0);
  92.         fcntl (0, F_SETFL, O_NDELAY);   /* non-blocking read. FNDELAY on BSD */
  93.         if (read (0, &sav_char, 1) != 1)
  94.             sav_char = 0;
  95.         return (sav_char ? 0 : -1);
  96. #else
  97.         long n;
  98.         if (!ttysetup) setuptty();
  99.         ioctl (0, FIONREAD, &n);
  100.         return (n > 0 ? 0 : -1);
  101. #endif
  102. #else
  103.         if (!ttysetup) setuptty();
  104.         return (_gs_rdy(0) > 0 ? 0 : -1);
  105. #endif
  106. }
  107.  
  108. /* read the next char, blocking if necessary, and return it. don't echo.
  109.  * map the arrow keys if we can too into hjkl
  110.  */
  111. read_char()
  112. {
  113.         char c;
  114.         if (!ttysetup) setuptty();
  115.         fflush (stdout);
  116. #ifdef USE_NDELAY
  117.         fcntl (0, F_SETFL, 0);  /* blocking read */
  118.         if (sav_char) {
  119.             c = sav_char;
  120.             sav_char = 0;
  121.         } else
  122. #endif
  123.         read (0, &c, 1);
  124. #ifndef OSK
  125.         c = chk_arrow (c & 0177); /* just ASCII, please */
  126.         return (c);
  127. #else
  128.         return(chk_arrow(c));
  129. #endif
  130. }
  131.  
  132. /* used to time out of a read */
  133. static got_alrm;
  134. static
  135. on_alrm()
  136. {
  137.         got_alrm = 1;
  138. }
  139.  
  140. /* see if c is the first of any of the curses arrow key sequences.
  141.  * if it is, read the rest of the sequence, and return the hjkl code
  142.  * that corresponds.
  143.  * if no match, just return c.
  144.  */
  145. static 
  146. chk_arrow (c)
  147. register char c;
  148. {
  149.         register char *seq;
  150.  
  151.         if (c == *(seq = kl) || c == *(seq = kd) || c == *(seq = ku)
  152.                                                  || c == *(seq = kr)) {
  153.             char seqa[32]; /* maximum arrow escape sequence ever expected */
  154.             unsigned l = strlen(seq);
  155.             seqa[0] = c;
  156.             if (l > 1) {
  157.                 extern unsigned alarm();
  158.                 /* cautiously read rest of arrow sequence */
  159.                 got_alrm = 0;
  160. #ifndef OSK
  161.                 signal (SIGALRM, on_alrm);
  162.                 alarm(2);
  163. #endif
  164.                 read (0, seqa+1, l-1);
  165. #ifndef OSK
  166.                 alarm(0);
  167. #endif
  168.                 if (got_alrm)
  169.                     return (c);
  170.             }
  171.             seqa[l] = '\0';
  172.             if (strcmp (seqa, kl) == 0)
  173.                 return ('h');
  174.             if (strcmp (seqa, kd) == 0)
  175.                 return ('j');
  176.             if (strcmp (seqa, ku) == 0)
  177.                 return ('k');
  178.             if (strcmp (seqa, kr) == 0)
  179.                 return ('l');
  180.         }
  181.         return (c);
  182. }
  183.  
  184. /* do whatever might be necessary to get the screen and/or tty back into shape.
  185.  */
  186. byetty()
  187. {
  188. #ifdef UNIX
  189.         ioctl (0, TIOCSETP, &orig_sgtty);
  190. #ifdef USE_NDELAY
  191.         fcntl (0, F_SETFL, 0);  /* be sure to go back to blocking read */
  192. #endif
  193. #else /* UNIX */
  194.         _ss_opt(0,&sg_buf);
  195. #endif
  196. }
  197.  
  198. static 
  199. tload()
  200. {
  201.         extern char *getenv(), *tgetstr();
  202.         extern char *UP, *BC;
  203.         char *egetstr();
  204.         static char tbuf[512];
  205.         char rawtbuf[1024];
  206.         char *tp;
  207.         char *ptr;
  208.  
  209.         if (!(tp = getenv ("TERM"))) {
  210.             printf ("Must have addressable cursor\n");
  211.             exit(1);
  212.         }
  213.  
  214.         if (!ttysetup) setuptty();
  215.         if (tgetent (rawtbuf, tp) != 1) {
  216.             printf ("Can't find termcap for %s\n", tp);
  217.             exit (1);
  218.         }
  219.         ptr = tbuf;
  220.         ku = egetstr ("ku", &ptr);
  221.         kd = egetstr ("kd", &ptr);
  222.         kl = egetstr ("kl", &ptr);
  223.         kr = egetstr ("kr", &ptr);
  224.         cm = egetstr ("cm", &ptr);
  225.         ce = egetstr ("ce", &ptr);
  226.         cl = egetstr ("cl", &ptr);
  227.         UP = egetstr ("up", &ptr);
  228.         if (!tgetflag ("bs"))
  229.             BC = egetstr ("bc", &ptr);
  230.         tloaded = 1;
  231. }
  232.  
  233. /* like tgetstr() but discard curses delay codes, for now anyways */
  234. static char *
  235. egetstr (name, sptr)
  236. char *name;
  237. char **sptr;
  238. {
  239.         extern char *tgetstr();
  240.         register char c, *s;
  241.  
  242.         s = tgetstr (name, sptr);
  243.         while (((c = *s) >= '0' && c <= '9') || c == '*')
  244.             s += 1;
  245.         return (s);
  246. }
  247.  
  248. /* set up tty for char-by-char read, non-blocking  */
  249. static
  250. setuptty()
  251. {
  252. #ifdef UNIX
  253.         struct sgttyb sg;
  254.  
  255.         ioctl (0, TIOCGETP, &orig_sgtty);
  256.         sg = orig_sgtty;
  257.         sg.sg_flags &= ~ECHO;   /* do our own echoing */
  258.         sg.sg_flags &= ~CRMOD;  /* leave CR and LF unchanged */
  259.         sg.sg_flags |= XTABS;   /* no tabs with termcap */
  260.         sg.sg_flags |= CBREAK;  /* wake up on each char but can still kill */
  261.         ioctl (0, TIOCSETP, &sg);
  262. #else
  263.         struct sgbuf sg_b;
  264.  
  265.         _gs_opt(0,&sg_buf);
  266.         _gs_opt(0,&sg_b);
  267.         sg_b.sg_echo = 0;
  268.         sg_b.sg_eofch = 0;
  269.         sg_b.sg_pause = 0;
  270.         _ss_opt(0,&sg_b);
  271. #endif
  272.         ttysetup = 1;
  273. }
  274. #endif
  275.  
  276. #ifdef TURBO_C
  277. #ifdef USE_ANSISYS
  278. #define ESC     '\033'
  279. /* position cursor.
  280.  * (ANSI: ESC [ r ; c f) (r/c are numbers given in ASCII digits)
  281.  */
  282. c_pos (r, c)
  283. int r, c;
  284. {
  285.         printf ("%c[%d;%df", ESC, r, c);
  286. }
  287.  
  288. /* erase entire screen. (ANSI: ESC [ 2 J) */
  289. c_erase()
  290. {
  291.         printf ("%c[2J", ESC);
  292. }
  293.  
  294. /* erase to end of line. (ANSI: ESC [ K) */
  295. c_eol()
  296. {
  297.         printf ("%c[K", ESC);
  298. }
  299. #else
  300. #include <dos.h>   
  301. union REGS rg;
  302.  
  303. /* position cursor.
  304.  */
  305. c_pos (r, c)
  306. int r, c;
  307. {
  308.         rg.h.ah = 2;
  309.         rg.h.bh = 0;
  310.         rg.h.dh = r-1;
  311.         rg.h.dl = c-1;
  312.         int86(16,&rg,&rg);
  313. }
  314.  
  315. /* erase entire screen.  */
  316. c_erase()
  317. {
  318.         int cur_cursor, i;
  319.         rg.h.ah = 3;
  320.         rg.h.bh = 0;
  321.         int86(16,&rg,&rg);
  322.         cur_cursor = rg.x.dx;
  323.         for(i = 0; i < 25; i++){
  324.             c_pos(i+1,1);
  325.             rg.h.ah = 10;
  326.             rg.h.bh = 0;
  327.             rg.h.al = 32;
  328.             rg.x.cx = 80;
  329.             int86(16,&rg,&rg);
  330.         }
  331.         rg.h.ah = 2;
  332.         rg.h.bh = 0;
  333.         rg.x.dx = cur_cursor;
  334.         int86(16,&rg,&rg);
  335.         
  336. }
  337.  
  338. /* erase to end of line.*/
  339. c_eol()
  340. {
  341.         int cur_cursor, i;
  342.         rg.h.ah = 3;
  343.         rg.h.bh = 0;
  344.         int86(16,&rg,&rg);
  345.         cur_cursor = rg.x.dx;
  346.         rg.h.ah = 10;
  347.         rg.h.bh = 0;
  348.         rg.h.al = 32;
  349.         rg.x.cx = 80 - rg.h.dl;
  350.         int86(16,&rg,&rg);
  351.         rg.h.ah = 2;
  352.         rg.h.bh = 0;
  353.         rg.x.dx = cur_cursor;
  354.         int86(16,&rg,&rg);
  355.  
  356. }
  357. #endif
  358.  
  359. /* return 0 if there is a char that may be read without blocking, else -1 */
  360. chk_char()
  361. {
  362.         return (kbhit() == 0 ? -1 : 0);
  363. }
  364.  
  365. /* read the next char, blocking if necessary, and return it. don't echo.
  366.  * map the arrow keys if we can too into hjkl
  367.  */
  368. read_char()
  369. {
  370.         int c;
  371.         fflush (stdout);
  372.         c = getch();
  373.         if (c == 0) {
  374.             /* get scan code; convert to direction hjkl if possible */
  375.             c = getch();
  376.             switch (c) {
  377.             case 0x4b: c = 'h'; break;
  378.             case 0x50: c = 'j'; break;
  379.             case 0x48: c = 'k'; break;
  380.             case 0x4d: c = 'l'; break;
  381.             }
  382.         }
  383.         return (c);
  384. }
  385.  
  386. /* do whatever might be necessary to get the screen and/or tty back into shape.
  387.  */
  388. byetty()
  389. {
  390. }
  391. #endif
  392.  
  393. /* read up to max chars into buf, with cannonization.
  394.  * add trailing '\0' (buf is really max+1 chars long).
  395.  * return count of chars read (not counting '\0').
  396.  * assume cursor is already positioned as desired.
  397.  * if type END when n==0 then return -1.
  398.  */
  399. read_line (buf, max)
  400. char buf[];
  401. int max;
  402. {
  403.         static char erase[] = "\b \b";
  404.         int n, c;
  405.         int done;
  406.  
  407. #ifdef UNIX
  408.         if (!ttysetup) setuptty();
  409. #endif
  410.  
  411.         for (done = 0, n = 0; !done; )
  412.             switch (c = read_char()) {  /* does not echo */
  413.             case cntrl('h'):    /* backspace or */
  414.             case 0177:          /* delete are each char erase */
  415.                 if (n > 0) {
  416.                     fputs (erase, stdout);
  417.                     n -= 1;
  418.                 }
  419.                 break;
  420.             case cntrl('u'):            /* line erase */
  421.                 while (n > 0) {
  422.                     fputs (erase, stdout);
  423.                     n -= 1;
  424.                 }
  425.                 break;
  426.             case '\r':  /* EOL */
  427.                 done++;
  428.                 break;
  429.             default:                    /* echo and store, if ok */
  430.                 if (n == 0 && c == END)
  431.                     return (-1);
  432.                 if (n >= max)
  433.                     putchar (cntrl('g'));
  434.                 else if (c >= ' ') {
  435.                     putchar (c);
  436.                     buf[n++] = c;
  437.                 }
  438.             }
  439.  
  440.         buf[n] = '\0';
  441.         return (n);
  442. }
  443.