1/* Copyright (c) 1985 Ceriel J.H. Jacobs */
2
3/*
4 * Terminal handling routines, mostly initializing.
5 */
6
7#include "term.h"
8#include "display.h"
9#include "getline.h"
10#include "in_all.h"
11#include "keys.h"
12#include "machine.h"
13#include "main.h"
14#include "options.h"
15#include "output.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 char *s;
206 struct linelist *lp, *lp1;
207 int i;
208 int UG, SG;
209 char tempbuf[20];
210 char *mb, *mh, *mr; /* attributes */
211 int err;
212
213 initkeys();
214#ifdef TIOCSPGRP
215 proc_id = getpid();
216 ioctl(0, TIOCGPGRP, (char *)&saved_pgrpid);
217#endif
218 inittty();
219 stupid = 1;
220 BC = "\b";
221 TA = "\t";
222 if (!(s = getenv("TERM")))
223 s = "dumb";
224 if (setupterm(s, 1, &err) != 0) {
225 panic("No terminfo entry");
226 }
227 stupid = 0;
228 hardcopy = getflag("hc"); /* Hard copy terminal?*/
229 if (*(s = getcap("cub1"))) {
230 /*
231 * Backspace if not ^H
232 */
233 BC = s;
234 }
235 UP = getcap("cuu1"); /* move up a line */
236 CE = getcap("el"); /* clear to end of line */
237 CL = getcap("clear"); /* clear screen */
238 if (!*CL)
239 cflag = 1;
240 TI = getcap("smcup"); /* Initialization for CM */
241 TE = getcap("rmcup"); /* end for CM */
242 CM = getcap("cup"); /* cursor addressing */
243 SR = getcap("ri"); /* scroll reverse */
244 AL = getcap("il"); /* Insert line */
245 SO = getcap("smso"); /* standout */
246 SE = getcap("rmso"); /* standend */
247 SG = getnumcap("xmc"); /* blanks left by attributes */
248 if (SG < 0)
249 SG = 0;
250 US = getcap("smul"); /* underline */
251 UE = getcap("rmul"); /* end underline */
252 UG = getnumcap("xmc"); /* blanks left by attributes */
253 if (UG < 0)
254 UG = 0;
255 UC = getcap("uc"); /* underline a character */
256 mb = getcap("blink"); /* blinking attribute */
257 MD = getcap("bold"); /* bold attribute */
258 ME = getcap("sgr0"); /* turn off attributes */
259 mh = getcap("dim"); /* half bright attribute */
260 mr = getcap("rev"); /* reversed video attribute */
261 if (!nflag) {
262 /*
263 * Recognize special strings
264 */
265 (void)addstring(SO, SG, &sppat);
266 (void)addstring(SE, SG, &sppat);
267 (void)addstring(US, UG, &sppat);
268 (void)addstring(UE, UG, &sppat);
269 (void)addstring(mb, 0, &sppat);
270 (void)addstring(MD, 0, &sppat);
271 (void)addstring(ME, 0, &sppat);
272 (void)addstring(mh, 0, &sppat);
273 (void)addstring(mr, 0, &sppat);
274 if (*UC) {
275 (void)strcpy(tempbuf, BC);
276 (void)strcat(tempbuf, UC);
277 (void)addstring(tempbuf, 0, &sppat);
278 }
279 }
280 if (UG > 0 || uflag) {
281 US = "";
282 UE = "";
283 }
284 if (*US || uflag)
285 UC = "";
286 COLS = getnumcap("cols"); /* columns on page */
287 i = getnumcap("lines"); /* Lines on page */
288 AM = getflag("am"); /* terminal wraps automatically? */
289 XN = getflag("xenl"); /* and then ignores next newline? */
290 DB = getflag("db"); /* terminal retains lines below */
291 HO = getcap("home");
292 if (!*HO && *CM) {
293 HO = tiparm(CM, 0, 0); /* Another way of getting home */
294 }
295 if ((!*CE && !*AL) || !*HO || hardcopy) {
296 cflag = stupid = 1;
297 }
298 if (*(s = getcap("ht"))) {
299 /*
300 * Tab (other than ^I or padding)
301 */
302 TA = s;
303 }
304 if (!*(ll = getcap("ll")) && *CM && i > 0) {
305 /*
306 * Lower left hand corner
307 */
308 BO = tiparm(CM, i - 1, 0);
309 } else
310 BO = ll;
311 if (COLS <= 0 || COLS > 256) {
312 if ((unsigned)COLS >= 65409) {
313 /* SUN bug */
314 COLS &= 0xffff;
315 COLS -= (65409 - 128);
316 }
317 if (COLS <= 0 || COLS > 256)
318 COLS = 80;
319 }
320 if (i <= 0) {
321 i = 24;
322 cflag = stupid = 1;
323 }
324 LINES = i;
325 maxpagesize = i - 1;
326 scrollsize = maxpagesize / 2;
327 if (scrollsize <= 0)
328 scrollsize = 1;
329 if (!pagesize || pagesize >= i) {
330 pagesize = maxpagesize;
331 }
332
333 /*
334 * The next part does not really belong here, but there it is ...
335 * Initialize a circular list for the screenlines.
336 */
337
338 scr_info.tail = lp = _X;
339 lp1 = lp + (100 - 1);
340 for (; lp <= lp1; lp++) {
341 /*
342 * Circular doubly linked list
343 */
344 lp->next = lp + 1;
345 lp->prev = lp - 1;
346 }
347 lp1->next = scr_info.tail;
348 lp1->next->prev = lp1;
349 if (stupid) {
350 BO = "\r\n";
351 }
352 putline(TI);
353 window();
354}
355
356/*
357 * Place cursor at start of line n.
358 */
359
360void
361mgoto(int n)
362{
363 if (n == 0)
364 home();
365 else if (n == maxpagesize && *BO)
366 bottom();
367 else if (*CM) {
368 /*
369 * Cursor addressing
370 */
371 tputs(tiparm(CM, n, 0), 1, fputch);
372 } else if (*BO && *UP && n >= (maxpagesize >> 1)) {
373 /*
374 * Bottom and then up
375 */
376 bottom();
377 while (n++ < maxpagesize)
378 putline(UP);
379 } else { /* Home, and then down */
380 home();
381 while (n--)
382 putline("\r\n");
383 }
384}
385
386/*
387 * Clear bottom line
388 */
389
390void
391clrbline()
392{
393 if (stupid) {
394 putline("\r\n");
395 return;
396 }
397 bottom();
398 if (*CE) {
399 /*
400 * We can clear to end of line
401 */
402 clrtoeol();
403 return;
404 }
405 ins_line(maxpagesize);
406}
407
408void
409ins_line(int l)
410{
411 tputs(tiparm(AL, l), maxpagesize - l, fputch);
412}
413
414void
415home()
416{
417 tputs(HO, 1, fputch);
418}
419
420void
421bottom()
422{
423 tputs(BO, 1, fputch);
424 if (!*BO)
425 mgoto(maxpagesize);
426}
427
428int
429window()
430{
431#ifdef TIOCGWINSZ
432 if (ioctl(1, TIOCGWINSZ, &w) < 0)
433 return 0;
434
435 if (w.ws_col == 0)
436 w.ws_col = COLS;
437 if (w.ws_row == 0)
438 w.ws_row = LINES;
439 if (w.ws_col != COLS || w.ws_row != LINES) {
440 COLS = w.ws_col;
441 LINES = w.ws_row;
442 maxpagesize = LINES - 1;
443 pagesize = maxpagesize;
444 if (!*ll)
445 BO = tiparm(CM, maxpagesize, 0);
446 scr_info.currentpos = 0;
447 scrollsize = maxpagesize / 2;
448 if (scrollsize <= 0)
449 scrollsize = 1;
450 return 1;
451 }
452#endif
453 return 0;
454}