main
term.c
1/* Copyright (c) 1985 Ceriel J.H. Jacobs */
2
3/*
4 * Terminal handling routines, mostly initializing.
5 */
6
7#include "in_all.h"
8#include "term.h"
9#include "machine.h"
10#include "output.h"
11#include "display.h"
12#include "options.h"
13#include "getline.h"
14#include "keys.h"
15#include "main.h"
16#define getline yap_getline
17#define getch yap_getch
18#include <term.h>
19#undef getch
20#undef getline
21#undef insert_line
22
23int expandtabs;
24int stupid;
25int hardcopy;
26char *CE, *CL, *SO, *SE, *US, *UE, *UC, *MD, *ME, *TI, *TE, *CM, *TA, *SR, *AL;
27char *UP, *HO, *BO;
28int LINES, COLS, AM, XN, DB;
29int erasech, killch;
30struct state *sppat;
31char *BC;
32
33#ifdef TIOCGWINSZ
34static struct winsize w;
35#endif
36
37#ifdef TIOCSPGRP
38static int proc_id, saved_pgrpid;
39#endif
40
41static char *ll;
42
43struct linelist _X[100]; /* 100 is enough ? */
44
45static struct termios _tty, _svtty;
46
47static void
48handle(cc_t *c)
49{ /* if character *c is used, set it to undefined */
50
51 if (isused(*c))
52 *c = 0xff;
53}
54
55/*
56 * Set terminal in cbreak mode.
57 * Also check if tabs need expanding.
58 */
59
60void
61inittty()
62{
63 struct termios *p = &_tty;
64
65 tcgetattr(0, p);
66 _svtty = *p;
67 p->c_oflag &= ~OPOST;
68 p->c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL | ICANON);
69 if (isused('S' & 0x1f) || isused('Q' & 0x1f))
70 p->c_iflag &= ~IXON;
71 handle(&p->c_cc[VINTR]);
72 handle(&p->c_cc[VQUIT]);
73 erasech = p->c_cc[VERASE];
74 killch = p->c_cc[VKILL];
75 p->c_cc[VMIN] = 1; /* Just wait for one character */
76 p->c_cc[VTIME] = 0;
77 tcsetattr(0, TCSANOW, p);
78}
79
80void
81backspace()
82{
83 putline(BC);
84}
85
86void
87clrscreen()
88{
89 tputs(CL, LINES, fputch);
90}
91
92void
93clrtoeol()
94{
95 tputs(CE, 1, fputch);
96}
97
98void
99scrollreverse()
100{
101 tputs(SR, LINES, fputch);
102}
103
104void
105standout()
106{
107 tputs(SO, 1, fputch);
108}
109
110void
111standend()
112{
113 tputs(SE, 1, fputch);
114}
115
116void
117underline()
118{
119 tputs(US, 1, fputch);
120}
121
122void
123end_underline()
124{
125 tputs(UE, 1, fputch);
126}
127
128void
129bold()
130{
131 tputs(MD, 1, fputch);
132}
133
134void
135end_bold()
136{
137 tputs(ME, 1, fputch);
138}
139
140void
141underchar()
142{
143 tputs(UC, 1, fputch);
144}
145
146void
147givetab()
148{
149 tputs(TA, 1, fputch);
150}
151
152/*
153 * Reset the terminal to its original state
154 */
155
156void
157resettty()
158{
159 tcsetattr(0, TCSANOW, &_svtty);
160 putline(TE);
161 flush();
162}
163
164/*
165 * Get string terminal capability "cap".
166 * If not present, return an empty string.
167 */
168
169static char *
170getcap(char *cap)
171{
172 char *s;
173
174 s = tigetstr(cap);
175 if (!s || s == (char *)-1)
176 return "";
177 return s;
178}
179
180static int
181getflag(char *cap)
182{
183 int value;
184
185 value = tigetflag(cap);
186 return value < 0 ? 0 : value;
187}
188
189static int
190getnumcap(char *cap)
191{
192 int value;
193
194 value = tigetnum(cap);
195 return value < 0 ? -1 : value;
196}
197
198/*
199 * Initialize some terminal-dependent stuff.
200 */
201
202void
203ini_terminal()
204{
205
206 char *s;
207 struct linelist *lp, *lp1;
208 int i;
209 int UG, SG;
210 char tempbuf[20];
211 char *mb, *mh, *mr; /* attributes */
212 int err;
213
214 initkeys();
215#ifdef TIOCSPGRP
216 proc_id = getpid();
217 ioctl(0, TIOCGPGRP, (char *)&saved_pgrpid);
218#endif
219 inittty();
220 stupid = 1;
221 BC = "\b";
222 TA = "\t";
223 if (!(s = getenv("TERM")))
224 s = "dumb";
225 if (setupterm(s, 1, &err) != 0) {
226 panic("No terminfo entry");
227 }
228 stupid = 0;
229 hardcopy = getflag("hc"); /* Hard copy terminal?*/
230 if (*(s = getcap("cub1"))) {
231 /*
232 * Backspace if not ^H
233 */
234 BC = s;
235 }
236 UP = getcap("cuu1"); /* move up a line */
237 CE = getcap("el"); /* clear to end of line */
238 CL = getcap("clear"); /* clear screen */
239 if (!*CL)
240 cflag = 1;
241 TI = getcap("smcup"); /* Initialization for CM */
242 TE = getcap("rmcup"); /* end for CM */
243 CM = getcap("cup"); /* cursor addressing */
244 SR = getcap("ri"); /* scroll reverse */
245 AL = getcap("il"); /* Insert line */
246 SO = getcap("smso"); /* standout */
247 SE = getcap("rmso"); /* standend */
248 SG = getnumcap("xmc"); /* blanks left by attributes */
249 if (SG < 0)
250 SG = 0;
251 US = getcap("smul"); /* underline */
252 UE = getcap("rmul"); /* end underline */
253 UG = getnumcap("xmc"); /* blanks left by attributes */
254 if (UG < 0)
255 UG = 0;
256 UC = getcap("uc"); /* underline a character */
257 mb = getcap("blink"); /* blinking attribute */
258 MD = getcap("bold"); /* bold attribute */
259 ME = getcap("sgr0"); /* turn off attributes */
260 mh = getcap("dim"); /* half bright attribute */
261 mr = getcap("rev"); /* reversed video attribute */
262 if (!nflag) {
263 /*
264 * Recognize special strings
265 */
266 (void)addstring(SO, SG, &sppat);
267 (void)addstring(SE, SG, &sppat);
268 (void)addstring(US, UG, &sppat);
269 (void)addstring(UE, UG, &sppat);
270 (void)addstring(mb, 0, &sppat);
271 (void)addstring(MD, 0, &sppat);
272 (void)addstring(ME, 0, &sppat);
273 (void)addstring(mh, 0, &sppat);
274 (void)addstring(mr, 0, &sppat);
275 if (*UC) {
276 (void)strcpy(tempbuf, BC);
277 (void)strcat(tempbuf, UC);
278 (void)addstring(tempbuf, 0, &sppat);
279 }
280 }
281 if (UG > 0 || uflag) {
282 US = "";
283 UE = "";
284 }
285 if (*US || uflag)
286 UC = "";
287 COLS = getnumcap("cols"); /* columns on page */
288 i = getnumcap("lines"); /* Lines on page */
289 AM = getflag("am"); /* terminal wraps automatically? */
290 XN = getflag("xenl"); /* and then ignores next newline? */
291 DB = getflag("db"); /* terminal retains lines below */
292 HO = getcap("home");
293 if (!*HO && *CM) {
294 HO = tiparm(CM, 0, 0); /* Another way of getting home */
295 }
296 if ((!*CE && !*AL) || !*HO || hardcopy) {
297 cflag = stupid = 1;
298 }
299 if (*(s = getcap("ht"))) {
300 /*
301 * Tab (other than ^I or padding)
302 */
303 TA = s;
304 }
305 if (!*(ll = getcap("ll")) && *CM && i > 0) {
306 /*
307 * Lower left hand corner
308 */
309 BO = tiparm(CM, i - 1, 0);
310 } else
311 BO = ll;
312 if (COLS <= 0 || COLS > 256) {
313 if ((unsigned)COLS >= 65409) {
314 /* SUN bug */
315 COLS &= 0xffff;
316 COLS -= (65409 - 128);
317 }
318 if (COLS <= 0 || COLS > 256)
319 COLS = 80;
320 }
321 if (i <= 0) {
322 i = 24;
323 cflag = stupid = 1;
324 }
325 LINES = i;
326 maxpagesize = i - 1;
327 scrollsize = maxpagesize / 2;
328 if (scrollsize <= 0)
329 scrollsize = 1;
330 if (!pagesize || pagesize >= i) {
331 pagesize = maxpagesize;
332 }
333
334 /*
335 * The next part does not really belong here, but there it is ...
336 * Initialize a circular list for the screenlines.
337 */
338
339 scr_info.tail = lp = _X;
340 lp1 = lp + (100 - 1);
341 for (; lp <= lp1; lp++) {
342 /*
343 * Circular doubly linked list
344 */
345 lp->next = lp + 1;
346 lp->prev = lp - 1;
347 }
348 lp1->next = scr_info.tail;
349 lp1->next->prev = lp1;
350 if (stupid) {
351 BO = "\r\n";
352 }
353 putline(TI);
354 window();
355}
356
357/*
358 * Place cursor at start of line n.
359 */
360
361void
362mgoto(int n)
363{
364
365 if (n == 0)
366 home();
367 else if (n == maxpagesize && *BO)
368 bottom();
369 else if (*CM) {
370 /*
371 * Cursor addressing
372 */
373 tputs(tiparm(CM, n, 0), 1, fputch);
374 } else if (*BO && *UP && n >= (maxpagesize >> 1)) {
375 /*
376 * Bottom and then up
377 */
378 bottom();
379 while (n++ < maxpagesize)
380 putline(UP);
381 } else { /* Home, and then down */
382 home();
383 while (n--)
384 putline("\r\n");
385 }
386}
387
388/*
389 * Clear bottom line
390 */
391
392void
393clrbline()
394{
395
396 if (stupid) {
397 putline("\r\n");
398 return;
399 }
400 bottom();
401 if (*CE) {
402 /*
403 * We can clear to end of line
404 */
405 clrtoeol();
406 return;
407 }
408 ins_line(maxpagesize);
409}
410
411void
412ins_line(int l)
413{
414 tputs(tiparm(AL, l), maxpagesize - l, fputch);
415}
416
417void
418home()
419{
420
421 tputs(HO, 1, fputch);
422}
423
424void
425bottom()
426{
427
428 tputs(BO, 1, fputch);
429 if (!*BO)
430 mgoto(maxpagesize);
431}
432
433int
434window()
435{
436#ifdef TIOCGWINSZ
437 if (ioctl(1, TIOCGWINSZ, &w) < 0)
438 return 0;
439
440 if (w.ws_col == 0)
441 w.ws_col = COLS;
442 if (w.ws_row == 0)
443 w.ws_row = LINES;
444 if (w.ws_col != COLS || w.ws_row != LINES) {
445 COLS = w.ws_col;
446 LINES = w.ws_row;
447 maxpagesize = LINES - 1;
448 pagesize = maxpagesize;
449 if (!*ll)
450 BO = tiparm(CM, maxpagesize, 0);
451 scr_info.currentpos = 0;
452 scrollsize = maxpagesize / 2;
453 if (scrollsize <= 0)
454 scrollsize = 1;
455 return 1;
456 }
457#endif
458 return 0;
459}