source: trunk/third/tcsh/ed.screen.c @ 12039

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