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}