1 /* $Header: /src/pub/tcsh/ed.screen.c,v 3.49 2002/03/08 17:36:45 christos Exp $ */
3 * ed.screen.c: Editor/termcap-curses interface
6 * Copyright (c) 1980, 1991 The Regents of the University of California.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 RCSID("$Id: ed.screen.c,v 3.49 2002/03/08 17:36:45 christos Exp $")
43 * We don't prototype these, cause some systems have them wrong!
45 extern int tgetent
__P(());
46 extern char *tgetstr
__P(());
47 extern int tgetflag
__P(());
48 extern int tgetnum
__P(());
49 extern char *tgoto
__P(());
50 # define PUTPURE putpure
51 # define PUTRAW putraw
53 extern int tgetent
__P((char *, char *));
54 extern char *tgetstr
__P((char *, char **));
55 extern int tgetflag
__P((char *));
56 extern int tgetnum
__P((char *));
57 extern char *tgoto
__P((char *, int, int));
58 extern void tputs
__P((char *, int, void (*)(int)));
59 # define PUTPURE ((void (*)__P((int))) putpure)
60 # define PUTRAW ((void (*)__P((int))) putraw)
64 /* #define DEBUG_LITERAL */
67 * IMPORTANT NOTE: these routines are allowed to look at the current screen
68 * and the current possition assuming that it is correct. If this is not
69 * true, then the update will be WRONG! This is (should be) a valid
73 #define TC_BUFSIZE 2048
75 #define GoodStr(a) (tstr[a].str != NULL && tstr[a].str[0] != '\0')
76 #define Str(a) tstr[a].str
77 #define Val(a) tval[a].val
189 static struct termcapstr
{
203 static struct termcapval
{
215 for (i
= 0; i
< T_str
+ 1; i
++)
216 xfree((ptr_t
) tstr
[i
].long_name
);
218 for (i
= 0; i
< T_val
+ 1; i
++)
219 xfree((ptr_t
) tval
[i
].long_name
);
222 tstr
[T_al
].name
= "al";
223 tstr
[T_al
].long_name
= CSAVS(4, 1, "add new blank line");
225 tstr
[T_bl
].name
= "bl";
226 tstr
[T_bl
].long_name
= CSAVS(4, 2, "audible bell");
228 tstr
[T_cd
].name
= "cd";
229 tstr
[T_cd
].long_name
= CSAVS(4, 3, "clear to bottom");
231 tstr
[T_ce
].name
= "ce";
232 tstr
[T_ce
].long_name
= CSAVS(4, 4, "clear to end of line");
234 tstr
[T_ch
].name
= "ch";
235 tstr
[T_ch
].long_name
= CSAVS(4, 5, "cursor to horiz pos");
237 tstr
[T_cl
].name
= "cl";
238 tstr
[T_cl
].long_name
= CSAVS(4, 6, "clear screen");
240 tstr
[T_dc
].name
= "dc";
241 tstr
[T_dc
].long_name
= CSAVS(4, 7, "delete a character");
243 tstr
[T_dl
].name
= "dl";
244 tstr
[T_dl
].long_name
= CSAVS(4, 8, "delete a line");
246 tstr
[T_dm
].name
= "dm";
247 tstr
[T_dm
].long_name
= CSAVS(4, 9, "start delete mode");
249 tstr
[T_ed
].name
= "ed";
250 tstr
[T_ed
].long_name
= CSAVS(4, 10, "end delete mode");
252 tstr
[T_ei
].name
= "ei";
253 tstr
[T_ei
].long_name
= CSAVS(4, 11, "end insert mode");
255 tstr
[T_fs
].name
= "fs";
256 tstr
[T_fs
].long_name
= CSAVS(4, 12, "cursor from status line");
258 tstr
[T_ho
].name
= "ho";
259 tstr
[T_ho
].long_name
= CSAVS(4, 13, "home cursor");
261 tstr
[T_ic
].name
= "ic";
262 tstr
[T_ic
].long_name
= CSAVS(4, 14, "insert character");
264 tstr
[T_im
].name
= "im";
265 tstr
[T_im
].long_name
= CSAVS(4, 15, "start insert mode");
267 tstr
[T_ip
].name
= "ip";
268 tstr
[T_ip
].long_name
= CSAVS(4, 16, "insert padding");
270 tstr
[T_kd
].name
= "kd";
271 tstr
[T_kd
].long_name
= CSAVS(4, 17, "sends cursor down");
273 tstr
[T_kl
].name
= "kl";
274 tstr
[T_kl
].long_name
= CSAVS(4, 18, "sends cursor left");
276 tstr
[T_kr
].name
= "kr";
277 tstr
[T_kr
].long_name
= CSAVS(4, 19, "sends cursor right");
279 tstr
[T_ku
].name
= "ku";
280 tstr
[T_ku
].long_name
= CSAVS(4, 20, "sends cursor up");
282 tstr
[T_md
].name
= "md";
283 tstr
[T_md
].long_name
= CSAVS(4, 21, "begin bold");
285 tstr
[T_me
].name
= "me";
286 tstr
[T_me
].long_name
= CSAVS(4, 22, "end attributes");
288 tstr
[T_nd
].name
= "nd";
289 tstr
[T_nd
].long_name
= CSAVS(4, 23, "non destructive space");
291 tstr
[T_se
].name
= "se";
292 tstr
[T_se
].long_name
= CSAVS(4, 24, "end standout");
294 tstr
[T_so
].name
= "so";
295 tstr
[T_so
].long_name
= CSAVS(4, 25, "begin standout");
297 tstr
[T_ts
].name
= "ts";
298 tstr
[T_ts
].long_name
= CSAVS(4, 26, "cursor to status line");
300 tstr
[T_up
].name
= "up";
301 tstr
[T_up
].long_name
= CSAVS(4, 27, "cursor up one");
303 tstr
[T_us
].name
= "us";
304 tstr
[T_us
].long_name
= CSAVS(4, 28, "begin underline");
306 tstr
[T_ue
].name
= "ue";
307 tstr
[T_ue
].long_name
= CSAVS(4, 29, "end underline");
309 tstr
[T_vb
].name
= "vb";
310 tstr
[T_vb
].long_name
= CSAVS(4, 30, "visible bell");
312 tstr
[T_DC
].name
= "DC";
313 tstr
[T_DC
].long_name
= CSAVS(4, 31, "delete multiple chars");
315 tstr
[T_DO
].name
= "DO";
316 tstr
[T_DO
].long_name
= CSAVS(4, 32, "cursor down multiple");
318 tstr
[T_IC
].name
= "IC";
319 tstr
[T_IC
].long_name
= CSAVS(4, 33, "insert multiple chars");
321 tstr
[T_LE
].name
= "LE";
322 tstr
[T_LE
].long_name
= CSAVS(4, 34, "cursor left multiple");
324 tstr
[T_RI
].name
= "RI";
325 tstr
[T_RI
].long_name
= CSAVS(4, 35, "cursor right multiple");
327 tstr
[T_UP
].name
= "UP";
328 tstr
[T_UP
].long_name
= CSAVS(4, 36, "cursor up multiple");
330 tstr
[T_kh
].name
= "kh";
331 tstr
[T_kh
].long_name
= CSAVS(4, 37, "send cursor home");
333 tstr
[T_at7
].name
= "@7";
334 tstr
[T_at7
].long_name
= CSAVS(4, 38, "send cursor end");
336 tstr
[T_str
].name
= NULL
;
337 tstr
[T_str
].long_name
= NULL
;
340 tval
[T_am
].name
= "am";
341 tval
[T_am
].long_name
= CSAVS(4, 37, "Has automatic margins");
343 tval
[T_pt
].name
= "pt";
344 tval
[T_pt
].long_name
= CSAVS(4, 38, "Can use physical tabs");
346 tval
[T_li
].name
= "li";
347 tval
[T_li
].long_name
= CSAVS(4, 39, "Number of lines");
349 tval
[T_co
].name
= "co";
350 tval
[T_co
].long_name
= CSAVS(4, 40, "Number of columns");
352 tval
[T_km
].name
= "km";
353 tval
[T_km
].long_name
= CSAVS(4, 41, "Has meta key");
355 tval
[T_xn
].name
= "xn";
356 tval
[T_xn
].long_name
= CSAVS(4, 42, "Newline ignored at right margin");
358 tval
[T_val
].name
= NULL
;
359 tval
[T_val
].long_name
= NULL
;
363 * A very useful table from justin@crim.ca (Justin Bur) :-)
364 * (Modified by per@erix.ericsson.se (Per Hedeland)
365 * - first (and second:-) case fixed)
367 * Description Termcap variables tcsh behavior
368 * am xn UseRightmost SendCRLF
369 * -------------- ------- ------- ------------ ------------
370 * Automargins yes no yes no
371 * Magic Margins yes yes yes no
372 * No Wrap no -- yes yes
375 static bool me_all
= 0; /* does two or more of the attributes use me */
377 static void ReBufferDisplay
__P((void));
378 static void TCalloc
__P((struct termcapstr
*, char *));
383 struct termcapstr
*t
;
386 static char termcap_alloc
[TC_BUFSIZE
];
387 char termbuf
[TC_BUFSIZE
];
388 struct termcapstr
*ts
;
392 if (cap
== NULL
|| *cap
== '\0') {
402 tlen
= strlen(t
->str
);
405 * New string is shorter; no need to allocate space
408 (void) strcpy(t
->str
, cap
);
413 * New string is longer; see if we have enough space to append
415 if (tloc
+ 3 < TC_BUFSIZE
) {
416 (void) strcpy(t
->str
= &termcap_alloc
[tloc
], cap
);
417 tloc
+= clen
+ 1; /* one for \0 */
422 * Compact our buffer; no need to check compaction, cause we know it
426 for (ts
= tstr
; ts
->name
!= NULL
; ts
++)
427 if (t
!= ts
&& ts
->str
!= NULL
&& ts
->str
[0] != '\0') {
430 for (ptr
= ts
->str
; *ptr
!= '\0'; termbuf
[tlen
++] = *ptr
++)
432 termbuf
[tlen
++] = '\0';
434 (void) memmove((ptr_t
) termcap_alloc
, (ptr_t
) termbuf
, (size_t) TC_BUFSIZE
);
436 if (tloc
+ 3 >= TC_BUFSIZE
) {
437 stderror(ERR_NAME
| ERR_TCNOSTR
);
440 (void) strcpy(t
->str
= &termcap_alloc
[tloc
], cap
);
441 tloc
+= clen
+ 1; /* one for \0 */
451 struct termcapstr
*t
;
454 xprintf(CGETS(7, 1, "\n\tTcsh thinks your terminal has the\n"));
455 xprintf(CGETS(7, 2, "\tfollowing characteristics:\n\n"));
456 xprintf(CGETS(7, 3, "\tIt has %d columns and %d lines\n"),
457 Val(T_co
), Val(T_li
));
458 xprintf(CGETS(7, 4, "\tIt has %s meta key\n"), T_HasMeta
?
459 CGETS(7, 5, "a") : CGETS(7, 6, "no"));
460 xprintf(CGETS(7, 7, "\tIt can%s use tabs\n"), T_Tabs
?
461 "" : CGETS(7, 8, " not"));
462 xprintf(CGETS(7, 9, "\tIt %s automatic margins\n"),
463 (T_Margin
&MARGIN_AUTO
)?
465 CGETS(7, 11, "does not have"));
466 if (T_Margin
& MARGIN_AUTO
)
467 xprintf(CGETS(7, 12, "\tIt %s magic margins\n"),
468 (T_Margin
& MARGIN_MAGIC
) ?
470 CGETS(7, 11, "does not have"));
472 for (t
= tstr
; t
->name
!= NULL
; t
++)
473 xprintf("\t%36s (%s) == %s\n", t
->long_name
, t
->name
,
474 t
->str
&& *t
->str
? t
->str
: CGETS(7, 13, "(empty)"));
489 for (bufp
= b
; *bufp
!= NULL
; bufp
++)
490 xfree((ptr_t
) * bufp
);
496 for (bufp
= b
; *bufp
!= NULL
; bufp
++)
497 xfree((ptr_t
) * bufp
);
501 TermV
= (INBUFSIZE
* 4) / TermH
+ 1;
502 b
= (Char
**) xmalloc((size_t) (sizeof(Char
*) * (TermV
+ 1)));
503 for (i
= 0; i
< TermV
; i
++)
504 b
[i
] = (Char
*) xmalloc((size_t) (sizeof(Char
) * (TermH
+ 1)));
507 b
= (Char
**) xmalloc((size_t) (sizeof(Char
*) * (TermV
+ 1)));
508 for (i
= 0; i
< TermV
; i
++)
509 b
[i
] = (Char
*) xmalloc((size_t) (sizeof(Char
) * (TermH
+ 1)));
518 struct termcapstr
*ts
;
519 struct termcapval
*tv
;
522 * Do the strings first
525 for (ts
= tstr
; ts
->name
!= NULL
; ts
++)
526 if (strcmp(ts
->name
, what
) == 0)
528 if (ts
->name
!= NULL
) {
533 if (GoodStr(T_me
) && GoodStr(T_ue
))
534 me_all
= (strcmp(Str(T_me
), Str(T_ue
)) == 0);
537 if (GoodStr(T_me
) && GoodStr(T_se
))
538 me_all
|= (strcmp(Str(T_me
), Str(T_se
)) == 0);
540 T_CanCEOL
= GoodStr(T_ce
);
541 T_CanDel
= GoodStr(T_dc
) || GoodStr(T_DC
);
542 T_CanIns
= GoodStr(T_im
) || GoodStr(T_ic
) || GoodStr(T_IC
);
543 T_CanUP
= GoodStr(T_up
) || GoodStr(T_UP
);
548 * Do the numeric ones second
550 for (tv
= tval
; tv
->name
!= NULL
; tv
++)
551 if (strcmp(tv
->name
, what
) == 0)
554 if (tv
->name
!= NULL
) {
555 if (tv
== &tval
[T_pt
] || tv
== &tval
[T_km
] ||
556 tv
== &tval
[T_am
] || tv
== &tval
[T_xn
]) {
557 if (strcmp(how
, "yes") == 0)
559 else if (strcmp(how
, "no") == 0)
562 stderror(ERR_SETTCUS
, tv
->name
);
565 T_Tabs
= (Char
) Val(T_pt
);
566 T_HasMeta
= (Char
) Val(T_km
);
567 T_Margin
= (Char
) Val(T_am
) ? MARGIN_AUTO
: 0;
568 T_Margin
|= (Char
) Val(T_xn
) ? MARGIN_MAGIC
: 0;
569 if (tv
== &tval
[T_am
] || tv
== &tval
[T_xn
])
570 ChangeSize(Val(T_li
), Val(T_co
));
575 T_Cols
= (Char
) Val(T_co
);
576 T_Lines
= (Char
) Val(T_li
);
577 if (tv
== &tval
[T_co
] || tv
== &tval
[T_li
])
578 ChangeSize(Val(T_li
), Val(T_co
));
582 stderror(ERR_NAME
| ERR_TCCAP
, what
);
588 * Print the termcap string out with variable substitution
594 char *cap
, *scap
, cv
[BUFSIZE
];
595 int arg_need
, arg_cols
, arg_rows
;
596 int verbose
= 0, silent
= 0;
598 static char *fmts
= "%s\n", *fmtd
= "%d\n";
599 struct termcapstr
*t
;
600 char buf
[TC_BUFSIZE
];
610 stderror(ERR_NAME
| ERR_NOMATCH
);
613 v
= gargv
= saveblk(v
);
616 if (!*v
|| *v
[0] == '\0')
618 if (v
[0][0] == '-') {
627 stderror(ERR_NAME
| ERR_TCUSAGE
);
632 if (!*v
|| *v
[0] == '\0')
634 (void) strcpy(cv
, short2str(*v
));
635 if (strcmp(cv
, "tabs") == 0) {
636 xprintf(fmts
, T_Tabs
? CGETS(7, 14, "yes") :
641 else if (strcmp(cv
, "meta") == 0) {
642 xprintf(fmts
, Val(T_km
) ? CGETS(7, 14, "yes") :
647 else if (strcmp(cv
, "xn") == 0) {
648 xprintf(fmts
, T_Margin
& MARGIN_MAGIC
? CGETS(7, 14, "yes") :
653 else if (strcmp(cv
, "am") == 0) {
654 xprintf(fmts
, T_Margin
& MARGIN_AUTO
? CGETS(7, 14, "yes") :
659 else if (strcmp(cv
, "baud") == 0) {
662 for (i
= 0; baud_rate
[i
].b_name
!= NULL
; i
++)
663 if (T_Speed
== baud_rate
[i
].b_rate
) {
664 xprintf(fmts
, baud_rate
[i
].b_name
);
672 else if (strcmp(cv
, "rows") == 0 || strcmp(cv
, "lines") == 0) {
673 xprintf(fmtd
, Val(T_li
));
677 else if (strcmp(cv
, "cols") == 0) {
678 xprintf(fmtd
, Val(T_co
));
684 * Try to use our local definition first
687 for (t
= tstr
; t
->name
!= NULL
; t
++)
688 if (strcmp(t
->name
, cv
) == 0) {
693 scap
= tgetstr(cv
, &area
);
694 if (!scap
|| scap
[0] == '\0') {
696 xprintf(CGETS(7, 14, "yes\n"));
702 stderror(ERR_NAME
| ERR_TCCAP
, cv
);
706 * Count home many values we need for this capability.
708 for (cap
= scap
, arg_need
= 0; *cap
; cap
++)
728 * hpux has lot's of them...
731 stderror(ERR_NAME
| ERR_TCPARM
, *cap
);
732 /* This is bad, but I won't complain */
743 stderror(ERR_NAME
| ERR_TCARGS
, cv
, arg_need
);
745 (void) tputs(scap
, 1, PUTRAW
);
749 if (!*v
|| *v
[0] == '\0')
750 stderror(ERR_NAME
| ERR_TCNARGS
, cv
, 1);
752 arg_rows
= atoi(short2str(*v
));
758 stderror(ERR_NAME
| ERR_TCARGS
, cv
, arg_need
);
760 (void) tputs(tgoto(scap
, arg_cols
, arg_rows
), 1, PUTRAW
);
763 /* This is wrong, but I will ignore it... */
765 stderror(ERR_NAME
| ERR_TCARGS
, cv
, arg_need
);
769 if (!*v
|| *v
[0] == '\0') {
773 stderror(ERR_NAME
| ERR_TCNARGS
, cv
, 2);
775 arg_cols
= atoi(short2str(*v
));
777 if (!*v
|| *v
[0] == '\0') {
781 stderror(ERR_NAME
| ERR_TCNARGS
, cv
, 2);
783 arg_rows
= atoi(short2str(*v
));
789 stderror(ERR_NAME
| ERR_TCARGS
, cv
, arg_need
);
791 (void) tputs(tgoto(scap
, arg_cols
, arg_rows
), arg_rows
, PUTRAW
);
801 bool GotTermCaps
= 0;
827 arrow
[A_K_DN
].fun
.cmd
= F_DOWN_HIST
;
828 arrow
[A_K_DN
].type
= XK_CMD
;
830 arrow
[A_K_UP
].fun
.cmd
= F_UP_HIST
;
831 arrow
[A_K_UP
].type
= XK_CMD
;
833 arrow
[A_K_LT
].fun
.cmd
= F_CHARBACK
;
834 arrow
[A_K_LT
].type
= XK_CMD
;
836 arrow
[A_K_RT
].fun
.cmd
= F_CHARFWD
;
837 arrow
[A_K_RT
].type
= XK_CMD
;
839 arrow
[A_K_HO
].fun
.cmd
= F_TOBEG
;
840 arrow
[A_K_HO
].type
= XK_CMD
;
842 arrow
[A_K_EN
].fun
.cmd
= F_TOEND
;
843 arrow
[A_K_EN
].type
= XK_CMD
;
849 static Char strA
[] = {033, '[', 'A', '\0'};
850 static Char strB
[] = {033, '[', 'B', '\0'};
851 static Char strC
[] = {033, '[', 'C', '\0'};
852 static Char strD
[] = {033, '[', 'D', '\0'};
853 static Char strH
[] = {033, '[', 'H', '\0'};
854 static Char strF
[] = {033, '[', 'F', '\0'};
855 static Char stOA
[] = {033, 'O', 'A', '\0'};
856 static Char stOB
[] = {033, 'O', 'B', '\0'};
857 static Char stOC
[] = {033, 'O', 'C', '\0'};
858 static Char stOD
[] = {033, 'O', 'D', '\0'};
859 static Char stOH
[] = {033, 'O', 'H', '\0'};
860 static Char stOF
[] = {033, 'O', 'F', '\0'};
866 strA
[0] = CTL_ESC('\033');
867 strB
[0] = CTL_ESC('\033');
868 strC
[0] = CTL_ESC('\033');
869 strD
[0] = CTL_ESC('\033');
870 strH
[0] = CTL_ESC('\033');
871 strF
[0] = CTL_ESC('\033');
872 stOA
[0] = CTL_ESC('\033');
873 stOB
[0] = CTL_ESC('\033');
874 stOC
[0] = CTL_ESC('\033');
875 stOD
[0] = CTL_ESC('\033');
876 stOH
[0] = CTL_ESC('\033');
877 stOF
[0] = CTL_ESC('\033');
883 cs
.buf
= strA
; AddXkey(&cs
, &arrow
[A_K_UP
].fun
, arrow
[A_K_UP
].type
);
884 cs
.buf
= strB
; AddXkey(&cs
, &arrow
[A_K_DN
].fun
, arrow
[A_K_DN
].type
);
885 cs
.buf
= strC
; AddXkey(&cs
, &arrow
[A_K_RT
].fun
, arrow
[A_K_RT
].type
);
886 cs
.buf
= strD
; AddXkey(&cs
, &arrow
[A_K_LT
].fun
, arrow
[A_K_LT
].type
);
887 cs
.buf
= strH
; AddXkey(&cs
, &arrow
[A_K_HO
].fun
, arrow
[A_K_HO
].type
);
888 cs
.buf
= strF
; AddXkey(&cs
, &arrow
[A_K_EN
].fun
, arrow
[A_K_EN
].type
);
889 cs
.buf
= stOA
; AddXkey(&cs
, &arrow
[A_K_UP
].fun
, arrow
[A_K_UP
].type
);
890 cs
.buf
= stOB
; AddXkey(&cs
, &arrow
[A_K_DN
].fun
, arrow
[A_K_DN
].type
);
891 cs
.buf
= stOC
; AddXkey(&cs
, &arrow
[A_K_RT
].fun
, arrow
[A_K_RT
].type
);
892 cs
.buf
= stOD
; AddXkey(&cs
, &arrow
[A_K_LT
].fun
, arrow
[A_K_LT
].type
);
893 cs
.buf
= stOH
; AddXkey(&cs
, &arrow
[A_K_HO
].fun
, arrow
[A_K_HO
].type
);
894 cs
.buf
= stOF
; AddXkey(&cs
, &arrow
[A_K_EN
].fun
, arrow
[A_K_EN
].type
);
898 cs
.buf
= &strA
[1]; AddXkey(&cs
, &arrow
[A_K_UP
].fun
, arrow
[A_K_UP
].type
);
899 cs
.buf
= &strB
[1]; AddXkey(&cs
, &arrow
[A_K_DN
].fun
, arrow
[A_K_DN
].type
);
900 cs
.buf
= &strC
[1]; AddXkey(&cs
, &arrow
[A_K_RT
].fun
, arrow
[A_K_RT
].type
);
901 cs
.buf
= &strD
[1]; AddXkey(&cs
, &arrow
[A_K_LT
].fun
, arrow
[A_K_LT
].type
);
902 cs
.buf
= &strH
[1]; AddXkey(&cs
, &arrow
[A_K_HO
].fun
, arrow
[A_K_HO
].type
);
903 cs
.buf
= &strF
[1]; AddXkey(&cs
, &arrow
[A_K_EN
].fun
, arrow
[A_K_EN
].type
);
904 cs
.buf
= &stOA
[1]; AddXkey(&cs
, &arrow
[A_K_UP
].fun
, arrow
[A_K_UP
].type
);
905 cs
.buf
= &stOB
[1]; AddXkey(&cs
, &arrow
[A_K_DN
].fun
, arrow
[A_K_DN
].type
);
906 cs
.buf
= &stOC
[1]; AddXkey(&cs
, &arrow
[A_K_RT
].fun
, arrow
[A_K_RT
].type
);
907 cs
.buf
= &stOD
[1]; AddXkey(&cs
, &arrow
[A_K_LT
].fun
, arrow
[A_K_LT
].type
);
908 cs
.buf
= &stOH
[1]; AddXkey(&cs
, &arrow
[A_K_HO
].fun
, arrow
[A_K_HO
].type
);
909 cs
.buf
= &stOF
[1]; AddXkey(&cs
, &arrow
[A_K_EN
].fun
, arrow
[A_K_EN
].type
);
915 SetArrowKeys(name
, fun
, type
)
921 for (i
= 0; i
< A_K_NKEYS
; i
++)
922 if (Strcmp(name
->buf
, arrow
[i
].name
) == 0) {
924 arrow
[i
].type
= type
;
935 for (i
= 0; i
< A_K_NKEYS
; i
++)
936 if (Strcmp(name
, arrow
[i
].name
) == 0)
946 for (i
= 0; i
< A_K_NKEYS
; i
++)
947 if (Strcmp(name
->buf
, arrow
[i
].name
) == 0) {
948 arrow
[i
].type
= XK_NOD
;
960 for (i
= 0; i
< A_K_NKEYS
; i
++)
961 if (name
->len
== 0 || Strcmp(name
->buf
, arrow
[i
].name
) == 0)
962 if (arrow
[i
].type
!= XK_NOD
) {
964 cs
.buf
= arrow
[i
].name
;
965 cs
.len
= Strlen(cs
.buf
);
966 (void) printOne(&cs
, &arrow
[i
].fun
, arrow
[i
].type
);
981 map
= VImode
? CcAltMap
: CcKeyMap
;
982 dmap
= VImode
? CcViCmdMap
: CcEmacsMap
;
986 for (i
= 0; i
< A_K_NKEYS
; i
++) {
987 p
= tstr
[arrow
[i
].key
].str
;
989 j
= (unsigned char) *p
;
990 cs
.buf
= str2short(p
);
991 cs
.len
= Strlen(cs
.buf
);
993 * Assign the arrow keys only if:
995 * 1. They are multi-character arrow keys and the user
996 * has not re-assigned the leading character, or
997 * has re-assigned the leading character to be F_XKEY
998 * 2. They are single arrow keys pointing to an unassigned key.
1000 if (arrow
[i
].type
== XK_NOD
) {
1001 ClearXkey(map
, &cs
);
1004 if (p
[1] && (dmap
[j
] == map
[j
] || map
[j
] == F_XKEY
)) {
1005 AddXkey(&cs
, &arrow
[i
].fun
, arrow
[i
].type
);
1008 else if (map
[j
] == F_UNASSIGNED
) {
1009 ClearXkey(map
, &cs
);
1010 if (arrow
[i
].type
== XK_CMD
)
1011 map
[j
] = arrow
[i
].fun
.cmd
;
1013 AddXkey(&cs
, &arrow
[i
].fun
, arrow
[i
].type
);
1020 static Char cur_atr
= 0; /* current attributes */
1027 if (atr
!= cur_atr
) {
1028 if (me_all
&& GoodStr(T_me
)) {
1029 if (((cur_atr
& BOLD
) && !(atr
& BOLD
)) ||
1030 ((cur_atr
& UNDER
) && !(atr
& UNDER
)) ||
1031 ((cur_atr
& STANDOUT
) && !(atr
& STANDOUT
))) {
1032 (void) tputs(Str(T_me
), 1, PUTPURE
);
1036 if ((atr
& BOLD
) != (cur_atr
& BOLD
)) {
1038 if (GoodStr(T_md
) && GoodStr(T_me
)) {
1039 (void) tputs(Str(T_md
), 1, PUTPURE
);
1044 if (GoodStr(T_md
) && GoodStr(T_me
)) {
1045 (void) tputs(Str(T_me
), 1, PUTPURE
);
1046 if ((cur_atr
& STANDOUT
) && GoodStr(T_se
)) {
1047 (void) tputs(Str(T_se
), 1, PUTPURE
);
1048 cur_atr
&= ~STANDOUT
;
1050 if ((cur_atr
& UNDER
) && GoodStr(T_ue
)) {
1051 (void) tputs(Str(T_ue
), 1, PUTPURE
);
1058 if ((atr
& STANDOUT
) != (cur_atr
& STANDOUT
)) {
1059 if (atr
& STANDOUT
) {
1060 if (GoodStr(T_so
) && GoodStr(T_se
)) {
1061 (void) tputs(Str(T_so
), 1, PUTPURE
);
1062 cur_atr
|= STANDOUT
;
1066 if (GoodStr(T_se
)) {
1067 (void) tputs(Str(T_se
), 1, PUTPURE
);
1068 cur_atr
&= ~STANDOUT
;
1072 if ((atr
& UNDER
) != (cur_atr
& UNDER
)) {
1074 if (GoodStr(T_us
) && GoodStr(T_ue
)) {
1075 (void) tputs(Str(T_us
), 1, PUTPURE
);
1080 if (GoodStr(T_ue
)) {
1081 (void) tputs(Str(T_ue
), 1, PUTPURE
);
1089 /* PWP 6-27-88 -- if the tty driver thinks that we can tab, we ask termcap */
1097 MoveToLine(where
) /* move to line <where> (first line == 0) */
1098 int where
; /* as efficiently as possible; */
1102 if (where
== CursorV
)
1105 if (where
> TermV
) {
1107 xprintf("MoveToLine: where is ridiculous: %d\r\n", where
);
1109 #endif /* DEBUG_SCREEN */
1113 del
= where
- CursorV
;
1115 #ifndef WINNT_NATIVE
1118 if ((T_Margin
& MARGIN_AUTO
) && Display
[CursorV
][0] != '\0') {
1119 /* move without newline */
1120 MoveToChar(TermH
- 1);
1121 so_write(&Display
[CursorV
][CursorH
], 1); /* updates CursorH/V*/
1125 if ((del
> 1) && GoodStr(T_DO
)) {
1126 (void) tputs(tgoto(Str(T_DO
), del
, del
), del
, PUTPURE
);
1130 for ( ; del
> 0; del
--)
1131 (void) putraw('\n');
1132 CursorH
= 0; /* because the \n will become \r\n */
1137 else { /* del < 0 */
1138 if (GoodStr(T_UP
) && (-del
> 1 || !GoodStr(T_up
)))
1139 (void) tputs(tgoto(Str(T_UP
), -del
, -del
), -del
, PUTPURE
);
1143 for (i
= 0; i
< -del
; i
++)
1144 (void) tputs(Str(T_up
), 1, PUTPURE
);
1147 #else /* WINNT_NATIVE */
1148 NT_MoveToLineOrChar(del
, 1);
1149 #endif /* !WINNT_NATIVE */
1150 CursorV
= where
; /* now where is here */
1154 MoveToChar(where
) /* move to character position (where) */
1156 { /* as efficiently as possible */
1157 #ifndef WINNT_NATIVE
1161 #endif /* WINNT_NATIVE */
1162 if (where
== CursorH
)
1165 if (where
>= TermH
) {
1167 xprintf("MoveToChar: where is riduculous: %d\r\n", where
);
1169 #endif /* DEBUG_SCREEN */
1173 if (!where
) { /* if where is first column */
1174 (void) putraw('\r'); /* do a CR */
1179 #ifndef WINNT_NATIVE
1180 del
= where
- CursorH
;
1182 if ((del
< -4 || del
> 4) && GoodStr(T_ch
))
1183 /* go there directly */
1184 (void) tputs(tgoto(Str(T_ch
), where
, where
), where
, PUTPURE
);
1187 if (del
> 0) { /* moving forward */
1188 if ((del
> 4) && GoodStr(T_RI
))
1189 (void) tputs(tgoto(Str(T_RI
), del
, del
), del
, PUTPURE
);
1191 /* if I can do tabs, use them */
1195 #endif /* DSPMBYTE */
1197 if ((CursorH
& 0370) != (where
& 0370)) {
1198 /* if not within tab stop */
1199 for (i
= (CursorH
& 0370); i
< (where
& 0370); i
+= 8)
1200 (void) putraw('\t'); /* then tab over */
1201 CursorH
= where
& 0370;
1202 /* Note: considering that we often want to go to
1203 TermH - 1 for the wrapping, it would be nice to
1204 optimize this case by tabbing to the last column
1205 - but this doesn't work for all terminals! */
1208 /* it's usually cheaper to just write the chars, so we do. */
1210 /* NOTE THAT so_write() WILL CHANGE CursorH!!! */
1211 so_write(&Display
[CursorV
][CursorH
], where
- CursorH
);
1215 else { /* del < 0 := moving backward */
1216 if ((-del
> 4) && GoodStr(T_LE
))
1217 (void) tputs(tgoto(Str(T_LE
), -del
, -del
), -del
, PUTPURE
);
1218 else { /* can't go directly there */
1219 /* if the "cost" is greater than the "cost" from col 0 */
1220 if (T_Tabs
? (-del
> ((where
>> 3) + (where
& 07)))
1222 (void) putraw('\r'); /* do a CR */
1224 goto mc_again
; /* and try again */
1226 for (i
= 0; i
< -del
; i
++)
1227 (void) putraw('\b');
1231 #else /* WINNT_NATIVE */
1232 NT_MoveToLineOrChar(where
, 0);
1233 #endif /* !WINNT_NATIVE */
1234 CursorH
= where
; /* now where is here */
1243 return; /* catch bugs */
1247 xprintf("so_write: n is riduculous: %d\r\n", n
);
1249 #endif /* DEBUG_SCREEN */
1254 if (*cp
& LITERAL
) {
1255 extern Char
*litptr
[];
1258 #ifdef DEBUG_LITERAL
1259 xprintf("so: litnum %d, litptr %x\r\n",
1260 *cp
& CHAR
, litptr
[*cp
& CHAR
]);
1261 #endif /* DEBUG_LITERAL */
1262 #if defined(WINNT_NATIVE) && !defined(COLOR_LS_F)
1264 char buf
[256], *ptr
= &buf
[0];
1265 for (d
= litptr
[*cp
++ & CHAR
]; *d
& LITERAL
; d
++)
1266 *ptr
++ = (*d
& CHAR
);
1270 #else /* !WINNT_NATIVE || COLOR_LS_F */
1271 for (d
= litptr
[*cp
++ & CHAR
]; *d
& LITERAL
; d
++)
1272 (void) putraw(*d
& CHAR
);
1273 #endif /* WINNT_NATIVE && !COLOR_LS_F */
1278 (void) putraw(*cp
++);
1282 if (CursorH
>= TermH
) { /* wrap? */
1283 if (T_Margin
& MARGIN_AUTO
) { /* yes */
1286 if (T_Margin
& MARGIN_MAGIC
) {
1287 /* force the wrap to avoid the "magic" situation */
1289 if ((c
= Display
[CursorV
][CursorH
]) != '\0')
1296 else /* no wrap, but cursor stays on screen */
1297 CursorH
= TermH
- 1;
1303 DeleteChars(num
) /* deletes <num> characters */
1311 xprintf(CGETS(7, 16, "ERROR: cannot delete\r\n"));
1312 #endif /* DEBUG_EDIT */
1319 xprintf(CGETS(7, 17, "DeleteChars: num is riduculous: %d\r\n"), num
);
1321 #endif /* DEBUG_SCREEN */
1325 if (GoodStr(T_DC
)) /* if I have multiple delete */
1326 if ((num
> 1) || !GoodStr(T_dc
)) { /* if dc would be more expen. */
1327 (void) tputs(tgoto(Str(T_DC
), num
, num
), num
, PUTPURE
);
1331 if (GoodStr(T_dm
)) /* if I have delete mode */
1332 (void) tputs(Str(T_dm
), 1, PUTPURE
);
1334 if (GoodStr(T_dc
)) /* else do one at a time */
1336 (void) tputs(Str(T_dc
), 1, PUTPURE
);
1338 if (GoodStr(T_ed
)) /* if I have delete mode */
1339 (void) tputs(Str(T_ed
), 1, PUTPURE
);
1343 Insert_write(cp
, num
) /* Puts terminal in insert character mode, */
1345 register int num
; /* or inserts num characters in the line */
1351 xprintf(CGETS(7, 18, "ERROR: cannot insert\r\n"));
1352 #endif /* DEBUG_EDIT */
1359 xprintf(CGETS(7, 19, "StartInsert: num is riduculous: %d\r\n"), num
);
1361 #endif /* DEBUG_SCREEN */
1365 if (GoodStr(T_IC
)) /* if I have multiple insert */
1366 if ((num
> 1) || !GoodStr(T_ic
)) { /* if ic would be more expen. */
1367 (void) tputs(tgoto(Str(T_IC
), num
, num
), num
, PUTPURE
);
1368 so_write(cp
, num
); /* this updates CursorH/V */
1372 if (GoodStr(T_im
) && GoodStr(T_ei
)) { /* if I have insert mode */
1373 (void) tputs(Str(T_im
), 1, PUTPURE
);
1377 (void) putraw(*cp
++);
1380 if (GoodStr(T_ip
)) /* have to make num chars insert */
1381 (void) tputs(Str(T_ip
), 1, PUTPURE
);
1383 (void) tputs(Str(T_ei
), 1, PUTPURE
);
1388 if (GoodStr(T_ic
)) /* have to make num chars insert */
1389 (void) tputs(Str(T_ic
), 1, PUTPURE
); /* insert a char */
1391 (void) putraw(*cp
++);
1395 if (GoodStr(T_ip
)) /* have to make num chars insert */
1396 (void) tputs(Str(T_ip
), 1, PUTPURE
);/* pad the inserted char */
1403 ClearEOL(num
) /* clear to end of line. There are num */
1404 int num
; /* characters to clear */
1411 if (T_CanCEOL
&& GoodStr(T_ce
))
1412 (void) tputs(Str(T_ce
), 1, PUTPURE
);
1414 for (i
= 0; i
< num
; i
++)
1416 CursorH
+= num
; /* have written num spaces */
1422 { /* clear the whole screen and home */
1424 /* send the clear screen code */
1425 (void) tputs(Str(T_cl
), Val(T_li
), PUTPURE
);
1426 else if (GoodStr(T_ho
) && GoodStr(T_cd
)) {
1427 (void) tputs(Str(T_ho
), Val(T_li
), PUTPURE
); /* home */
1428 /* clear to bottom of screen */
1429 (void) tputs(Str(T_cd
), Val(T_li
), PUTPURE
);
1432 (void) putraw('\r');
1433 (void) putraw('\n');
1439 { /* produce a sound */
1441 if (adrof(STRnobeep
))
1444 if (GoodStr(T_vb
) && adrof(STRvisiblebell
))
1445 (void) tputs(Str(T_vb
), 1, PUTPURE
); /* visible bell */
1446 else if (GoodStr(T_bl
))
1447 /* what termcap says we should use */
1448 (void) tputs(Str(T_bl
), 1, PUTPURE
);
1450 #ifndef WINNT_NATIVE
1451 (void) putraw(CTL_ESC('\007')); /* an ASCII bell; ^G */
1452 #else /* WINNT_NATIVE */
1453 MessageBeep(MB_ICONQUESTION
);
1454 #endif /* !WINNT_NATIVE */
1459 { /* clear to the bottom of the screen */
1461 (void) tputs(Str(T_cd
), Val(T_li
), PUTPURE
);
1462 else if (GoodStr(T_ce
))
1463 (void) tputs(Str(T_ce
), Val(T_li
), PUTPURE
);
1468 { /* read in the needed terminal capabilites */
1471 char buf
[TC_BUFSIZE
];
1472 static char bp
[TC_BUFSIZE
];
1474 struct termcapstr
*t
;
1480 # endif /* BSDSIGS */
1483 /* don't want to confuse things here */
1485 omask
= sigblock(sigmask(SIG_WINDOW
)) & ~sigmask(SIG_WINDOW
);
1486 # else /* BSDSIGS */
1487 (void) sighold(SIG_WINDOW
);
1488 # endif /* BSDSIGS */
1489 #endif /* SIG_WINDOW */
1494 setname("gettermcaps");
1495 ptr
= getenv("TERM");
1499 * If we are on a pad, we pretend that we are dumb. Otherwise the termcap
1500 * library will put us in a weird screen mode, thinking that we are going
1507 if (!ptr
|| !ptr
[0] || !strcmp(ptr
, "wm") || !strcmp(ptr
,"dmx"))
1510 setzero(bp
, TC_BUFSIZE
);
1512 i
= tgetent(bp
, ptr
);
1515 #if (SYSVREL == 0) || defined(IRIS3D)
1516 xprintf(CGETS(7, 20, "%s: Cannot open /etc/termcap.\n"), progname
);
1519 #endif /* SYSVREL */
1520 xprintf(CGETS(7, 21,
1521 "%s: No entry for terminal type \"%s\"\n"), progname
,
1524 xprintf(CGETS(7, 22, "%s: using dumb terminal settings.\n"), progname
);
1525 Val(T_co
) = 80; /* do a dumb terminal */
1526 Val(T_pt
) = Val(T_km
) = Val(T_li
) = 0;
1527 for (t
= tstr
; t
->name
!= NULL
; t
++)
1532 Val(T_pt
) = tgetflag("pt") && !tgetflag("xt");
1533 /* do we have a meta? */
1534 Val(T_km
) = (tgetflag("km") || tgetflag("MT"));
1535 Val(T_am
) = tgetflag("am");
1536 Val(T_xn
) = tgetflag("xn");
1537 Val(T_co
) = tgetnum("co");
1538 Val(T_li
) = tgetnum("li");
1539 for (t
= tstr
; t
->name
!= NULL
; t
++)
1540 TCalloc(t
, tgetstr(t
->name
, &area
));
1543 Val(T_co
) = 80; /* just in case */
1547 T_Cols
= (Char
) Val(T_co
);
1548 T_Lines
= (Char
) Val(T_li
);
1550 T_Tabs
= (Char
) Val(T_pt
);
1551 T_HasMeta
= (Char
) Val(T_km
);
1552 T_Margin
= (Char
) Val(T_am
) ? MARGIN_AUTO
: 0;
1553 T_Margin
|= (Char
) Val(T_xn
) ? MARGIN_MAGIC
: 0;
1554 T_CanCEOL
= GoodStr(T_ce
);
1555 T_CanDel
= GoodStr(T_dc
) || GoodStr(T_DC
);
1556 T_CanIns
= GoodStr(T_im
) || GoodStr(T_ic
) || GoodStr(T_IC
);
1557 T_CanUP
= GoodStr(T_up
) || GoodStr(T_UP
);
1558 if (GoodStr(T_me
) && GoodStr(T_ue
))
1559 me_all
= (strcmp(Str(T_me
), Str(T_ue
)) == 0);
1562 if (GoodStr(T_me
) && GoodStr(T_se
))
1563 me_all
|= (strcmp(Str(T_me
), Str(T_se
)) == 0);
1568 xprintf(CGETS(7, 23, "%s: WARNING: Your terminal cannot move up.\n",
1570 xprintf(CGETS(7, 24, "Editing may be odd for long lines.\n"));
1573 xprintf(CGETS(7, 25, "no clear EOL capability.\n"));
1575 xprintf(CGETS(7, 26, "no delete char capability.\n"));
1577 xprintf(CGETS(7, 27, "no insert char capability.\n"));
1578 #endif /* DEBUG_SCREEN */
1583 (void) GetSize(&lins
, &cols
); /* get the correct window size */
1584 ChangeSize(lins
, cols
);
1587 (void) sigsetmask(omask
); /* can change it again */
1588 # else /* BSDSIGS */
1589 (void) sigrelse(SIG_WINDOW
);
1590 # endif /* BSDSIGS */
1591 #else /* SIG_WINDOW */
1592 ChangeSize(Val(T_li
), Val(T_co
));
1593 #endif /* SIG_WINDOW */
1600 * Return the new window size in lines and cols, and
1601 * true if the size was changed. This can fail if SHIN
1602 * is not a tty, but it will work in most cases.
1615 struct winsize ws
; /* from 4.3 */
1617 if (ioctl(SHIN
, TIOCGWINSZ
, (ioctl_t
) &ws
) != -1) {
1625 #else /* TIOCGWINSZ */
1629 struct ttysize ts
; /* from Sun */
1631 if (ioctl(SHIN
, TIOCGSIZE
, (ioctl_t
) &ts
) != -1) {
1635 *lins
= ts
.ts_lines
;
1638 # endif /* TIOCGSIZE */
1639 #endif /* TIOCGWINSZ */
1641 return (Val(T_co
) != *cols
|| Val(T_li
) != *lins
);
1644 #endif /* SIGWINDOW */
1647 ChangeSize(lins
, cols
)
1653 Val(T_co
) = (cols
< 2) ? 80 : cols
;
1654 Val(T_li
) = (lins
< 1) ? 24 : lins
;
1657 nt_set_size(lins
,cols
);
1658 #endif /* WINNT_NATIVE */
1661 * We want to affect the environment only when we have a valid
1662 * setup, not when we get bad settings. Consider the following scenario:
1663 * We just logged in, and we have not initialized the editor yet.
1664 * We reset termcap with tset, and not $TERMCAP has the right
1665 * terminal size. But since the editor is not initialized yet, and
1666 * the kernel's notion of the terminal size might be wrong we arrive
1667 * here with lines = columns = 0. If we reset the environment we lose
1668 * our only chance to get the window size right.
1670 if (Val(T_co
) == cols
&& Val(T_li
) == lins
) {
1674 if (getenv("COLUMNS")) {
1675 (void) Itoa(Val(T_co
), buf
, 0, 0);
1676 tsetenv(STRCOLUMNS
, buf
);
1679 if (getenv("LINES")) {
1680 (void) Itoa(Val(T_li
), buf
, 0, 0);
1681 tsetenv(STRLINES
, buf
);
1684 if ((tptr
= getenv("TERMCAP")) != NULL
) {
1685 /* Leave 64 characters slop in case we enlarge the termcap string */
1686 Char termcap
[1024+64], backup
[1024+64], *ptr
;
1689 ptr
= str2short(tptr
);
1690 (void) Strncpy(termcap
, ptr
, 1024);
1691 termcap
[1023] = '\0';
1693 /* update termcap string; first do columns */
1698 if ((ptr
= Strstr(termcap
, buf
)) == NULL
) {
1699 (void) Strcpy(backup
, termcap
);
1702 i
= (int) (ptr
- termcap
+ Strlen(buf
));
1703 (void) Strncpy(backup
, termcap
, (size_t) i
);
1705 (void) Itoa(Val(T_co
), buf
, 0, 0);
1706 (void) Strcat(backup
+ i
, buf
);
1707 ptr
= Strchr(ptr
, ':');
1708 (void) Strcat(backup
, ptr
);
1716 if ((ptr
= Strstr(backup
, buf
)) == NULL
) {
1717 (void) Strcpy(termcap
, backup
);
1720 i
= (int) (ptr
- backup
+ Strlen(buf
));
1721 (void) Strncpy(termcap
, backup
, (size_t) i
);
1723 (void) Itoa(Val(T_li
), buf
, 0, 0);
1724 (void) Strcat(termcap
, buf
);
1725 ptr
= Strchr(ptr
, ':');
1726 (void) Strcat(termcap
, ptr
);
1729 * Chop the termcap string at 1024 characters to avoid core-dumps
1730 * in the termcap routines
1732 termcap
[1023] = '\0';
1733 tsetenv(STRTERMCAP
, termcap
);
1736 #endif /* KNOWsize */
1738 ReBufferDisplay(); /* re-make display buffers */