📄 term.c
字号:
/* $Id: term.c,v 3.0 1992/02/01 03:09:32 davison Trn $ *//* This software is Copyright 1991 by Stan Barber. * * Permission is hereby granted to copy, reproduce, redistribute or otherwise * use this software as long as: there is no monetary profit gained * specifically from the use or reproduction of this software, it is not * sold, rented, traded or otherwise marketed, and this copyright notice is * included prominently in any copy made. * * The author make no claims as to the fitness or correctness of this software * for any use whatsoever, and it is provided as is. Any use of this software * is at the user's own risk. */#include "EXTERN.h"#include "common.h"#include "util.h"#include "final.h"#include "help.h"#include "cache.h"#include "intrp.h"#include "INTERN.h"#include "term.h"char ERASECH; /* rubout character */char KILLCH; /* line delete character */char tcarea[TCSIZE]; /* area for "compiled" termcap strings */int upcost;/* guarantee capability pointer != Nullch *//* (I believe terminfo will ignore the &tmpaddr argument.) */char *tgetstr();#define Tgetstr(key) ((tmpstr = tgetstr(key,&tmpaddr)) ? tmpstr : nullstr)struct keymap { char km_type[128]; union km_union { struct keymap *km_km; char *km_str; } km_ptr[128];};#define KM_NOTHIN 0#define KM_STRING 1#define KM_KEYMAP 2#define KM_BOGUS 3#define KM_TMASK 3#define KM_GSHIFT 4#define KM_GMASK 7typedef struct keymap KEYMAP;KEYMAP *topmap INIT(Null(KEYMAP*));void mac_init();KEYMAP *newkeymap();void show_keymap();void line_col_calcs();/* terminal initialization */voidterm_init(){ savetty(); /* remember current tty state */#ifdef I_TERMIO outspeed = _tty.c_cflag & CBAUD; /* for tputs() */ ERASECH = _tty.c_cc[VERASE]; /* for finish_command() */ KILLCH = _tty.c_cc[VKILL]; /* for finish_command() */ if (GT = ((_tty.c_oflag & TABDLY) != TAB3)) /* we have tabs, so that's OK */; else _tty.c_oflag &= ~TAB3; /* turn off kernel tabbing -- done in rn */#else /* !I_TERMIO */# ifdef I_TERMIOS outspeed = cfgetospeed(&_tty); /* for tputs() (output) */ ERASECH = _tty.c_cc[VERASE]; /* for finish_command() */ KILLCH = _tty.c_cc[VKILL]; /* for finish_command() *//* _tty.c_oflag &= ~OXTABS; /* turn off kernel tabbing-done in rn */# else /* !I_TERMIOS */ outspeed = _tty.sg_ospeed; /* for tputs() */ ERASECH = _tty.sg_erase; /* for finish_command() */ KILLCH = _tty.sg_kill; /* for finish_command() */ if (GT = ((_tty.sg_flags & XTABS) != XTABS)) /* we have tabs, so that's OK */; else _tty.sg_flags &= ~XTABS;# endif /* I_TERMIOS */#endif /* I_TERMIO */ /* The following could be a table but I can't be sure that there isn't */ /* some degree of sparsity out there in the world. */ switch (outspeed) { /* 1 second of padding */#ifdef BEXTA case BEXTA: just_a_sec = 1920; break;#else#ifdef B19200 case B19200: just_a_sec = 1920; break;#endif#endif case B9600: just_a_sec = 960; break; case B4800: just_a_sec = 480; break; case B2400: just_a_sec = 240; break; case B1800: just_a_sec = 180; break; case B1200: just_a_sec = 120; break; case B600: just_a_sec = 60; break; case B300: just_a_sec = 30; break; /* do I really have to type the rest of this??? */ case B200: just_a_sec = 20; break; case B150: just_a_sec = 15; break; case B134: just_a_sec = 13; break; case B110: just_a_sec = 11; break; case B75: just_a_sec = 8; break; case B50: just_a_sec = 5; break; default: just_a_sec = 960; break; /* if we are running detached I */ } /* don't want to know about it! */}/* set terminal characteristics */voidterm_set(tcbuf)char *tcbuf; /* temp area for "uncompiled" termcap entry */{ char *tmpaddr; /* must not be register */ register char *tmpstr; char *s; int status;#ifdef TIOCGWINSZ struct winsize winsize;#endif#ifdef PENDING#if ! defined (FIONREAD) && ! defined (HAS_RDCHK) /* do no delay reads on something that always gets closed on exit */ devtty = open("/dev/tty",0); if (devtty < 0) { printf(cantopen,"/dev/tty") FLUSH; finalize(1); } fcntl(devtty,F_SETFL,O_NDELAY);#endif#endif /* get all that good termcap stuff */#ifdef HAS_TERMLIB status = tgetent(tcbuf,getenv("TERM")); /* get termcap entry */ if (status < 1) {#ifdef VERBOSE printf("No termcap %s found.\n", status ? "file" : "entry") FLUSH;#else fputs("Termcap botch\n",stdout) FLUSH;#endif finalize(1); } tmpaddr = tcarea; /* set up strange tgetstr pointer */ s = Tgetstr("pc"); /* get pad character */ PC = *s; /* get it where tputs wants it */ if (!tgetflag("bs")) { /* is backspace not used? */ BC = Tgetstr("bc"); /* find out what is */ if (BC == nullstr) /* terminfo grok's 'bs' but not 'bc' */ BC = Tgetstr("le"); } else BC = "\b"; /* make a backspace handy */ UP = Tgetstr("up"); /* move up a line */ if (!*UP) /* no UP string? */ marking = 0; /* disable any marking */ if (muck_up_clear) /* this is for weird HPs */ CL = "\n\n\n\n"; else CL = Tgetstr("cl"); /* get clear string */ CE = Tgetstr("ce"); /* clear to end of line string */ TI = Tgetstr("ti"); /* initialize display */ TE = Tgetstr("te"); /* reset display */ HO = Tgetstr("ho"); /* home cursor if no CM */ CM = Tgetstr("cm"); /* cursor motion */ if (*CM || *HO) can_home = TRUE;#ifdef CLEAREOL CD = Tgetstr("cd"); /* clear to end of display */ if (!*CE || !*CD || !can_home) /* can we CE, CD, and home? */ can_home_clear = FALSE; /* no, so disable use of clear eol */ if (!*CE) CE = CD;#endif /* CLEAREOL */ upcost = strlen(UP); SO = Tgetstr("so"); /* begin standout */ SE = Tgetstr("se"); /* end standout */ if ((SG = tgetnum("sg"))<0) SG = 0; /* blanks left by SG, SE */ US = Tgetstr("us"); /* start underline */ UE = Tgetstr("ue"); /* end underline */ if ((UG = tgetnum("ug"))<0) UG = 0; /* blanks left by US, UE */ if (*US) UC = nullstr; /* UC must not be NULL */ else UC = Tgetstr("uc"); /* underline a character */ if (!*US && !*UC) { /* no underline mode? */ US = SO; /* substitute standout mode */ UE = SE; UG = SG; } LINES = tgetnum("li"); /* lines per page */ COLS = tgetnum("co"); /* columns on page */#ifdef TIOCGWINSZ { struct winsize ws; if (ioctl(0, TIOCGWINSZ, &ws) >= 0 && ws.ws_row > 0 && ws.ws_col > 0) { LINES = ws.ws_row; COLS = ws.ws_col; } }#endif AM = tgetflag("am"); /* terminal wraps automatically? */ XN = tgetflag("xn"); /* then eats next newline? */ VB = Tgetstr("vb"); if (!*VB) VB = "\007"; CR = Tgetstr("cr"); if (!*CR) { if (tgetflag("nc") && *UP) { CR = safemalloc((MEM_SIZE)strlen(UP)+2); sprintf(CR,"%s\r",UP); } else CR = "\r"; }#ifdef TIOCGWINSZ if (ioctl(1, TIOCGWINSZ, &winsize)>=0) { if (winsize.ws_row>0) LINES=winsize.ws_row; if (winsize.ws_col>0) COLS=winsize.ws_col; }#endif#else ?????? /* Roll your own... */#endif termlib_init(); line_col_calcs(); noecho(); /* turn off echo */ crmode(); /* enter cbreak mode */ mac_init(tcbuf);}voidset_macro(seq,def)char *seq; /* input sequence of keys */char *def; /* definition */{ mac_line(def,seq,0); /* check for common (?) brain damage: ku/kd/etc sequence may be the * cursor move sequence instead of the input sequence. * (This happens on the local xterm definitions.) * Try to recognize and adjust for this case. */ if ((seq[0]==(char)27) && (seq[1]=='[') && seq[2]) { char lbuf[LBUFLEN]; /* copy of possibly non-writable string */ strcpy(lbuf,seq); lbuf[1] = 'O'; mac_line(def,lbuf,0); } if ((seq[0]==(char)27) && (seq[1]=='O') && seq[2]) { char lbuf[LBUFLEN]; /* copy of possibly non-writable string */ strcpy(lbuf,seq); lbuf[1] = '['; mac_line(def,lbuf,0); }}/* Turn the arrow keys into macros that do some basic trn functions.** Code provided by Clifford Adams.*/voidarrow_macros(tmpbuf)char *tmpbuf;{ char lbuf[256]; /* should be long enough */ char *tmpaddr = tmpbuf; register char *tmpstr; /* If arrows are defined as single keys, we probably don't * want to redefine them. (The tvi912c defines kl as ^H) */ strcpy(lbuf,Tgetstr("ku")); /* up */ /* '(' at article or pager, 'p' otherwise */ if (strlen(lbuf)>1) set_macro(lbuf,"%(%m=[ap]?\\(:p)"); strcpy(lbuf,Tgetstr("kd")); /* down */ /* ')' at article or pager, 'n' otherwise */ if (strlen(lbuf)>1) set_macro(lbuf,"%(%m=[ap]?\\):n)"); strcpy(lbuf,Tgetstr("kl")); /* left */ /* '[' at article or pager, '<' otherwise */ if (strlen(lbuf)>1) set_macro(lbuf,"%(%m=[ap]?\\[:<)"); strcpy(lbuf,Tgetstr("kr")); /* right */ /* CR at newsgroups, ']' at article or pager, '>' otherwise */ if (strlen(lbuf)>1) set_macro(lbuf,"%(%m=n?^j:%(%m=[ap]?\\]:>))");}voidmac_init(tcbuf)char *tcbuf;{ char tmpbuf[1024]; if (auto_arrow_macros) arrow_macros(tmpbuf); if (use_threads) tmpfp = fopen(filexp(getval("TRNMACRO",TRNMACRO)),"r"); else tmpfp = Nullfp; if (!tmpfp) tmpfp = fopen(filexp(getval("RNMACRO",RNMACRO)),"r"); if (tmpfp) { while (fgets(tcbuf,1024,tmpfp) != Nullch) { mac_line(tcbuf,tmpbuf,(sizeof tmpbuf)); } fclose(tmpfp); }}voidmac_line(line,tmpbuf,tbsize)char *line;char *tmpbuf;int tbsize;{ register char *s, *m; register KEYMAP *curmap; register int ch; register int garbage = 0; static char override[] = "\nkeymap overrides string\n"; if (topmap == Null(KEYMAP*)) topmap = newkeymap(); if (*line == '#' || *line == '\n') return; if (line[ch = strlen(line)-1] == '\n') line[ch] = '\0'; /* A 0 length signifies we already parsed the macro into tmpbuf, ** so line is just the definition. */ if (tbsize) m = dointerp(tmpbuf,tbsize,line," \t"); else m = line; if (!*m) return; while (*m == ' ' || *m == '\t') m++; for (s=tmpbuf,curmap=topmap; *s; s++) { ch = *s & 0177; if (s[1] == '+' && isdigit(s[2])) { s += 2; garbage = (*s & KM_GMASK) << KM_GSHIFT; } else garbage = 0; if (s[1]) { if ((curmap->km_type[ch] & KM_TMASK) == KM_STRING) { if (tbsize) fputs(override,stdout) FLUSH; free(curmap->km_ptr[ch].km_str); curmap->km_ptr[ch].km_str = Nullch; } curmap->km_type[ch] = KM_KEYMAP + garbage; if (curmap->km_ptr[ch].km_km == Null(KEYMAP*)) curmap->km_ptr[ch].km_km = newkeymap(); curmap = curmap->km_ptr[ch].km_km; } else { if (tbsize && (curmap->km_type[ch] & KM_TMASK) == KM_KEYMAP) fputs(override,stdout) FLUSH; else { curmap->km_type[ch] = KM_STRING + garbage; curmap->km_ptr[ch].km_str = savestr(m); } } }}KEYMAP*newkeymap(){ register int i; register KEYMAP *map;#ifndef lint map = (KEYMAP*)safemalloc(sizeof(KEYMAP));#else map = Null(KEYMAP*);#endif /* lint */ for (i=127; i>=0; --i) { map->km_ptr[i].km_km = Null(KEYMAP*); map->km_type[i] = KM_NOTHIN; } return map;}voidshow_macros(){ char prebuf[64]; if (topmap != Null(KEYMAP*)) { print_lines("Macros:\n",STANDOUT); *prebuf = '\0'; show_keymap(topmap,prebuf); } else { print_lines("No macros defined.\n", NOMARKING); }}voidshow_keymap(curmap,prefix)register KEYMAP *curmap;char *prefix;{ register int i; register char *next = prefix + strlen(prefix); register int kt; for (i=0; i<128; i++) { if (kt = curmap->km_type[i]) { if (i < ' ') sprintf(next,"^%c",i+64); else if (i == ' ') strcpy(next,"\\040"); else if (i == 127) strcpy(next,"^?"); else sprintf(next,"%c",i); if ((kt >> KM_GSHIFT) & KM_GMASK) { sprintf(cmd_buf,"+%d", (kt >> KM_GSHIFT) & KM_GMASK); strcat(next,cmd_buf); } switch (kt & KM_TMASK) { case KM_NOTHIN: sprintf(cmd_buf,"%s %c\n",prefix,i); print_lines(cmd_buf,NOMARKING); break; case KM_KEYMAP: show_keymap(curmap->km_ptr[(char)i].km_km, prefix); break; case KM_STRING: sprintf(cmd_buf,"%s %s\n",prefix,curmap->km_ptr[i].km_str); print_lines(cmd_buf,NOMARKING); break; case KM_BOGUS: sprintf(cmd_buf,"%s BOGUS\n",prefix); print_lines(cmd_buf,STANDOUT); break; } } }}/* routine to pass to tputs */charputchr(ch)register char_int ch;{ putchar(ch);#ifdef lint ch = Null(char); ch = ch;#endif return((char) 0);}/* input the 2nd and succeeding characters of a multi-character command *//* returns TRUE if command finished, FALSE if they rubbed out first character */int buflimit = LBUFLEN;boolfinish_command(donewline)int donewline;{ register char *s; register bool quoteone = FALSE; s = buf; if (s[1] != FINISHCMD) /* someone faking up a command? */ return TRUE; do { top: if (*(unsigned char *)s < ' ') { putchar('^'); putchar(*s | 64); } else if (*s == '\177') { putchar('^'); putchar('?'); } else putchar(*s); /* echo previous character */ s++; if (s - buf == buflimit) break;re_read: fflush(stdout); getcmd(s); if (quoteone) { quoteone = FALSE; continue; } if (errno || *s == '\f') { *s = Ctl('r'); /* force rewrite on CONT */ } if (*s == '\033') { /* substitution desired? */#ifdef ESCSUBS char tmpbuf[4], *cpybuf; tmpbuf[0] = '%'; read_tty(&tmpbuf[1],1);#ifdef RAWONLY tmpbuf[1] &= 0177;#endif tmpbuf[2] = '\0'; if (tmpbuf[1] == 'h') { (void) help_subs(); *s = '\0'; reprint(); goto re_read; } else if (tmpbuf[1] == '\033') { *s = '\0'; cpybuf = savestr(buf); interp(buf, (sizeof buf), cpybuf); free(cpybuf); s = buf + strlen(buf); reprint(); goto re_read; } else { interp(s,(sizeof buf) - (s-buf),tmpbuf); fputs(s,stdout); s += strlen(s); } goto re_read;#else notincl("^["); *s = '\0'; reprint(); goto re_read;#endif } else if (*s == ERASECH) { /* they want to rubout a char? */ rubout(); s--; /* discount the char rubbed out */ if (*(unsigned char *)s < ' ' || *s == '\177') rubout(); if (s == buf) { /* entire string gone? */ fflush(stdout); /* return to single char command mode */ return FALSE; } else goto re_read; } else if (*s == KILLCH) { /* wipe out the whole line? */ while (s-- != buf) { /* emulate that many ERASEs */ rubout(); if (*(unsigned char *)s < ' ' || *s == '\177') rubout(); } fflush(stdout); return FALSE; /* return to single char mode */ }#ifdef WORDERASE else if (*s == Ctl('w')) { /* wipe out one word? */ *s-- = ' '; while (!isspace(*s) || isspace(s[1])) { rubout(); if (s-- == buf) { fflush(stdout); return FALSE; /* return to single char mode */ } if (*(unsigned char *)s < ' ' || *s == '\177') rubout(); } s++; goto re_read; }#endif else if (*s == Ctl('r')) { *s = '\0'; reprint(); goto re_read; } else if (*s == Ctl('v')) { putchar('^'); backspace(); fflush(stdout); getcmd(s); goto top; } else if (*s == '\\') { quoteone = TRUE; }#ifdef cray } while (*s != '\r'); /* till a newline (not echoed) */#else } while (*s != '\n'); /* till a newline (not echoed) */#endif *s = '\0'; /* terminate the string nicely */ if (donewline) putchar('\n') FLUSH; return TRUE; /* say we succeeded */}boolfinish_dblchar(){ bool ret; buflimit = 2; ret = finish_command(FALSE); buflimit = LBUFLEN; return ret;}/* discard any characters typed ahead */void
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -