home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Unix / Shells / tcsh / Source / ed.screen.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-02-21  |  34.6 KB  |  1,506 lines

  1. /* $Header: /u/christos/src/tcsh-6.03/RCS/ed.screen.c,v 3.27 1992/10/27 16:18:15 christos Exp $ */
  2. /*
  3.  * ed.screen.c: Editor/termcap-curses interface
  4.  */
  5. /*-
  6.  * Copyright (c) 1980, 1991 The Regents of the University of California.
  7.  * All rights reserved.
  8.  *
  9.  * Redistribution and use in source and binary forms, with or without
  10.  * modification, are permitted provided that the following conditions
  11.  * are met:
  12.  * 1. Redistributions of source code must retain the above copyright
  13.  *    notice, this list of conditions and the following disclaimer.
  14.  * 2. Redistributions in binary form must reproduce the above copyright
  15.  *    notice, this list of conditions and the following disclaimer in the
  16.  *    documentation and/or other materials provided with the distribution.
  17.  * 3. All advertising materials mentioning features or use of this software
  18.  *    must display the following acknowledgement:
  19.  *    This product includes software developed by the University of
  20.  *    California, Berkeley and its contributors.
  21.  * 4. Neither the name of the University nor the names of its contributors
  22.  *    may be used to endorse or promote products derived from this software
  23.  *    without specific prior written permission.
  24.  *
  25.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  26.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  27.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  28.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  29.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  30.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  31.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  32.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  33.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  34.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  35.  * SUCH DAMAGE.
  36.  */
  37. #include "sh.h"
  38.  
  39. RCSID("$Id: ed.screen.c,v 3.27 1992/10/27 16:18:15 christos Exp $")
  40.  
  41. #include "ed.h"
  42. #include "tc.h"
  43. #include "ed.defns.h"
  44.  
  45. /*
  46.  * We don't prototype these, cause some systems have them wrong!
  47.  */
  48. extern char *tgoto();
  49. extern char *tgetstr();
  50. extern char *tputs();
  51. extern int tgetent();
  52. extern int tgetflag();
  53. extern int tgetnum();
  54.  
  55.  
  56. /* #define DEBUG_LITERAL */
  57.  
  58. /*
  59.  * IMPORTANT NOTE: these routines are allowed to look at the current screen
  60.  * and the current possition assuming that it is correct.  If this is not
  61.  * true, then the update will be WRONG!  This is (should be) a valid
  62.  * assumption...
  63.  */
  64.  
  65. #define TC_BUFSIZE 2048
  66.  
  67. #define GoodStr(a) (tstr[a].str != NULL && tstr[a].str[0] != '\0')
  68. #define Str(a) tstr[a].str
  69. #define Val(a) tval[a].val
  70.  
  71. static struct {
  72.     char   *b_name;
  73.     int     b_rate;
  74. }       baud_rate[] = {
  75.  
  76. #ifdef B0
  77.     { "0", B0 },
  78. #endif
  79. #ifdef B50
  80.     { "50", B50 },
  81. #endif
  82. #ifdef B75
  83.     { "75", B75 },
  84. #endif
  85. #ifdef B110
  86.     { "110", B110 },
  87. #endif
  88. #ifdef B134
  89.     { "134", B134 },
  90. #endif
  91. #ifdef B150
  92.     { "150", B150 },
  93. #endif
  94. #ifdef B200
  95.     { "200", B200 },
  96. #endif
  97. #ifdef B300
  98.     { "300", B300 },
  99. #endif
  100. #ifdef B600
  101.     { "600", B600 },
  102. #endif
  103. #ifdef B900
  104.     { "900", B900 },
  105. #endif
  106. #ifdef B1200
  107.     { "1200", B1200 },
  108. #endif
  109. #ifdef B1800
  110.     { "1800", B1800 },
  111. #endif
  112. #ifdef B2400
  113.     { "2400", B2400 },
  114. #endif
  115. #ifdef B3600
  116.     { "3600", B3600 },
  117. #endif
  118. #ifdef B4800
  119.     { "4800", B4800 },
  120. #endif
  121. #ifdef B7200
  122.     { "7200", B7200 },
  123. #endif
  124. #ifdef B9600
  125.     { "9600", B9600 },
  126. #endif
  127. #ifdef EXTA
  128.     { "19200", EXTA },
  129. #endif
  130. #ifdef B19200
  131.     { "19200", B19200 },
  132. #endif
  133. #ifdef EXTB
  134.     { "38400", EXTB },
  135. #endif
  136. #ifdef B38400
  137.     { "38400", B38400 },
  138. #endif
  139.     { NULL, 0 }
  140. };
  141.  
  142. static struct termcapstr {
  143.     char   *name;
  144.     char   *long_name;
  145.     char   *str;
  146. }       tstr[] = {
  147.  
  148. #define T_al    0
  149.     {    "al",    "add new blank line",        NULL },
  150. #define T_bl    1
  151.     {    "bl",    "audible bell",            NULL },
  152. #define T_cd    2
  153.     {    "cd",    "clear to bottom",        NULL },
  154. #define T_ce    3
  155.     {    "ce",    "clear to end of line",        NULL },
  156. #define T_ch    4
  157.     {    "ch",    "cursor to horiz pos",        NULL },
  158. #define T_cl    5
  159.     {    "cl",    "clear screen",            NULL },
  160. #define    T_dc    6
  161.     {    "dc",    "delete a character",        NULL },
  162. #define    T_dl    7
  163.     {    "dl",    "delete a line",        NULL },
  164. #define    T_dm    8
  165.     {    "dm",    "start delete mode",        NULL },
  166. #define    T_ed    9
  167.     {    "ed",    "end delete mode",        NULL },
  168. #define    T_ei    10
  169.     {    "ei",    "end insert mode",        NULL },
  170. #define    T_fs    11
  171.     {    "fs",    "cursor from status line",    NULL },
  172. #define    T_ho    12
  173.     {    "ho",    "home cursor",            NULL },
  174. #define    T_ic    13
  175.     {    "ic",    "insert character",        NULL },
  176. #define    T_im    14 
  177.     {    "im",    "start insert mode",        NULL },
  178. #define    T_ip    15
  179.     {    "ip",    "insert padding",        NULL },
  180. #define    T_kd    16
  181.     {    "kd",    "sends cursor down",        NULL },
  182. #define    T_kl    17
  183.     {    "kl",    "sends cursor left",        NULL },
  184. #define T_kr    18
  185.     {    "kr",    "sends cursor right",        NULL },
  186. #define T_ku    19
  187.     {    "ku",    "sends cursor up",        NULL },
  188. #define T_md    20
  189.     {    "md",    "begin bold",            NULL },
  190. #define T_me    21
  191.     {    "me",    "end attributes",        NULL },
  192. #define T_nd    22
  193.     {    "nd",    "non destructive space",    NULL },
  194. #define T_se    23
  195.     {    "se",    "end standout",            NULL },
  196. #define T_so    24
  197.     {    "so",    "begin standout",        NULL },
  198. #define T_ts    25
  199.     {    "ts",    "cursor to status line",    NULL },
  200. #define T_up    26
  201.     {    "up",    "cursor up one",        NULL },
  202. #define T_us    27
  203.     {    "us",    "begin underline",        NULL },
  204. #define T_ue    28
  205.     {    "ue",    "end underline",        NULL },
  206. #define T_vb    29
  207.     {    "vb",    "visible bell",            NULL },
  208. #define T_DC    30
  209.     {    "DC",    "delete multiple chars",    NULL },
  210. #define T_DO    31
  211.     {    "DO",    "cursor down multiple",        NULL },
  212. #define T_IC    32
  213.     {    "IC",    "insert multiple chars",    NULL },
  214. #define T_LE    33
  215.     {    "LE",    "cursor left multiple",        NULL },
  216. #define T_RI    34
  217.     {    "RI",    "cursor right multiple",    NULL },
  218. #define T_UP    35
  219.     {    "UP",    "cursor up multiple",        NULL },
  220. #define T_str    36
  221.     {    NULL,    NULL,        NULL }
  222. };
  223.  
  224. static struct termcapval {
  225.     char   *name;
  226.     char   *long_name;
  227.     int     val;
  228. }       tval[] = {
  229. #define T_am    0
  230.     {    "am",    "Has automatic margins",        0 },
  231. #define T_pt    1
  232.     {    "pt",    "Can use physical tabs",         0 },
  233. #define T_li    2
  234.     {    "li",    "Number of lines",             0 },
  235. #define T_co    3
  236.     {    "co",    "Number of columns",             0 },
  237. #define T_km    4
  238.     {    "km",    "Has meta key",                 0 },
  239. #define T_xn    5
  240.     {    "xn",    "Newline ignored at right margin",    0 },
  241. #define T_val    6
  242.     {    NULL,     NULL,                     0 }
  243. };
  244.  
  245.  
  246. /*
  247.  * A very useful table from justin@crim.ca (Justin Bur) :-)
  248.  * (Modified by per@erix.ericsson.se (Per Hedeland)
  249.  *  - first (and second:-) case fixed)
  250.  *
  251.  * Description     Termcap variables       tcsh behavior
  252.  *            am      xn              UseRightmost    SendCRLF
  253.  * --------------  ------- -------         ------------    ------------
  254.  * Automargins     yes     no              yes             no
  255.  * Magic Margins   yes     yes             yes             no
  256.  * No Wrap         no      --              yes             yes
  257.  */
  258.  
  259. static bool me_all = 0;        /* does two or more of the attributes use me */
  260.  
  261. static    void    ReBufferDisplay    __P((void));
  262. static    void    TCalloc        __P((struct termcapstr *, char *)); 
  263.  
  264.  
  265. static void
  266. TCalloc(t, cap)
  267.     struct termcapstr *t;
  268.     char   *cap;
  269. {
  270.     static char termcap_alloc[TC_BUFSIZE];
  271.     char    termbuf[TC_BUFSIZE];
  272.     struct termcapstr *ts;
  273.     static int tloc = 0;
  274.     int     tlen, clen;
  275.  
  276.     if (cap == NULL || *cap == '\0') {
  277.     t->str = NULL;
  278.     return;
  279.     }
  280.     else
  281.     clen = strlen(cap);
  282.  
  283.     if (t->str == NULL)
  284.     tlen = 0;
  285.     else
  286.     tlen = strlen(t->str);
  287.  
  288.     /*
  289.      * New string is shorter; no need to allocate space
  290.      */
  291.     if (clen <= tlen) {
  292.     (void) strcpy(t->str, cap);
  293.     return;
  294.     }
  295.  
  296.     /*
  297.      * New string is longer; see if we have enough space to append
  298.      */
  299.     if (tloc + 3 < TC_BUFSIZE) {
  300.     (void) strcpy(t->str = &termcap_alloc[tloc], cap);
  301.     tloc += clen + 1;    /* one for \0 */
  302.     return;
  303.     }
  304.  
  305.     /*
  306.      * Compact our buffer; no need to check compaction, cause we know it
  307.      * fits...
  308.      */
  309.     tlen = 0;
  310.     for (ts = tstr; ts->name != NULL; ts++)
  311.     if (t != ts && ts->str != NULL && ts->str[0] != '\0') {
  312.         char   *ptr;
  313.  
  314.         for (ptr = ts->str; *ptr != '\0'; termbuf[tlen++] = *ptr++)
  315.         continue;
  316.         termbuf[tlen++] = '\0';
  317.     }
  318.     (void) memmove((ptr_t) termcap_alloc, (ptr_t) termbuf, TC_BUFSIZE);
  319.     tloc = tlen;
  320.     if (tloc + 3 >= TC_BUFSIZE) {
  321.     stderror(ERR_NAME | ERR_TCNOSTR);
  322.     return;
  323.     }
  324.     (void) strcpy(t->str = &termcap_alloc[tloc], cap);
  325.     tloc += clen + 1;        /* one for \0 */
  326.     return;
  327. }
  328.  
  329.  
  330. /*ARGSUSED*/
  331. void
  332. TellTC(what)
  333.     char   *what;
  334. {
  335.     struct termcapstr *t;
  336.  
  337.     xprintf("\n\tTcsh thinks your terminal has the\n");
  338.     xprintf("\tfollowing characteristics:\n\n");
  339.     xprintf("\tIt has %d columns and %d lines\n",
  340.         Val(T_co), Val(T_li));
  341.     xprintf("\tIt has %s meta key\n", T_HasMeta ? "a" : "no");
  342.     xprintf("\tIt can%suse tabs\n", T_Tabs ? " " : "not ");
  343.     xprintf("\tIt %s automatic margins\n", (T_Margin&MARGIN_AUTO)?"has":"does not have");
  344.     if (T_Margin&MARGIN_AUTO)
  345.     xprintf("\tIt %s magic margins\n", (T_Margin&MARGIN_MAGIC)?"has":"does not have");
  346.  
  347.     for (t = tstr; t->name != NULL; t++)
  348.     xprintf("\t%25s (%s) == %s\n", t->long_name, t->name,
  349.         t->str && *t->str ? t->str : "(empty)");
  350.     xputchar('\n');
  351. }
  352.  
  353.  
  354. static void
  355. ReBufferDisplay()
  356. {
  357.     register int i;
  358.     Char  **b;
  359.     Char  **bufp;
  360.  
  361.     b = Display;
  362.     Display = NULL;
  363.     if (b != NULL) {
  364.     for (bufp = b; *bufp != NULL; bufp++)
  365.         xfree((ptr_t) * bufp);
  366.     xfree((ptr_t) b);
  367.     }
  368.     b = Vdisplay;
  369.     Vdisplay = NULL;
  370.     if (b != NULL) {
  371.     for (bufp = b; *bufp != NULL; bufp++)
  372.         xfree((ptr_t) * bufp);
  373.     xfree((ptr_t) b);
  374.     }
  375.     TermH = Val(T_co);
  376.     TermV = (INBUFSIZE * 4) / TermH + 1;
  377.     b = (Char **) xmalloc((size_t) (sizeof(Char *) * (TermV + 1)));
  378.     for (i = 0; i < TermV; i++)
  379.     b[i] = (Char *) xmalloc((size_t) (sizeof(Char) * (TermH + 1)));
  380.     b[TermV] = NULL;
  381.     Display = b;
  382.     b = (Char **) xmalloc((size_t) (sizeof(Char *) * (TermV + 1)));
  383.     for (i = 0; i < TermV; i++)
  384.     b[i] = (Char *) xmalloc((size_t) (sizeof(Char) * (TermH + 1)));
  385.     b[TermV] = NULL;
  386.     Vdisplay = b;
  387. }
  388.  
  389. void
  390. SetTC(what, how)
  391.     char   *what, *how;
  392. {
  393.     struct termcapstr *ts;
  394.     struct termcapval *tv;
  395.  
  396.     /*
  397.      * Do the strings first
  398.      */
  399.     setname("settc");
  400.     for (ts = tstr; ts->name != NULL; ts++)
  401.     if (strcmp(ts->name, what) == 0)
  402.         break;
  403.     if (ts->name != NULL) {
  404.     TCalloc(ts, how);
  405.     /*
  406.      * Reset variables
  407.      */
  408.     if (GoodStr(T_me) && GoodStr(T_ue))
  409.         me_all = (strcmp(Str(T_me), Str(T_ue)) == 0);
  410.     else
  411.         me_all = 0;
  412.     if (GoodStr(T_me) && GoodStr(T_se))
  413.         me_all |= (strcmp(Str(T_me), Str(T_se)) == 0);
  414.  
  415.     T_CanCEOL = GoodStr(T_ce);
  416.     T_CanDel = GoodStr(T_dc) || GoodStr(T_DC);
  417.     T_CanIns = GoodStr(T_im) || GoodStr(T_ic) || GoodStr(T_IC);
  418.     T_CanUP = GoodStr(T_up) || GoodStr(T_UP);
  419.     return;
  420.     }
  421.  
  422.     /*
  423.      * Do the numeric ones second
  424.      */
  425.     for (tv = tval; tv->name != NULL; tv++)
  426.     if (strcmp(tv->name, what) == 0)
  427.         break;
  428.  
  429.     if (tv->name != NULL) {
  430.     if (tv == &tval[T_pt] || tv == &tval[T_km] || 
  431.         tv == &tval[T_am] || tv == &tval[T_xn]) {
  432.         if (strcmp(how, "yes") == 0)
  433.         tv->val = 1;
  434.         else if (strcmp(how, "no") == 0)
  435.         tv->val = 0;
  436.         else {
  437.         stderror(ERR_SETTCUS, tv->name);
  438.         return;
  439.         }
  440.         T_Tabs = Val(T_pt);
  441.         T_HasMeta = Val(T_km);
  442.         T_Margin = Val(T_am) ? MARGIN_AUTO : 0;
  443.         T_Margin |= Val(T_xn) ? MARGIN_MAGIC : 0;
  444.         if (tv == &tval[T_am] || tv == &tval[T_xn]) 
  445.         ChangeSize(Val(T_li), Val(T_co));
  446.         return;
  447.     }
  448.     else {
  449.         tv->val = atoi(how);
  450.         T_Cols = Val(T_co);
  451.         T_Lines = Val(T_li);
  452.         if (tv == &tval[T_co] || tv == &tval[T_li])
  453.         ChangeSize(Val(T_li), Val(T_co));
  454.         return;
  455.     }
  456.     }
  457.     stderror(ERR_NAME | ERR_TCCAP, what);
  458.     return;
  459. }
  460.  
  461.  
  462. /*
  463.  * Print the termcap string out with variable substitution
  464.  */
  465. void
  466. EchoTC(v)
  467.     Char  **v;
  468. {
  469.     char   *cap, *scap, cv[BUFSIZE];
  470.     int     arg_need, arg_cols, arg_rows;
  471.     int     verbose = 0, silent = 0;
  472.     char   *area;
  473.     static char *fmts = "%s\n", *fmtd = "%d\n";
  474.     struct termcapstr *t;
  475.     char    buf[TC_BUFSIZE];
  476.  
  477.     area = buf;
  478.  
  479.     setname("echotc");
  480.  
  481.     tglob(v);
  482.     if (gflag) {
  483.     v = globall(v);
  484.     if (v == 0)
  485.         stderror(ERR_NAME | ERR_NOMATCH);
  486.     }
  487.     else
  488.     v = gargv = saveblk(v);
  489.     trim(v);
  490.  
  491.     if (!*v || *v[0] == '\0')
  492.     return;
  493.     if (v[0][0] == '-') {
  494.     switch (v[0][1]) {
  495.     case 'v':
  496.         verbose = 1;
  497.         break;
  498.     case 's':
  499.         silent = 1;
  500.         break;
  501.     default:
  502.         stderror(ERR_NAME | ERR_TCUSAGE);
  503.         break;
  504.     }
  505.     v++;
  506.     }
  507.     if (!*v || *v[0] == '\0')
  508.     return;
  509.     (void) strcpy(cv, short2str(*v));
  510.     if (strcmp(cv, "tabs") == 0) {
  511.     xprintf(fmts, T_Tabs ? "yes" : "no");
  512.     flush();
  513.     return;
  514.     }
  515.     else if (strcmp(cv, "meta") == 0) {
  516.     xprintf(fmts, Val(T_km) ? "yes" : "no");
  517.     flush();
  518.     return;
  519.     }
  520.     else if (strcmp(cv, "xn") == 0) {
  521.     xprintf(fmts, T_Margin & MARGIN_MAGIC ? "yes" : "no");
  522.     flush();
  523.     return;
  524.     }
  525.     else if (strcmp(cv, "am") == 0) {
  526.     xprintf(fmts, T_Margin & MARGIN_AUTO ? "yes" : "no");
  527.     flush();
  528.     return;
  529.     }
  530.     else if (strcmp(cv, "baud") == 0) {
  531.     int     i;
  532.  
  533.     for (i = 0; baud_rate[i].b_name != NULL; i++)
  534.         if (T_Speed == baud_rate[i].b_rate) {
  535.         xprintf(fmts, baud_rate[i].b_name);
  536.         flush();
  537.         return;
  538.         }
  539.     xprintf(fmtd, 0);
  540.     flush();
  541.     return;
  542.     }
  543.     else if (strcmp(cv, "rows") == 0 || strcmp(cv, "lines") == 0) {
  544.     xprintf(fmtd, Val(T_li));
  545.     flush();
  546.     return;
  547.     }
  548.     else if (strcmp(cv, "cols") == 0) {
  549.     xprintf(fmtd, Val(T_co));
  550.     flush();
  551.     return;
  552.     }
  553.  
  554.     /* 
  555.      * Try to use our local definition first
  556.      */
  557.     scap = NULL;
  558.     for (t = tstr; t->name != NULL; t++)
  559.     if (strcmp(t->name, cv) == 0) {
  560.         scap = t->str;
  561.         break;
  562.     }
  563.     if (t->name == NULL)
  564.     scap = tgetstr(cv, &area);
  565.     if (!scap || scap[0] == '\0') {
  566.     if (tgetflag(cv, &area)) {
  567.         xprintf("yes\n");
  568.         return;
  569.     }
  570.     if (silent)
  571.         return;
  572.     else
  573.         stderror(ERR_NAME | ERR_TCCAP, cv);
  574.     }
  575.  
  576.     /*
  577.      * Count home many values we need for this capability.
  578.      */
  579.     for (cap = scap, arg_need = 0; *cap; cap++)
  580.     if (*cap == '%')
  581.         switch (*++cap) {
  582.         case 'd':
  583.         case '2':
  584.         case '3':
  585.         case '.':
  586.         case '+':
  587.         arg_need++;
  588.         break;
  589.         case '%':
  590.         case '>':
  591.         case 'i':
  592.         case 'r':
  593.         case 'n':
  594.         case 'B':
  595.         case 'D':
  596.         break;
  597.         default:
  598.         /*
  599.          * hpux has lot's of them...
  600.          */
  601.         if (verbose)
  602.             stderror(ERR_NAME | ERR_TCPARM, *cap);
  603.         /* This is bad, but I won't complain */
  604.         break;
  605.         }
  606.  
  607.     switch (arg_need) {
  608.     case 0:
  609.     v++;
  610.     if (*v && *v[0]) {
  611.         if (silent)
  612.         return;
  613.         else
  614.         stderror(ERR_NAME | ERR_TCARGS, cv, arg_need);
  615.     }
  616.     (void) tputs(scap, 1, putraw);
  617.     break;
  618.     case 1:
  619.     v++;
  620.     if (!*v || *v[0] == '\0')
  621.         stderror(ERR_NAME | ERR_TCNARGS, cv, 1);
  622.     arg_cols = 0;
  623.     arg_rows = atoi(short2str(*v));
  624.     v++;
  625.     if (*v && *v[0]) {
  626.         if (silent)
  627.         return;
  628.         else
  629.         stderror(ERR_NAME | ERR_TCARGS, cv, arg_need);
  630.     }
  631.     (void) tputs(tgoto(scap, arg_cols, arg_rows), 1, putraw);
  632.     break;
  633.     default:
  634.     /* This is wrong, but I will ignore it... */
  635.     if (verbose)
  636.         stderror(ERR_NAME | ERR_TCARGS, cv, arg_need);
  637.     /*FALLTHROUGH*/
  638.     case 2:
  639.     v++;
  640.     if (!*v || *v[0] == '\0') {
  641.         if (silent)
  642.         return;
  643.         else
  644.         stderror(ERR_NAME | ERR_TCNARGS, cv, 2);
  645.     }
  646.     arg_cols = atoi(short2str(*v));
  647.     v++;
  648.     if (!*v || *v[0] == '\0') {
  649.         if (silent)
  650.         return;
  651.         else
  652.         stderror(ERR_NAME | ERR_TCNARGS, cv, 2);
  653.     }
  654.     arg_rows = atoi(short2str(*v));
  655.     v++;
  656.     if (*v && *v[0]) {
  657.         if (silent)
  658.         return;
  659.         else
  660.         stderror(ERR_NAME | ERR_TCARGS, cv, arg_need);
  661.     }
  662.     (void) tputs(tgoto(scap, arg_cols, arg_rows), arg_rows, putraw);
  663.     break;
  664.     }
  665.     flush();
  666.     if (gargv) {
  667.     blkfree(gargv);
  668.     gargv = 0;
  669.     }
  670. }
  671.  
  672. bool    GotTermCaps = 0;
  673.  
  674. static struct {
  675.     Char   *name;
  676.     int     key;
  677.     XmapVal fun;
  678.     int        type;
  679. } arrow[] = {
  680. #define A_K_DN    0
  681.     { STRdown,    T_kd },
  682. #define A_K_UP    1
  683.     { STRup,    T_ku },
  684. #define A_K_LT    2
  685.     { STRleft,    T_kl },
  686. #define A_K_RT    3
  687.     { STRright,    T_kr }
  688. };
  689.  
  690.  
  691. void
  692. ResetArrowKeys()
  693. {
  694.     arrow[A_K_DN].fun.cmd = F_DOWN_HIST;
  695.     arrow[A_K_DN].type    = XK_CMD;
  696.  
  697.     arrow[A_K_UP].fun.cmd = F_UP_HIST;
  698.     arrow[A_K_UP].type    = XK_CMD;
  699.  
  700.     arrow[A_K_LT].fun.cmd = F_CHARBACK;
  701.     arrow[A_K_LT].type    = XK_CMD;
  702.  
  703.     arrow[A_K_RT].fun.cmd = F_CHARFWD;
  704.     arrow[A_K_RT].type    = XK_CMD;
  705.  
  706. }
  707.  
  708. void
  709. DefaultArrowKeys() 
  710. {
  711.     static Char strA[] = {033, '[', 'A', '\0'};
  712.     static Char strB[] = {033, '[', 'B', '\0'};
  713.     static Char strC[] = {033, '[', 'C', '\0'};
  714.     static Char strD[] = {033, '[', 'D', '\0'};
  715.     static Char stOA[] = {033, 'O', 'A', '\0'};
  716.     static Char stOB[] = {033, 'O', 'B', '\0'};
  717.     static Char stOC[] = {033, 'O', 'C', '\0'};
  718.     static Char stOD[] = {033, 'O', 'D', '\0'};
  719.  
  720.     AddXkey(strA, &arrow[A_K_UP].fun, arrow[A_K_UP].type);
  721.     AddXkey(strB, &arrow[A_K_DN].fun, arrow[A_K_DN].type);
  722.     AddXkey(strC, &arrow[A_K_RT].fun, arrow[A_K_RT].type);
  723.     AddXkey(strD, &arrow[A_K_LT].fun, arrow[A_K_LT].type);
  724.     AddXkey(stOA, &arrow[A_K_UP].fun, arrow[A_K_UP].type);
  725.     AddXkey(stOB, &arrow[A_K_DN].fun, arrow[A_K_DN].type);
  726.     AddXkey(stOC, &arrow[A_K_RT].fun, arrow[A_K_RT].type);
  727.     AddXkey(stOD, &arrow[A_K_LT].fun, arrow[A_K_LT].type);
  728.     if (VImode) {
  729.     AddXkey(&strA[1], &arrow[A_K_UP].fun, arrow[A_K_UP].type);
  730.     AddXkey(&strB[1], &arrow[A_K_DN].fun, arrow[A_K_DN].type);
  731.     AddXkey(&strC[1], &arrow[A_K_RT].fun, arrow[A_K_RT].type);
  732.     AddXkey(&strD[1], &arrow[A_K_LT].fun, arrow[A_K_LT].type);
  733.     AddXkey(&stOA[1], &arrow[A_K_UP].fun, arrow[A_K_UP].type);
  734.     AddXkey(&stOB[1], &arrow[A_K_DN].fun, arrow[A_K_DN].type);
  735.     AddXkey(&stOC[1], &arrow[A_K_RT].fun, arrow[A_K_RT].type);
  736.     AddXkey(&stOD[1], &arrow[A_K_LT].fun, arrow[A_K_LT].type);
  737.     }
  738. }
  739.  
  740.  
  741. int
  742. SetArrowKeys(name, fun, type)
  743.     Char *name;
  744.     XmapVal *fun;
  745.     int type;
  746. {
  747.     int i;
  748.     for (i = 0; i < 4; i++)
  749.     if (Strcmp(name, arrow[i].name) == 0) {
  750.         arrow[i].fun  = *fun;
  751.         arrow[i].type = type;
  752.         return 0;
  753.     }
  754.     return -1;
  755. }
  756.  
  757.  
  758. int
  759. ClearArrowKeys(name)
  760.     Char *name;
  761. {
  762.     int i;
  763.     for (i = 0; i < 4; i++)
  764.     if (Strcmp(name, arrow[i].name) == 0) {
  765.         arrow[i].type = XK_NOD;
  766.         return 0;
  767.     }
  768.     return -1;
  769. }
  770.  
  771. void
  772. PrintArrowKeys(name)
  773.     Char *name;
  774. {
  775.     int i;
  776.  
  777.     for (i = 0; i < 4; i++)
  778.     if (name == STRNULL || Strcmp(name, arrow[i].name) == 0)
  779.         if (arrow[i].type != XK_NOD)
  780.         printOne(arrow[i].name, &arrow[i].fun, arrow[i].type);
  781. }
  782.  
  783.  
  784. void
  785. BindArrowKeys()
  786. {
  787.     KEYCMD *map, *dmap;
  788.     int     i, j;
  789.     char   *p;
  790.  
  791.     if (!GotTermCaps)
  792.     return;
  793.     map = VImode ? CcAltMap : CcKeyMap;
  794.     dmap = VImode ? CcViCmdMap : CcEmacsMap;
  795.  
  796.     DefaultArrowKeys();
  797.  
  798.     for (i = 0; i < 4; i++) {
  799.     p = tstr[arrow[i].key].str;
  800.     if (p && *p) {
  801.         j = (unsigned char) *p;
  802.         /*
  803.          * Assign the arrow keys only if:
  804.          *
  805.          * 1. They are multi-character arrow keys and the user 
  806.          *    has not re-assigned the leading character, or 
  807.          *    has re-assigned the leading character to be F_XKEY
  808.          * 2. They are single arrow keys pointing to an unassigned key.
  809.          */
  810.         if (arrow[i].type == XK_NOD)
  811.         ClearXkey(map, str2short(p));
  812.         else {
  813.         if (p[1] && (dmap[j] == map[j] || map[j] == F_XKEY)) {
  814.             AddXkey(str2short(p), &arrow[i].fun, arrow[i].type);
  815.             map[j] = F_XKEY;
  816.         }
  817.         else if (map[j] == F_UNASSIGNED) {
  818.             ClearXkey(map, str2short(p));
  819.             if (arrow[i].type == XK_CMD)
  820.             map[j] = arrow[i].fun.cmd;
  821.             else
  822.             AddXkey(str2short(p), &arrow[i].fun, arrow[i].type);
  823.         }
  824.         }
  825.     }
  826.     }
  827. }
  828.  
  829. static Char cur_atr = 0;    /* current attributes */
  830.  
  831. void
  832. SetAttributes(atr)
  833.     int     atr;
  834. {
  835.     atr &= ATTRIBUTES;
  836.     if (atr != cur_atr) {
  837.     if (me_all && GoodStr(T_me)) {
  838.         if (((cur_atr & BOLD) && !(atr & BOLD)) ||
  839.         ((cur_atr & UNDER) && !(atr & UNDER)) ||
  840.         ((cur_atr & STANDOUT) && !(atr & STANDOUT))) {
  841.         (void) tputs(Str(T_me), 1, putpure);
  842.         cur_atr = 0;
  843.         }
  844.     }
  845.     if ((atr & BOLD) != (cur_atr & BOLD)) {
  846.         if (atr & BOLD) {
  847.         if (GoodStr(T_md) && GoodStr(T_me)) {
  848.             (void) tputs(Str(T_md), 1, putpure);
  849.             cur_atr |= BOLD;
  850.         }
  851.         }
  852.         else {
  853.         if (GoodStr(T_md) && GoodStr(T_me)) {
  854.             (void) tputs(Str(T_me), 1, putpure);
  855.             if ((cur_atr & STANDOUT) && GoodStr(T_se)) {
  856.             (void) tputs(Str(T_se), 1, putpure);
  857.             cur_atr &= ~STANDOUT;
  858.             }
  859.             if ((cur_atr & UNDER) && GoodStr(T_ue)) {
  860.             (void) tputs(Str(T_ue), 1, putpure);
  861.             cur_atr &= ~UNDER;
  862.             }
  863.             cur_atr &= ~BOLD;
  864.         }
  865.         }
  866.     }
  867.     if ((atr & STANDOUT) != (cur_atr & STANDOUT)) {
  868.         if (atr & STANDOUT) {
  869.         if (GoodStr(T_so) && GoodStr(T_se)) {
  870.             (void) tputs(Str(T_so), 1, putpure);
  871.             cur_atr |= STANDOUT;
  872.         }
  873.         }
  874.         else {
  875.         if (GoodStr(T_se)) {
  876.             (void) tputs(Str(T_se), 1, putpure);
  877.             cur_atr &= ~STANDOUT;
  878.         }
  879.         }
  880.     }
  881.     if ((atr & UNDER) != (cur_atr & UNDER)) {
  882.         if (atr & UNDER) {
  883.         if (GoodStr(T_us) && GoodStr(T_ue)) {
  884.             (void) tputs(Str(T_us), 1, putpure);
  885.             cur_atr |= UNDER;
  886.         }
  887.         }
  888.         else {
  889.         if (GoodStr(T_ue)) {
  890.             (void) tputs(Str(T_ue), 1, putpure);
  891.             cur_atr &= ~UNDER;
  892.         }
  893.         }
  894.     }
  895.     }
  896. }
  897.  
  898. /* PWP 6-27-88 -- if the tty driver thinks that we can tab, we ask termcap */
  899. int
  900. CanWeTab()
  901. {
  902.     return (Val(T_pt));
  903. }
  904.  
  905. void
  906. MoveToLine(where)        /* move to line <where> (first line == 0) */
  907.     int     where;        /* as efficiently as possible; */
  908. {
  909.     int     del, i;
  910.  
  911.     if (where == CursorV)
  912.     return;
  913.  
  914.     if (where > TermV) {
  915. #ifdef DEBUG_SCREEN
  916.     xprintf("MoveToLine: where is ridiculous: %d\r\n", where);
  917.     flush();
  918. #endif /* DEBUG_SCREEN */
  919.     return;
  920.     }
  921.  
  922.     if ((del = where - CursorV) > 0) {
  923.     while (del > 0) {
  924.         if ((T_Margin & MARGIN_AUTO) && Display[CursorV][0] != '\0') {
  925.         /* move without newline */
  926.         MoveToChar(TermH - 1);
  927.         so_write(&Display[CursorV][CursorH], 1); /* updates CursorH/V*/
  928.         del--;
  929.         }
  930.         else {
  931.         if ((del > 1) && GoodStr(T_DO)) {
  932.             (void) tputs(tgoto(Str(T_DO), del, del), del, putpure);
  933.             del = 0;
  934.         }
  935.         else {
  936.             for ( ; del > 0; del--) 
  937.             (void) putraw('\n');
  938.             CursorH = 0;    /* because the \n will become \r\n */
  939.         }
  940.         }
  941.     }
  942.     }
  943.     else {            /* del < 0 */
  944.     if (GoodStr(T_UP) && (-del > 1 || !GoodStr(T_up)))
  945.         (void) tputs(tgoto(Str(T_UP), -del, -del), -del, putpure);
  946.     else {
  947.         if (GoodStr(T_up))
  948.         for (i = 0; i < -del; i++)
  949.             (void) tputs(Str(T_up), 1, putpure);
  950.     }
  951.     }
  952.     CursorV = where;        /* now where is here */
  953. }
  954.  
  955. void
  956. MoveToChar(where)        /* move to character position (where) */
  957.     int     where;
  958. {                /* as efficiently as possible */
  959.     int     del, i;
  960.  
  961. mc_again:
  962.     if (where == CursorH)
  963.     return;
  964.  
  965.     if (where >= TermH) {
  966. #ifdef DEBUG_SCREEN
  967.     xprintf("MoveToChar: where is riduculous: %d\r\n", where);
  968.     flush();
  969. #endif /* DEBUG_SCREEN */
  970.     return;
  971.     }
  972.  
  973.     if (!where) {        /* if where is first column */
  974.     (void) putraw('\r');    /* do a CR */
  975.     CursorH = 0;
  976.     return;
  977.     }
  978.  
  979.     del = where - CursorH;
  980.  
  981.     if ((del < -4 || del > 4) && GoodStr(T_ch))
  982.     /* go there directly */
  983.     (void) tputs(tgoto(Str(T_ch), where, where), where, putpure);
  984.     else {
  985.     if (del > 0) {        /* moving forward */
  986.         if ((del > 4) && GoodStr(T_RI))
  987.         (void) tputs(tgoto(Str(T_RI), del, del), del, putpure);
  988.         else {
  989.         if (T_Tabs) {    /* if I can do tabs, use them */
  990.             if ((CursorH & 0370) != (where & 0370)) {
  991.             /* if not within tab stop */
  992.             for (i = (CursorH & 0370); i < (where & 0370); i += 8)
  993.                 (void) putraw('\t');    /* then tab over */
  994.             CursorH = where & 0370;
  995.             /* Note: considering that we often want to go to
  996.                TermH - 1 for the wrapping, it would be nice to
  997.                optimize this case by tabbing to the last column
  998.                - but this doesn't work for all terminals! */
  999.             }
  1000.         }
  1001.         /* it's usually cheaper to just write the chars, so we do. */
  1002.  
  1003.         /* NOTE THAT so_write() WILL CHANGE CursorH!!! */
  1004.         so_write(&Display[CursorV][CursorH], where - CursorH);
  1005.  
  1006.         }
  1007.     }
  1008.     else {            /* del < 0 := moving backward */
  1009.         if ((-del > 4) && GoodStr(T_LE))
  1010.         (void) tputs(tgoto(Str(T_LE), -del, -del), -del, putpure);
  1011.         else {        /* can't go directly there */
  1012.         /* if the "cost" is greater than the "cost" from col 0 */
  1013.         if (T_Tabs ? (-del > ((where >> 3) + (where & 07)))
  1014.             : (-del > where)) {
  1015.             (void) putraw('\r');    /* do a CR */
  1016.             CursorH = 0;
  1017.             goto mc_again;    /* and try again */
  1018.         }
  1019.         for (i = 0; i < -del; i++)
  1020.             (void) putraw('\b');
  1021.         }
  1022.     }
  1023.     }
  1024.     CursorH = where;        /* now where is here */
  1025. }
  1026.  
  1027. void
  1028. so_write(cp, n)
  1029.     register Char *cp;
  1030.     register int n;
  1031. {
  1032.     if (n <= 0)
  1033.     return;            /* catch bugs */
  1034.  
  1035.     if (n > TermH) {
  1036. #ifdef DEBUG_SCREEN
  1037.     xprintf("so_write: n is riduculous: %d\r\n", n);
  1038.     flush();
  1039. #endif /* DEBUG_SCREEN */
  1040.     return;
  1041.     }
  1042.  
  1043.     do {
  1044.     if (*cp & LITERAL) {
  1045.         extern Char *litptr[];
  1046.         Char   *d;
  1047.  
  1048. #ifdef DEBUG_LITERAL
  1049.         xprintf("so: litnum %d, litptr %x\r\n",
  1050.             *cp & CHAR, litptr[*cp & CHAR]);
  1051. #endif /* DEBUG_LITERAL */
  1052.         for (d = litptr[*cp++ & CHAR]; *d & LITERAL; d++)
  1053.         (void) putraw(*d & CHAR);
  1054.         (void) putraw(*d);
  1055.  
  1056.     }
  1057.     else
  1058.         (void) putraw(*cp++);
  1059.     CursorH++;
  1060.     } while (--n);
  1061.  
  1062.     if (CursorH >= TermH) { /* wrap? */
  1063.     if (T_Margin & MARGIN_AUTO) { /* yes */
  1064.         CursorH = 0;
  1065.         CursorV++;
  1066.         if (T_Margin & MARGIN_MAGIC) {
  1067.         /* force the wrap to avoid the "magic" situation */
  1068.         Char c;
  1069.         if ((c = Display[CursorV][CursorH]) != '\0')
  1070.             so_write(&c, 1);
  1071.         else
  1072.             putraw(' ');
  1073.         CursorH = 1;
  1074.         }
  1075.     }
  1076.     else            /* no wrap, but cursor stays on screen */
  1077.         CursorH = TermH - 1;
  1078.     }
  1079. }
  1080.  
  1081.  
  1082. void
  1083. DeleteChars(num)        /* deletes <num> characters */
  1084.     int     num;
  1085. {
  1086.     if (num <= 0)
  1087.     return;
  1088.  
  1089.     if (!T_CanDel) {
  1090. #ifdef DEBUG_EDIT
  1091.     xprintf("   ERROR: cannot delete   \n");
  1092. #endif /* DEBUG_EDIT */
  1093.     flush();
  1094.     return;
  1095.     }
  1096.  
  1097.     if (num > TermH) {
  1098. #ifdef DEBUG_SCREEN
  1099.     xprintf("DeleteChars: num is riduculous: %d\r\n", num);
  1100.     flush();
  1101. #endif /* DEBUG_SCREEN */
  1102.     return;
  1103.     }
  1104.  
  1105.     if (GoodStr(T_DC))        /* if I have multiple delete */
  1106.     if ((num > 1) || !GoodStr(T_dc)) {    /* if dc would be more expen. */
  1107.         (void) tputs(tgoto(Str(T_DC), num, num), num, putpure);
  1108.         return;
  1109.     }
  1110.  
  1111.     if (GoodStr(T_dm))        /* if I have delete mode */
  1112.     (void) tputs(Str(T_dm), 1, putpure);
  1113.  
  1114.     if (GoodStr(T_dc))        /* else do one at a time */
  1115.     while (num--)
  1116.         (void) tputs(Str(T_dc), 1, putpure);
  1117.  
  1118.     if (GoodStr(T_ed))        /* if I have delete mode */
  1119.     (void) tputs(Str(T_ed), 1, putpure);
  1120. }
  1121.  
  1122. void
  1123. Insert_write(cp, num)        /* Puts terminal in insert character mode, */
  1124.     register Char *cp;
  1125.     register int num;        /* or inserts num characters in the line */
  1126. {
  1127.     if (num <= 0)
  1128.     return;
  1129.     if (!T_CanIns) {
  1130. #ifdef DEBUG_EDIT
  1131.     xprintf("   ERROR: cannot insert   \n");
  1132. #endif /* DEBUG_EDIT */
  1133.     flush();
  1134.     return;
  1135.     }
  1136.  
  1137.     if (num > TermH) {
  1138. #ifdef DEBUG_SCREEN
  1139.     xprintf("StartInsert: num is riduculous: %d\r\n", num);
  1140.     flush();
  1141. #endif /* DEBUG_SCREEN */
  1142.     return;
  1143.     }
  1144.  
  1145.     if (GoodStr(T_IC))        /* if I have multiple insert */
  1146.     if ((num > 1) || !GoodStr(T_ic)) {    /* if ic would be more expen. */
  1147.         (void) tputs(tgoto(Str(T_IC), num, num), num, putpure);
  1148.         so_write(cp, num);    /* this updates CursorH/V */
  1149.         return;
  1150.     }
  1151.  
  1152.     if (GoodStr(T_im) && GoodStr(T_ei)) { /* if I have insert mode */
  1153.     (void) tputs(Str(T_im), 1, putpure);
  1154.  
  1155.     CursorH += num;
  1156.     do 
  1157.         (void) putraw(*cp++);
  1158.     while (--num);
  1159.  
  1160.     if (GoodStr(T_ip))    /* have to make num chars insert */
  1161.         (void) tputs(Str(T_ip), 1, putpure);
  1162.  
  1163.     (void) tputs(Str(T_ei), 1, putpure);
  1164.     return;
  1165.     }
  1166.  
  1167.     do {
  1168.     if (GoodStr(T_ic))    /* have to make num chars insert */
  1169.         (void) tputs(Str(T_ic), 1, putpure);    /* insert a char */
  1170.  
  1171.     (void) putraw(*cp++);
  1172.  
  1173.     CursorH++;
  1174.  
  1175.     if (GoodStr(T_ip))    /* have to make num chars insert */
  1176.         (void) tputs(Str(T_ip), 1, putpure);/* pad the inserted char */
  1177.  
  1178.     } while (--num);
  1179.  
  1180. }
  1181.  
  1182. void
  1183. ClearEOL(num)            /* clear to end of line.  There are num */
  1184.     int     num;        /* characters to clear */
  1185. {
  1186.     register int i;
  1187.  
  1188.     if (num <= 0)
  1189.     return;
  1190.  
  1191.     if (T_CanCEOL && GoodStr(T_ce))
  1192.     (void) tputs(Str(T_ce), 1, putpure);
  1193.     else {
  1194.     for (i = 0; i < num; i++)
  1195.         (void) putraw(' ');
  1196.     CursorH += num;        /* have written num spaces */
  1197.     }
  1198. }
  1199.  
  1200. void
  1201. ClearScreen()
  1202. {                /* clear the whole screen and home */
  1203.     if (GoodStr(T_cl))
  1204.     /* send the clear screen code */
  1205.     (void) tputs(Str(T_cl), Val(T_li), putpure);
  1206.     else if (GoodStr(T_ho) && GoodStr(T_cd)) {
  1207.     (void) tputs(Str(T_ho), Val(T_li), putpure);    /* home */
  1208.     /* clear to bottom of screen */
  1209.     (void) tputs(Str(T_cd), Val(T_li), putpure);
  1210.     }
  1211.     else {
  1212.     (void) putraw('\r');
  1213.     (void) putraw('\n');
  1214.     }
  1215. }
  1216.  
  1217. void
  1218. Beep()
  1219. {                /* produce a sound */
  1220.     beep_cmd ();
  1221.     if (adrof(STRnobeep))
  1222.     return;
  1223.  
  1224.     if (GoodStr(T_vb) && adrof(STRvisiblebell))
  1225.     (void) tputs(Str(T_vb), 1, putpure);    /* visible bell */
  1226.     else if (GoodStr(T_bl))
  1227.     /* what termcap says we should use */
  1228.     (void) tputs(Str(T_bl), 1, putpure);
  1229.     else
  1230.     (void) putraw('\007');    /* an ASCII bell; ^G */
  1231. }
  1232.  
  1233. void
  1234. ClearToBottom()
  1235. {                /* clear to the bottom of the screen */
  1236.     if (GoodStr(T_cd))
  1237.     (void) tputs(Str(T_cd), Val(T_li), putpure);
  1238.     else if (GoodStr(T_ce))
  1239.     (void) tputs(Str(T_ce), Val(T_li), putpure);
  1240. }
  1241.  
  1242. void
  1243. GetTermCaps()
  1244. {                /* read in the needed terminal capabilites */
  1245.     register int i;
  1246.     char   *ptr;
  1247.     char    buf[TC_BUFSIZE];
  1248.     static char bp[TC_BUFSIZE];
  1249.     char   *area;
  1250.     struct termcapstr *t;
  1251.  
  1252.  
  1253. #ifdef SIG_WINDOW
  1254. # ifdef BSDSIGS
  1255.     sigmask_t omask;
  1256. # endif /* BSDSIGS */
  1257.     int     lins, cols;
  1258.  
  1259.     /* don't want to confuse things here */
  1260. # ifdef BSDSIGS
  1261.     omask = sigblock(sigmask(SIG_WINDOW)) & ~sigmask(SIG_WINDOW);
  1262. # else /* BSDSIGS */
  1263.     (void) sighold(SIG_WINDOW);
  1264. # endif /* BSDSIGS */
  1265. #endif /* SIG_WINDOW */
  1266.     area = buf;
  1267.  
  1268.     GotTermCaps = 1;
  1269.  
  1270.     setname("gettermcaps");
  1271.     ptr = getenv("TERM");
  1272.  
  1273. #ifdef apollo
  1274.     /* 
  1275.      * If we are on a pad, we pretend that we are dumb. Otherwise the termcap
  1276.      * library will put us in a weird screen mode, thinking that we are going
  1277.      * to use curses
  1278.      */
  1279.     if (isapad())
  1280.     ptr = "dumb";
  1281. #endif /* apollo */
  1282.  
  1283.     if (!ptr || !ptr[0])
  1284.     ptr = "dumb";
  1285.  
  1286.     setzero(bp, TC_BUFSIZE);
  1287.  
  1288.     i = tgetent(bp, ptr);
  1289.     if (i <= 0) {
  1290.     if (i == -1) {
  1291. #if (SYSVREL == 0) || defined(IRIS3D)
  1292.         xprintf("tcsh: Cannot open /etc/termcap.\n");
  1293.     }
  1294.     else if (i == 0) {
  1295. #endif /* SYSVREL */
  1296.         xprintf("tcsh: No entry for terminal type \"%s\"\n",
  1297.             getenv("TERM"));
  1298.     }
  1299.     xprintf("tcsh: using dumb terminal settings.\n");
  1300.     Val(T_co) = 80;        /* do a dumb terminal */
  1301.     Val(T_pt) = Val(T_km) = Val(T_li) = 0;
  1302.     for (t = tstr; t->name != NULL; t++)
  1303.         TCalloc(t, NULL);
  1304.     }
  1305.     else {
  1306.     /* Can we tab */
  1307.     Val(T_pt) = tgetflag("pt") && !tgetflag("xt");
  1308.     /* do we have a meta? */
  1309.     Val(T_km) = (tgetflag("km") || tgetflag("MT"));
  1310.     Val(T_am) = tgetflag("am");
  1311.     Val(T_xn) = tgetflag("xn");
  1312.     Val(T_co) = tgetnum("co");
  1313.     Val(T_li) = tgetnum("li");
  1314.     for (t = tstr; t->name != NULL; t++)
  1315.         TCalloc(t, tgetstr(t->name, &area));
  1316.     }
  1317.     if (Val(T_co) < 2)
  1318.     Val(T_co) = 80;        /* just in case */
  1319.     if (Val(T_li) < 1)
  1320.     Val(T_li) = 24;
  1321.  
  1322.     T_Cols = Val(T_co);
  1323.     T_Lines = Val(T_li);
  1324.     if (T_Tabs)
  1325.     T_Tabs = Val(T_pt);
  1326.     T_HasMeta = Val(T_km);
  1327.     T_Margin = Val(T_am) ? MARGIN_AUTO : 0;
  1328.     T_Margin |= Val(T_xn) ? MARGIN_MAGIC : 0;
  1329.     T_CanCEOL = GoodStr(T_ce);
  1330.     T_CanDel = GoodStr(T_dc) || GoodStr(T_DC);
  1331.     T_CanIns = GoodStr(T_im) || GoodStr(T_ic) || GoodStr(T_IC);
  1332.     T_CanUP = GoodStr(T_up) || GoodStr(T_UP);
  1333.     if (GoodStr(T_me) && GoodStr(T_ue))
  1334.     me_all = (strcmp(Str(T_me), Str(T_ue)) == 0);
  1335.     else
  1336.     me_all = 0;
  1337.     if (GoodStr(T_me) && GoodStr(T_se))
  1338.     me_all |= (strcmp(Str(T_me), Str(T_se)) == 0);
  1339.  
  1340.  
  1341. #ifdef DEBUG_SCREEN
  1342.     if (!T_CanUP) {
  1343.     xprintf("tcsh: WARNING: Your terminal cannot move up.\n");
  1344.     xprintf("Editing may be odd for long lines.\n");
  1345.     }
  1346.     if (!T_CanCEOL)
  1347.     xprintf("no clear EOL capability.\n");
  1348.     if (!T_CanDel)
  1349.     xprintf("no delete char capability.\n");
  1350.     if (!T_CanIns)
  1351.     xprintf("no insert char capability.\n");
  1352. #endif /* DEBUG_SCREEN */
  1353.  
  1354.  
  1355.  
  1356. #ifdef SIG_WINDOW
  1357.     (void) GetSize(&lins, &cols);    /* get the correct window size */
  1358.     ChangeSize(lins, cols);
  1359.  
  1360. # ifdef BSDSIGS
  1361.     (void) sigsetmask(omask);    /* can change it again */
  1362. # else /* BSDSIGS */
  1363.     (void) sigrelse(SIG_WINDOW);
  1364. # endif /* BSDSIGS */
  1365. #else /* SIG_WINDOW */
  1366.     ChangeSize(Val(T_li), Val(T_co));
  1367. #endif /* SIG_WINDOW */
  1368.  
  1369.     BindArrowKeys();
  1370. }
  1371.  
  1372. #ifdef SIG_WINDOW
  1373. /* GetSize():
  1374.  *    Return the new window size in lines and cols, and
  1375.  *    true if the size was changed. This can fail if SHIN
  1376.  *    is not a tty, but it will work in most cases.
  1377.  */
  1378. int
  1379. GetSize(lins, cols)
  1380.     int    *lins, *cols;
  1381. {
  1382.     *cols = Val(T_co);
  1383.     *lins = Val(T_li);
  1384.  
  1385. #ifdef TIOCGWINSZ
  1386. # define KNOWsize
  1387. # ifndef lint
  1388.     {
  1389.     struct winsize ws;    /* from 4.3 */
  1390.  
  1391.     if (ioctl(SHIN, TIOCGWINSZ, (ioctl_t) &ws) != -1) {
  1392.         if (ws.ws_col)
  1393.         *cols = ws.ws_col;
  1394.         if (ws.ws_row)
  1395.         *lins = ws.ws_row;
  1396.     }
  1397.     }
  1398. # endif /* !lint */
  1399. #else /* TIOCGWINSZ */
  1400. # ifdef TIOCGSIZE
  1401. #  define KNOWsize
  1402.     {
  1403.     struct ttysize ts;    /* from Sun */
  1404.  
  1405.     if (ioctl(SHIN, TIOCGSIZE, (ioctl_t) &ts) != -1) {
  1406.         if (ts.ts_cols)
  1407.         *cols = ts.ts_cols;
  1408.         if (ts.ts_lines)
  1409.         *lins = ts.ts_lines;
  1410.     }
  1411.     }
  1412. # endif /* TIOCGSIZE */
  1413. #endif /* TIOCGWINSZ */
  1414.  
  1415.     return (Val(T_co) != *cols || Val(T_li) != *lins);
  1416. }
  1417.  
  1418. #endif /* SIGWINDOW */
  1419.  
  1420. void
  1421. ChangeSize(lins, cols)
  1422.     int     lins, cols;
  1423. {
  1424.     /*
  1425.      * Just in case
  1426.      */
  1427.     Val(T_co) = (cols < 2) ? 80 : cols;
  1428.     Val(T_li) = (lins < 1) ? 24 : lins;
  1429.  
  1430. #ifdef KNOWsize
  1431.     /*
  1432.      * We want to affect the environment only when we have a valid
  1433.      * setup, not when we get bad settings. Consider the following scenario:
  1434.      * We just logged in, and we have not initialized the editor yet.
  1435.      * We reset termcap with tset, and not $TERMCAP has the right
  1436.      * terminal size. But since the editor is not initialized yet, and
  1437.      * the kernel's notion of the terminal size might be wrong we arrive
  1438.      * here with lines = columns = 0. If we reset the environment we lose
  1439.      * our only chance to get the window size right.
  1440.      */
  1441.     if (Val(T_co) == cols && Val(T_li) == lins) {
  1442.     Char    buf[10];
  1443.     char   *tptr;
  1444.  
  1445.     if (getenv("COLUMNS")) {
  1446.         Itoa(Val(T_co), buf);
  1447.         tsetenv(STRCOLUMNS, buf);
  1448.     }
  1449.  
  1450.     if (getenv("LINES")) {
  1451.         Itoa(Val(T_li), buf);
  1452.         tsetenv(STRLINES, buf);
  1453.     }
  1454.  
  1455.     if ((tptr = getenv("TERMCAP")) != NULL) {
  1456.         Char    termcap[1024], backup[1024], *ptr;
  1457.         int     i;
  1458.  
  1459.         ptr = str2short(tptr);
  1460.         (void) Strncpy(termcap, ptr, 1024);
  1461.         termcap[1023] = '\0';
  1462.  
  1463.         /* update termcap string; first do columns */
  1464.         buf[0] = 'c';
  1465.         buf[1] = 'o';
  1466.         buf[2] = '#';
  1467.         buf[3] = '\0';
  1468.         if ((ptr = Strstr(termcap, buf)) == NULL) {
  1469.         (void) Strcpy(backup, termcap);
  1470.         }
  1471.         else {
  1472.         i = ptr - termcap + Strlen(buf);
  1473.         (void) Strncpy(backup, termcap, i);
  1474.         backup[i] = '\0';
  1475.         Itoa(Val(T_co), buf);
  1476.         (void) Strcat(backup + i, buf);
  1477.         ptr = Strchr(ptr, ':');
  1478.         (void) Strcat(backup, ptr);
  1479.         }
  1480.  
  1481.         /* now do lines */
  1482.         buf[0] = 'l';
  1483.         buf[1] = 'i';
  1484.         buf[2] = '#';
  1485.         buf[3] = '\0';
  1486.         if ((ptr = Strstr(backup, buf)) == NULL) {
  1487.         (void) Strcpy(termcap, backup);
  1488.         }
  1489.         else {
  1490.         i = ptr - backup + Strlen(buf);
  1491.         (void) Strncpy(termcap, backup, i);
  1492.         termcap[i] = '\0';
  1493.         Itoa(Val(T_li), buf);
  1494.         (void) Strcat(termcap, buf);
  1495.         ptr = Strchr(ptr, ':');
  1496.         (void) Strcat(termcap, ptr);
  1497.         }
  1498.         tsetenv(STRTERMCAP, termcap);
  1499.     }
  1500.     }
  1501. #endif /* KNOWsize */
  1502.  
  1503.     ReBufferDisplay();        /* re-make display buffers */
  1504.     ClearDisp();
  1505. }
  1506.