/* * term.c - deal with termcap, and unix terminal mode settings * * Pace Willisson, 1983 * * Copyright 1987, 1988, 1989, 1992, 1993, Geoff Kuenning, Granada Hills, CA * All rights reserved. * * see COPYRIGHT file for more information. */ /* new */ #ifndef TCSETAW #define TCSETAW 0x5407 #endif /* new */ #ifndef TCGETA #define TCGETA 0x5405 #endif #include #include #include #include "jsconfig.h" #include "jspell.h" #include "proto.h" #include "msgs.h" #include "myterm.h" #ifndef NOCURSES #include #include #include #endif #include static int putch(int c); SIGNAL_TYPE done(int signo); #ifdef SIGTSTP static SIGNAL_TYPE onstop(int signo); #endif /* SIGTSTP */ int shellescape(char * buf); /*---------------------------------------------------------------------------*/ void inverse(void) { #ifndef NOCURSES tputs(so, 10, putch); #endif } /*---------------------------------------------------------------------------*/ void normal(void) { #ifndef NOCURSES tputs(se, 10, putch); #endif } /*---------------------------------------------------------------------------*/ void erase_EOL(void) { #ifndef NOCURSES tputs(ce, 10, putch); #endif } /*---------------------------------------------------------------------------*/ void curs_left(void) { #ifndef NOCURSES tputs(le, 10, putch); #endif } /*---------------------------------------------------------------------------*/ void curs_right(void) { #ifndef NOCURSES tputs(nd, 10, putch); #endif } /*---------------------------------------------------------------------------*/ void backup(void) { #ifndef NOCURSES if (BC) tputs(BC, 1, putch); else putchar('\b'); #endif } /*---------------------------------------------------------------------------*/ static int putch(int c) { #ifndef NOCURSES return putchar(c); #endif } /*---------------------------------------------------------------------------*/ #ifndef NOCURSES static struct termios sbuf; static struct termios osbuf; #endif static int termchanged = 0; static SIGNAL_TYPE (*oldint) (); static SIGNAL_TYPE (*oldterm) (); #ifdef SIGTSTP static SIGNAL_TYPE (*oldttin) (); static SIGNAL_TYPE (*oldttou) (); static SIGNAL_TYPE (*oldtstp) (); #endif /*---------------------------------------------------------------------------*/ void terminit(void) { #ifndef NOCURSES #ifdef TIOCPGRP int tpgrp; #else #ifdef TIOCGPGRP int tpgrp; #endif #endif #ifdef TIOCGWINSZ struct winsize wsize; #endif /* TIOCGWINSZ */ tgetent(termcap, getenv("TERM")); termptr = termstr; BC = tgetstr("bc", &termptr); cd = tgetstr("cd", &termptr); /* clear to end of screen */ ce = tgetstr("ce", &termptr); /* clear to end of line */ cl = tgetstr("cl", &termptr); /* clear screen and cursor home */ cm = tgetstr("cm", &termptr); /* cursor move */ ho = tgetstr("ho", &termptr); /* cursor home */ le = tgetstr("nd", &termptr); /* cursor left one character */ nd = tgetstr("nd", &termptr); /* cursor right one character */ so = tgetstr("so", &termptr); /* inverse video on */ se = tgetstr("se", &termptr); /* inverse video off */ kl = tgetstr("kl", &termptr); /* cursor left key */ kr = tgetstr("kr", &termptr); /* cursor right key */ ku = tgetstr("ku", &termptr); /* cursor up key */ kd = tgetstr("kd", &termptr); /* cursor down key */ kP = tgetstr("kP", &termptr); /* cursor pgup key */ kN = tgetstr("kN", &termptr); /* cursor pgdown key */ kh = tgetstr("kh", &termptr); /* cursor home key */ kH = tgetstr("kH", &termptr); /* cursor end key */ kI = tgetstr("kI", &termptr); /* insert key */ /* NOT STANDARD */ kD = tgetstr("kD", &termptr); /* delete key */ if ((sg = tgetnum("sg")) < 0) /* space taken by so/se */ sg = 0; ti = tgetstr("ti", &termptr); /* terminal initialization */ te = tgetstr("te", &termptr); /* terminal termination */ co = tgetnum("co"); /* Number of columns */ li = tgetnum("li"); /* Number of lines */ #ifdef TIOCGWINSZ if (ioctl(0, TIOCGWINSZ, (char *) &wsize) >= 0) { if (wsize.ws_col != 0) co = wsize.ws_col; if (wsize.ws_row != 0) li = wsize.ws_row; } #endif /* TIOCGWINSZ */ /* * Let the variables "LINES" and "COLUMNS" override the termcap * entry. Technically, this is a terminfo-ism, but I think the * vast majority of users will find it pretty handy. */ if (getenv("COLUMNS") != NULL) co = atoi (getenv ("COLUMNS")); if (getenv("LINES") != NULL) li = atoi(getenv("LINES")); #if MAX_SCREEN_SIZE > 0 if (li > MAX_SCREEN_SIZE) li = MAX_SCREEN_SIZE; #endif /* MAX_SCREEN_SIZE > 0 */ #if MAXCONTEXT == MINCONTEXT contextsize = MINCONTEXT; #else /* MAXCONTEXT == MINCONTEXT */ if (contextsize == 0) #ifdef CONTEXTROUNDUP contextsize = (li * CONTEXTPCT + 99) / 100; #else /* CONTEXTROUNDUP */ contextsize = (li * CONTEXTPCT) / 100; #endif /* CONTEXTROUNDUP */ if (contextsize > MAXCONTEXT) contextsize = MAXCONTEXT; else if (contextsize < MINCONTEXT) contextsize = MINCONTEXT; #endif /* MAX_CONTEXT == MIN_CONTEXT */ /* * Insist on 2 lines for the screen header, 2 for blank lines * separating areas of the screen, 2 for word choices, and 2 for * the minimenu, plus however many are needed for context. If * possible, make the context smaller to fit on the screen. */ if (li < contextsize + 8 && contextsize > MINCONTEXT) { contextsize = li - 8; if (contextsize < MINCONTEXT) contextsize = MINCONTEXT; } if (li < MINCONTEXT + 8) fprintf(stderr, TERM_C_SMALL_SCREEN, MINCONTEXT + 8); #ifdef SIGTSTP #ifdef TIOCPGRP retry: #endif /* SIGTSTP */ #endif /* TIOCPGRP */ if (!isatty(0)) { fprintf(stderr, TERM_C_NO_BATCH); exit(1); } ioctl(0, TCGETA, (char *) &osbuf); termchanged = 1; sbuf = osbuf; sbuf.c_lflag &= ~(ECHO | ECHOK | ECHONL | ICANON); sbuf.c_oflag &= ~(OPOST); sbuf.c_iflag &= ~(INLCR | IGNCR | ICRNL); sbuf.c_cc[VMIN] = 1; sbuf.c_cc[VTIME] = 1; ioctl(0, TCSETAW, (char *) &sbuf); jerasechar = osbuf.c_cc[VERASE]; /* killchar = osbuf.c_cc[VKILL]; */ #ifdef SIGTSTP sigsetmask (1<<(SIGTSTP-1) | 1<<(SIGTTIN-1) | 1<<(SIGTTOU-1)); #endif #ifdef TIOCGPGRP if (ioctl(0, TIOCGPGRP, (char *) &tpgrp) != 0) { fprintf(stderr, TERM_C_NO_BATCH); exit(1); } #endif #ifdef SIGTSTP #ifdef TIOCPGRP if (tpgrp != getpgrp(0)) { /* not in foreground */ signal(SIGTTOU, SIG_DFL); kill(0, SIGTTOU); /* job stops here waiting for SIGCONT */ goto retry; } #endif #endif if ((oldint = signal (SIGINT, SIG_IGN)) != SIG_IGN) signal (SIGINT, done); if ((oldterm = signal (SIGTERM, SIG_IGN)) != SIG_IGN) signal (SIGTERM, done); #ifdef SIGTSTP if ((oldttin = signal(SIGTTIN, SIG_IGN)) != SIG_IGN) signal(SIGTTIN, onstop); if ((oldttou = signal(SIGTTOU, SIG_IGN)) != SIG_IGN) signal(SIGTTOU, onstop); if ((oldtstp = signal(SIGTSTP, SIG_IGN)) != SIG_IGN) signal(SIGTSTP, onstop); #endif if (ti) tputs(ti, 1, putch); init_filt(); #endif } /*---------------------------------------------------------------------------*/ /* ARGSUSED */ SIGNAL_TYPE done(int signo) { #ifndef NOCURSES if (tempfile[0] != '\0') unlink(tempfile); if (termchanged) { if (te) tputs(te, 1, putch); ioctl(0, TCSETAW, (char *) &osbuf); } /* WAS: ((nothing)) */ endwin(); #endif exit(0); } /*---------------------------------------------------------------------------*/ #ifdef SIGTSTP static SIGNAL_TYPE onstop(int signo) { #ifndef NOCURSES ioctl(0, TCSETAW, (char *) &osbuf); signal(signo, SIG_DFL); kill(0, signo); /* stop here until continued */ signal(signo, onstop); ioctl(0, TCSETAW, (char *) &sbuf); #endif } #endif /*---------------------------------------------------------------------------*/ void stop(void) { #ifndef NOCURSES #ifdef SIGTSTP onstop(SIGTSTP); #else /* for System V */ move(li - 1, 0); fflush(stdout); if (getenv("SHELL")) shellescape(getenv("SHELL")); else shellescape("sh"); #endif #endif } /*---------------------------------------------------------------------------*/ /* Fork and exec a process. Returns NZ if command found, regardless of ** command's return status. Returns zero if command was not found. ** Doesn't use a shell. */ #define NEED_SHELLESCAPE #ifndef REGEX_LOOKUP #define NEED_SHELLESCAPE #endif /* REGEX_LOOKUP */ #ifdef NEED_SHELLESCAPE int shellescape(char *buf) { #ifndef NOCURSES char *argv[100]; char *cp = buf; int i = 0; int termstat; /* parse buf to args (destroying it in the process) */ while (*cp != '\0') { while (*cp == ' ' || *cp == '\t') ++cp; if (*cp == '\0') break; argv[i++] = cp; while (*cp != ' ' && *cp != '\t' && *cp != '\0') ++cp; if (*cp != '\0') *cp++ = '\0'; } argv[i] = NULL; ioctl(0, TCSETAW, (char *) &osbuf); signal(SIGINT, oldint); signal(SIGTERM, oldterm); #ifdef SIGTSTP signal(SIGTTIN, oldttin); signal(SIGTTOU, oldttou); signal(SIGTSTP, oldtstp); #endif if ((i = fork()) == 0) { execvp(argv[0], (char **) argv); _exit(123); /* Command not found */ } else if (i > 0) { while (wait (&termstat) != i) ; termstat = (termstat == (123 << 8)) ? 0 : -1; } else { printf(TERM_C_CANT_FORK); termstat = -1; /* Couldn't fork */ } if (oldint != SIG_IGN) signal(SIGINT, done); if (oldterm != SIG_IGN) signal(SIGTERM, done); #ifdef SIGTSTP if (oldttin != SIG_IGN) signal(SIGTTIN, onstop); if (oldttou != SIG_IGN) signal(SIGTTOU, onstop); if (oldtstp != SIG_IGN) signal(SIGTSTP, onstop); #endif ioctl(0, TCSETAW, (char *) &sbuf); if (termstat) { printf(TERM_C_TYPE_SPACE); fflush(stdout); #ifdef COMMANDFORSPACE i = GETKEYSTROKE(); if (i != ' ' && i != '\n' && i != '\r') ungetc(i, stdin); #else while (GETKEYSTROKE() != ' ') ; #endif } return termstat; #endif } #endif /* NEED_SHELLESCAPE */ /*---------------------------------------------------------------------------*/ #define NFILTS 12 struct sfilter { char st[20]; int cont; int key; } filt[NFILTS]; void put_key(int pos, char *st, int key) { if (st) strcpy(filt[pos].st, st); else strcpy(filt[pos].st, "////"); /* dummy value */ filt[pos].key = key; } void init_filt(void) { #ifndef NOCURSES put_key(0, kl, CLEFT); put_key(1, kr, CRIGHT); put_key(2, kh, HOME); put_key(3, kH, END_); put_key(4, kI, INS); put_key(5, kD, DEL); /* put also ANSI definitions */ strcpy(filt[6].st, "\E[D"); filt[6].key = CLEFT; strcpy(filt[7].st, "\E[C"); filt[7].key = CRIGHT; strcpy(filt[8].st, "\E[1~"); filt[8].key = HOME; strcpy(filt[9].st, "\E[4~"); filt[9].key = END_; strcpy(filt[10].st, "\E[2~"); filt[10].key = INS; strcpy(filt[11].st, "\E[B"); filt[11].key = DEL; #endif } int verify_cond(char ch, int i) { int j, suc; j = 0; suc = 0; while (j < NFILTS && !suc) if (filt[j].st[i+1] != '\0' && ch == filt[j].st[i] && filt[j].cont == i) suc = 1; else j++; return suc; } int jfilter(int ch) { #ifndef NOCURSES int i, j, suc; char old_ch; if (ch == jerasechar) return BACKSPACE; if (ch == 8) return BACKSPACE; /* CTRL-H used in ANSI and XTERM */ i = 0; for (j = 0; j < NFILTS; j++) filt[j].cont = 0; /* printf("ch=%c, kh[0]=%c ", ch, kh[0]); fflush(stdout); */ while (verify_cond(ch, i)) { /* increment counter */ for (j = 0; j < NFILTS; j++) if (ch == filt[j].st[i]) filt[j].cont++; old_ch = ch; ch = (GETKEYSTROKE() & NOPARITY); i++; /* printf("ch=%c,kh[%d]=%c; ", ch, i, kh[i]); fflush(stdout); */ } j = 0; suc = 0; while (j < NFILTS && !suc) { if (filt[j].st[i+1] == '\0' && ch == filt[j].st[i] && filt[j].cont == i) /* conseguiu ler toda a string kl */ suc = 1; else j++; } if (suc) return filt[j].key; else return ch; #endif }