master xplshn/aruu / cmd / extra / yap / term.c
  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}