home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / TELECOM / rn_4_3_blars.lzh / term.c < prev    next >
Text File  |  1990-11-03  |  24KB  |  1,135 lines

  1. /* $Header: term.c,v 4.3.2.7 90/04/21 16:54:29 sob Exp $
  2.  *
  3.  * $Log:    term.c,v $
  4.  * Revision 4.3.2.7  90/04/21  16:54:29  sob
  5.  * Installed patches provided by SCO for SCO Xenix
  6.  * 
  7.  * Revision 4.3.2.6  90/04/13  23:48:17  sob
  8.  * Modifications provided by Gene Hackney for 3b2.
  9.  * 
  10.  * Revision 4.3.2.5  90/04/06  20:35:08  sob
  11.  * Added fixes for SCO Xenix sent by ronald@robobar.co.uk.
  12.  * 
  13.  * Revision 4.3.2.4  90/03/22  23:05:38  sob
  14.  * Fixes provided by Wayne Davison <drivax!davison>
  15.  * 
  16.  * Revision 4.3.2.3  89/11/28  01:51:58  sob
  17.  * Now handles SIGWINCH correctly.
  18.  * 
  19.  * Revision 4.3.2.2  89/11/27  01:31:34  sob
  20.  * Altered NNTP code per ideas suggested by Bela Lubkin
  21.  * <filbo@gorn.santa-cruz.ca.us>
  22.  * 
  23.  * Revision 4.3.2.1  89/11/06  01:02:12  sob
  24.  * Added RRN support from NNTP 1.5
  25.  * 
  26.  * Revision 4.3.1.3  85/09/10  11:05:23  lwall
  27.  * Improved %m in in_char().
  28.  * 
  29.  * Revision 4.3.1.2  85/05/16  16:45:35  lwall
  30.  * Forced \r to \n on input.
  31.  * Fix for terminfo braindamage regarding bc emulation.
  32.  * 
  33.  * Revision 4.3.1.1  85/05/10  11:41:03  lwall
  34.  * Branch for patches.
  35.  * 
  36.  * Revision 4.3  85/05/01  11:51:10  lwall
  37.  * Baseline for release with 4.3bsd.
  38.  * 
  39.  */
  40.  
  41. #include "EXTERN.h"
  42. #include "common.h"
  43. #include "util.h"
  44. #include "final.h"
  45. #include "help.h"
  46. #include "cheat.h"
  47. #include "intrp.h"
  48. #include "INTERN.h"
  49. #include "term.h"
  50.  
  51. char ERASECH;        /* rubout character */
  52. char KILLCH;        /* line delete character */
  53. char tcarea[TCSIZE];    /* area for "compiled" termcap strings */
  54.  
  55. /* guarantee capability pointer != Nullch */
  56. /* (I believe terminfo will ignore the &tmpaddr argument.) */
  57.  
  58. #define Tgetstr(key) ((tmpstr = tgetstr(key,&tmpaddr)) ? tmpstr : nullstr)
  59.  
  60. #ifdef PUSHBACK
  61. struct keymap {
  62.     char km_type[128];
  63.     union km_union {
  64.     struct keymap *km_km;
  65.     char *km_str;
  66.     } km_ptr[128];
  67. };
  68.  
  69. #define KM_NOTHIN 0
  70. #define KM_STRING 1
  71. #define KM_KEYMAP 2
  72. #define KM_BOGUS 3
  73.  
  74. #define KM_TMASK 3
  75. #define KM_GSHIFT 4
  76. #define KM_GMASK 7
  77.  
  78. typedef struct keymap KEYMAP;
  79.  
  80. KEYMAP *topmap INIT(Null(KEYMAP*));
  81.  
  82. void mac_init();
  83. KEYMAP *newkeymap();
  84. void show_keymap();
  85. void pushstring();
  86. #endif
  87.  
  88. void line_col_calcs();
  89.  
  90. /* terminal initialization */
  91.  
  92. void
  93. term_init()
  94. {
  95.     savetty();                /* remember current tty state */
  96.  
  97. #ifdef TERMIO
  98.     ospeed = _tty.c_cflag & CBAUD;    /* for tputs() */
  99.     ERASECH = _tty.c_cc[VERASE];    /* for finish_command() */
  100.     KILLCH = _tty.c_cc[VKILL];        /* for finish_command() */
  101. #else
  102. #ifndef OSK
  103.     ospeed = _tty.sg_ospeed;        /* for tputs() */
  104.     ERASECH = _tty.sg_erase;        /* for finish_command() */
  105.     KILLCH = _tty.sg_kill;        /* for finish_command() */
  106. #else    /* OSK */
  107.     ospeed = _tty.sg_baud;        /* for tputs() */
  108.     ERASECH = _tty.sg_bspch;        /* for finish_command() */
  109.     KILLCH = _tty.sg_dlnch;        /* for finish_command() */
  110. #endif
  111. #endif
  112.  
  113.     /* The following could be a table but I can't be sure that there isn't */
  114.     /* some degree of sparsity out there in the world. */
  115.  
  116.     switch (ospeed) {            /* 1 second of padding */
  117. #ifdef BEXTA
  118.         case BEXTA:  just_a_sec = 1920; break;
  119. #else
  120. #ifdef B19200
  121.         case B19200: just_a_sec = 1920; break;
  122. #endif
  123. #endif
  124.         case B9600:  just_a_sec =  960; break;
  125.         case B4800:  just_a_sec =  480; break;
  126.         case B2400:  just_a_sec =  240; break;
  127.         case B1800:  just_a_sec =  180; break;
  128.         case B1200:  just_a_sec =  120; break;
  129.         case B600:   just_a_sec =   60; break;
  130.     case B300:   just_a_sec =   30; break;
  131.     /* do I really have to type the rest of this??? */
  132. #ifdef B200
  133.         case B200:   just_a_sec =   20; break;
  134. #endif
  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. #ifdef u3b2
  158. struct winsize {
  159.     unsigned short ws_row;       /* rows, in characters*/
  160.     unsigned short ws_col;       /* columns, in character */
  161.     unsigned short ws_xpixel;    /* horizontal size, pixels */
  162.     unsigned short ws_ypixel;    /* vertical size, pixels */
  163. };
  164. #endif
  165.     struct winsize winsize;
  166. #endif
  167.  
  168. #ifndef OSK
  169. #ifdef PENDING
  170. #if ! defined (FIONREAD) && ! defined (RDCHK)
  171.     /* do no delay reads on something that always gets closed on exit */
  172.  
  173.     devtty = open("/dev/tty",0);
  174.     if (devtty < 0) {
  175.     printf(cantopen,"/dev/tty") FLUSH;
  176.     finalize(1);
  177.     }
  178.     fcntl(devtty,F_SETFL,O_NDELAY);
  179. #endif
  180. #endif
  181. #endif
  182.     
  183.     /* get all that good termcap stuff */
  184.  
  185. #ifdef HAVETERMLIB
  186.     status = tgetent(tcbuf,getenv("TERM"));    /* get termcap entry */
  187.     if (status < 1) {
  188. #ifdef VERBOSE
  189.     printf("No termcap %s found.\n", status ? "file" : "entry") FLUSH;
  190. #else
  191.     fputs("Termcap botch\n",stdout) FLUSH
  192. #endif
  193.     finalize(1);
  194.     }
  195.     tmpaddr = tcarea;            /* set up strange tgetstr pointer */
  196.     s = Tgetstr("pc");            /* get pad character */
  197.     PC = *s;                /* get it where tputs wants it */
  198.     if (!tgetflag("bs")) {        /* is backspace not used? */
  199.     BC = Tgetstr("bc");        /* find out what is */
  200.     if (BC == nullstr)         /* terminfo grok's 'bs' but not 'bc' */
  201.         BC = Tgetstr("le");
  202.     } else
  203.     BC = "\b";            /* make a backspace handy */
  204.     UP = Tgetstr("up");            /* move up a line */
  205.     if (!*UP)                /* no UP string? */
  206.     marking = 0;            /* disable any marking */
  207.     if (muck_up_clear)            /* this is for weird HPs */
  208.     CL = "\n\n\n\n";
  209.     else
  210.     CL = Tgetstr("cl");        /* get clear string */
  211.     CE = Tgetstr("ce");            /* clear to end of line string */
  212. #ifdef CLEAREOL
  213.     CM = Tgetstr("cm");            /* cursor motion */
  214.     HO = Tgetstr("ho");            /* home cursor if no CM */
  215.     CD = Tgetstr("cd");            /* clear to end of display */
  216.     if (!*CE || !*CD || (!*CM && !*HO))    /* can we CE, CD, and home? */
  217.     can_home_clear = FALSE;        /*  no, so disable use of clear eol */
  218. #endif CLEAREOL
  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.     COLS = tgetnum("co");        /* columns on page */
  238.  
  239. #ifdef TIOCGWINSZ
  240.     { struct winsize ws;
  241.     if (ioctl(0, TIOCGWINSZ, &ws) >= 0 && ws.ws_row > 0 && ws.ws_col > 0) {
  242.         LINES = ws.ws_row;
  243.         COLS = ws.ws_col;
  244.     }
  245.     }
  246. #endif
  247.     
  248.     AM = tgetflag("am");        /* terminal wraps automatically? */
  249.     XN = tgetflag("xn");        /* then eats next newline? */
  250.     VB = Tgetstr("vb");
  251.     if (!*VB)
  252.     VB = "\007";
  253.     CR = Tgetstr("cr");
  254.     if (!*CR) {
  255. #ifndef OSK
  256.     if (tgetflag("nc") && *UP) {
  257. #else
  258.     if (*UP) {        /* OSK prints cr as crlf */
  259. #endif
  260.         CR = safemalloc((MEM_SIZE)strlen(UP)+2);
  261.         sprintf(CR,"%s\r",UP);
  262.     }
  263.     else
  264.         CR = "\r";
  265.     }
  266. #ifdef TIOCGWINSZ
  267.     if (ioctl(1, TIOCGWINSZ, &winsize)>=0) {
  268.         if (winsize.ws_row>0) LINES=winsize.ws_row;
  269.         if (winsize.ws_col>0) COLS=winsize.ws_col;
  270.     }
  271. #endif
  272. #else
  273.     ??????                /* Roll your own... */
  274. #endif
  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 = fopen(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.         else {
  345.         curmap->km_type[ch] = KM_STRING + garbage;
  346.         curmap->km_ptr[ch].km_str = savestr(m);
  347.         }
  348.     }
  349.     }
  350. }
  351.  
  352. KEYMAP*
  353. newkeymap()
  354. {
  355.     register int i;
  356.     register KEYMAP *map;
  357.  
  358. #ifndef lint
  359.     map = (KEYMAP*)safemalloc(sizeof(KEYMAP));
  360. #else
  361.     map = Null(KEYMAP*);
  362. #endif lint
  363.     for (i=127; i>=0; --i) {
  364.     map->km_ptr[i].km_km = Null(KEYMAP*);
  365.     map->km_type[i] = KM_NOTHIN;
  366.     }
  367.     return map;
  368. }
  369.  
  370. void
  371. show_macros()
  372. {
  373.     char prebuf[64];
  374.  
  375.     if (topmap != Null(KEYMAP*)) {
  376.     print_lines("Macros:\n",STANDOUT);
  377.     *prebuf = '\0';
  378.     show_keymap(topmap,prebuf);
  379.     }
  380. }
  381.  
  382. void
  383. show_keymap(curmap,prefix)
  384. register KEYMAP *curmap;
  385. char *prefix;
  386. {
  387.     register int i;
  388.     register char *next = prefix + strlen(prefix);
  389.     register int kt;
  390.  
  391.     for (i=0; i<128; i++) {
  392.     if (kt = curmap->km_type[i]) {
  393.         if (i < ' ')
  394.         sprintf(next,"^%c",i+64);
  395.         else if (i == ' ')
  396.         strcpy(next,"\\040");
  397.         else if (i == 127)
  398.         strcpy(next,"^?");
  399.         else
  400.         sprintf(next,"%c",i);
  401.         if ((kt >> KM_GSHIFT) & KM_GMASK) {
  402.         sprintf(cmd_buf,"+%d", (kt >> KM_GSHIFT) & KM_GMASK);
  403.         strcat(next,cmd_buf);
  404.         }
  405.         switch (kt & KM_TMASK) {
  406.         case KM_NOTHIN:
  407.         sprintf(cmd_buf,"%s    %c\n",prefix,i);
  408.         print_lines(cmd_buf,NOMARKING);
  409.         break;
  410.         case KM_KEYMAP:
  411.         show_keymap(curmap->km_ptr[(char)i].km_km, prefix);
  412.         break;
  413.         case KM_STRING:
  414.         sprintf(cmd_buf,"%s    %s\n",prefix,curmap->km_ptr[i].km_str);
  415.         print_lines(cmd_buf,NOMARKING);
  416.         break;
  417.         case KM_BOGUS:
  418.         sprintf(cmd_buf,"%s    BOGUS\n",prefix);
  419.         print_lines(cmd_buf,STANDOUT);
  420.         break;
  421.         }
  422.     }
  423.     }
  424. }
  425.  
  426. #endif
  427.  
  428. /* routine to pass to tputs */
  429.  
  430. char
  431. putchr(ch)
  432. register char ch;
  433. {
  434.     putchar(ch);
  435. #ifdef lint
  436.     ch = Null(char);
  437.     ch = ch;
  438. #endif
  439.     return((char) 0);
  440. }
  441.  
  442. /* input the 2nd and succeeding characters of a multi-character command */
  443. /* returns TRUE if command finished, FALSE if they rubbed out first character */
  444.  
  445. bool
  446. finish_command(donewline)
  447. int donewline;
  448. {
  449.     register char *s;
  450.     register bool quoteone = FALSE;
  451.  
  452.     s = buf;
  453.     if (s[1] != FINISHCMD)        /* someone faking up a command? */
  454.     return TRUE;
  455.     do {
  456.       top:
  457.     if (*s < ' ') {
  458.         putchar('^');
  459.         putchar(*s | 64);
  460.     }
  461.     else if (*s == '\177') {
  462.         putchar('^');
  463.         putchar('?');
  464.     }
  465.     else
  466.         putchar(*s);        /* echo previous character */
  467.     s++;
  468. re_read:
  469.     fflush(stdout);
  470.     getcmd(s);
  471.     if (quoteone) {
  472.         quoteone = FALSE;
  473.         continue;
  474.     }
  475.     if (errno || *s == Ctl('l')) {
  476.         *s = Ctl('r');        /* force rewrite on CONT */
  477.     }
  478.     if (*s == '\033') {        /* substitution desired? */
  479. #ifdef ESCSUBS
  480.         char tmpbuf[4], *cpybuf;
  481.  
  482.         tmpbuf[0] = '%';
  483.         read_tty(&tmpbuf[1],1);
  484. #ifdef RAWONLY
  485.         tmpbuf[1] &= 0177;
  486. #endif
  487.         tmpbuf[2] = '\0';
  488.         if (tmpbuf[1] == 'h') {
  489.         (void) help_subs();
  490.         *s = '\0';
  491.         reprint();
  492.         goto re_read;
  493.         }
  494.         else if (tmpbuf[1] == '\033') {
  495.         *s = '\0';
  496.         cpybuf = savestr(buf);
  497.         interp(buf, (sizeof buf), cpybuf);
  498.         free(cpybuf);
  499.         s = buf + strlen(buf);
  500.         reprint();
  501.         goto re_read;
  502.         }
  503.         else {
  504.         interp(s,(sizeof buf) - (s-buf),tmpbuf);
  505.         fputs(s,stdout);
  506.         s += strlen(s);
  507.         }
  508.         goto re_read;
  509. #else
  510.         notincl("^[");
  511.         *s = '\0';
  512.         reprint();
  513.         goto re_read;
  514. #endif
  515.     }
  516.     else if (*s == ERASECH) {    /* they want to rubout a char? */
  517.         rubout();
  518.         s--;            /* discount the char rubbed out */
  519.         if (*s < ' ' || *s == '\177')
  520.         rubout();
  521.         if (s == buf) {        /* entire string gone? */
  522.         fflush(stdout);        /* return to single char command mode */
  523.         return FALSE;
  524.         }
  525.         else
  526.         goto re_read;
  527.     }
  528.     else if (*s == KILLCH) {    /* wipe out the whole line? */
  529.         while (s-- != buf) {    /* emulate that many ERASEs */
  530.         rubout();
  531.         if (*s < ' ' || *s == '\177')
  532.             rubout();
  533.         }
  534.         fflush(stdout);
  535.         return FALSE;        /* return to single char mode */
  536.     }
  537. #ifdef WORDERASE
  538.     else if (*s == Ctl('w')) {    /* wipe out one word? */
  539.         *s-- = ' ';
  540.         while (!isspace(*s) || isspace(s[1])) {
  541.         rubout();
  542.         if (s-- == buf) {
  543.             fflush(stdout);
  544.             return FALSE;    /* return to single char mode */
  545.         }
  546.         if (*s < ' ' || *s == '\177')
  547.             rubout();
  548.         }
  549.         s++;
  550.         goto re_read;
  551.     }
  552. #endif
  553.     else if (*s == Ctl('r')) {
  554.         *s = '\0';
  555.         reprint();
  556.         goto re_read;
  557.     }
  558.     else if (*s == Ctl('v')) {
  559.         putchar('^');
  560.         backspace();
  561.         fflush(stdout);
  562.         getcmd(s);
  563.         goto top;
  564.     }
  565.     else if (*s == '\\') {
  566.         quoteone = TRUE;
  567.     }
  568.     } while (*s != '\n');        /* till a newline (not echoed) */
  569.     *s = '\0';                /* terminate the string nicely */
  570.     if (donewline)
  571.     putchar('\n') FLUSH;
  572.     return TRUE;            /* say we succeeded */
  573. }
  574.  
  575. /* discard any characters typed ahead */
  576.  
  577. void
  578. eat_typeahead()
  579. {
  580. #ifdef PUSHBACK
  581.     if (!typeahead && nextin==nextout)    /* cancel only keyboard stuff */
  582. #else
  583.     if (!typeahead)
  584. #endif
  585.     {
  586. #ifdef PENDING
  587. #ifndef OSK
  588.     while (input_pending())
  589.         read_tty(buf,sizeof(buf));
  590. #else
  591.     int max;
  592.     
  593.     while((max = _gs_rdy(0)) > 0) {
  594.         if(max > sizeof(buf)) max = sizeof(buf);
  595.         read_tty(buf,max);
  596.     }
  597. #endif
  598. #else /* this is probably v7 */
  599.     ioctl(_tty_ch,TIOCSETP,&_tty);
  600. #endif
  601.     }
  602. }
  603.  
  604. void
  605. settle_down()
  606. {
  607.     dingaling();
  608.     fflush(stdout);
  609.     sleep(1);
  610. #ifdef PUSHBACK
  611.     nextout = nextin;            /* empty circlebuf */
  612. #endif
  613.     eat_typeahead();
  614. }
  615.  
  616. #ifdef PUSHBACK
  617. /* read a character from the terminal, with multi-character pushback */
  618.  
  619. int
  620. read_tty(addr,size)
  621. char *addr;
  622. int size;
  623. {
  624.     if (nextout != nextin) {
  625.     *addr = circlebuf[nextout++];
  626.     nextout %= PUSHSIZE;
  627.     return 1;
  628.     }
  629.     else {
  630.     size = read(0,addr,size);
  631. #ifdef RAWONLY
  632.     *addr &= 0177;
  633. #endif
  634.     return size;
  635.     }
  636. }
  637.  
  638. #ifdef PENDING
  639. #if ! defined (FIONREAD) && ! defined (RDCHK)
  640. int
  641. circfill()
  642. {
  643.     register int Howmany = read(devtty,circlebuf+nextin,1);
  644.  
  645.     if (Howmany) {
  646.     nextin += Howmany;
  647.     nextin %= PUSHSIZE;
  648.     }
  649.     return Howmany;
  650. }
  651. #endif PENDING
  652. #endif FIONREAD
  653.  
  654. void
  655. pushchar(c)
  656. char c;
  657. {
  658.     nextout--;
  659.     if (nextout < 0)
  660.     nextout = PUSHSIZE - 1;
  661.     if (nextout == nextin) {
  662.     fputs("\npushback buffer overflow\n",stdout) FLUSH;
  663.     sig_catcher(0);
  664.     }
  665.     circlebuf[nextout] = c;
  666. }
  667.  
  668. #else PUSHBACK
  669. #ifndef read_tty
  670. /* read a character from the terminal, with hacks for O_NDELAY reads */
  671.  
  672. int
  673. read_tty(addr,size)
  674. char *addr;
  675. int size;
  676. {
  677.     if (is_input) {
  678.     *addr = pending_ch;
  679.     is_input = FALSE;
  680.     return 1;
  681.     }
  682.     else {
  683.     size = read(0,addr,size);
  684. #ifdef RAWONLY
  685.     *addr &= 0177;
  686. #endif
  687.     return size;
  688.     }
  689. }
  690. #endif read_tty
  691. #endif PUSHBACK
  692.  
  693. /* print an underlined string, one way or another */
  694.  
  695. void
  696. underprint(s)
  697. register char *s;
  698. {
  699.     assert(UC);
  700.     if (*UC) {        /* char by char underline? */
  701.     while (*s) {
  702.         if (*s < ' ') {
  703.         putchar('^');
  704.         backspace();/* back up over it */
  705.         underchar();/* and do the underline */
  706.         putchar(*s+64);
  707.         backspace();/* back up over it */
  708.         underchar();/* and do the underline */
  709.         }
  710.         else {
  711.         putchar(*s);
  712.         backspace();/* back up over it */
  713.         underchar();/* and do the underline */
  714.         }
  715.         s++;
  716.     }
  717.     }
  718.     else {        /* start and stop underline */
  719.     underline();    /* start underlining */
  720.     while (*s) {
  721.         if (*s < ' ') {
  722.         putchar('^');
  723.         putchar(*s+64);
  724.         }
  725.         else
  726.         putchar(*s);
  727.         s++;
  728.     }
  729.     un_underline();    /* stop underlining */
  730.     }
  731. }
  732.  
  733. /* keep screen from flashing strangely on magic cookie terminals */
  734.  
  735. #ifdef NOFIREWORKS
  736. void
  737. no_sofire()
  738. {
  739.     if (*UP && *SE) {        /* should we disable fireworks? */
  740.     putchar('\n');
  741.     un_standout();
  742.     up_line();
  743.     carriage_return();
  744.     }
  745. }
  746.  
  747. void
  748. no_ulfire()
  749. {
  750.     if (*UP && *US) {        /* should we disable fireworks? */
  751.     putchar('\n');
  752.     un_underline();
  753.     up_line();
  754.     carriage_return();
  755.     }
  756. }
  757. #endif
  758.  
  759. /* get a character into a buffer */
  760.  
  761. void
  762. getcmd(whatbuf)
  763. register char *whatbuf;
  764. {
  765. #ifdef PUSHBACK
  766.     register KEYMAP *curmap;
  767.     register int i;
  768.     bool no_macros; 
  769.     int times = 0;            /* loop detector */
  770.     char scrchar;
  771.  
  772. tryagain:
  773.     curmap = topmap;
  774.     no_macros = (whatbuf != buf && nextin == nextout); 
  775. #endif
  776.     for (;;) {
  777.     int_count = 0;
  778.     errno = 0;
  779.     if (read_tty(whatbuf,1) < 0)
  780.         if (!errno)
  781.             errno = EINTR;
  782.         else {
  783.         perror(readerr);
  784.         sig_catcher(0);
  785.     }
  786. #ifdef PUSHBACK
  787.     if (*whatbuf & 0200 || no_macros) {
  788.         *whatbuf &= 0177;
  789.         goto got_canonical;
  790.     }
  791.     if (curmap == Null(KEYMAP*))
  792.         goto got_canonical;
  793.     for (i = (curmap->km_type[*whatbuf] >> KM_GSHIFT) & KM_GMASK; i; --i){
  794.         read_tty(&scrchar,1);
  795.     }
  796.     switch (curmap->km_type[*whatbuf] & KM_TMASK) {
  797.     case KM_NOTHIN:            /* no entry? */
  798.         if (curmap == topmap)    /* unmapped canonical */
  799.         goto got_canonical;
  800.         settle_down();
  801.         goto tryagain;
  802.     case KM_KEYMAP:            /* another keymap? */
  803.         curmap = curmap->km_ptr[*whatbuf].km_km;
  804.         assert(curmap != Null(KEYMAP*));
  805.         break;
  806.     case KM_STRING:            /* a string? */
  807.         pushstring(curmap->km_ptr[*whatbuf].km_str);
  808.         if (++times > 20) {        /* loop? */
  809.         fputs("\nmacro loop?\n",stdout);
  810.         settle_down();
  811.         }
  812.         no_macros = FALSE;
  813.         goto tryagain;
  814.     }
  815. #else
  816. #ifdef RAWONLY
  817.     *whatbuf &= 0177;
  818. #endif
  819.     break;
  820. #endif
  821.     }
  822.  
  823. got_canonical:
  824. #ifndef TERMIO
  825.     if (*whatbuf == '\r')
  826.     *whatbuf = '\n';
  827. #endif
  828.     if (whatbuf == buf)
  829.     whatbuf[1] = FINISHCMD;        /* tell finish_command to work */
  830. }
  831.  
  832. #ifdef PUSHBACK
  833. void
  834. pushstring(str)
  835. char *str;
  836. {
  837.     register int i;
  838.     char tmpbuf[PUSHSIZE];
  839.     register char *s = tmpbuf;
  840.  
  841.     assert(str != Nullch);
  842.     interp(s,PUSHSIZE,str);
  843.     for (i = strlen(s)-1; i >= 0; --i) {
  844.     s[i] ^= 0200; 
  845.     pushchar(s[i]);
  846.     }
  847. }
  848. #endif
  849.  
  850. int
  851. get_anything()
  852. {
  853.     char tmpbuf[2];
  854.  
  855. reask_anything:
  856.     unflush_output();            /* disable any ^O in effect */
  857.     standout();
  858. #ifdef VERBOSE
  859.     IF(verbose)
  860.     fputs("[Type space to continue] ",stdout);
  861.     ELSE
  862. #endif
  863. #ifdef TERSE
  864.     fputs("[MORE] ",stdout);
  865. #endif
  866.     un_standout();
  867.     fflush(stdout);
  868.     eat_typeahead();
  869.     if (int_count) {
  870.     return -1;
  871.     }
  872.     collect_subjects();            /* loads subject cache until */
  873.                     /* input is pending */
  874.     getcmd(tmpbuf);
  875.     if (errno || *tmpbuf == '\f') {
  876.     putchar('\n') FLUSH;        /* if return from stop signal */
  877.     goto reask_anything;        /* give them a prompt again */
  878.     }
  879.     if (*tmpbuf == 'h') {
  880. #ifdef VERBOSE
  881.     IF(verbose)
  882.         fputs("\nType q to quit or space to continue.\n",stdout) FLUSH;
  883.     ELSE
  884. #endif
  885. #ifdef TERSE
  886.         fputs("\nq to quit, space to continue.\n",stdout) FLUSH;
  887. #endif
  888.     goto reask_anything;
  889.     }
  890.     else if (*tmpbuf != ' ' && *tmpbuf != '\n') {
  891.     carriage_return();
  892.     erase_eol();    /* erase the prompt */
  893.     carriage_return();
  894.     return *tmpbuf == 'q' ? -1 : *tmpbuf;
  895.     }
  896.     if (*tmpbuf == '\n') {
  897.     page_line = LINES - 1;
  898.     carriage_return();
  899.     erase_eol();
  900.     carriage_return();
  901.     }
  902.     else {
  903.     page_line = 1;
  904.     if (erase_screen)        /* -e? */
  905.         clear();            /* clear screen */
  906.     else {
  907.         carriage_return();
  908.         erase_eol();        /* erase the prompt */
  909.         carriage_return();
  910.     }
  911.     }
  912.     return 0;
  913. }
  914.  
  915. void
  916. in_char(prompt, newmode)
  917. char *prompt;
  918. char newmode;
  919. {
  920.     char oldmode = mode;
  921.  
  922. reask_in_char:
  923.     unflush_output();            /* disable any ^O in effect */
  924.     fputs(prompt,stdout);
  925.     fflush(stdout);
  926.     eat_typeahead();
  927.     mode = newmode;
  928.     getcmd(buf);
  929.     if (errno || *buf == '\f') {
  930.     putchar('\n') FLUSH;        /* if return from stop signal */
  931.     goto reask_in_char;        /* give them a prompt again */
  932.     }
  933.     mode = oldmode;
  934. }
  935.  
  936. int
  937. print_lines(what_to_print,hilite)
  938. char *what_to_print;
  939. int hilite;
  940. {
  941.     register char *s;
  942.     register int i;
  943.  
  944.     if (page_line < 0)            /* they do not want to see this? */
  945.     return -1;
  946.     for (s=what_to_print; *s; ) {
  947.     if (page_line >= LINES || int_count) {
  948.         if (i = -1, int_count || (i = get_anything())) {
  949.         page_line = -1;        /* disable further print_lines */
  950.         return i;
  951.         }
  952.     }
  953.     page_line++;
  954.     if (hilite == STANDOUT) {
  955. #ifdef NOFIREWORKS
  956.         if (erase_screen)
  957.         no_sofire();
  958. #endif
  959.         standout();
  960.     }
  961.     else if (hilite == UNDERLINE) {
  962. #ifdef NOFIREWORKS
  963.         if (erase_screen)
  964.         no_ulfire();
  965. #endif
  966.         underline();
  967.     }
  968.     for (i=0; i<COLS; i++) {
  969.         if (!*s)
  970.         break;
  971.         if (*s >= ' ')
  972.         putchar(*s);
  973.         else if (*s == '\t') {
  974.         putchar(*s);
  975.         i = ((i+8) & ~7) - 1; 
  976.         }
  977.         else if (*s == '\n') {
  978.         i = 32000;
  979.         }
  980.         else {
  981.         i++;
  982.         putchar('^');
  983.         putchar(*s + 64);
  984.         }
  985.         s++;
  986.     }
  987.     if (i) {
  988.         if (hilite == STANDOUT)
  989.         un_standout();
  990.         else if (hilite == UNDERLINE)
  991.         un_underline();
  992.         if (AM && i == COLS)
  993.         fflush(stdout);
  994.         else
  995.         putchar('\n') FLUSH;
  996.     }
  997.     }
  998.     return 0;
  999. }
  1000.  
  1001. void
  1002. page_init()
  1003. {
  1004.     page_line = 1;
  1005.     if (erase_screen)
  1006.     clear();
  1007.     else
  1008.     putchar('\n') FLUSH;
  1009. }
  1010.  
  1011. void
  1012. pad(num)
  1013. int num;
  1014. {
  1015.     register int i;
  1016.  
  1017.     for (i = num; i; --i)
  1018.     putchar(PC);
  1019.     fflush(stdout);
  1020. }
  1021.  
  1022. /* echo the command just typed */
  1023.  
  1024. #ifdef VERIFY
  1025. void
  1026. printcmd()
  1027. {
  1028.     if (verify && buf[1] == FINISHCMD) {
  1029.     if (*buf < ' ') {
  1030.         putchar('^');
  1031.         putchar(*buf | 64);
  1032.         backspace();
  1033.         backspace();
  1034.     }
  1035.     else {
  1036.         putchar(*buf);
  1037.         backspace();
  1038.     }
  1039.     fflush(stdout);
  1040.     }
  1041. }
  1042. #endif
  1043.  
  1044. void
  1045. rubout()
  1046. {
  1047.     backspace();            /* do the old backspace, */
  1048.     putchar(' ');            /*   space, */
  1049.     backspace();            /*     backspace trick */
  1050. }
  1051.  
  1052. void
  1053. reprint()
  1054. {
  1055.     register char *s;
  1056.  
  1057.     fputs("^R\n",stdout) FLUSH;
  1058.     for (s = buf; *s; s++) {
  1059.     if (*s < ' ') {
  1060.         putchar('^');
  1061.         putchar(*s | 64);
  1062.     }
  1063.     else
  1064.         putchar(*s);
  1065.     }
  1066. }
  1067.  
  1068. #ifdef CLEAREOL
  1069. void
  1070. home_cursor()
  1071. {
  1072.     char *tgoto();
  1073.  
  1074.     if (!*HO) {            /* no home sequence? */
  1075.     if (!*CM) {        /* no cursor motion either? */
  1076.         fputs ("\n\n\n", stdout);
  1077.         return;        /* forget it. */
  1078.     }
  1079.     tputs (tgoto (CM, 0, 0), 1, putchr);    /* go to home via CM */
  1080.     return;
  1081.     }
  1082.     else {            /* we have home sequence */
  1083.     tputs (HO, 1, putchr);    /* home via HO */
  1084.     }
  1085. }
  1086. #endif CLEAREOL
  1087.  
  1088.  
  1089. void
  1090. line_col_calcs()
  1091. {
  1092.      if (LINES > 0) {            /* is this a crt? */
  1093.       if ((!initlines) || (!initlines_specified))
  1094.            /* no -i or unreasonable value for initlines */
  1095.            if (ospeed >= B9600)     /* whole page at >= 9600 baud */
  1096.             initlines = LINES;
  1097.            else if (ospeed >= B4800)/* 16 lines at 4800 */
  1098.             initlines = 16;
  1099.            else            /* otherwise just header */
  1100.             initlines = 8;
  1101.      }
  1102.      else {                /* not a crt */
  1103.       LINES = 30000;        /* so don't page */
  1104.       CL = "\n\n";            /* put a couple of lines between */
  1105.       if ((!initlines) || (!initlines_specified))
  1106.            /* make initlines reasonable */
  1107.            initlines = 8;
  1108.      }
  1109.      if (COLS <= 0)
  1110.       COLS = 80;
  1111. }
  1112.  
  1113.  
  1114. #ifdef SIGWINCH
  1115. int
  1116. winch_catcher()
  1117. {
  1118.      /* Come here if window size change signal received */
  1119. #ifdef TIOCGWINSZ
  1120.      struct winsize ws;
  1121.  
  1122.      if (ioctl(0, TIOCGWINSZ, &ws) >= 0 && ws.ws_row > 0 && ws.ws_col > 0) {
  1123.           LINES = ws.ws_row;
  1124.           COLS = ws.ws_col;
  1125.           line_col_calcs();
  1126.      }
  1127. #else
  1128.      ???????
  1129.      /* Well, if SIGWINCH is defined, but TIOCGWINSZ isn't, there's    */
  1130.      /* almost certainly something wrong.  Figure it out for yourself, */
  1131.      /* because I don't know now to deal :-)                           */
  1132. #endif
  1133. }
  1134. #endif
  1135.