home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / trn_12.zip / src / term.c < prev    next >
C/C++ Source or Header  |  1993-12-04  |  29KB  |  1,275 lines

  1. /* $Id: term.c,v 4.4.3.1 1992/02/01 03:09:32 sob PATCH_3 sob $
  2.  *
  3.  * $Log: term.c,v $
  4.  * Revision 4.4.3.1  1992/02/01  03:09:32  sob
  5.  * Release 4.4 Patchlevel 3
  6.  *
  7.  * Revision 4.4.2.1  1991/12/01  18:05:42  sob
  8.  * Patchlevel 2 changes
  9.  *
  10.  * Revision 4.4  1991/09/09  20:27:37  sob
  11.  * release 4.4
  12.  *
  13.  *
  14.  * 
  15.  */
  16. /* This software is Copyright 1991 by Stan Barber. 
  17.  *
  18.  * Permission is hereby granted to copy, reproduce, redistribute or otherwise
  19.  * use this software as long as: there is no monetary profit gained
  20.  * specifically from the use or reproduction of this software, it is not
  21.  * sold, rented, traded or otherwise marketed, and this copyright notice is
  22.  * included prominently in any copy made. 
  23.  *
  24.  * The author make no claims as to the fitness or correctness of this software
  25.  * for any use whatsoever, and it is provided as is. Any use of this software
  26.  * is at the user's own risk. 
  27.  */
  28.  
  29. #include "EXTERN.h"
  30. #include "common.h"
  31. #include "util.h"
  32. #include "final.h"
  33. #include "help.h"
  34. #include "cheat.h"
  35. #include "intrp.h"
  36. #include "INTERN.h"
  37. #include "term.h"
  38.  
  39.  
  40. char ERASECH;        /* rubout character */
  41. char KILLCH;        /* line delete character */
  42. char tcarea[TCSIZE];    /* area for "compiled" termcap strings */
  43.  
  44. #ifdef USETHREADS
  45. int upcost;
  46. #endif
  47.  
  48. /* guarantee capability pointer != Nullch */
  49. /* (I believe terminfo will ignore the &tmpaddr argument.) */
  50.  
  51. #define Tgetstr(key) ((tmpstr = tgetstr(key,&tmpaddr)) ? tmpstr : nullstr)
  52.  
  53. #ifdef PUSHBACK
  54. struct keymap {
  55.     char km_type[128];
  56.     union km_union {
  57.     struct keymap *km_km;
  58.     char *km_str;
  59.     } km_ptr[128];
  60. };
  61.  
  62. #define KM_NOTHIN 0
  63. #define KM_STRING 1
  64. #define KM_KEYMAP 2
  65. #define KM_BOGUS 3
  66.  
  67. #define KM_TMASK 3
  68. #define KM_GSHIFT 4
  69. #define KM_GMASK 7
  70.  
  71. typedef struct keymap KEYMAP;
  72.  
  73. KEYMAP *topmap INIT(Null(KEYMAP*));
  74.  
  75. void mac_init();
  76. KEYMAP *newkeymap();
  77. void show_keymap();
  78. void pushstring();
  79. #endif
  80.  
  81. void line_col_calcs();
  82.  
  83. /* terminal initialization */
  84.  
  85. void
  86. term_init()
  87. {
  88.     savetty();                /* remember current tty state */
  89.  
  90. #ifdef TERMIO
  91.     outspeed = _tty.c_cflag & CBAUD;    /* for tputs() */
  92.     ERASECH = _tty.c_cc[VERASE];    /* for finish_command() */
  93.     KILLCH = _tty.c_cc[VKILL];        /* for finish_command() */
  94.     if (GT = ((_tty.c_oflag & TABDLY) != TAB3))
  95.     /* we have tabs, so that's OK */;
  96.     else
  97.     _tty.c_oflag &= ~TAB3;    /* turn off kernel tabbing -- done in rn */
  98. #else /* !TERMIO */
  99. # ifdef TERMIOS
  100.     outspeed = cfgetospeed(&_tty);    /* for tputs() (output) */
  101.     ERASECH = _tty.c_cc[VERASE];    /* for finish_command() */
  102.     KILLCH = _tty.c_cc[VKILL];        /* for finish_command() */
  103. /*    _tty.c_oflag &= ~OXTABS;        /* turn off kernel tabbing-done in rn */
  104. # else /* !TERMIOS */
  105.     outspeed = _tty.sg_ospeed;        /* for tputs() */
  106.     ERASECH = _tty.sg_erase;        /* for finish_command() */
  107.     KILLCH = _tty.sg_kill;        /* for finish_command() */
  108.     if (GT = ((_tty.sg_flags & XTABS) != XTABS))
  109.     /* we have tabs, so that's OK */;
  110.     else
  111.     _tty.sg_flags &= ~XTABS;
  112. # endif /* TERMIOS */
  113. #endif /* TERMIO */
  114.  
  115.     /* The following could be a table but I can't be sure that there isn't */
  116.     /* some degree of sparsity out there in the world. */
  117.  
  118.     switch (outspeed) {            /* 1 second of padding */
  119. #ifdef BEXTA
  120.         case BEXTA:  just_a_sec = 1920; break;
  121. #else
  122. #ifdef B19200
  123.         case B19200: just_a_sec = 1920; break;
  124. #endif
  125. #endif
  126.         case B9600:  just_a_sec =  960; break;
  127.         case B4800:  just_a_sec =  480; break;
  128.         case B2400:  just_a_sec =  240; break;
  129.         case B1800:  just_a_sec =  180; break;
  130.         case B1200:  just_a_sec =  120; break;
  131.         case B600:   just_a_sec =   60; break;
  132.     case B300:   just_a_sec =   30; break;
  133.     /* do I really have to type the rest of this??? */
  134.         case B200:   just_a_sec =   20; break;
  135.         case B150:   just_a_sec =   15; break;
  136.         case B134:   just_a_sec =   13; break;
  137.         case B110:   just_a_sec =   11; break;
  138.         case B75:    just_a_sec =    8; break;
  139.         case B50:    just_a_sec =    5; break;
  140.         default:     just_a_sec =  960; break;
  141.                     /* if we are running detached I */
  142.     }                    /*  don't want to know about it! */
  143. }
  144.  
  145. /* set terminal characteristics */
  146.  
  147. void
  148. term_set(tcbuf)
  149. char *tcbuf;        /* temp area for "uncompiled" termcap entry */
  150. {
  151.     char *tmpaddr;            /* must not be register */
  152.     register char *tmpstr;
  153.     char *tgetstr();
  154.     char *s;
  155.     int status;
  156. #ifdef TIOCGWINSZ
  157.     struct winsize winsize;
  158. #endif
  159.  
  160. #ifdef PENDING
  161. #if ! defined (FIONREAD) && ! defined (RDCHK)
  162.     /* do no delay reads on something that always gets closed on exit */
  163.  
  164.     devtty = open("/dev/tty",0);
  165.     if (devtty < 0) {
  166.     printf(cantopen,"/dev/tty") ; FLUSH;
  167.     finalize(1);
  168.     }
  169.     fcntl(devtty,F_SETFL,O_NDELAY);
  170. #endif
  171. #endif
  172.     
  173.     /* get all that good termcap stuff */
  174.  
  175. #ifdef HAVETERMLIB
  176.     status = tgetent(tcbuf,getenv("TERM"));    /* get termcap entry */
  177.     if (status < 1) {
  178. #ifdef VERBOSE
  179.     printf("No termcap %s found.\n", status ? "file" : "entry") ; FLUSH;
  180. #else
  181.     fputs("Termcap botch\n",stdout) ; FLUSH;
  182. #endif
  183.     finalize(1);
  184.     }
  185.     tmpaddr = tcarea;            /* set up strange tgetstr pointer */
  186.     s = Tgetstr("pc");            /* get pad character */
  187.     PC = *s;                /* get it where tputs wants it */
  188.     if (!tgetflag("bs")) {        /* is backspace not used? */
  189.     BC = Tgetstr("bc");        /* find out what is */
  190.     if (BC == nullstr)         /* terminfo grok's 'bs' but not 'bc' */
  191.         BC = Tgetstr("le");
  192.     } else
  193.     BC = "\b";            /* make a backspace handy */
  194.     UP = Tgetstr("up");            /* move up a line */
  195.     if (!*UP)                /* no UP string? */
  196.     marking = 0;            /* disable any marking */
  197.     if (muck_up_clear)            /* this is for weird HPs */
  198.     CL = "\n\n\n\n";
  199.     else
  200.     CL = Tgetstr("cl");        /* get clear string */
  201.     CE = Tgetstr("ce");            /* clear to end of line string */
  202.     TI = Tgetstr("ti");            /* initialize display */
  203.     TE = Tgetstr("te");            /* reset display */
  204. #if defined(CLEAREOL) || defined(USETHREADS)
  205.     HO = Tgetstr("ho");            /* home cursor if no CM */
  206.     CM = Tgetstr("cm");            /* cursor motion */
  207.     if (*CM || *HO)
  208.     can_home = TRUE;
  209. #endif
  210. #ifdef CLEAREOL
  211.     CD = Tgetstr("cd");            /* clear to end of display */
  212.     if (!*CE || !*CD || !can_home)    /* can we CE, CD, and home? */
  213.     can_home_clear = FALSE;        /*  no, so disable use of clear eol */
  214.     if (!*CE) CE = CD;
  215. #endif /* CLEAREOL */
  216. #ifdef USETHREADS
  217.     upcost = strlen(UP);
  218. #endif
  219.     SO = Tgetstr("so");            /* begin standout */
  220.     SE = Tgetstr("se");            /* end standout */
  221.     if ((SG = tgetnum("sg"))<0)
  222.     SG = 0;                /* blanks left by SG, SE */
  223.     US = Tgetstr("us");            /* start underline */
  224.     UE = Tgetstr("ue");            /* end underline */
  225.     if ((UG = tgetnum("ug"))<0)
  226.     UG = 0;                /* blanks left by US, UE */
  227.     if (*US)
  228.     UC = nullstr;            /* UC must not be NULL */
  229.     else
  230.     UC = Tgetstr("uc");        /* underline a character */
  231.     if (!*US && !*UC) {            /* no underline mode? */
  232.     US = SO;            /* substitute standout mode */
  233.     UE = SE;
  234.     UG = SG;
  235.     }
  236.     LINES = tgetnum("li");        /* lines per page */
  237. /*** OS2: The number of columns must reduced by one, so that   ***
  238.  ***      the internal pagers break the line, before the       ***
  239.  ***      line is broken by the 'terminal'                     ***/
  240.     COLS = tgetnum("co");        /* columns on page */
  241.     if (COLS > 2) --COLS;
  242. #ifdef TIOCGWINSZ
  243.     { struct winsize ws;
  244.     if (ioctl(0, TIOCGWINSZ, &ws) >= 0 && ws.ws_row > 0 && ws.ws_col > 0) {
  245.         LINES = ws.ws_row;
  246.         COLS = ws.ws_col - 1;
  247.     }
  248.     }
  249. #endif
  250.     
  251.     AM = tgetflag("am");        /* terminal wraps automatically? */
  252.     XN = tgetflag("xn");        /* then eats next newline? */
  253.     VB = Tgetstr("vb");
  254.     if (!*VB)
  255.     VB = "\007";
  256.     CR = Tgetstr("cr");
  257.     if (!*CR) {
  258.     if (tgetflag("nc") && *UP) {
  259.         CR = safemalloc((MEM_SIZE)strlen(UP)+2);
  260.         sprintf(CR,"%s\r",UP);
  261.     }
  262.     else
  263.         CR = "\r";
  264.     }
  265. #ifdef TIOCGWINSZ
  266.     if (ioctl(1, TIOCGWINSZ, &winsize)>=0) {
  267.         if (winsize.ws_row>0) LINES=winsize.ws_row;
  268.         if (winsize.ws_col>0) COLS=winsize.ws_col - 1;
  269.     }
  270. #endif
  271. #else
  272.     ??????                /* Roll your own... */
  273. #endif
  274.     termlib_init();
  275.     line_col_calcs();
  276.     noecho();                /* turn off echo */
  277.     crmode();                /* enter cbreak mode */
  278.  
  279. #ifdef PUSHBACK
  280.     mac_init(tcbuf);
  281. #endif
  282. }
  283.  
  284. #ifdef PUSHBACK
  285. void
  286. mac_init(tcbuf)
  287. char *tcbuf;
  288. {
  289.     char tmpbuf[1024];
  290.  
  291.     tmpfp = fos2open(filexp(getval("RNMACRO",RNMACRO)),"r");
  292.     if (tmpfp != Nullfp) {
  293.     while (fgets(tcbuf,1024,tmpfp) != Nullch) {
  294.         mac_line(tcbuf,tmpbuf,(sizeof tmpbuf));
  295.     }
  296.     fclose(tmpfp);
  297.     }
  298. }
  299.  
  300. void
  301. mac_line(line,tmpbuf,tbsize)
  302. char *line;
  303. char *tmpbuf;
  304. int tbsize;
  305. {
  306.     register char *s, *m;
  307.     register KEYMAP *curmap;
  308.     register int ch;
  309.     register int garbage = 0;
  310.     static char override[] = "\nkeymap overrides string\n";
  311.  
  312.     if (topmap == Null(KEYMAP*))
  313.     topmap = newkeymap();
  314.     if (*line == '#' || *line == '\n')
  315.     return;
  316.     if (line[ch = strlen(line)-1] == '\n')
  317.     line[ch] = '\0';
  318.     m = dointerp(tmpbuf,tbsize,line," \t");
  319.     if (!*m)
  320.     return;
  321.     while (*m == ' ' || *m == '\t') m++;
  322.     for (s=tmpbuf,curmap=topmap; *s; s++) {
  323.     ch = *s & 0177;
  324.     if (s[1] == '+' && isdigit(s[2])) {
  325.         s += 2;
  326.         garbage = (*s & KM_GMASK) << KM_GSHIFT;
  327.     }
  328.     else
  329.         garbage = 0;
  330.     if (s[1]) {
  331.         if ((curmap->km_type[ch] & KM_TMASK) == KM_STRING) {
  332.         fputs(override,stdout) ; FLUSH;
  333.         free(curmap->km_ptr[ch].km_str);
  334.         curmap->km_ptr[ch].km_str = Nullch;
  335.         }
  336.         curmap->km_type[ch] = KM_KEYMAP + garbage;
  337.         if (curmap->km_ptr[ch].km_km == Null(KEYMAP*))
  338.         curmap->km_ptr[ch].km_km = newkeymap();
  339.         curmap = curmap->km_ptr[ch].km_km;
  340.     }
  341.     else {
  342.         if ((curmap->km_type[ch] & KM_TMASK) == KM_KEYMAP) {
  343.         fputs(override,stdout) ; FLUSH;
  344.         }
  345.         else {
  346.         curmap->km_type[ch] = KM_STRING + garbage;
  347.         curmap->km_ptr[ch].km_str = savestr(m);
  348.         }
  349.     }
  350.     }
  351. }
  352.  
  353. KEYMAP*
  354. newkeymap()
  355. {
  356.     register int i;
  357.     register KEYMAP *map;
  358.  
  359. #ifndef lint
  360.     map = (KEYMAP*)safemalloc(sizeof(KEYMAP));
  361. #else
  362.     map = Null(KEYMAP*);
  363. #endif /* lint */
  364.     for (i=127; i>=0; --i) {
  365.     map->km_ptr[i].km_km = Null(KEYMAP*);
  366.     map->km_type[i] = KM_NOTHIN;
  367.     }
  368.     return map;
  369. }
  370.  
  371. void
  372. show_macros()
  373. {
  374.     char prebuf[64];
  375.  
  376.     if (topmap != Null(KEYMAP*)) {
  377.     print_lines("Macros:\n",STANDOUT);
  378.     *prebuf = '\0';
  379.     show_keymap(topmap,prebuf);
  380.     }
  381.     else {
  382.     print_lines("No macros defined.\n", NOMARKING);
  383.     }
  384. }
  385.  
  386. void
  387. show_keymap(curmap,prefix)
  388. register KEYMAP *curmap;
  389. char *prefix;
  390. {
  391.     register int i;
  392.     register char *next = prefix + strlen(prefix);
  393.     register int kt;
  394.  
  395.     for (i=0; i<128; i++) {
  396.     if (kt = curmap->km_type[i]) {
  397.         if (i < ' ')
  398.         sprintf(next,"^%c",i+64);
  399.         else if (i == ' ')
  400.         strcpy(next,"\\040");
  401.         else if (i == 127)
  402.         strcpy(next,"^?");
  403.         else
  404.         sprintf(next,"%c",i);
  405.         if ((kt >> KM_GSHIFT) & KM_GMASK) {
  406.         sprintf(cmd_buf,"+%d", (kt >> KM_GSHIFT) & KM_GMASK);
  407.         strcat(next,cmd_buf);
  408.         }
  409.         switch (kt & KM_TMASK) {
  410.         case KM_NOTHIN:
  411.         sprintf(cmd_buf,"%s    %c\n",prefix,i);
  412.         print_lines(cmd_buf,NOMARKING);
  413.         break;
  414.         case KM_KEYMAP:
  415.         show_keymap(curmap->km_ptr[(char)i].km_km, prefix);
  416.         break;
  417.         case KM_STRING:
  418.         sprintf(cmd_buf,"%s    %s\n",prefix,curmap->km_ptr[i].km_str);
  419.         print_lines(cmd_buf,NOMARKING);
  420.         break;
  421.         case KM_BOGUS:
  422.         sprintf(cmd_buf,"%s    BOGUS\n",prefix);
  423.         print_lines(cmd_buf,STANDOUT);
  424.         break;
  425.         }
  426.     }
  427.     }
  428. }
  429.  
  430. #endif
  431.  
  432. /* routine to pass to tputs */
  433.  
  434. char
  435. putchr(ch)
  436. register char_int ch;
  437. {
  438.     putchar(ch);
  439. #ifdef lint
  440.     ch = Null(char);
  441.     ch = ch;
  442. #endif
  443.     return((char) 0);
  444. }
  445.  
  446. /* input the 2nd and succeeding characters of a multi-character command */
  447. /* returns TRUE if command finished, FALSE if they rubbed out first character */
  448.  
  449. bool
  450. finish_command(donewline)
  451. int donewline;
  452. {
  453.     register char *s;
  454.     register bool quoteone = FALSE;
  455.  
  456.     s = buf;
  457.     if (s[1] != FINISHCMD)        /* someone faking up a command? */
  458.     return TRUE;
  459.     do {
  460.       top:
  461.     if (*(unsigned char *)s < ' ') {
  462.         putchar('^');
  463.         putchar(*s | 64);
  464.     }
  465.     else if (*s == '\177') {
  466.         putchar('^');
  467.         putchar('?');
  468.     }
  469.     else
  470.         putchar(*s);        /* echo previous character */
  471.     s++;
  472. re_read:
  473.     fflush(stdout);
  474.     getcmd(s);
  475.     if (quoteone) {
  476.         quoteone = FALSE;
  477.         continue;
  478.     }
  479.     if (errno || *s == '\f') {
  480.         *s = Ctl('r');        /* force rewrite on CONT */
  481.     }
  482.     if (*s == '\033') {        /* substitution desired? */
  483. #ifdef ESCSUBS
  484.         char tmpbuf[4], *cpybuf;
  485.  
  486.         tmpbuf[0] = '%';
  487.         read_tty(&tmpbuf[1],1);
  488. #ifdef RAWONLY
  489.         tmpbuf[1] &= 0177;
  490. #endif
  491.         tmpbuf[2] = '\0';
  492.         if (tmpbuf[1] == 'h') {
  493.         (void) help_subs();
  494.         *s = '\0';
  495.         reprint();
  496.         goto re_read;
  497.         }
  498.         else if (tmpbuf[1] == '\033') {
  499.         *s = '\0';
  500.         cpybuf = savestr(buf);
  501.         interp(buf, (sizeof buf), cpybuf);
  502.         free(cpybuf);
  503.         s = buf + strlen(buf);
  504.         reprint();
  505.         goto re_read;
  506.         }
  507.         else {
  508.         interp(s,(sizeof buf) - (s-buf),tmpbuf);
  509.         fputs(s,stdout);
  510.         s += strlen(s);
  511.         }
  512.         goto re_read;
  513. #else
  514.         notincl("^[");
  515.         *s = '\0';
  516.         reprint();
  517.         goto re_read;
  518. #endif
  519.     }
  520.     else if (*s == ERASECH) {    /* they want to rubout a char? */
  521.         rubout();
  522.         s--;            /* discount the char rubbed out */
  523.         if (*(unsigned char *)s < ' ' || *s == '\177')
  524.         rubout();
  525.         if (s == buf) {        /* entire string gone? */
  526.         fflush(stdout);        /* return to single char command mode */
  527.         return FALSE;
  528.         }
  529.         else
  530.         goto re_read;
  531.     }
  532.     else if (*s == KILLCH) {    /* wipe out the whole line? */
  533.         while (s-- != buf) {    /* emulate that many ERASEs */
  534.         rubout();
  535.         if (*(unsigned char *)s < ' ' || *s == '\177')
  536.             rubout();
  537.         }
  538.         fflush(stdout);
  539.         return FALSE;        /* return to single char mode */
  540.     }
  541. #ifdef WORDERASE
  542.     else if (*s == Ctl('w')) {    /* wipe out one word? */
  543.         *s-- = ' ';
  544.         while (!isspace(*s) || isspace(s[1])) {
  545.         rubout();
  546.         if (s-- == buf) {
  547.             fflush(stdout);
  548.             return FALSE;    /* return to single char mode */
  549.         }
  550.         if (*(unsigned char *)s < ' ' || *s == '\177')
  551.             rubout();
  552.         }
  553.         s++;
  554.         goto re_read;
  555.     }
  556. #endif
  557.     else if (*s == Ctl('r')) {
  558.         *s = '\0';
  559.         reprint();
  560.         goto re_read;
  561.     }
  562.     else if (*s == Ctl('v')) {
  563.         putchar('^');
  564.         backspace();
  565.         fflush(stdout);
  566.         getcmd(s);
  567.         goto top;
  568.     }
  569.     else if (*s == '\\') {
  570.         quoteone = TRUE;
  571.     }
  572. /*** OS2: end on newline-character or cr-character ***/
  573.     } while ((*s != '\r') && (*s != '\n'));
  574. /*#ifdef cray */
  575. /*    } while (*s != '\r');       /* till a newline (not echoed) */
  576. /*#else
  577. /*    } while (*s != '\n');       /* till a newline (not echoed) */
  578. /*#endif  */
  579.     *s = '\0';                /* terminate the string nicely */
  580.     if (donewline)
  581.     putchar('\n') ; FLUSH;
  582.     return TRUE;            /* say we succeeded */
  583. }
  584.  
  585. /* discard any characters typed ahead */
  586.  
  587. void
  588. eat_typeahead()
  589. {
  590. #ifdef PUSHBACK
  591.     if (!typeahead && nextin==nextout)    /* cancel only keyboard stuff */
  592. #else
  593.     if (!typeahead)
  594. #endif
  595.     {
  596. #ifdef PENDING
  597.     while (input_pending())
  598.         read_tty(buf,sizeof(buf));
  599. #else /* this is probably v7 */
  600. #if defined(TERMIO) || defined(TERMIOS)
  601.     ioctl(_tty_ch,TCSETAW,&_tty);
  602. #else
  603.     ioctl(_tty_ch,TIOCSETP,&_tty);
  604. #endif
  605. #endif
  606.     }
  607. }
  608.  
  609. void
  610. settle_down()
  611. {
  612.     dingaling();
  613.     fflush(stdout);
  614. /*    sleep(1); */
  615. #ifdef PUSHBACK
  616.     nextout = nextin;            /* empty circlebuf */
  617. #endif
  618.     eat_typeahead();
  619. }
  620.  
  621. #ifdef PUSHBACK
  622. /* read a character from the terminal, with multi-character pushback */
  623.  
  624. int
  625. read_tty(addr,size)
  626. char *addr;
  627. int size;
  628. {
  629.  
  630. /*** OS2: we need this tmp-variables */
  631.     int tmp_char, tmp_size;
  632.  
  633.     if (nextout != nextin) {
  634.     *addr = circlebuf[nextout++];
  635.     nextout %= PUSHSIZE;
  636.     return 1;
  637.     }
  638.     else {
  639.  
  640. /*** OS2: hmm..., I want to read only one character without
  641.           pressing cr. How can this be realized ???
  642.           We display the read character in this routine, but
  643.           the cursor will remain on the same position. This is
  644.           done by calling backspace(). This is necessary,
  645.           because some of the functions which call read_tty,
  646.           display the character themselved, but some don't do
  647.           that, for example if it is a one character command. **/
  648.  
  649. /*    size = read(0,addr,size);  */
  650.  
  651.     tmp_size = 0;
  652.     while ((tmp_size < size) &&
  653.            (tmp_char != 13)  &&
  654.            (tmp_char != 10)) {
  655.         tmp_char = _read_kbd(0,1,0);
  656.         /* I don't know why, but there is a coredump
  657.            if we try to use the echo flag ...???
  658.            But that's not a problem, because we don't
  659.            want an echo. */
  660.         addr[tmp_size] = (unsigned char)tmp_char;
  661.         tmp_size++;
  662.     }
  663.     size = tmp_size;
  664.  
  665. #ifdef RAWONLY
  666.     *addr &= 0177;
  667. #endif
  668.     return size;
  669.     }
  670. }
  671.  
  672. #ifdef PENDING
  673. #if ! defined (FIONREAD) && ! defined (RDCHK)
  674. int
  675. circfill()
  676. {
  677.     register int Howmany;
  678.  
  679.     errno = 0;
  680.     Howmany = read(devtty,circlebuf+nextin,1);
  681.  
  682.     if (Howmany < 0 && (errno == EAGAIN || errno == EINTR))
  683.     Howmany = 0;
  684.     if (Howmany) {
  685.     nextin += Howmany;
  686.     nextin %= PUSHSIZE;
  687.     }
  688.     return Howmany;
  689. }
  690. #endif /* PENDING */
  691. #endif /* FIONREAD */
  692.  
  693. void
  694. pushchar(c)
  695. char_int c;
  696. {
  697.     nextout--;
  698.     if (nextout < 0)
  699.     nextout = PUSHSIZE - 1;
  700.     if (nextout == nextin) {
  701.     fputs("\npushback buffer overflow\n",stdout) ; FLUSH;
  702.     sig_catcher(0);
  703.     }
  704.     circlebuf[nextout] = c;
  705. }
  706.  
  707. #else /* PUSHBACK */
  708. #ifndef read_tty
  709. /* read a character from the terminal, with hacks for O_NDELAY reads */
  710.  
  711. int
  712. read_tty(addr,size)
  713. char *addr;
  714. int size;
  715. {
  716.     if (is_input) {
  717.     *addr = pending_ch;
  718.     is_input = FALSE;
  719.     return 1;
  720.     }
  721.     else {
  722.     size = read(0,addr,size);
  723. #ifdef RAWONLY
  724.     *addr &= 0177;
  725. #endif
  726.     return size;
  727.     }
  728. }
  729. #endif /* read_tty */
  730. #endif /* PUSHBACK */
  731.  
  732. /* print an underlined string, one way or another */
  733.  
  734. void
  735. underprint(s)
  736. register char *s;
  737. {
  738.     assert(UC);
  739.     if (*UC) {        /* char by char underline? */
  740.     while (*s) {
  741.         if (*(unsigned char *)s < ' ') {
  742.         putchar('^');
  743.         backspace();/* back up over it */
  744.         underchar();/* and do the underline */
  745.         putchar(*s+64);
  746.         backspace();/* back up over it */
  747.         underchar();/* and do the underline */
  748.         }
  749.         else {
  750.         putchar(*s);
  751.         backspace();/* back up over it */
  752.         underchar();/* and do the underline */
  753.         }
  754.         s++;
  755.     }
  756.     }
  757.     else {        /* start and stop underline */
  758.     underline();    /* start underlining */
  759.     while (*s) {
  760.         if (*(unsigned char *)s < ' ') {
  761.         putchar('^');
  762.         putchar(*s+64);
  763.         }
  764.         else
  765.         putchar(*s);
  766.         s++;
  767.     }
  768.     un_underline();    /* stop underlining */
  769.     }
  770. }
  771.  
  772. /* keep screen from flashing strangely on magic cookie terminals */
  773.  
  774. #ifdef NOFIREWORKS
  775. void
  776. no_sofire()
  777. {
  778.     if (*UP && *SE) {        /* should we disable fireworks? */
  779.     putchar('\n');
  780.     un_standout();
  781.     up_line();
  782.     carriage_return();
  783.     }
  784. }
  785.  
  786. void
  787. no_ulfire()
  788. {
  789.     if (*UP && *US) {        /* should we disable fireworks? */
  790.     putchar('\n');
  791.     un_underline();
  792.     up_line();
  793.     carriage_return();
  794.     }
  795. }
  796. #endif
  797.  
  798. /* get a character into a buffer */
  799.  
  800. void
  801. getcmd(whatbuf)
  802. register char *whatbuf;
  803. {
  804. #ifdef PUSHBACK
  805.     register KEYMAP *curmap;
  806.     register int i;
  807.     bool no_macros; 
  808.     int times = 0;            /* loop detector */
  809.     char scrchar;
  810.  
  811. tryagain:
  812.     curmap = topmap;
  813.     no_macros = (whatbuf != buf && nextin == nextout); 
  814. #endif
  815.     for (;;) {
  816.     int_count = 0;
  817.     errno = 0;
  818.     if (read_tty(whatbuf,1) < 0){
  819.         if (!errno)
  820.             errno = EINTR;
  821.         if (errno == EINTR)
  822.         return;
  823.         perror(readerr);
  824.         sig_catcher(0);
  825.     }
  826. #ifdef PUSHBACK
  827.     if (*whatbuf & 0200 || no_macros) {
  828.         *whatbuf &= 0177;
  829.         goto got_canonical;
  830.     }
  831.     if (curmap == Null(KEYMAP*))
  832.         goto got_canonical;
  833.     for (i = (curmap->km_type[*whatbuf] >> KM_GSHIFT) & KM_GMASK; i; --i){
  834.         read_tty(&scrchar,1);
  835.     }
  836.     switch (curmap->km_type[*whatbuf] & KM_TMASK) {
  837.     case KM_NOTHIN:            /* no entry? */
  838.         if (curmap == topmap)    /* unmapped canonical */
  839.         goto got_canonical;
  840.         settle_down();
  841.         goto tryagain;
  842.     case KM_KEYMAP:            /* another keymap? */
  843.         curmap = curmap->km_ptr[*whatbuf].km_km;
  844.         assert(curmap != Null(KEYMAP*));
  845.         break;
  846.     case KM_STRING:            /* a string? */
  847.         pushstring(curmap->km_ptr[*whatbuf].km_str);
  848.         if (++times > 20) {        /* loop? */
  849.         fputs("\nmacro loop?\n",stdout);
  850.         settle_down();
  851.         }
  852.         no_macros = FALSE;
  853.         goto tryagain;
  854.     }
  855. #else
  856. #ifdef RAWONLY
  857.     *whatbuf &= 0177;
  858. #endif
  859.     break;
  860. #endif
  861.     }
  862.  
  863. got_canonical:
  864. #if !defined(TERMIO) && !defined(TERMIOS)
  865.     if (*whatbuf == '\r')
  866.     *whatbuf = '\n';
  867. #endif
  868.     if (whatbuf == buf)
  869.     whatbuf[1] = FINISHCMD;        /* tell finish_command to work */
  870. }
  871.  
  872. #ifdef PUSHBACK
  873. void
  874. pushstring(str)
  875. char *str;
  876. {
  877.     register int i;
  878.     char tmpbuf[PUSHSIZE];
  879.     register char *s = tmpbuf;
  880.  
  881.     assert(str != Nullch);
  882.     interp(s,PUSHSIZE,str);
  883.     for (i = strlen(s)-1; i >= 0; --i) {
  884.     s[i] ^= 0200; 
  885.     pushchar(s[i]);
  886.     }
  887. }
  888. #endif
  889.  
  890. int
  891. get_anything()
  892. {
  893.     char tmpbuf[2];
  894.  
  895. reask_anything:
  896.     unflush_output();            /* disable any ^O in effect */
  897.     standout();
  898. #ifdef VERBOSE
  899.     IF(verbose)
  900.     fputs("[Type space to continue] ",stdout);
  901.     ELSE
  902. #endif
  903. #ifdef TERSE
  904.     fputs("[MORE] ",stdout);
  905. #endif
  906.     un_standout();
  907.     fflush(stdout);
  908.     eat_typeahead();
  909.     if (int_count) {
  910.     return -1;
  911.     }
  912.     collect_subjects();            /* loads subject cache until */
  913.                     /* input is pending */
  914.     getcmd(tmpbuf);
  915.     if (errno || *tmpbuf == '\f') {
  916.     putchar('\n') ; FLUSH;        /* if return from stop signal */
  917.     goto reask_anything;        /* give them a prompt again */
  918.     }
  919.     if (*tmpbuf == 'h') {
  920. #ifdef VERBOSE
  921.     IF(verbose) {
  922.         fputs("\nType q to quit or space to continue.\n",stdout) ; FLUSH;
  923.     }
  924.     ELSE
  925. #endif
  926. #ifdef TERSE
  927.         fputs("\nq to quit, space to continue.\n",stdout) ; FLUSH;
  928. #endif
  929.     goto reask_anything;
  930.     }
  931.     else if (*tmpbuf != ' ' && *tmpbuf != '\n') {
  932.     carriage_return();
  933.     erase_eol();    /* erase the prompt */
  934.     carriage_return();
  935.     return *tmpbuf == 'q' ? -1 : *tmpbuf;
  936.     }
  937.     if (*tmpbuf == '\n') {
  938.     page_line = LINES - 1;
  939.     carriage_return();
  940.     erase_eol();
  941.     carriage_return();
  942.     }
  943.     else {
  944.     page_line = 1;
  945.     if (erase_screen)        /* -e? */
  946.         clear();            /* clear screen */
  947.     else {
  948.         carriage_return();
  949.         erase_eol();        /* erase the prompt */
  950.         carriage_return();
  951.     }
  952.     }
  953.     return 0;
  954. }
  955.  
  956. #ifdef USETHREADS
  957. int
  958. pause_getcmd()
  959. {
  960.     unflush_output();            /* disable any ^O in effect */
  961.     standout();
  962. #ifdef VERBOSE
  963.     IF(verbose)
  964.     fputs("[Type space or a command] ",stdout);
  965.     ELSE
  966. #endif
  967. #ifdef TERSE
  968.     fputs("[CMD] ",stdout);
  969. #endif
  970.     un_standout();
  971.     fflush(stdout);
  972.     eat_typeahead();
  973.     if (int_count) {
  974.     return -1;
  975.     }
  976.     getcmd(buf);
  977.     if (errno || *buf == '\f') {
  978.     return 0;            /* if return from stop signal */
  979.     }
  980.     else if (*buf != ' ') {
  981.     carriage_return();
  982.     erase_eol();    /* erase the prompt */
  983.     carriage_return();
  984.     return *buf;
  985.     }
  986.     return 0;
  987. }
  988. #endif
  989.  
  990. void
  991. in_char(prompt, newmode)
  992. char *prompt;
  993. char_int newmode;
  994. {
  995.     char oldmode = mode;
  996.  
  997. reask_in_char:
  998.     unflush_output();            /* disable any ^O in effect */
  999.     fputs(prompt,stdout);
  1000.     fflush(stdout);
  1001.     eat_typeahead();
  1002.     mode = newmode;
  1003.     getcmd(buf);
  1004.     if (errno || *buf == '\f') {
  1005.     putchar('\n') ; FLUSH;        /* if return from stop signal */
  1006.     goto reask_in_char;        /* give them a prompt again */
  1007.     }
  1008.     mode = oldmode;
  1009. }
  1010.  
  1011. int
  1012. print_lines(what_to_print,hilite)
  1013. char *what_to_print;
  1014. int hilite;
  1015. {
  1016.     register char *s;
  1017.     register int i;
  1018.  
  1019. /*** OS2: this is only a temporary patch, blank out
  1020.           \r-characters when printing ***/
  1021.     for (s=what_to_print;*s!='\0';++s)
  1022.        if (*s == '\r') *s = ' ';
  1023. /*** end of patch ***/
  1024.     if (page_line < 0)            /* they do not want to see this? */
  1025.     return -1;
  1026.     for (s=what_to_print; *s; ) {
  1027.     if (page_line >= LINES || int_count) {
  1028.         if (i = -1, int_count || (i = get_anything())) {
  1029.         page_line = -1;        /* disable further print_lines */
  1030.         return i;
  1031.         }
  1032.     }
  1033.     page_line++;
  1034.     if (hilite == STANDOUT) {
  1035. #ifdef NOFIREWORKS
  1036.         if (erase_screen)
  1037.         no_sofire();
  1038. #endif
  1039.         standout();
  1040.     }
  1041.     else if (hilite == UNDERLINE) {
  1042. #ifdef NOFIREWORKS
  1043.         if (erase_screen)
  1044.         no_ulfire();
  1045. #endif
  1046.         underline();
  1047.     }
  1048.     for (i=0; i<COLS; i++) {
  1049.         if (!*s)
  1050.         break;
  1051.         if (*(unsigned char *)s >= ' ')
  1052.         putchar(*s);
  1053.         else if (*s == '\t') {
  1054.         putchar(*s);
  1055.         i = ((i+8) & ~7) - 1; 
  1056.         }
  1057.         else if (*s == '\n') {
  1058.         i = 32000;
  1059.         }
  1060.         else {
  1061.         i++;
  1062.         putchar('^');
  1063.         putchar(*s + 64);
  1064.         }
  1065.         s++;
  1066.     }
  1067.     if (i) {
  1068.         if (hilite == STANDOUT)
  1069.         un_standout();
  1070.         else if (hilite == UNDERLINE)
  1071.         un_underline();
  1072.         if (AM && i == COLS)
  1073.         fflush(stdout);
  1074.         else
  1075.         putchar('\n') ; FLUSH;
  1076.     }
  1077.     }
  1078.     return 0;
  1079. }
  1080.  
  1081. void
  1082. page_init()
  1083. {
  1084.     page_line = 1;
  1085.     if (erase_screen)
  1086.     clear();
  1087.     else
  1088.     putchar('\n') ; FLUSH;
  1089. }
  1090.  
  1091. void
  1092. pad(num)
  1093. int num;
  1094. {
  1095.     register int i;
  1096.  
  1097.     for (i = num; i; --i)
  1098.     putchar(PC);
  1099.     fflush(stdout);
  1100. }
  1101.  
  1102. /* echo the command just typed */
  1103.  
  1104. #ifdef VERIFY
  1105. void
  1106. printcmd()
  1107. {
  1108.     if (verify && buf[1] == FINISHCMD) {
  1109.     if (*(unsigned char *)buf < ' ') {
  1110.         putchar('^');
  1111.         putchar(*buf | 64);
  1112.         backspace();
  1113.         backspace();
  1114.     }
  1115.     else {
  1116.         putchar(*buf);
  1117.         backspace();
  1118.     }
  1119.     fflush(stdout);
  1120.     }
  1121. }
  1122. #endif
  1123.  
  1124. void
  1125. rubout()
  1126. {
  1127.     backspace();            /* do the old backspace, */
  1128.     putchar(' ');            /*   space, */
  1129.     backspace();            /*     backspace trick */
  1130. }
  1131.  
  1132. void
  1133. reprint()
  1134. {
  1135.     register char *s;
  1136.  
  1137.     fputs("^R\n",stdout) ; FLUSH;
  1138.     for (s = buf; *s; s++) {
  1139.     if (*(unsigned char *)s < ' ') {
  1140.         putchar('^');
  1141.         putchar(*s | 64);
  1142.     }
  1143.     else
  1144.         putchar(*s);
  1145.     }
  1146. }
  1147.  
  1148. #if defined(CLEAREOL) || defined(USETHREADS)
  1149. void
  1150. home_cursor()
  1151. {
  1152.     char *tgoto();
  1153.  
  1154.     if (!*HO) {            /* no home sequence? */
  1155.     if (!*CM) {        /* no cursor motion either? */
  1156.         fputs ("\n\n\n", stdout);
  1157.         return;        /* forget it. */
  1158.     }
  1159.     tputs (tgoto (CM, 0, 0), 1, putchr);    /* go to home via CM */
  1160.     return;
  1161.     }
  1162.     else {            /* we have home sequence */
  1163.     tputs (HO, 1, putchr);    /* home via HO */
  1164.     }
  1165. }
  1166. #endif
  1167.  
  1168. #ifdef USETHREADS
  1169. void
  1170. goto_line(from,to)    /* assumes caller is already at beginning of line */
  1171. int from,to;
  1172. {
  1173.     char *tgoto(), *str;
  1174.     int cmcost;
  1175.  
  1176.     if (from == to) {
  1177.     return;
  1178.     }
  1179.     if (*CM && !muck_up_clear) {
  1180.     cmcost = strlen(str = tgoto(CM,0,to));
  1181.     } else {
  1182.     cmcost = 9999;
  1183.     }
  1184.     if (to > from) {
  1185.       go_down:
  1186.     if (to - from <= cmcost) {
  1187.         while(from++ < to) {
  1188.         putchar('\n');
  1189.         }
  1190.         return;
  1191.     }
  1192.     } else if(*UP) {
  1193.     if ((from - to) * upcost <= cmcost) {
  1194.         while(from-- > to) {
  1195.         tputs(UP,1,putchr);
  1196.         }
  1197.         return;
  1198.     }
  1199.     } else if (cmcost == 9999) {
  1200.     home_cursor();
  1201.     from = 0;
  1202.     goto go_down;
  1203.     }
  1204.     tputs(str,1,putchr);
  1205. }
  1206. #endif
  1207.  
  1208. void
  1209. line_col_calcs()
  1210. {
  1211.      if (LINES > 0) {            /* is this a crt? */
  1212.       if ((!initlines) || (!initlines_specified))
  1213.            /* no -i or unreasonable value for initlines */
  1214.            if (outspeed >= B9600)     /* whole page at >= 9600 baud */
  1215.             initlines = LINES;
  1216.            else if (outspeed >= B4800)/* 16 lines at 4800 */
  1217.             initlines = 16;
  1218.            else            /* otherwise just header */
  1219.             initlines = 8;
  1220.      }
  1221.      else {                /* not a crt */
  1222.       LINES = 30000;        /* so don't page */
  1223.       CL = "\n\n";            /* put a couple of lines between */
  1224.       if ((!initlines) || (!initlines_specified))
  1225.            /* make initlines reasonable */
  1226.            initlines = 8;
  1227.      }
  1228.      if (COLS <= 0)
  1229.       COLS = 79;
  1230. }
  1231.  
  1232.  
  1233. #ifdef SIGWINCH
  1234. SIGRET
  1235. winch_catcher(dummy)
  1236. int dummy;
  1237. {
  1238.      /* Reset signal in case of System V dain bramage */
  1239.      sigset(SIGWINCH, winch_catcher);
  1240.  
  1241.      /* Come here if window size change signal received */
  1242. #ifdef TIOCGWINSZ
  1243.      { struct winsize ws;
  1244.        if (ioctl(0, TIOCGWINSZ, &ws) >= 0 && ws.ws_row > 0 && ws.ws_col > 0) {
  1245.      LINES = ws.ws_row;
  1246.      COLS = ws.ws_col - 1;
  1247.      line_col_calcs();
  1248.        }
  1249.      }
  1250. #else
  1251.      /* Well, if SIGWINCH is defined, but TIOCGWINSZ isn't, there's    */
  1252.      /* almost certainly something wrong.  Figure it out for yourself, */
  1253.      /* because I don't know now to deal :-)                           */
  1254. #endif
  1255. }
  1256. #endif
  1257. void
  1258. termlib_init()
  1259. {
  1260. #ifdef USETITE
  1261.     if (TI && *TI)
  1262.         tputs (TI,1,putchr);
  1263. #endif
  1264.     return;
  1265. }
  1266. void
  1267. termlib_reset()
  1268. {
  1269. #ifdef USETITE
  1270.     if (TE && *TE)
  1271.         tputs (TE,1,putchr);
  1272. #endif
  1273.     return;
  1274. }
  1275.