home *** CD-ROM | disk | FTP | other *** search
/ Beijing Paradise BBS Backup / PARADISE.ISO / software / BBSDOORW / UUPC11XT.ZIP / RN / TERM.C < prev    next >
Encoding:
C/C++ Source or Header  |  1992-11-21  |  33.7 KB  |  1,531 lines

  1. /* $Header: E:\SRC\UUPC\RN\RCS/TERM.C 1.1 1992/11/21 06:14:58 ahd Exp $
  2.  *
  3.  * $Log: TERM.C $
  4.  * Revision 1.1  1992/11/21  06:14:58  ahd
  5.  * Initial
  6.  *
  7.  *
  8.  *    Rev 1.0   18 Nov 1990  0:21:56
  9.  * Initial revision.
  10.  * Revision 4.3.2.7  90/04/21  16:54:29  sob
  11.  * Installed patches provided by SCO for SCO Xenix
  12.  *
  13.  * Revision 4.3.2.6  90/04/13  23:48:17  sob
  14.  * Modifications provided by Gene Hackney for 3b2.
  15.  *
  16.  * Revision 4.3.2.5  90/04/06  20:35:08  sob
  17.  * Added fixes for SCO Xenix sent by ronald@robobar.co.uk.
  18.  *
  19.  * Revision 4.3.2.4  90/03/22  23:05:38  sob
  20.  * Fixes provided by Wayne Davison <drivax!davison>
  21.  *
  22.  * Revision 4.3.2.3  89/11/28  01:51:58  sob
  23.  * Now handles SIGWINCH correctly.
  24.  *
  25.  * Revision 4.3.2.2  89/11/27  01:31:34  sob
  26.  * Altered NNTP code per ideas suggested by Bela Lubkin
  27.  * <filbo@gorn.santa-cruz.ca.us>
  28.  *
  29.  * Revision 4.3.2.1  89/11/06  01:02:12  sob
  30.  * Added RRN support from NNTP 1.5
  31.  *
  32.  * Revision 4.3.1.3  85/09/10  11:05:23  lwall
  33.  * Improved %m in in_char().
  34.  *
  35.  * Revision 4.3.1.2  85/05/16  16:45:35  lwall
  36.  * Forced \r to \n on input.
  37.  * Fix for terminfo braindamage regarding bc emulation.
  38.  *
  39.  * Revision 4.3.1.1  85/05/10  11:41:03  lwall
  40.  * Branch for patches.
  41.  *
  42.  * Revision 4.3  85/05/01  11:51:10  lwall
  43.  * Baseline for release with 4.3bsd.
  44.  *
  45.  */
  46.  
  47. #include <string.h>
  48. #include <stdlib.h>
  49. #include <conio.h>
  50.  
  51. #ifdef msdos
  52. #include <dos.h>
  53. #endif
  54.  
  55.  
  56. #include "EXTERN.h"
  57. #include "common.h"
  58. #include "util.h"
  59. #include "final.h"
  60. #include "help.h"
  61. #include "cheat.h"
  62. #include "intrp.h"
  63. #include "INTERN.h"
  64. #include "term.h"
  65.  
  66. char ERASECH;                /* rubout character */
  67. char KILLCH;                 /* line delete character */
  68. char tcarea[TCSIZE];         /* area for "compiled"
  69.                               * termcap strings */
  70.  
  71. /* guarantee capability pointer != Nullch */
  72. /* (I believe terminfo will ignore the &tmpaddr argument.) */
  73.  
  74. #define Tgetstr(key) ((tmpstr = tgetstr(key,&tmpaddr)) ? tmpstr : nullstr)
  75.  
  76. #ifdef PUSHBACK
  77. struct keymap
  78. {
  79.    char km_type[128];
  80.    union km_union
  81.    {
  82.       struct keymap *km_km;
  83.       char *km_str;
  84.    } km_ptr[128];
  85. };
  86.  
  87. #define KM_NOTHIN 0
  88. #define KM_STRING 1
  89. #define KM_KEYMAP 2
  90. #define KM_BOGUS 3
  91.  
  92. #define KM_TMASK 3
  93. #define KM_GSHIFT 4
  94. #define KM_GMASK 7
  95.  
  96. typedef struct keymap KEYMAP;
  97.  
  98. KEYMAP *topmap INIT(Null(KEYMAP *));
  99.  
  100. void mac_init();
  101. KEYMAP *newkeymap();
  102. void show_keymap();
  103. void pushstring();
  104.  
  105. #endif
  106.  
  107. void line_col_calcs();
  108.  
  109. /* terminal initialization */
  110.  
  111. void
  112.   term_init()
  113. {
  114.    savetty();                /* remember current tty
  115.                               * state */
  116.  
  117. #ifdef   unix
  118.  
  119. #ifdef TERMIO
  120.    ospeed = _tty.c_cflag & CBAUD;       /* for tputs() */
  121.    ERASECH = _tty.c_cc[VERASE]; /* for finish_command() */
  122.    KILLCH = _tty.c_cc[VKILL];/* for finish_command() */
  123. #else
  124.    ospeed = _tty.sg_ospeed;  /* for tputs() */
  125.    ERASECH = _tty.sg_erase;  /* for finish_command() */
  126.    KILLCH = _tty.sg_kill;    /* for finish_command() */
  127. #endif
  128.  
  129. #else                        /* unix */
  130.    ERASECH = '\b';
  131.    KILLCH = 'U' - '@';
  132. #endif                       /* unix */
  133.  
  134. #if   unix
  135.    /* The following could be a table but I can't be sure that there isn't */
  136.    /* some degree of sparsity out there in the world. */
  137.  
  138.    switch (ospeed)
  139.    {                         /* 1 second of padding */
  140.  
  141. #ifdef BEXTA
  142.     case BEXTA:
  143.       just_a_sec = 1920;
  144.       break;
  145. #else
  146.  
  147. #ifdef B19200
  148.     case B19200:
  149.       just_a_sec = 1920;
  150.       break;
  151. #endif
  152.  
  153. #endif
  154.  
  155.     case B9600:
  156.       just_a_sec = 960;
  157.       break;
  158.     case B4800:
  159.       just_a_sec = 480;
  160.       break;
  161.     case B2400:
  162.       just_a_sec = 240;
  163.       break;
  164.     case B1800:
  165.       just_a_sec = 180;
  166.       break;
  167.     case B1200:
  168.       just_a_sec = 120;
  169.       break;
  170.     case B600:
  171.       just_a_sec = 60;
  172.       break;
  173.     case B300:
  174.       just_a_sec = 30;
  175.       break;
  176.       /* do I really have to type the rest of this??? */
  177.     case B200:
  178.       just_a_sec = 20;
  179.       break;
  180.     case B150:
  181.       just_a_sec = 15;
  182.       break;
  183.     case B134:
  184.       just_a_sec = 13;
  185.       break;
  186.     case B110:
  187.       just_a_sec = 11;
  188.       break;
  189.     case B75:
  190.       just_a_sec = 8;
  191.       break;
  192.     case B50:
  193.       just_a_sec = 5;
  194.       break;
  195.     default:
  196.       just_a_sec = 960;
  197.       break;
  198.       /* if we are running detached I */
  199.    }                         /* don't want to know
  200.                               * about it! */
  201. #endif                       /* unix */
  202. }
  203.  
  204. /* set terminal characteristics */
  205.  
  206. void
  207.   term_set(tcbuf)
  208.    char *tcbuf;              /* temp area for
  209.                               * "uncompiled" termcap
  210.                               * entry */
  211. {
  212.    char *tmpaddr;            /* must not be register */
  213.    register char *tmpstr;
  214.    char *tgetstr();
  215.    char *s;
  216.    int status;
  217.  
  218. #ifdef TIOCGWINSZ
  219.  
  220. #ifdef u3b2
  221.    struct winsize
  222.    {
  223.       unsigned short ws_row; /* rows, in characters */
  224.       unsigned short ws_col; /* columns, in character */
  225.       unsigned short ws_xpixel; /* horizontal size,
  226.                                  * pixels */
  227.       unsigned short ws_ypixel; /* vertical size, pixels */
  228.    };
  229.  
  230. #endif
  231.    struct winsize winsize;
  232.  
  233. #endif
  234.  
  235. #ifdef PENDING
  236.  
  237. #if ! defined (FIONREAD) && ! defined (RDCHK)  && !defined(msdos)
  238.    /* do no delay reads on something that always gets closed on exit */
  239.  
  240.    devtty = open("/dev/tty", 0);
  241.    if (devtty < 0)
  242.    {
  243.       printf(cantopen, "/dev/tty") FLUSH;
  244.       finalize(1);
  245.    }
  246.    fcntl(devtty, F_SETFL, O_NDELAY);
  247. #endif
  248.  
  249. #endif
  250.  
  251.    /* get all that good termcap stuff */
  252.  
  253. #ifdef HAVETERMLIB
  254.    status = tgetent(tcbuf, getenv("TERM"));     /* get termcap entry */
  255.    if (status < 1)
  256.    {
  257.  
  258. #ifdef VERBOSE
  259.       printf("No termcap %s found.\n", status ? "file" : "entry") FLUSH;
  260. #else
  261.       fputs("Termcap botch\n", stdout) FLUSH
  262. #endif
  263.  
  264.          finalize(1);
  265.    }
  266.    tmpaddr = tcarea;         /* set up strange
  267.                               * tgetstr pointer */
  268.    s = Tgetstr("pc");        /* get pad character */
  269.    PC = *s;                  /* get it where tputs
  270.                               * wants it */
  271.    if (!tgetflag("bs"))
  272.    {                         /* is backspace not
  273.                               * used? */
  274.       BC = Tgetstr("bc");    /* find out what is */
  275.       if (BC == nullstr)     /* terminfo grok's 'bs'
  276.                               * but not 'bc' */
  277.          BC = Tgetstr("le");
  278.    }
  279.    else
  280.       BC = "\b";             /* make a backspace
  281.                               * handy */
  282.    UP = Tgetstr("up");       /* move up a line */
  283.    if (!*UP)                 /* no UP string? */
  284.       marking = 0;           /* disable any marking */
  285.    if (muck_up_clear)        /* this is for weird HPs */
  286.       CL = "\n\n\n\n";
  287.    else
  288.       CL = Tgetstr("cl");    /* get clear string */
  289.    CE = Tgetstr("ce");       /* clear to end of line
  290.                               * string */
  291.  
  292. #ifdef CLEAREOL
  293.    CM = Tgetstr("cm");       /* cursor motion */
  294.    HO = Tgetstr("ho");       /* home cursor if no CM */
  295.    CD = Tgetstr("cd");       /* clear to end of
  296.                               * display */
  297.    if (!*CE || !*CD || (!*CM && !*HO))  /* can we CE, CD, and
  298.                                          * home? */
  299.       can_home_clear = FALSE;/* no, so disable use of
  300.                               * clear eol */
  301. #endif                       /* CLEAREOL */
  302.  
  303.    SO = Tgetstr("so");       /* begin standout */
  304.    SE = Tgetstr("se");       /* end standout */
  305.    if ((SG = tgetnum("sg")) < 0)
  306.       SG = 0;                /* blanks left by SG, SE */
  307.    US = Tgetstr("us");       /* start underline */
  308.    UE = Tgetstr("ue");       /* end underline */
  309.    if ((UG = tgetnum("ug")) < 0)
  310.       UG = 0;                /* blanks left by US, UE */
  311.    if (*US)
  312.       UC = nullstr;          /* UC must not be NULL */
  313.    else
  314.       UC = Tgetstr("uc");    /* underline a character */
  315.    if (!*US && !*UC)
  316.    {                         /* no underline mode? */
  317.       US = SO;               /* substitute standout
  318.                               * mode */
  319.       UE = SE;
  320.       UG = SG;
  321.    }
  322.    LINES = tgetnum("li");    /* lines per page */
  323.    COLS = tgetnum("co");     /* columns on page */
  324.  
  325. #ifdef TIOCGWINSZ
  326.    {
  327.       struct winsize ws;
  328.  
  329.       if (ioctl(0, TIOCGWINSZ, &ws) >= 0 && ws.ws_row > 0 && ws.ws_col > 0)
  330.       {
  331.          LINES = ws.ws_row;
  332.          COLS = ws.ws_col;
  333.       }
  334.    }
  335. #endif
  336.  
  337.    AM = tgetflag("am");      /* terminal wraps
  338.                               * automatically? */
  339.    XN = tgetflag("xn");      /* then eats next
  340.                               * newline? */
  341.    VB = Tgetstr("vb");
  342.    if (!*VB)
  343.       VB = "\007";
  344.    CR = Tgetstr("cr");
  345.    if (!*CR)
  346.    {
  347.       if (tgetflag("nc") && *UP)
  348.       {
  349.          CR = safemalloc((MEM_SIZE) strlen(UP) + 2);
  350.          sprintf(CR, "%s\r", UP);
  351.       }
  352.       else
  353.          CR = "\r";
  354.    }
  355.  
  356. #ifdef TIOCGWINSZ
  357.    if (ioctl(1, TIOCGWINSZ, &winsize) >= 0)
  358.    {
  359.       if (winsize.ws_row > 0)
  360.          LINES = winsize.ws_row;
  361.       if (winsize.ws_col > 0)
  362.          COLS = winsize.ws_col;
  363.    }
  364. #endif
  365.  
  366. #else
  367.  
  368. #ifdef   msdos
  369.  
  370. #if   0
  371.    PC = 0;                   /* get it where tputs
  372.                               * wants it */
  373.    BC = "\b";                /* make a backspace
  374.                               * handy */
  375.    UP = "\033[A";            /* move up a line */
  376.    CL = "\033[H\033[J";      /* get clear string */
  377.    CE = "\033[K";            /* clear to end of line
  378.                               * string */
  379.  
  380. #ifdef CLEAREOL
  381.    CM = NULL;                /* cursor motion:
  382.                               * NEEDSWORK */
  383.    HO = "\033[H";            /* home cursor if no CM */
  384.    CD = "\033[J";            /* clear to end of
  385.                               * display */
  386.    if (!*CE || !*CD || (!*CM && !*HO))  /* can we CE, CD, and
  387.                                          * home? */
  388.       can_home_clear = FALSE;/* no, so disable use of
  389.                               * clear eol */
  390. #endif                       /* CLEAREOL */
  391.  
  392.    SO = "\033[1m";           /* begin standout */
  393.    SE = "\033[0m";           /* end standout */
  394.    SG = 0;                   /* blanks left by SG, SE */
  395.    US = "\033[4m";           /* start underline */
  396.    UE = "\033[0m";           /* end underline */
  397.    UG = 0;                   /* blanks left by US, UE */
  398.    UC = nullstr;             /* UC must not be NULL */
  399.    if (!*US && !*UC)
  400.    {                         /* no underline mode? */
  401.       US = SO;               /* substitute standout
  402.                               * mode */
  403.       UE = SE;
  404.       UG = SG;
  405.    }
  406.    LINES = 25;               /* lines per page
  407.                               * NEEDSWORK */
  408.    COLS = 80;                /* columns on page
  409.                               * NEEDSWORK */
  410.  
  411.    AM = TRUE;                /* terminal wraps
  412.                               * automatically? */
  413.    XN = FALSE;               /* then eats next
  414.                               * newline? */
  415.    VB = "\007";
  416.    CR = "\r";
  417. #endif                       /* 0 */
  418.  
  419. #else
  420.    ? ? ? ? ? ?               /* Roll your own... */
  421. #endif
  422.  
  423. #endif
  424.  
  425.       line_col_calcs();
  426.    noecho();                 /* turn off echo */
  427.    crmode();                 /* enter cbreak mode */
  428.  
  429. #ifdef PUSHBACK
  430.    mac_init(tcbuf);
  431. #endif
  432. }
  433.  
  434. #ifdef PUSHBACK
  435. void
  436.   mac_init(tcbuf)
  437.    char *tcbuf;
  438. {
  439.    char tmpbuf[1024];
  440.  
  441.    tmpfp = fopen(filexp(getval("RNMACRO", RNMACRO)), "r");
  442.    if (tmpfp != Nullfp)
  443.    {
  444.       while (fgets(tcbuf, 1024, tmpfp) != Nullch)
  445.       {
  446.          mac_line(tcbuf, tmpbuf, (sizeof tmpbuf));
  447.       }
  448.       fclose(tmpfp);
  449.    }
  450. }
  451.  
  452. void
  453.   mac_line(line, tmpbuf, tbsize)
  454.    char *line;
  455.    char *tmpbuf;
  456.    int tbsize;
  457. {
  458.    register char *s, *m;
  459.    register KEYMAP *curmap;
  460.    register int ch;
  461.    register int garbage = 0;
  462.    static char override[] = "\nkeymap overrides string\n";
  463.  
  464.    if (topmap == Null(KEYMAP *))
  465.       topmap = newkeymap();
  466.    if (*line == '#' || *line == '\n')
  467.       return;
  468.    if (line[ch = strlen(line) - 1] == '\n')
  469.       line[ch] = '\0';
  470.    m = dointerp(tmpbuf, tbsize, line, " \t");
  471.    if (!*m)
  472.       return;
  473.    while (*m == ' ' || *m == '\t')
  474.       m++;
  475.    for (s = tmpbuf, curmap = topmap; *s; s++)
  476.    {
  477.       ch = *s & 0177;
  478.       if (s[1] == '+' && isdigit(s[2]))
  479.       {
  480.          s += 2;
  481.          garbage = (*s & KM_GMASK) << KM_GSHIFT;
  482.       }
  483.       else
  484.          garbage = 0;
  485.       if (s[1])
  486.       {
  487.          if ((curmap->km_type[ch] & KM_TMASK) == KM_STRING)
  488.          {
  489.             fputs(override, stdout) FLUSH;
  490.             free(curmap->km_ptr[ch].km_str);
  491.             curmap->km_ptr[ch].km_str = Nullch;
  492.          }
  493.          curmap->km_type[ch] = KM_KEYMAP + garbage;
  494.          if (curmap->km_ptr[ch].km_km == Null(KEYMAP *))
  495.             curmap->km_ptr[ch].km_km = newkeymap();
  496.          curmap = curmap->km_ptr[ch].km_km;
  497.       }
  498.       else
  499.       {
  500.          if ((curmap->km_type[ch] & KM_TMASK) == KM_KEYMAP)
  501.             fputs(override, stdout) FLUSH;
  502.          else
  503.          {
  504.             curmap->km_type[ch] = KM_STRING + garbage;
  505.             curmap->km_ptr[ch].km_str = savestr(m);
  506.          }
  507.       }
  508.    }
  509. }
  510.  
  511. KEYMAP *
  512.   newkeymap()
  513. {
  514.    register int i;
  515.    register KEYMAP *map;
  516.  
  517. #ifndef lint
  518.    map = (KEYMAP *) safemalloc(sizeof (KEYMAP));
  519. #else
  520.    map = Null(KEYMAP *);
  521. #endif                       /* lint */
  522.  
  523.    for (i = 127; i >= 0; --i)
  524.    {
  525.       map->km_ptr[i].km_km = Null(KEYMAP *);
  526.       map->km_type[i] = KM_NOTHIN;
  527.    }
  528.    return map;
  529. }
  530.  
  531. void
  532.   show_macros()
  533. {
  534.    char prebuf[64];
  535.  
  536.    if (topmap != Null(KEYMAP *))
  537.    {
  538.       print_lines("Macros:\n", STANDOUT);
  539.       *prebuf = '\0';
  540.       show_keymap(topmap, prebuf);
  541.    }
  542. }
  543.  
  544. void
  545.   show_keymap(curmap, prefix)
  546.    register KEYMAP *curmap;
  547.    char *prefix;
  548. {
  549.    register int i;
  550.    register char *next = prefix + strlen(prefix);
  551.    register int kt;
  552.  
  553.    for (i = 0; i < 128; i++)
  554.    {
  555.       if (kt = curmap->km_type[i])
  556.       {
  557.          if (i < ' ')
  558.             sprintf(next, "^%c", i + 64);
  559.          else if (i == ' ')
  560.             strcpy(next, "\\040");
  561.          else if (i == 127)
  562.             strcpy(next, "^?");
  563.          else
  564.             sprintf(next, "%c", i);
  565.          if ((kt >> KM_GSHIFT) & KM_GMASK)
  566.          {
  567.             sprintf(cmd_buf, "+%d", (kt >> KM_GSHIFT) & KM_GMASK);
  568.             strcat(next, cmd_buf);
  569.          }
  570.          switch (kt & KM_TMASK)
  571.          {
  572.           case KM_NOTHIN:
  573.             sprintf(cmd_buf, "%s  %c\n", prefix, i);
  574.             print_lines(cmd_buf, NOMARKING);
  575.             break;
  576.           case KM_KEYMAP:
  577.             show_keymap(curmap->km_ptr[(char) i].km_km, prefix);
  578.             break;
  579.           case KM_STRING:
  580.             sprintf(cmd_buf, "%s  %s\n", prefix, curmap->km_ptr[i].km_str);
  581.             print_lines(cmd_buf, NOMARKING);
  582.             break;
  583.           case KM_BOGUS:
  584.             sprintf(cmd_buf, "%s  BOGUS\n", prefix);
  585.             print_lines(cmd_buf, STANDOUT);
  586.             break;
  587.          }
  588.       }
  589.    }
  590. }
  591.  
  592. #endif
  593.  
  594. /* routine to pass to tputs */
  595.  
  596. char
  597.   putchr(ch)
  598.    register char ch;
  599. {
  600.    putchar(ch);
  601.  
  602. #ifdef lint
  603.    ch = Null(char);
  604.    ch = ch;
  605. #endif
  606.  
  607.    return ((char) 0);
  608. }
  609.  
  610. /* input the 2nd and succeeding characters of a multi-character command */
  611. /* returns TRUE if command finished, FALSE if they rubbed out first character */
  612.  
  613. bool
  614. finish_command(donewline)
  615.    int donewline;
  616. {
  617.    register char *s;
  618.    register bool quoteone = FALSE;
  619.  
  620.    s = buf;
  621.    if (s[1] != FINISHCMD)    /* someone faking up a
  622.                               * command? */
  623.       return TRUE;
  624.    do
  625.    {
  626. top:
  627.       if (*s < ' ')
  628.       {
  629.          putchar('^');
  630.          putchar(*s | 64);
  631.       }
  632.       else if (*s == '\177')
  633.       {
  634.          putchar('^');
  635.          putchar('?');
  636.       }
  637.       else
  638.          putchar(*s);        /* echo previous
  639.                               * character */
  640.       s++;
  641. re_read:
  642.       fflush(stdout);
  643.       getcmd(s);
  644.       if (quoteone)
  645.       {
  646.          quoteone = FALSE;
  647.          continue;
  648.       }
  649.       if (errno || *s == Ctl('l'))
  650.       {
  651.          *s = Ctl('r');      /* force rewrite on CONT */
  652.       }
  653.       if (*s == '\033')
  654.       {                      /* substitution desired? */
  655.  
  656. #ifdef ESCSUBS
  657.          char tmpbuf[4], *cpybuf;
  658.  
  659.          tmpbuf[0] = '%';
  660.          read_tty(&tmpbuf[1], 1);
  661.  
  662. #ifdef RAWONLY
  663.          tmpbuf[1] &= 0177;
  664. #endif
  665.  
  666.          tmpbuf[2] = '\0';
  667.          if (tmpbuf[1] == 'h')
  668.          {
  669.             (void) help_subs();
  670.             *s = '\0';
  671.             reprint();
  672.             goto re_read;
  673.          }
  674.          else if (tmpbuf[1] == '\033')
  675.          {
  676.             *s = '\0';
  677.             cpybuf = savestr(buf);
  678.             interp(buf, (sizeof buf), cpybuf);
  679.             free(cpybuf);
  680.             s = buf + strlen(buf);
  681.             reprint();
  682.             goto re_read;
  683.          }
  684.          else
  685.          {
  686.             interp(s, (sizeof buf) - (s - buf), tmpbuf);
  687.             fputs(s, stdout);
  688.             s += strlen(s);
  689.          }
  690.          goto re_read;
  691. #else
  692.          notincl("^[");
  693.          *s = '\0';
  694.          reprint();
  695.          goto re_read;
  696. #endif
  697.       }
  698.       else if (*s == ERASECH)
  699.       {                      /* they want to rubout a
  700.                               * char? */
  701.          rubout();
  702.          s--;                /* discount the char
  703.                               * rubbed out */
  704.          if (*s < ' ' || *s == '\177')
  705.             rubout();
  706.          if (s == buf)
  707.          {                   /* entire string gone? */
  708.             fflush(stdout);  /* return to single char
  709.                               * command mode */
  710.             return FALSE;
  711.          }
  712.          else
  713.             goto re_read;
  714.       }
  715.       else if (*s == KILLCH)
  716.       {                      /* wipe out the whole
  717.                               * line? */
  718.          while (s-- != buf)
  719.          {                   /* emulate that many
  720.                               * ERASEs */
  721.             rubout();
  722.             if (*s < ' ' || *s == '\177')
  723.                rubout();
  724.          }
  725.          fflush(stdout);
  726.          return FALSE;       /* return to single char
  727.                               * mode */
  728.       }
  729.  
  730. #ifdef WORDERASE
  731.       else if (*s == Ctl('w'))
  732.       {                      /* wipe out one word? */
  733.          *s-- = ' ';
  734.          while (!isspace(*s) || isspace(s[1]))
  735.          {
  736.             rubout();
  737.             if (s-- == buf)
  738.             {
  739.                fflush(stdout);
  740.                return FALSE; /* return to single char
  741.                               * mode */
  742.             }
  743.             if (*s < ' ' || *s == '\177')
  744.                rubout();
  745.          }
  746.          s++;
  747.          goto re_read;
  748.       }
  749. #endif
  750.  
  751.       else if (*s == Ctl('r'))
  752.       {
  753.          *s = '\0';
  754.          reprint();
  755.          goto re_read;
  756.       }
  757.       else if (*s == Ctl('v'))
  758.       {
  759.          putchar('^');
  760.          backspace();
  761.          fflush(stdout);
  762.          getcmd(s);
  763.          goto top;
  764.       }
  765.       else if (*s == '\\')
  766.       {
  767.          quoteone = TRUE;
  768.       }
  769.    } while (*s != '\n');     /* till a newline (not
  770.                               * echoed) */
  771.    *s = '\0';                /* terminate the string
  772.                               * nicely */
  773.    if (donewline)
  774.       putchar('\n') FLUSH;
  775.    return TRUE;              /* say we succeeded */
  776. }
  777.  
  778. /* discard any characters typed ahead */
  779.  
  780. void
  781.   eat_typeahead()
  782. {
  783.  
  784. #ifdef PUSHBACK
  785.    if (!typeahead && nextin == nextout) /* cancel only keyboard
  786.                                          * stuff */
  787. #else
  788.    if (!typeahead)
  789. #endif
  790.  
  791.    {
  792.  
  793. #ifdef PENDING
  794.       while (input_pending())
  795.          read_tty(buf, sizeof (buf));
  796. #else                        /* this is probably v7 */
  797.       ioctl(_tty_ch, TIOCSETP, &_tty);
  798. #endif
  799.    }
  800. }
  801.  
  802. void
  803.   settle_down()
  804. {
  805.    dingaling();
  806.    fflush(stdout);
  807.    sleep(1);
  808.  
  809. #ifdef PUSHBACK
  810.    nextout = nextin;         /* empty circlebuf */
  811. #endif
  812.  
  813.    eat_typeahead();
  814. }
  815.  
  816. #ifdef PUSHBACK
  817.  
  818. #ifdef   msdos
  819. /* read a character from the terminal, with multi-character pushback */
  820.  
  821. int
  822.   read_tty(addr, size)
  823.    char *addr;
  824.    int size;
  825. {
  826.    register int i;
  827.  
  828.    if (nextout != nextin)
  829.    {
  830.       *addr = circlebuf[nextout++];
  831.       nextout %= PUSHSIZE;
  832.       return 1;
  833.    }
  834.    else
  835.    {
  836.       i = 0;
  837.       do
  838.       {
  839.          addr[i] = getch();
  840.  
  841. #ifdef RAWONLY
  842.          addr[i] &= 0177;
  843. #endif
  844.       } while (++i < size && kbhit());
  845.       return i;
  846.    }
  847. }
  848.  
  849. #else                        /* msdos */
  850. /* read a character from the terminal, with multi-character pushback */
  851.  
  852. int
  853.   read_tty(addr, size)
  854.    char *addr;
  855.    int size;
  856. {
  857.    if (nextout != nextin)
  858.    {
  859.       *addr = circlebuf[nextout++];
  860.       nextout %= PUSHSIZE;
  861.       return 1;
  862.    }
  863.    else
  864.    {
  865.       size = read(0, addr, size);
  866.  
  867. #ifdef RAWONLY
  868.       *addr &= 0177;
  869. #endif
  870.  
  871.       return size;
  872.    }
  873. }
  874.  
  875. #endif                       /* msdos */
  876.  
  877. #ifdef PENDING
  878.  
  879. #if ! defined (FIONREAD) && ! defined (RDCHK) && !defined(msdos)
  880. int
  881.   circfill()
  882. {
  883.    register int Howmany = read(devtty, circlebuf + nextin, 1);
  884.  
  885.    if (Howmany)
  886.    {
  887.       nextin += Howmany;
  888.       nextin %= PUSHSIZE;
  889.    }
  890.    return Howmany;
  891. }
  892.  
  893. #endif                       /* PENDING */
  894.  
  895. #endif                       /* FIONREAD */
  896.  
  897. void
  898.   pushchar(c)
  899.    char c;
  900. {
  901.    nextout--;
  902.    if (nextout < 0)
  903.       nextout = PUSHSIZE - 1;
  904.    if (nextout == nextin)
  905.    {
  906.       fputs("\npushback buffer overflow\n", stdout) FLUSH;
  907.       sig_catcher(0);
  908.    }
  909.    circlebuf[nextout] = c;
  910. }
  911.  
  912. #else                        /* PUSHBACK */
  913.  
  914. #ifndef read_tty
  915.  
  916. #ifdef msdos
  917. /* read a character from the terminal */
  918.  
  919. int
  920.   read_tty(addr, size)
  921.    char *addr;
  922.    int size;
  923. {
  924.    register int i;
  925.  
  926.    for (i = 0; i < size; i++)
  927.    {
  928.       addr[i] = getch();
  929.  
  930. #ifdef RAWONLY
  931.       addr[i] &= 0177;
  932. #endif
  933.    }
  934.    return i;
  935. }
  936.  
  937. #else                        /* msdos */
  938. /* read a character from the terminal, with hacks for O_NDELAY reads */
  939.  
  940. int
  941.   read_tty(addr, size)
  942.    char *addr;
  943.    int size;
  944. {
  945.    if (is_input)
  946.    {
  947.       *addr = pending_ch;
  948.       is_input = FALSE;
  949.       return 1;
  950.    }
  951.    else
  952.    {
  953.       size = read(0, addr, size);
  954.  
  955. #ifdef RAWONLY
  956.       *addr &= 0177;
  957. #endif
  958.  
  959.       return size;
  960.    }
  961. }
  962.  
  963. #endif                       /* msdos */
  964.  
  965. #endif                       /* read_tty */
  966.  
  967. #endif                       /* PUSHBACK */
  968.  
  969. /* print an underlined string, one way or another */
  970.  
  971. void
  972.   underprint(s)
  973.    register char *s;
  974. {
  975.    assert(UC);
  976.    if (*UC)
  977.    {                         /* char by char
  978.                               * underline? */
  979.       while (*s)
  980.       {
  981.          if (*s < ' ')
  982.          {
  983.             putchar('^');
  984.             backspace();     /* back up over it */
  985.             underchar();     /* and do the underline */
  986.             putchar(*s + 64);
  987.             backspace();     /* back up over it */
  988.             underchar();     /* and do the underline */
  989.          }
  990.          else
  991.          {
  992.             putchar(*s);
  993.             backspace();     /* back up over it */
  994.             underchar();     /* and do the underline */
  995.          }
  996.          s++;
  997.       }
  998.    }
  999.    else
  1000.    {                         /* start and stop
  1001.                               * underline */
  1002.       underline();           /* start underlining */
  1003.       while (*s)
  1004.       {
  1005.          if (*s < ' ')
  1006.          {
  1007.             putchar('^');
  1008.             putchar(*s + 64);
  1009.          }
  1010.          else
  1011.             putchar(*s);
  1012.          s++;
  1013.       }
  1014.       un_underline();        /* stop underlining */
  1015.    }
  1016. }
  1017.  
  1018. /* keep screen from flashing strangely on magic cookie terminals */
  1019.  
  1020. #ifdef NOFIREWORKS
  1021. void
  1022.   no_sofire()
  1023. {
  1024.    if (*UP && *SE)
  1025.    {                         /* should we disable
  1026.                               * fireworks? */
  1027.       putchar('\n');
  1028.       un_standout();
  1029.       up_line();
  1030.       carriage_return();
  1031.    }
  1032. }
  1033.  
  1034. void
  1035.   no_ulfire()
  1036. {
  1037.    if (*UP && *US)
  1038.    {                         /* should we disable
  1039.                               * fireworks? */
  1040.       putchar('\n');
  1041.       un_underline();
  1042.       up_line();
  1043.       carriage_return();
  1044.    }
  1045. }
  1046.  
  1047. #endif
  1048.  
  1049. /* get a character into a buffer */
  1050.  
  1051. void
  1052.   getcmd(whatbuf)
  1053.    register char *whatbuf;
  1054. {
  1055.  
  1056. #ifdef PUSHBACK
  1057.    register KEYMAP *curmap;
  1058.    register int i;
  1059.    bool no_macros;
  1060.    int times = 0;            /* loop detector */
  1061.    char scrchar;
  1062.  
  1063. tryagain:
  1064.    curmap = topmap;
  1065.    no_macros = (whatbuf != buf && nextin == nextout);
  1066. #endif
  1067.  
  1068.    for (;;)
  1069.    {
  1070.       int_count = 0;
  1071.       errno = 0;
  1072.       if (read_tty(whatbuf, 1) < 0)
  1073.          if (!errno)
  1074.             errno = EINTR;
  1075.          else
  1076.          {
  1077.             perror(readerr);
  1078.             sig_catcher(0);
  1079.          }
  1080.  
  1081. #ifdef PUSHBACK
  1082.       if (*whatbuf & 0200 || no_macros)
  1083.       {
  1084.          *whatbuf &= 0177;
  1085.          goto got_canonical;
  1086.       }
  1087.       if (curmap == Null(KEYMAP *))
  1088.          goto got_canonical;
  1089.       for (i = (curmap->km_type[*whatbuf] >> KM_GSHIFT) & KM_GMASK; i; --i)
  1090.       {
  1091.          read_tty(&scrchar, 1);
  1092.       }
  1093.       switch (curmap->km_type[*whatbuf] & KM_TMASK)
  1094.       {
  1095.        case KM_NOTHIN:       /* no entry? */
  1096.          if (curmap == topmap)  /* unmapped canonical */
  1097.             goto got_canonical;
  1098.          settle_down();
  1099.          goto tryagain;
  1100.        case KM_KEYMAP:       /* another keymap? */
  1101.          curmap = curmap->km_ptr[*whatbuf].km_km;
  1102.          assert(curmap != Null(KEYMAP *));
  1103.          break;
  1104.        case KM_STRING:       /* a string? */
  1105.          pushstring(curmap->km_ptr[*whatbuf].km_str);
  1106.          if (++times > 20)
  1107.          {                   /* loop? */
  1108.             fputs("\nmacro loop?\n", stdout);
  1109.             settle_down();
  1110.          }
  1111.          no_macros = FALSE;
  1112.          goto tryagain;
  1113.       }
  1114. #else
  1115.  
  1116. #ifdef RAWONLY
  1117.       *whatbuf &= 0177;
  1118. #endif
  1119.  
  1120.       break;
  1121. #endif
  1122.    }
  1123.  
  1124. got_canonical:
  1125.  
  1126. #ifndef TERMIO
  1127.    if (*whatbuf == '\r')
  1128.       *whatbuf = '\n';
  1129. #endif
  1130.  
  1131.    if (whatbuf == buf)
  1132.       whatbuf[1] = FINISHCMD;/* tell finish_command
  1133.                               * to work */
  1134. }
  1135.  
  1136. #ifdef PUSHBACK
  1137. void
  1138.   pushstring(str)
  1139.    char *str;
  1140. {
  1141.    register int i;
  1142.    char tmpbuf[PUSHSIZE];
  1143.    register char *s = tmpbuf;
  1144.  
  1145.    assert(str != Nullch);
  1146.    interp(s, PUSHSIZE, str);
  1147.    for (i = strlen(s) - 1; i >= 0; --i)
  1148.    {
  1149.       s[i] ^= 0200;
  1150.       pushchar(s[i]);
  1151.    }
  1152. }
  1153.  
  1154. #endif
  1155.  
  1156. int
  1157.   get_anything()
  1158. {
  1159.    char tmpbuf[2];
  1160.  
  1161. reask_anything:
  1162.    unflush_output();         /* disable any ^O in
  1163.                               * effect */
  1164.    standout();
  1165.  
  1166. #ifdef VERBOSE
  1167.    IF(verbose)
  1168.       fputs("[Type space to continue] ", stdout);
  1169.    ELSE
  1170. #endif
  1171.  
  1172. #ifdef TERSE
  1173.       fputs("[MORE] ", stdout);
  1174. #endif
  1175.  
  1176.    un_standout();
  1177.    fflush(stdout);
  1178.    eat_typeahead();
  1179.    if (int_count)
  1180.    {
  1181.       return -1;
  1182.    }
  1183.    collect_subjects();       /* loads subject cache
  1184.                               * until */
  1185.    /* input is pending */
  1186.    getcmd(tmpbuf);
  1187.    if (errno || *tmpbuf == '\f')
  1188.    {
  1189.       putchar('\n') FLUSH;   /* if return from stop
  1190.                               * signal */
  1191.       goto reask_anything;   /* give them a prompt
  1192.                               * again */
  1193.    }
  1194.    if (*tmpbuf == 'h')
  1195.    {
  1196.  
  1197. #ifdef VERBOSE
  1198.       IF(verbose)
  1199.          fputs("\nType q to quit or space to continue.\n", stdout) FLUSH;
  1200.       ELSE
  1201. #endif
  1202.  
  1203. #ifdef TERSE
  1204.          fputs("\nq to quit, space to continue.\n", stdout) FLUSH;
  1205. #endif
  1206.  
  1207.       goto reask_anything;
  1208.    }
  1209.    else if (*tmpbuf != ' ' && *tmpbuf != '\n')
  1210.    {
  1211.       carriage_return();
  1212.       erase_eol();           /* erase the prompt */
  1213.       carriage_return();
  1214.       return *tmpbuf == 'q' ? -1 : *tmpbuf;
  1215.    }
  1216.    if (*tmpbuf == '\n')
  1217.    {
  1218.       page_line = LINES - 1;
  1219.       carriage_return();
  1220.       erase_eol();
  1221.       carriage_return();
  1222.    }
  1223.    else
  1224.    {
  1225.       page_line = 1;
  1226.       if (erase_screen)      /* -e? */
  1227.          clear();            /* clear screen */
  1228.       else
  1229.       {
  1230.          carriage_return();
  1231.          erase_eol();        /* erase the prompt */
  1232.          carriage_return();
  1233.       }
  1234.    }
  1235.    return 0;
  1236. }
  1237.  
  1238. void
  1239.   in_char(prompt, newmode)
  1240.    char *prompt;
  1241.    char newmode;
  1242. {
  1243.    char oldmode = mode;
  1244.  
  1245. reask_in_char:
  1246.    unflush_output();         /* disable any ^O in
  1247.                               * effect */
  1248.    fputs(prompt, stdout);
  1249.    fflush(stdout);
  1250.    eat_typeahead();
  1251.    mode = newmode;
  1252.    getcmd(buf);
  1253.    if (errno || *buf == '\f')
  1254.    {
  1255.       putchar('\n') FLUSH;   /* if return from stop
  1256.                               * signal */
  1257.       goto reask_in_char;    /* give them a prompt
  1258.                               * again */
  1259.    }
  1260.    mode = oldmode;
  1261. }
  1262.  
  1263. int
  1264.   print_lines(what_to_print, hilite)
  1265.    char *what_to_print;
  1266.    int hilite;
  1267. {
  1268.    register char *s;
  1269.    register int i;
  1270.  
  1271.    if (page_line < 0)        /* they do not want to
  1272.                               * see this? */
  1273.       return -1;
  1274.    for (s = what_to_print; *s;)
  1275.    {
  1276.       if (page_line >= LINES || int_count)
  1277.       {
  1278.          if (i = -1, int_count || (i = get_anything()))
  1279.          {
  1280.             page_line = -1;  /* disable further
  1281.                               * print_lines */
  1282.             return i;
  1283.          }
  1284.       }
  1285.       page_line++;
  1286.       if (hilite == STANDOUT)
  1287.       {
  1288.  
  1289. #ifdef NOFIREWORKS
  1290.          if (erase_screen)
  1291.             no_sofire();
  1292. #endif
  1293.  
  1294.          standout();
  1295.       }
  1296.       else if (hilite == UNDERLINE)
  1297.       {
  1298.  
  1299. #ifdef NOFIREWORKS
  1300.          if (erase_screen)
  1301.             no_ulfire();
  1302. #endif
  1303.  
  1304.          underline();
  1305.       }
  1306.       for (i = 0; i < COLS; i++)
  1307.       {
  1308.          if (!*s)
  1309.             break;
  1310.          if (*s >= ' ')
  1311.             putchar(*s);
  1312.          else if (*s == '\t')
  1313.          {
  1314.             putchar(*s);
  1315.             i = ((i + 8) & ~7) - 1;
  1316.          }
  1317.          else if (*s == '\n')
  1318.          {
  1319.             i = 32000;
  1320.          }
  1321.          else
  1322.          {
  1323.             i++;
  1324.             putchar('^');
  1325.             putchar(*s + 64);
  1326.          }
  1327.          s++;
  1328.       }
  1329.       if (i)
  1330.       {
  1331.          if (hilite == STANDOUT)
  1332.             un_standout();
  1333.          else if (hilite == UNDERLINE)
  1334.             un_underline();
  1335.          if (AM && i == COLS)
  1336.             fflush(stdout);
  1337.          else
  1338.             putchar('\n') FLUSH;
  1339.       }
  1340.    }
  1341.    return 0;
  1342. }
  1343.  
  1344. void
  1345.   page_init()
  1346. {
  1347.    page_line = 1;
  1348.    if (erase_screen)
  1349.       clear();
  1350.    else
  1351.       putchar('\n') FLUSH;
  1352. }
  1353.  
  1354. void
  1355.   pad(num)
  1356.    int num;
  1357. {
  1358.  
  1359. #ifdef   msdos
  1360.    /* eventually, wait "num" ms */
  1361. #else
  1362.    register int i;
  1363.  
  1364.    for (i = num; i; --i)
  1365.       putchar(PC);
  1366.    fflush(stdout);
  1367. #endif                       /* msdos */
  1368. }
  1369.  
  1370. /* echo the command just typed */
  1371.  
  1372. #ifdef VERIFY
  1373. void
  1374.   printcmd()
  1375. {
  1376.    if (verify && buf[1] == FINISHCMD)
  1377.    {
  1378.       if (*buf < ' ')
  1379.       {
  1380.          putchar('^');
  1381.          putchar(*buf | 64);
  1382.          backspace();
  1383.          backspace();
  1384.       }
  1385.       else
  1386.       {
  1387.          putchar(*buf);
  1388.          backspace();
  1389.       }
  1390.       fflush(stdout);
  1391.    }
  1392. }
  1393.  
  1394. #endif
  1395.  
  1396. void
  1397.   rubout()
  1398. {
  1399.    backspace();              /* do the old backspace, */
  1400.    putchar(' ');             /* space, */
  1401.    backspace();              /* backspace trick */
  1402. }
  1403.  
  1404. void
  1405.   reprint()
  1406. {
  1407.    register char *s;
  1408.  
  1409.    fputs("^R\n", stdout) FLUSH;
  1410.    for (s = buf; *s; s++)
  1411.    {
  1412.       if (*s < ' ')
  1413.       {
  1414.          putchar('^');
  1415.          putchar(*s | 64);
  1416.       }
  1417.       else
  1418.          putchar(*s);
  1419.    }
  1420. }
  1421.  
  1422. #ifdef CLEAREOL
  1423. void
  1424.   home_cursor()
  1425. {
  1426.  
  1427.    if (!*HO)
  1428.    {                         /* no home sequence? */
  1429.       if (!*CM)
  1430.       {                      /* no cursor motion
  1431.                               * either? */
  1432.          fputs("\n\n\n", stdout);
  1433.          return;             /* forget it. */
  1434.       }
  1435.       tputs(tgoto(CM, 0, 0), 1, putchr);        /* go to home via CM */
  1436.       return;
  1437.    }
  1438.    else
  1439.    {                         /* we have home sequence */
  1440.       tputs(HO, 1, putchr);  /* home via HO */
  1441.    }
  1442. }
  1443.  
  1444. #endif                       /* CLEAREOL */
  1445.  
  1446.  
  1447. void
  1448.   line_col_calcs()
  1449. {
  1450.    if (LINES > 0)
  1451.    {                         /* is this a crt? */
  1452.       if ((!initlines) || (!initlines_specified))
  1453.          /* no -i or unreasonable value for initlines */
  1454.          if (ospeed >= B9600)/* whole page at >= 9600
  1455.                               * baud */
  1456.             initlines = LINES;
  1457.          else if (ospeed >= B4800)      /* 16 lines at 4800 */
  1458.             initlines = 16;
  1459.          else                /* otherwise just header */
  1460.             initlines = 8;
  1461.    }
  1462.  
  1463. #ifndef  msdos
  1464.    else
  1465.    {                         /* not a crt */
  1466.       LINES = 30000;         /* so don't page */
  1467.       CL = "\n\n";           /* put a couple of lines
  1468.                               * between */
  1469.       if ((!initlines) || (!initlines_specified))
  1470.          /* make initlines reasonable */
  1471.          initlines = 8;
  1472.    }
  1473. #endif                       /* msdos */
  1474.  
  1475.    if (COLS <= 0)
  1476.       COLS = 80;
  1477. }
  1478.  
  1479.  
  1480. #ifdef SIGWINCH
  1481. int
  1482.   winch_catcher()
  1483. {
  1484.    /* Come here if window size change signal received */
  1485.  
  1486. #ifdef TIOCGWINSZ
  1487.    struct winsize ws;
  1488.  
  1489.    if (ioctl(0, TIOCGWINSZ, &ws) >= 0 && ws.ws_row > 0 && ws.ws_col > 0)
  1490.    {
  1491.       LINES = ws.ws_row;
  1492.       COLS = ws.ws_col;
  1493.       line_col_calcs();
  1494.    }
  1495. #else
  1496.    ? ? ? ? ? ? ?
  1497.    /* Well, if SIGWINCH is defined, but TIOCGWINSZ isn't, there's    */
  1498.    /* almost certainly something wrong.  Figure it out for yourself, */
  1499.    /* because I don't know now to deal :-)                           */
  1500. #endif
  1501. }
  1502.  
  1503. #endif
  1504.  
  1505. #ifdef   msdos
  1506. noecho()
  1507. {
  1508. }
  1509.  
  1510. char *tgoto(char *command, int x, int y)
  1511. {
  1512. }
  1513.  
  1514. crmode()
  1515. {
  1516. }
  1517.  
  1518. unflush_output()
  1519. {
  1520. }
  1521.  
  1522. savetty()
  1523. {
  1524. }
  1525.  
  1526. resetty()
  1527. {
  1528. }
  1529.  
  1530. #endif                       /* msdos */
  1531.