1 /* Copyright (c) 1985 Ceriel J.H. Jacobs */
4 * Terminal handling routines, mostly initializing.
8 static char rcsid
[] = "$Header$";
24 static struct winsize w
;
33 static char tcbuf1
[1024]; /* Holds terminal capability strings */
34 static char * ptc
; /* Pointer in it */
35 static char tcbuf
[1024]; /* Another termcap buffer */
36 short ospeed
; /* Needed for tputs() */
37 char PC
; /* Needed for tputs() */
38 char * UP
; /* Needed for tgoto() */
41 struct linelist _X
[100]; /* 100 is enough ? */
44 static struct termio _tty
,_svtty
;
46 static struct termios _tty
, _svtty
;
49 static int proc_id
, saved_pgrpid
;
51 static struct sgttyb _tty
,_svtty
;
53 static struct tchars _ttyc
, _svttyc
;
56 static int line_discipline
;
57 static struct ltchars _lttyc
, _svlttyc
;
62 handle(c
) char *c
; { /* if character *c is used, set it to undefined */
64 if (isused(*c
)) *c
= 0377;
68 * Set terminal in cbreak mode.
69 * Also check if tabs need expanding.
75 register struct termio
*p
= &_tty
;
77 ioctl(0,TCGETA
,(char *) p
);
79 if (p
->c_oflag
& TAB3
) {
81 * We do tab expansion ourselves
85 p
->c_oflag
&= ~(TAB3
|OCRNL
|ONLRET
|ONLCR
);
86 p
->c_oflag
|= (/*ONOCR|*/OPOST
); /* ONOCR does not seem to work
87 very well in combination with
90 p
->c_lflag
&= ~(ECHO
|ECHOE
|ECHOK
|ECHONL
|ICANON
);
91 if (isused('S'&037) || isused('Q'&037)) p
->c_iflag
&= ~IXON
;
92 handle(&(p
->c_cc
[0])); /* INTR and QUIT (mnemonics not defined ??) */
93 handle(&(p
->c_cc
[1]));
94 erasech
= p
->c_cc
[VERASE
];
95 killch
= p
->c_cc
[VKILL
];
96 p
->c_cc
[VMIN
] = 1; /* Just wait for one character */
98 ospeed
= p
->c_cflag
& CBAUD
;
99 ioctl(0,TCSETAW
,(char *) p
);
101 register struct termios
*p
= &_tty
;
105 #ifdef _MINIX /* Should be XTABS */
106 if (p
->c_oflag
& XTABS
) {
108 * We do tab expansion ourselves
112 p
->c_oflag
&= (OPOST
|XTABS
);
114 p
->c_oflag
&= ~OPOST
;
116 p
->c_lflag
&= ~(ECHO
|ECHOE
|ECHOK
|ECHONL
|ICANON
);
117 if (isused('S'&037) || isused('Q'&037)) p
->c_iflag
&= ~IXON
;
118 handle(&(p
->c_cc
[VINTR
]));
119 handle(&(p
->c_cc
[VQUIT
]));
120 erasech
= p
->c_cc
[VERASE
];
121 killch
= p
->c_cc
[VKILL
];
122 p
->c_cc
[VMIN
] = 1; /* Just wait for one character */
124 ospeed
= cfgetospeed(p
);
125 tcsetattr(0, TCSANOW
, p
);
127 register struct sgttyb
*p
= &_tty
;
131 * If we can, we put yap in another process group, and the terminal
132 * with it. This is done, so that interrupts given by the user
133 * will only affect yap and not it's children (processes writing
136 if (ioctl(0, TIOCSPGRP
, (char *) &proc_id
) != -1) {
140 ioctl(0,TIOCGETP
,(char *) p
);
142 erasech
= p
->sg_erase
;
144 ospeed
= p
->sg_ospeed
;
145 if (p
->sg_flags
& XTABS
) {
147 * We do tab expansion ourselves
151 p
->sg_flags
|= (CBREAK
);
152 p
->sg_flags
&= ~(ECHO
|XTABS
|RAW
|LCASE
|CRMOD
);
154 ioctl(0, TIOCSETN
, (char *) p
);
156 ioctl(0,TIOCSETP
,(char *) p
);
168 { register struct tchars
*q
= &_ttyc
;
170 ioctl(0,TIOCGETC
,(char *) q
);
172 handle(&(q
->t_intrc
));
173 handle(&(q
->t_quitc
));
174 if (isused(q
->t_startc
) || isused(q
->t_stopc
)) {
175 q
->t_startc
= q
->t_stopc
= 0377;
177 ioctl(0,TIOCSETC
, (char *) q
);
181 { register struct ltchars
*q
= &_lttyc
;
183 ioctl(0,TIOCGETD
,(char *) &line_discipline
);
184 if (line_discipline
== NTTYDISC
) {
185 ioctl(0, TIOCGLTC
,(char *) q
);
187 handle(&(q
->t_suspc
));
188 handle(&(q
->t_dsuspc
));
189 q
->t_flushc
= q
->t_lnextc
= 0377;
190 ioctl(0,TIOCSLTC
, (char *) q
);
198 * Reset the terminal to its original state
205 ioctl(0,TCSETAW
,(char *) &_svtty
);
207 tcsetattr(0, TCSANOW
, &_svtty
);
210 ioctl(0, TIOCSPGRP
, (char *) &saved_pgrpid
);
211 setpgrp(0, saved_pgrpid
);
213 ioctl(0,TIOCSETP
,(char *) &_svtty
);
215 ioctl(0,TIOCSETC
, (char *) &_svttyc
);
218 if (line_discipline
== NTTYDISC
) ioctl(0,TIOCSLTC
, (char *) &_svlttyc
);
226 * Get terminal capability "cap".
227 * If not present, return an empty string.
231 getcap(cap
) char *cap
; {
234 s
= tgetstr(cap
, &ptc
);
240 * Initialize some terminal-dependent stuff.
247 register struct linelist
*lp
, *lp1
;
251 char *mb
, *mh
, *mr
; /* attributes */
257 ioctl(0,TIOCGPGRP
, (char *) &saved_pgrpid
);
265 if (!(s
= getenv("TERM"))) s
= "dumb";
266 if (tgetent(tcbuf
, s
) <= 0) {
267 panic("No termcap entry");
270 hardcopy
= tgetflag("hc"); /* Hard copy terminal?*/
271 PC
= *(getcap("pc"));
272 if (*(s
= getcap("bc"))) {
274 * Backspace if not ^H
278 UP
= getcap("up"); /* move up a line */
279 CE
= getcap("ce"); /* clear to end of line */
280 CL
= getcap("cl"); /* clear screen */
282 TI
= getcap("ti"); /* Initialization for CM */
283 TE
= getcap("te"); /* end for CM */
284 CM
= getcap("cm"); /* cursor addressing */
285 SR
= getcap("sr"); /* scroll reverse */
286 AL
= getcap("al"); /* Insert line */
287 SO
= getcap("so"); /* standout */
288 SE
= getcap("se"); /* standend */
289 SG
= tgetnum("sg"); /* blanks left by SO, SE */
291 US
= getcap("us"); /* underline */
292 UE
= getcap("ue"); /* end underline */
293 UG
= tgetnum("ug"); /* blanks left by US, UE */
295 UC
= getcap("uc"); /* underline a character */
296 mb
= getcap("mb"); /* blinking attribute */
297 MD
= getcap("md"); /* bold attribute */
298 ME
= getcap("me"); /* turn off attributes */
299 mh
= getcap("mh"); /* half bright attribute */
300 mr
= getcap("mr"); /* reversed video attribute */
303 * Recognize special strings
305 (VOID
) addstring(SO
,SG
,&sppat
);
306 (VOID
) addstring(SE
,SG
,&sppat
);
307 (VOID
) addstring(US
,UG
,&sppat
);
308 (VOID
) addstring(UE
,UG
,&sppat
);
309 (VOID
) addstring(mb
,0,&sppat
);
310 (VOID
) addstring(MD
,0,&sppat
);
311 (VOID
) addstring(ME
,0,&sppat
);
312 (VOID
) addstring(mh
,0,&sppat
);
313 (VOID
) addstring(mr
,0,&sppat
);
315 (VOID
) strcpy(tempbuf
,BC
);
316 (VOID
) strcat(tempbuf
,UC
);
317 (VOID
) addstring(tempbuf
,0,&sppat
);
320 if (UG
> 0 || uflag
) {
324 if (*US
|| uflag
) UC
= "";
325 COLS
= tgetnum("co"); /* columns on page */
326 i
= tgetnum("li"); /* Lines on page */
327 AM
= tgetflag("am"); /* terminal wraps automatically? */
328 XN
= tgetflag("xn"); /* and then ignores next newline? */
329 DB
= tgetflag("db"); /* terminal retains lines below */
330 if (!*(s
= getcap("ho")) && *CM
) {
331 s
= tgoto(CM
,0,0); /* Another way of getting home */
333 if ((!*CE
&& !*AL
) || !*s
|| hardcopy
) {
337 if (*(s
= getcap("ta"))) {
339 * Tab (other than ^I or padding)
343 if (!*(ll
= getcap("ll")) && *CM
&& i
> 0) {
345 * Lower left hand corner
347 (VOID
) strcpy(BO
, tgoto(CM
,0,i
-1));
349 else (VOID
) strcpy(BO
, ll
);
350 if (COLS
<= 0 || COLS
> 256) {
351 if ((unsigned) COLS
>= 65409) {
354 COLS
-= (65409 - 128);
356 if (COLS
<= 0 || COLS
> 256) COLS
= 80;
364 scrollsize
= maxpagesize
/ 2;
365 if (scrollsize
<= 0) scrollsize
= 1;
366 if (!pagesize
|| pagesize
>= i
) {
367 pagesize
= maxpagesize
;
371 * The next part does not really belong here, but there it is ...
372 * Initialize a circular list for the screenlines.
375 scr_info
.tail
= lp
= _X
;
376 lp1
= lp
+ (100 - 1);
377 for (; lp
<= lp1
; lp
++) {
379 * Circular doubly linked list
384 lp1
->next
= scr_info
.tail
;
385 lp1
->next
->prev
= lp1
;
387 (VOID
) strcpy(BO
,"\r\n");
394 * Place cursor at start of line n.
398 mgoto(n
) register n
; {
401 else if (n
== maxpagesize
&& *BO
) bottom();
406 tputs(tgoto(CM
,0,n
),1,fputch
);
408 else if (*BO
&& *UP
&& n
>= (maxpagesize
>> 1)) {
413 while (n
++ < maxpagesize
) putline(UP
);
415 else { /* Home, and then down */
417 while (n
--) putline("\r\n");
435 * We can clear to end of line
441 insert_line(maxpagesize
);
449 tputs(tgoto(AL
, l
, 0), maxpagesize
- l
, fputch
);
463 if (!*BO
) mgoto(maxpagesize
);
470 if (ioctl(1, TIOCGWINSZ
, &w
) < 0) return 0;
472 if (w
.ws_col
== 0) w
.ws_col
= COLS
;
473 if (w
.ws_row
== 0) w
.ws_row
= LINES
;
474 if (w
.ws_col
!= COLS
|| w
.ws_row
!= LINES
) {
477 maxpagesize
= LINES
- 1;
478 pagesize
= maxpagesize
;
479 if (! *ll
) (VOID
) strcpy(BO
, tgoto(CM
,0,maxpagesize
));
480 scr_info
.currentpos
= 0;
481 scrollsize
= maxpagesize
/ 2;
482 if (scrollsize
<= 0) scrollsize
= 1;