guido@cwi.nl (Guido van Rossum) (06/07/91)
Archive-name: stdwin0.9.6/patch5 #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of shell archive." # Contents: stdwin/Ports/vtrm/vtrm.c # Wrapped by guido@voorn.cwi.nl on Fri Jun 7 15:21:41 1991 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'stdwin/Ports/vtrm/vtrm.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'stdwin/Ports/vtrm/vtrm.c'\" else echo shar: Extracting \"'stdwin/Ports/vtrm/vtrm.c'\" \(46848 characters\) sed "s/^X//" >'stdwin/Ports/vtrm/vtrm.c' <<'END_OF_FILE' X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1991. */ X X/* X * Virtual TeRMinal package. X * (For a description see at the end of this file.) X * X * Big change: X * output goes to /dev/tty, in case stdout is redirected to a file. X * X * TO DO: X * - add interrupt handling (trminterrupt) X * - adapt to changed window size when suspended or at SIGWINCH X * (unfortunately, the calling module must be changed first -- X * it is not prepared for the changed window size...) X */ X X/* Includes: */ X X#include "os.h" /* operating system features and C compiler dependencies */ X#include "vtrm.h" /* terminal capabilities */ X X#ifndef HAS_TERMIO X#include <sgtty.h> X#else X#include <termio.h> X#endif X X#ifdef SIGNAL X#include <signal.h> X#endif X X#ifdef SETJMP X#include <setjmp.h> X#endif X X#ifdef HAS_SELECT X#include <sys/time.h> X#endif X X/* Style definitions: */ X X#define Visible X#define Hidden static X#define Procedure X Xtypedef int bool; Xtypedef char *string; Xtypedef short intlet; X X#define Yes ((bool) 1) X#define No ((bool) 0) X X/* Forward declarations: */ X Xextern char *malloc(); Xextern char *getenv(); Xextern int tgetent(); Xextern int tgetnum(); Xextern int tgetflag(); Xextern char *tgetstr(); Xextern char *tgoto(); X XHidden int getttyfp(); XHidden int str0cost(); XHidden int gettermcaps(); XHidden int setttymode(); XHidden Procedure resetttymode(); XHidden int start_trm(); XHidden bool get_pos(); XHidden int put_line(); XHidden Procedure set_mode(); XHidden Procedure get_so_mode(); XHidden Procedure standout(); XHidden Procedure standend(); XHidden Procedure put_str(); XHidden Procedure ins_str(); XHidden Procedure del_str(); XHidden Procedure put_c(); XHidden Procedure clear_lines(); XHidden Procedure clr_to_eol(); XHidden int outchar(); XHidden Procedure set_blanks(); XHidden Procedure scr1up(); XHidden Procedure scr1down(); XHidden Procedure scr2up(); XHidden Procedure scr2down(); XHidden Procedure scr_lines(); XHidden Procedure addlines(); XHidden Procedure dellines(); XHidden Procedure scr3up(); XHidden Procedure lf_scroll(); XHidden Procedure move_lines(); XHidden Procedure trmpushback(); XHidden Procedure subshell(); X X/* Data definitions: */ X X#ifdef VTRMTRACE X#define TRACEFILE "trace.vtrm" XHidden FILE *vtrmfp= (FILE *) NULL; X#endif X X#define Min(a,b) ((a) <= (b) ? (a) : (b)) X X/* tty modes */ X X#ifndef HAS_TERMIO X X/* v7/BSD tty control */ XHidden struct sgttyb oldtty, newtty; X X#ifdef TIOCSETN X/* Redefine stty to use TIOCSETN, so type-ahead is not flushed */ X#define stty(fd, bp) VOID ioctl(fd, TIOCSETN, (char *) bp) X#endif /* TIOCSETN */ X X#ifdef TIOCSLTC /* BSD -- local special chars, must all be turned off */ XHidden struct ltchars oldltchars; XHidden struct ltchars newltchars= {-1, -1, -1, -1, -1, -1}; X#endif /* TIOCSLTC */ X X#ifdef TIOCSETC /* V7 -- standard special chars, some must be turned off too */ XHidden struct tchars oldtchars; XHidden struct tchars newtchars; X#endif /* TIOCSETC */ X X#else /* HAS_TERMIO */ X X/* AT&T tty control */ XHidden struct termio oldtty, newtty, polltty; X#define gtty(fd,bp) ioctl(fd, TCGETA, (char *) bp) X#define stty(fd,bp) VOID ioctl(fd, TCSETAW, (char *) bp) X X#endif /* HAS_TERMIO */ X X/* If you can't lookahead in the system's input queue, and so can't implement X * trmavail(), you have to enable keyboard interrupts. X * Otherwise, computations are uninterruptable. X */ X#ifndef HAS_TERMIO X#ifndef HAS_SELECT X#ifdef SIGNAL X#define CATCHINTR X#endif X#endif X#endif X XHidden bool know_ttys = No; X X/* visible data for termcap */ Xchar PC; Xchar *BC; Xchar *UP; Xshort ospeed; X XHidden FILE *fp= (FILE *) NULL; X#define Putstr(str) tputs((str), 1, outchar) X X/* termcap terminal capabilities */ X XHidden int lines; XHidden int cols; X X/* X * String-valued capabilities are saved in one big array. X * Extend this only at the end (even though it disturbs the sorting) X * because otherwise you have to change all macros... X */ X X#define par_al_str strcaps[0] /* parametrized al (AL) */ X#define cap_cm_str strcaps[1] /* screen-relative cursor motion (CM) */ X#define par_dl_str strcaps[2] /* parametrized dl (DL) */ X#define al_str strcaps[3] /* add new blank line */ X#define cd_str strcaps[4] /* clear to end of display */ X#define ce_str strcaps[5] /* clear to end of line */ X#define cl_str strcaps[6] /* cursor home and clear screen */ X#define cm_str strcaps[7] /* cursor motion */ X#define cp_str strcaps[8] /* cursor position sense reply; obsolete */ X#define cr_str strcaps[9] /* carriage return */ X#define cs_str strcaps[10] /* change scrolling region */ X#define dc_str strcaps[11] /* delete character */ X#define dl_str strcaps[12] /* delete line */ X#define dm_str strcaps[13] /* enter delete mode */ X#define do_str strcaps[14] /* cursor down one line */ X#define ed_str strcaps[15] /* end delete mode */ X#define ei_str strcaps[16] /* end insert mode */ X#define ho_str strcaps[17] /* cursor home */ X#define ic_str strcaps[18] /* insert character (if necessary; may pad) */ X#define im_str strcaps[19] /* enter insert mode */ X#define nd_str strcaps[20] /* cursor right (non-destructive space) */ X#define nl_str strcaps[21] /* newline */ X#define se_str strcaps[22] /* end standout mode */ X#define sf_str strcaps[23] /* scroll text up (from bottom of region) */ X#define so_str strcaps[24] /* begin standout mode */ X#define sp_str strcaps[25] /* sense cursor position; obsolete */ X#define sr_str strcaps[26] /* scroll text down (from top of region) */ X#define te_str strcaps[27] /* end termcap */ X#define ti_str strcaps[28] /* start termcap */ X#define vb_str strcaps[29] /* visible bell */ X#define ve_str strcaps[30] /* make cursor visible again */ X#define vi_str strcaps[31] /* make cursor invisible */ X#define le_str strcaps[32] /* cursor left */ X#define bc_str strcaps[33] /* backspace character */ X#define up_str strcaps[34] /* cursor up */ X#define pc_str strcaps[35] /* pad character */ X#define ks_str strcaps[36] /* keypad mode start */ X#define ke_str strcaps[37] /* keypad mode end */ X#define us_str strcaps[38] /* start underscore mode */ X#define ue_str strcaps[39] /* end underscore mode */ X/* Insert new entries here only! Don't forget to change the next line! */ X#define NSTRCAPS 40 /* One more than the last entry's index */ X XHidden char *strcaps[NSTRCAPS]; XHidden char strcapnames[] = X"ALCMDLalcdceclcmcpcrcsdcdldmdoedeihoicimndnlsesfsospsrtetivbvevilebcuppckskeusue"; X X/* Same for Boolean-valued capabilities */ X X#define has_am flagcaps[0] /* has automatic margins */ X#define has_da flagcaps[1] /* display may be retained above screen */ X#define has_db flagcaps[2] /* display may be retained below screen */ X#define has_in flagcaps[3] /* not safe to have null chars on the screen */ X#define has_mi flagcaps[4] /* move safely in insert (and delete?) mode */ X#define has_ms flagcaps[5] /* move safely in standout mode */ X#define has_xs flagcaps[6] /* standout not erased by overwriting */ X#define has_bs flagcaps[7] /* terminal can backspace */ X#define hardcopy flagcaps[8] /* hardcopy terminal */ X#define has_xn flagcaps[9] /* Vt100 / Concept glitch */ X#define NFLAGS 10 X XHidden char flagcaps[NFLAGS]; XHidden char flagnames[]= "amdadbinmimsxsbshcxn"; X XHidden Procedure getcaps(parea) X register char **parea; X{ X register char *capname; X register char **capvar; X register char *flagvar; X X for (capname= flagnames, flagvar= flagcaps; X *capname != '\0'; capname += 2, ++flagvar) X *flagvar= tgetflag(capname); X X for (capname= strcapnames, capvar= strcaps; X *capname != '\0'; capname += 2, ++capvar) X *capvar= tgetstr(capname, parea); X} X X/* terminal status */ X X/* calling order of Visible Procs */ XHidden bool started = No; X X/* to exports the capabilities mentioned in vtrm.h: */ XHidden int flags = 0; X X/* cost for impossible operations */ X#define Infinity 9999 X /* Allow for adding Infinity+Infinity within range */ X /* (Range is assumed at least 2**15 - 1) */ X X/* The following for all sorts of undefined things (except for UNKNOWN char) */ X#define Undefined (-1) X X/* current mode of putting char's */ X#define Normal 0 X#define Insert 1 X#define Delete 2 XHidden short mode = Normal; X X/* masks for char's */ X#define NULCHAR '\000' X#define UNKNOWN 1 X#define SOBIT 1 X/* if (has_xs) record cookies placed on screen in extra bit */ X/* type of cookie is determined by the SO bit */ X#define XSBIT 2 X#define SOCOOK 3 X#define SECOOK 2 X#define COOKBITS SOCOOK X#define NOCOOK 0 X X/* current standout mode */ X#define Off 0 X#define On SOBIT XHidden short so_mode = Off; X X/* current cursor position */ XHidden short cur_y = Undefined, cur_x = Undefined; X X/* "linedata[y][x]" holds the char on the terminal; X * "linemode[y][x]" holds the SOBIT and XSBIT. X * the SOBIT tells whether the character is standing out, the XSBIT whether X * there is a cookie on the screen at this position. X * In particular a standend-cookie may be recorded AFTER the line X * (just in case some trmputdata will write after that position). X * "lenline[y]" holds the length of the line. X * Unknown chars will be 1, so the optimising compare in putline will fail. X * (Partially) empty lines are distinghuished by "lenline[y] < cols". X */ XHidden char **linedata = NULL, **linemode = NULL; XHidden intlet *lenline = NULL; X X/* To compare the mode part of the line when the X * mode parameter of trmputdata == NULL, we use the following: X */ XHidden char plain[1]= {PLAIN}; X X/* Clear the screen initially iff only memory cursor addressing available */ XHidden bool mustclear = No; X X/* Make the cursor invisible when trmsync() tries to move outside the screen */ XHidden bool no_cursor = No; X X/* Optimise cursor motion */ XHidden int abs_cost; /* cost of absolute cursor motion */ XHidden int cr_cost; /* cost of carriage return */ XHidden int do_cost; /* cost of down */ XHidden int le_cost; /* cost of left */ XHidden int nd_cost; /* cost of right */ XHidden int up_cost; /* cost of up */ X X/* Optimise trailing match in put_line, iff the terminal can insert and delete X * characters; the cost per n characters will be: X * n * MultiplyFactor + OverHead X */ XHidden int ins_mf, ins_oh, del_mf, del_oh; XHidden int ed_cost, ei_cost; /* used in move() */ X X/* The type of scrolling possible determines which routines get used; X * these may be: X * (1) with addline and deleteline (termcap: al_str & dl_str); X * (2) with a settable scrolling region, like VT100 (cs_str, sr_str, sf_str); X * (3) no hardware scrolling available. X */ XHidden Procedure (*scr_up)(); XHidden Procedure (*scr_down)(); XHidden bool canscroll= Yes; X X/* X * Starting, Ending and (fatal) Error. X */ X X/* X * Initialization call. X * Determine terminal capabilities from termcap. X * Set up tty modes. X * Start up terminal and internal administration. X * Return 0 if all well, error code if in trouble. X */ XVisible int trmstart(plines, pcols, pflags) X int *plines; X int *pcols; X int *pflags; X{ X register int err; X X#ifdef VTRMTRACE X if (!started) vtrmfp= fopen(TRACEFILE, vtrmfp ? "a" : "w"); X if (vtrmfp) fprintf(vtrmfp, "\ttrmstart(&li, &co, &fl);\n"); X#endif X if (started) X return TE_TWICE; X err= getttyfp(); X if (err != TE_OK) X return err; X err= gettermcaps(); X if (err != TE_OK) X return err; X err= setttymode(); X if (err != TE_OK) X return err; X err= start_trm(); X if (err != TE_OK) { X trmend(); X return err; X } X X *plines = lines; X *pcols = cols; X *pflags = flags; X X started = Yes; X X trmsync(lines-1, 0); /* position to end of screen */ X X return TE_OK; X} X X/* X * Termination call. X * Reset tty modes, etc. X * Beware that it might be called by a caught interrupt even in the middle X * of trmstart()! X */ XVisible Procedure trmend() X{ X#ifdef VTRMTRACE X if (vtrmfp) fprintf(vtrmfp, "\ttrmend();\n"); X#endif X set_mode(Normal); X if (so_mode != Off) X standend(); X Putstr(ke_str); X Putstr(te_str); X VOID fflush(fp); X resetttymode(); X X started = No; X#ifdef VTRMTRACE X if (vtrmfp) fclose(vtrmfp); X#endif X} X X/* X * Set all internal statuses to undefined, especially the contents of X * the screen, so a hard redraw will not be optimised to heaven. X */ XVisible Procedure trmundefined() X{ X register int y, x; X#ifdef VTRMTRACE X if (vtrmfp) fprintf(vtrmfp, "\ttrmundefined();\n"); X#endif X X cur_y = cur_x = Undefined; X mode = so_mode = Undefined; X X for (y = 0; y < lines; y++) { X for (x = 0; x <= cols; x++) { X linedata[y][x] = UNKNOWN; /* impossible char */ X linemode[y][x] = NOCOOK; /* no so bits */ X } X lenline[y] = cols; X } X} X X#ifdef VTRMTRACE X X/*ARGSUSED*/ XHidden Procedure check_started(m) X char *m; X{ X if (!started) { X trmend(); X if (vtrmfp) fprintf(vtrmfp, "bad VTRM call\n"); X abort(); X } X} X X#else X X#define check_started(m) /*empty*/ X X#endif /* VTRMTRACE */ X XHidden int getttyfp() X{ X if (fp != NULL) /* already initialised */ X return TE_OK; X fp= fopen("/dev/tty", "w"); X if (fp == NULL) X return TE_NOTTY; X return TE_OK; X} X XHidden int ccc; X X/*ARGSUSED*/ XHidden Procedure countchar(ch) X char ch; X{ X ccc++; X} X XHidden int strcost(str) X char *str; X{ X if (str == NULL) X return Infinity; X return str0cost(str); X} X XHidden int str0cost(str) X char *str; X{ X ccc = 0; X tputs(str, 1, countchar); X return ccc; X} X X/* X * Get terminal capabilities from termcap and compute related static X * properties. Return TE_OK if all well, error code otherwise. X */ X XHidden int gettermcaps() X{ X string trmname; X char tc_buf[1024]; X static char strbuf[1024]; X char *area = strbuf; X int sg; X static bool tc_initialized = No; X X if (tc_initialized) X return TE_OK; X X trmname=getenv("TERM"); X if (trmname == NULL || trmname[0] == '\0') X return TE_NOTERM; X if (tgetent(tc_buf, trmname) != 1) X return TE_BADTERM; X X getcaps(&area); /* Read all flag and string type capabilities */ X if (hardcopy) X return TE_DUMB; X BC = le_str; X if (BC == NULL) { X BC = bc_str; X if (BC == NULL) { X if (has_bs) X BC = "\b"; X else X return TE_DUMB; X } X } X UP = up_str; X if (UP == NULL) X return TE_DUMB; X PC = (pc_str != NULL? pc_str[0] : NULCHAR); X X if (cm_str == NULL) { X cm_str = cap_cm_str; X if (cm_str == NULL) { X if (ho_str == NULL || do_str == NULL || nd_str == NULL) X return TE_DUMB; X } X else X mustclear = Yes; X } X if (al_str && dl_str) { X scr_up = scr1up; X scr_down = scr1down; X flags |= CAN_SCROLL; X } X else { X if (sf_str == NULL) X sf_str = "\n"; X if (cs_str && sr_str) { X scr_up = scr2up; X scr_down = scr2down; X flags |= CAN_SCROLL; X } X else { X canscroll= No; X } X } X X lines = tgetnum("li"); X cols = tgetnum("co"); X if (lines <= 0) lines = 24; X if (cols <= 0) cols = 80; X X if (!ce_str) X return TE_DUMB; X if (cr_str == NULL) cr_str = "\r"; X if (do_str == NULL) { X do_str = nl_str; X if (do_str == NULL) do_str = "\n"; X } X le_str = BC; X up_str = UP; X if (vb_str == NULL) /* then we will do with the audible bell */ X vb_str = "\007"; X X if (so_str != NULL && se_str != NULL && (sg=tgetnum("sg")) <= 0) { X if (sg == 0) X has_xs = Yes; X flags |= HAS_STANDOUT; X } X else if (us_str != NULL && ue_str != NULL) { X so_str = us_str; se_str = ue_str; X flags |= HAS_STANDOUT; X } X else X return TE_DUMB; X X /* calculate costs of local and absolute cursor motions */ X if (cm_str == NULL) X abs_cost = Infinity; X else X abs_cost = strcost(tgoto(cm_str, 0, 0)); X cr_cost = strcost(cr_str); X do_cost = strcost(do_str); X le_cost = strcost(le_str); X nd_cost = strcost(nd_str); X up_cost = strcost(up_str); X X /* cost of leaving insert or delete mode, used in move() */ X ei_cost = str0cost(ei_str); X ed_cost = str0cost(ed_str); X X /* calculate insert and delete cost multiply_factor and overhead */ X if (((im_str && ei_str) || ic_str) && dc_str) { X flags |= CAN_OPTIMISE; X ins_mf = 1 + str0cost(ic_str); X ins_oh = str0cost(im_str) + ei_cost; X del_mf = str0cost(dc_str); X del_oh = str0cost(dm_str) + ed_cost; X } X X tc_initialized = Yes; X return TE_OK; X} X X#ifdef CATCHINTR X XHidden char intrchar; XHidden bool trmintrptd = No; XHidden bool readintrcontext = No; X#ifdef SETJMP XHidden jmp_buf readinterrupt; X#endif X XHidden SIGTYPE trmintrhandler(sig) X int sig; X{ X VOID signal(SIGINT, trmintrhandler); X trmintrptd = Yes; X#ifdef SETJMP X if (readintrcontext) longjmp(readinterrupt, 1); X#endif X} X X#endif /* CATCHINTR */ X XHidden int setttymode() X{ X if (!know_ttys) { X if (gtty(0, &oldtty) != 0 X || gtty(0, &newtty) != 0 X#ifdef HAS_TERMIO X || gtty(0, &polltty) != 0 X#endif X ) X return TE_NOTTY; X#ifndef HAS_TERMIO X ospeed = oldtty.sg_ospeed; X newtty.sg_flags = (newtty.sg_flags & ~ECHO & ~CRMOD & ~XTABS) X | CBREAK; X#ifdef TIOCSLTC X VOID ioctl(0, TIOCGLTC, (char *) &oldltchars); X#endif X#ifdef TIOCSETC X VOID ioctl(0, TIOCGETC, (char *) &oldtchars); X#endif X X#else /* HAS_TERMIO */ X ospeed= oldtty.c_lflag & CBAUD; X newtty.c_iflag &= ~ICRNL; /* No CR->NL mapping on input */ X newtty.c_oflag &= ~ONLCR; /* NL doesn't output CR */ X newtty.c_lflag &= ~(ICANON|ECHO|ISIG); X /* No line editing, no echo, X * no quit, intr or susp signals */ X newtty.c_cc[VMIN]= 3; /* wait for 3 characters */ X newtty.c_cc[VTIME]= 1; /* or 0.1 sec. */ X X polltty.c_iflag= newtty.c_iflag; X polltty.c_oflag= newtty.c_oflag; X polltty.c_lflag= newtty.c_lflag; X polltty.c_cc[VQUIT]= newtty.c_cc[VQUIT]; X#ifdef VSUSP X polltty.c_cc[VSUSP]= newtty.c_cc[VSUSP]; X#endif X polltty.c_cc[VMIN]= 0; /* don't block read() */ X polltty.c_cc[VTIME]= 0; /* just give 'em chars iff available */ X#endif /* HAS_TERMIO */ X know_ttys = Yes; X } X stty(0, &newtty); X#ifndef HAS_TERMIO X#ifdef TIOCSLTC X VOID ioctl(0, TIOCSLTC, (char *) &newltchars); X#endif X#ifdef TIOCSETC X VOID ioctl(0, TIOCGETC, (char *) &newtchars); X#ifndef CATCHINTR X newtchars.t_intrc= -1; X#else X intrchar= oldtchars.t_intrc; X newtchars.t_intrc= intrchar; /* do not disable interupt */ X signal(SIGINT, trmintrhandler);/* but catch it */ X#endif /* CATCHINTR */ X newtchars.t_quitc= -1; X newtchars.t_eofc= -1; X newtchars.t_brkc= -1; X VOID ioctl(0, TIOCSETC, (char *) &newtchars); X#endif /* TIOCSETC */ X#endif /* !HAS_TERMIO */ X return TE_OK; X} X XHidden Procedure resetttymode() X{ X if (know_ttys) { X stty(0, &oldtty); X#ifndef HAS_TERMIO X#ifdef TIOCSLTC X VOID ioctl(0, TIOCSLTC, (char *) &oldltchars); X#endif X#ifdef TIOCSETC X VOID ioctl(0, TIOCSETC, (char *) &oldtchars); X#endif X#endif /* !HAS_TERMIO */ X know_ttys= No; X } X} X XHidden int start_trm() X{ X register int y; X#ifdef TIOCGWINSZ X struct winsize win; X X if (ioctl(0, TIOCGWINSZ, (char*)&win) == 0) { X if (win.ws_col > 0 && ((int) win.ws_col) != cols X || X win.ws_row > 0 && ((int) win.ws_row) != lines) { X /* Window size has changed. X Release previously allocated buffers. */ X if (linedata != NULL) { X for (y= 0; y < lines; ++y) { X free((char *) linedata[y]); X } X free((char *) linedata); X linedata= NULL; X } X if (linemode != NULL) { X for (y= 0; y < lines; ++y) { X free((char *) linemode[y]); X } X free((char *) linemode); X linemode= NULL; X } X if (lenline != NULL) { X free((char *) lenline); X lenline= NULL; X } X } X if (((int)win.ws_col) > 0) X cols = win.ws_col; X if (((int)win.ws_row) > 0) X lines = win.ws_row; X } X#endif X if (linedata == NULL) { X if ((linedata = (char**) malloc(lines * sizeof(char*))) == NULL) X return TE_NOMEM; X for (y = 0; y < lines; y++) { X if ((linedata[y] = (char*) malloc((cols+1) * sizeof(char))) == NULL) X return TE_NOMEM; X } X } X if (linemode == NULL) { X if ((linemode = (char**) malloc(lines * sizeof(char*))) == NULL) X return TE_NOMEM; X for (y = 0; y < lines; y++) { X if ((linemode[y] = (char*) malloc((cols+1) * sizeof(char))) == NULL) X return TE_NOMEM; X } X } X if (lenline == NULL) { X if ((lenline = (intlet*) malloc(lines * sizeof(intlet))) == NULL) X return TE_NOMEM; X } X X trmundefined(); X X Putstr(ti_str); X Putstr(ks_str); X if (cs_str) X Putstr(tgoto(cs_str, lines-1, 0)); X if (mustclear) X clear_lines(0, lines-1); X VOID fflush(fp); X X return TE_OK; X} X X X/* X * Sensing and moving the cursor. X */ X X/* X * Sense the current (y, x) cursor position. X * On terminals with local cursor motion, the first argument must be the X * string that must be sent to the terminal to ask for the current cursor X * position after a possible manual change by the user; X * the format describes the answer as a parameterized string X * a la termcap(5). X * If the terminal cannot be asked for the current cursor position, X * or if the string returned by the terminal is garbled, X * the position is made Undefined. X * This scheme can also be used for mouse clicks, if these can be made to X * send the cursor position; the sense string can normally be empty. X */ X XVisible Procedure trmsense(sense, format, py, px) X string sense; X string format; X int *py; X int *px; X{ X#ifdef VTRMTRACE X if (vtrmfp) fprintf(vtrmfp, "\ttrmsense(&yy, &xx);\n"); X#endif X check_started("trmsense"); X X if (sense != NULL) X Putstr(sense); X VOID fflush(fp); X X *py = *px = Undefined; X set_mode(Normal); X if (so_mode != Off) X standend(); X X if (format != NULL && get_pos(format, py, px)) { X if (*py < 0 || lines <= *py || *px < 0 || cols <= *px) X *py = *px = Undefined; X } X cur_y = Undefined; X cur_x = Undefined; X} X XHidden bool get_pos(format, py, px) X string format; X int *py; X int *px; X{ X int fc; /* current format character */ X int ic; /* current input character */ X int num; X int on_y = 1; X bool incr_orig = No; X int i, ni; X X while (fc = *format++) { X if (fc != '%') { X if (trminput() != fc) X return No; X } X else { X switch (fc = *format++) { X case '%': X if (trminput() != '%') X return No; X continue; X case '.': X VOID trminput(); /* skip one char */ X continue; X case 'r': X on_y = 1 - on_y; X continue; X case 'i': X incr_orig = Yes; X continue; X case 'd': X ic = trminput(); X if (!isdigit(ic)) X return No; X num = ic - '0'; X while (isdigit(ic=trminput())) X num = 10*num + ic - '0'; X trmpushback(ic); X break; X case '2': X case '3': X ni = fc - '0'; X num = 0; X for (i=0; i<ni; i++) { X ic = trminput(); X if (isdigit(ic)) X num = 10*num + ic - '0'; X else X return No; X } X break; X case '+': X num = trminput() - *format++; X break; X case '-': X num = trminput() + *format++; X break; X default: X return No; X } X /* assign num to parameter */ X if (incr_orig) X num--; X if (on_y) X *py = num; X else X *px = num; X on_y = 1 - on_y; X } X } X X return Yes; X} X X/* X * To move over characters by rewriting them, we have to check: X * (1) that the screen has been initialised on these positions; X * (2) we do not screw up characters or so_mode X * when rewriting linedata[y] from x_from upto x_to X */ XHidden bool rewrite_ok(y, xfrom, xto) X int y; X int xfrom; X int xto; X{ X register char *plnyx, *pmdyx, *plnyto; X X if (xto > lenline[y]) X return No; X X plnyto = &linedata[y][xto]; X plnyx = &linedata[y][xfrom]; X pmdyx = &linemode[y][xfrom]; X while (plnyx <= plnyto) { X if (*plnyx == UNKNOWN X || X (!has_xs && (*pmdyx != so_mode)) X ) X return No; X plnyx++, pmdyx++; X } X return Yes; X} X X/* X * Move to position y,x on the screen X */ X/* possible move types for y and x respectively: */ X#define None 0 X#define Down 1 X#define Up 2 X#define Right 1 X#define ReWrite 2 X#define Left 3 X#define CrWrite 4 X XHidden Procedure move(y, x) X int y; X int x; X{ X int dy, dx; X int y_cost, x_cost, y_move, x_move; X int mode_cost; X int xi; X X if (cur_y == y && cur_x == x) X return; X X if (!has_mi || mode == Undefined) X set_mode(Normal); X if (!has_xs && ((!has_ms && so_mode != Off) || so_mode == Undefined)) X standend(); X X if (cur_y == Undefined || cur_x == Undefined) X goto absmove; X X dy = y - cur_y; X dx = x - cur_x; X X if (dy > 0) { X y_move = Down; X y_cost = dy * do_cost; X } X else if (dy < 0) { X y_move = Up; X y_cost = -dy * up_cost; X } X else { X y_move = None; X y_cost = 0; X } X if (y_cost < abs_cost) { X switch (mode) { X case Normal: X mode_cost = 0; X break; X case Insert: X mode_cost = ei_cost; X break; X case Delete: X mode_cost = ed_cost; X break; X } X if (dx > 0) { X x_cost = dx + mode_cost; X if (dx*nd_cost < x_cost || !rewrite_ok(y, cur_x, x)) { X x_cost = dx * nd_cost; X x_move = Right; X } X else X x_move = ReWrite; X } X else if (dx < 0) { X x_cost = -dx * le_cost; X x_move = Left; X } X else { X x_cost = 0; X x_move = None; X } X if (cr_cost + x + mode_cost < x_cost && rewrite_ok(y, 0, x)) { X x_move = CrWrite; X x_cost = cr_cost + x + mode_cost; X } X } X else X x_cost = abs_cost; X X if (y_cost + x_cost < abs_cost) { X switch (y_move) { X case Down: X while (dy-- > 0) Putstr(do_str); X break; X case Up: X while (dy++ < 0) Putstr(up_str); X break; X } X switch (x_move) { X case Right: X while (dx-- > 0) Putstr(nd_str); X break; X case Left: X while (dx++ < 0) Putstr(le_str); X break; X case CrWrite: X Putstr(cr_str); X cur_x = 0; X /* FALL THROUGH */ X case ReWrite: X set_mode(Normal); X for (xi = cur_x; xi < x; xi++) X fputc(linedata[y][xi], fp); X break; X } X } X else X { X absmove: X if (cm_str == NULL) { X Putstr(ho_str); X for (cur_y = 0; cur_y < y; ++cur_y) X Putstr(do_str); X /* Should try to use tabs here: */ X for (cur_x = 0; cur_x < x; ++cur_x) X Putstr(nd_str); X } X else X Putstr(tgoto(cm_str, x, y)); X } X X cur_y = y; X cur_x = x; X} X X X/* X * Putting data on the screen. X */ X X/* X * Fill screen area with given "data". X * Characters for which the corresponding char in "mode" have the value X * STANDOUT must be put in inverse video. X */ XVisible Procedure trmputdata(yfirst, ylast, indent, data, mode) X int yfirst, ylast; X register int indent; X register string data; X register string mode; X{ X register int y; X int x, len, lendata, space; X X#ifdef VTRMTRACE X if (vtrmfp) fprintf(vtrmfp, "\ttrmputdata(%d, %d, %d, \"%s\");\n", yfirst, ylast, indent, data); X#endif X check_started("trmputdata"); X X if (yfirst < 0) X yfirst = 0; X if (ylast >= lines) X ylast = lines-1; X space = cols*(ylast-yfirst+1) - indent; X if (space <= 0) X return; X yfirst += indent/cols; X indent %= cols; X y= yfirst; X if (!data) X data= ""; /* Safety net */ X x = indent; X lendata = strlen(data); X if (ylast == lines-1 && lendata >= space) X lendata = space - 1; X len = Min(lendata, cols-x); X while (y <= ylast) { X put_line(y, x, data, mode, len); X y++; X lendata -= len; X if (lendata > 0) { X x = 0; X data += len; X if (mode != NULL) X mode += len; X len = Min(lendata, cols); X } X else X break; X } X if (y <= ylast) X clear_lines(y, ylast); X} X X/* X * We will first try to get the picture: X * X * op>>>>>>>>>>>op oq<<<<<<<<<<<<<<<<<<<<<<<<oq X * ^ ^ ^ ^ X * <xskip><-----m1----><----od-----><-----------m2-----------> X * OLD: "You're in a maze of twisty little pieces of code, all alike" X * NEW: "in a maze of little twisting pieces of code, all alike" X * <-----m1----><-----nd------><-----------m2-----------> X * ^ ^ ^ ^ X * np>>>>>>>>>>>np nq<<<<<<<<<<<<<<<<<<<<<<<<nq X * where X * op, oq, np, nq are pointers to start and end of Old and New data, X * and X * xskip = length of indent to be skipped, X * m1 = length of Matching part at start, X * od = length of Differing mid on screen, X * nd = length of Differing mid in data to be put, X * m2 = length of Matching trail. X * X * Then we will try to find a long blank-or-cleared piece in <nd+m2>: X * X * <---m1---><---d1---><---nb---><---d2---><---m2---> X * ^ ^ ^ ^ ^ X * np bp bq1 nq nend X * where X * bp, bq1 are pointers to start and AFTER end of blank piece, X * and X * d1 = length of differing part before blank piece, X * nb = length of blank piece to be skipped, X * d2 = length of differing part after blank piece. X * Remarks: X * d1 + nb + d2 == nd, X * and X * d2 maybe less than 0. X */ XHidden int put_line(y, xskip, data, mode, len) X int y; X int xskip; X string data; X string mode; X int len; X{ X register char *op, *oq, *mp; X register char *np, *nq, *nend, *mo; X char *bp, *bq1, *p, *q; X int m1, m2, od, nd, delta, dd, d1, nb, d2; X bool skipping; X int cost, o_cost; /* normal and optimising cost */ X X /* Bugfix GvR 19-June-87: */ X while (lenline[y] < xskip) { X linedata[y][lenline[y]] = ' '; X linemode[y][lenline[y]] = PLAIN; X lenline[y]++; X } X X /* calculate the magic parameters */ X op = &linedata[y][xskip]; X oq = &linedata[y][lenline[y]-1]; X mp = &linemode[y][xskip]; X np = data; X nq = nend = data + len - 1; X mo = (mode != NULL ? mode : plain); X m1 = m2 = 0; X while (op <= oq && np <= nq && *op == *np && ((*mp)&SOBIT) == *mo) { X op++, np++, mp++, m1++; X if (mode != NULL) mo++; X } X /* calculate m2, iff we can optimise or line keeps same length: */ X if (flags & CAN_OPTIMISE || (oq-op) == (nq-np)) { X if (mode != NULL) mo = mode + len - 1; X mp = &linemode[y][lenline[y]-1]; X while (op <= oq && np <= nq X && *oq == *nq && ((*mp)&SOBIT) == *mo) { X oq--, nq--, mp--, m2++; X if (mode != NULL) mo--; X } X } X od = oq - op + 1; X nd = nq - np + 1; X /* now we have the first picture above */ X X if (od==0 && nd==0) X return; X delta = nd - od; X X /* find the blank piece */ X p = q = bp = bq1 = np; X if (mode != NULL) mo = mode + (np - data); X oq += m2; /* back to current eol */ X if (delta == 0) /* if no change in linelength */ X nend -= m2; /* don't find blanks in m2 */ X if (!has_in) { X mp = &linemode[y][xskip + (op - (&linedata[y][xskip]))]; X while (p <= nend) { X while (q <= nend && *q == ' ' && *mo == PLAIN X && (op > oq X || (*op == ' ' && ((*mp)&SOBIT) == NOCOOK))) X { X q++, op++, mp++; X if (mode != NULL) mo++; X } X if (q - p > bq1 - bp) X bp = p, bq1 = q; X p = ++q; X if (mode != NULL) mo++; X op++, mp++; X } X } X d1 = bp - np; X nb = bq1 - bp; X d2 = nq - bq1 + 1; X X /* what is cheapest: X * ([+m2] means: leave m2 alone if same linelength) X * normal: put nd[+m2]; (dd = nd[+m2]) X * skipping: put d1, skip nb, put d2[+m2]; (dd = d2[+m2]) X * optimise: put dd, insert or delete delta. (dd = min(od,nd)) X */ X cost = nd + (delta == 0 ? 0 : m2); /* normal cost */ X if (nb > abs_cost || (d1 == 0 && nb > 0)) { X skipping = Yes; X cost -= nb - (d1>0 ? abs_cost : 0); /* skipping cost */ X dd = d2; X } X else { X skipping = No; X dd = nd; X } X X if (m2 != 0 && delta != 0) { X /* try optimising */ X o_cost = Min(od, nd); X if (delta > 0) X o_cost += delta * ins_mf + ins_oh; X else if (delta < 0) X o_cost += -delta * del_mf + del_oh; X if (o_cost >= cost) { X /* discard m2, no optimise */ X dd += m2; X m2 = 0; X } X else { X dd = Min(od, nd); X skipping = No; X } X } X X /* and now for the real work */ X if (!skipping || d1 > 0) X move(y, xskip + m1); X X if (has_xs) X get_so_mode(); X X if (skipping) { X if (d1 > 0) { X set_mode(Normal); X mo= (mode != NULL ? mode+(np-data) : NULL); X put_str(np, mo, d1, No); X } X if (has_xs && so_mode != Off) X standend(); X set_blanks(y, xskip+m1+d1, xskip+m1+d1+nb); X if (dd != 0 || delta < 0) { X move(y, xskip+m1+d1+nb); X np = bq1; X } X } X X if (dd > 0) { X set_mode(Normal); X mo= (mode != NULL ? mode+(np-data) : NULL); X put_str(np, mo, dd, No); X } X X if (m2 > 0) { X if (delta > 0) { X set_mode(Insert); X mo= (mode != NULL ? mode+(np+dd-data) : NULL); X ins_str(np+dd, mo, delta); X } X else if (delta < 0) { X if (so_mode != Off) X standend(); X /* Some terminals fill with standout spaces! */ X set_mode(Delete); X del_str(-delta); X } X } X else { X if (delta < 0) { X clr_to_eol(); X return; X } X } X X lenline[y] = xskip + len; X if (cur_x == cols) { X if (!has_mi) X set_mode(Normal); X if (!has_ms) X so_mode = Undefined; X if (has_am) { X if (has_xn) X cur_y= Undefined; X else X cur_y++; X } X else X Putstr(cr_str); X cur_x = 0; X } X else if (has_xs) { X if (m2 == 0) { X if (so_mode == On) X standend(); X } X else { X if (!(linemode[cur_y][cur_x] & XSBIT)) { X if (so_mode != (linemode[cur_y][cur_x] & SOBIT)) X (so_mode ? standend() : standout()); X } X } X } X} X XHidden Procedure set_mode(m) X int m; X{ X if (m == mode) X return; X switch (mode) { X case Insert: X Putstr(ei_str); X break; X case Delete: X Putstr(ed_str); X break; X case Undefined: X Putstr(ei_str); X Putstr(ed_str); X break; X } X switch (m) { X case Insert: X Putstr(im_str); X break; X case Delete: X Putstr(dm_str); X break; X } X mode = m; X} X XHidden Procedure get_so_mode() X{ X if (cur_x >= lenline[cur_y] || linemode[cur_y][cur_x] == NOCOOK) X so_mode = Off; X else X so_mode = linemode[cur_y][cur_x] & SOBIT; X} X XHidden Procedure standout() X{ X Putstr(so_str); X so_mode = On; X if (has_xs) X linemode[cur_y][cur_x] = SOCOOK; X} X XHidden Procedure standend() X{ X Putstr(se_str); X so_mode = Off; X if (has_xs) X linemode[cur_y][cur_x] = SECOOK; X} X XHidden Procedure put_str(data, mode, n, inserting) X char *data; X char *mode; X int n; X bool inserting; X{ X register char ch, mo; X register short so; X char *ln_y_x, *ln_y_end; X X so = so_mode; X if (has_xs) { X ln_y_x = &linemode[cur_y][cur_x]; X ln_y_end = &linemode[cur_y][lenline[cur_y]]; X } X while (n-- > 0) { X if (has_xs && ln_y_x <= ln_y_end && ((*ln_y_x)&XSBIT)) X so = so_mode = (*ln_y_x)&SOBIT; X /* this also checks for the standend cookie AFTER */ X /* the line because off the equals sign in <= */ X ch= *data++; X mo= (mode != NULL ? *mode++ : PLAIN); X if (mo != so) { X so = mo; X so ? standout() : standend(); X } X if (inserting) X Putstr(ic_str); X put_c(ch, mo); X if (has_xs) X ln_y_x++; X } X} X XHidden Procedure ins_str(data, mode, n) X char *data; X char *mode; X int n; X{ X int x; X X /* x will start AFTER the line, because there might be a cookie */ X for (x = lenline[cur_y]; x >= cur_x; x--) { X linedata[cur_y][x+n] = linedata[cur_y][x]; X linemode[cur_y][x+n] = linemode[cur_y][x]; X } X put_str(data, mode, n, Yes); X} X XHidden Procedure del_str(n) X int n; X{ X int x, xto; X X xto = lenline[cur_y] - n; /* again one too far because of cookie */ X if (has_xs) { X for (x = cur_x + n; x >= cur_x; x--) { X if (linemode[cur_y][x] & XSBIT) X break; X } X if (x >= cur_x) X linemode[cur_y][cur_x+n] = linemode[cur_y][x]; X } X for (x = cur_x; x <= xto; x++) { X linedata[cur_y][x] = linedata[cur_y][x+n]; X linemode[cur_y][x] = linemode[cur_y][x+n]; X } X while (n-- > 0) X Putstr(dc_str); X} X XHidden Procedure put_c(ch, mo) X char ch; X char mo; X{ X char sobit, xs_flag; X X fputc(ch, fp); X sobit = (mo == STANDOUT ? SOBIT : 0); X if (has_xs) X xs_flag = linemode[cur_y][cur_x]&XSBIT; X else X xs_flag = 0; X linedata[cur_y][cur_x] = ch; X linemode[cur_y][cur_x] = sobit|xs_flag; X cur_x++; X} X XHidden Procedure clear_lines(yfirst, ylast) X int yfirst; X int ylast; X{ X register int y; X X if (!has_xs && so_mode != Off) X standend(); X if (cl_str && yfirst == 0 && ylast == lines-1) { X Putstr(cl_str); X cur_y = cur_x = 0; X for (y = 0; y < lines; ++y) { X lenline[y] = 0; X if (has_xs) linemode[y][0] = NOCOOK; X } X return; X } X for (y = yfirst; y <= ylast; y++) { X if (lenline[y] > 0) { X move(y, 0); X if (ylast == lines-1 && cd_str) { X Putstr(cd_str); X while (y <= ylast) { X if (has_xs) linemode[y][0] = NOCOOK; X lenline[y++] = 0; X } X break; X } X else { X clr_to_eol(); X } X } X } X} X XHidden Procedure clr_to_eol() X{ X lenline[cur_y] = cur_x; X if (!has_xs && so_mode != Off) X standend(); X Putstr(ce_str); X if (has_xs) { X if (cur_x == 0) X linemode[cur_y][0] = NOCOOK; X else if (linemode[cur_y][cur_x-1]&SOBIT) X standend(); X } X} X XHidden Procedure set_blanks(y, xfrom, xto) X int y; X int xfrom; X int xto; X{ X register int x; X X for (x = xfrom; x < xto; x++) { X linedata[y][x] = ' '; X if (has_xs && lenline[y] >= x && linemode[y][x]&XSBIT) X linemode[y][x]= SECOOK; X else X linemode[y][x]= NOCOOK; X } X} X X/* X * outchar() is used by termcap's tputs. X */ XHidden int outchar(ch) X char ch; X{ X fputc(ch, fp); X} X X/* X * Scrolling (part of) the screen up (or down, by<0). X */ X XVisible Procedure trmscrollup(yfirst, ylast, by) X register int yfirst; X register int ylast; X register int by; X{ X#ifdef VTRMTRACE X if (vtrmfp) fprintf(vtrmfp, "\ttrmscrollup(%d, %d, %d);\n", yfirst, ylast, by); X#endif X check_started("trmscrollup"); X X if (by == 0) X return; X X if (yfirst < 0) X yfirst = 0; X if (ylast >= lines) X ylast = lines-1; X X if (yfirst > ylast) X return; X X if (!has_xs && so_mode != Off) X standend(); X X if (by > 0 && yfirst + by > ylast X || X by < 0 && yfirst - by > ylast) X { X clear_lines(yfirst, ylast); X return; X } X X if (canscroll) { X if (by > 0) { X (*scr_up)(yfirst, ylast, by); X scr_lines(yfirst, ylast, by, 1); X } X else if (by < 0) { X (*scr_down)(yfirst, ylast, -by); X scr_lines(ylast, yfirst, -by, -1); X } X } X else { X scr3up(yfirst, ylast, by); X } X X VOID fflush(fp); X} X XHidden Procedure scr_lines(yfrom, yto, n, dy) X int yfrom; X int yto; X int n; X int dy; X{ X register int y; X char *savedata; X char *savemode; X X while (n-- > 0) { X savedata = linedata[yfrom]; X savemode = linemode[yfrom]; X for (y = yfrom; y != yto; y += dy) { X linedata[y] = linedata[y+dy]; X linemode[y] = linemode[y+dy]; X lenline[y] = lenline[y+dy]; X } X linedata[yto] = savedata; X linemode[yto] = savemode; X lenline[yto] = 0; X if (has_xs) linemode[yto][0] = NOCOOK; X } X} X XHidden Procedure scr1up(yfirst, ylast, n) X int yfirst; X int ylast; X int n; X{ X move(yfirst, 0); X dellines(n); X if (ylast < lines-1) { X move(ylast-n+1, 0); X addlines(n); X } X} X X XHidden Procedure scr1down(yfirst, ylast, n) X int yfirst; X int ylast; X int n; X{ X if (ylast == lines-1) { X clear_lines(ylast-n+1, ylast); X } X else { X move(ylast-n+1, 0); X dellines(n); X } X move(yfirst, 0); X addlines(n); X} X X XHidden Procedure addlines(n) X register int n; X{ X if (par_al_str && n > 1) X Putstr(tgoto(par_al_str, n, n)); X else { X while (n-- > 0) X Putstr(al_str); X } X} X X XHidden Procedure dellines(n) X register int n; X{ X if (par_dl_str && n > 1) X Putstr(tgoto(par_dl_str, n, n)); X else { X while (n-- > 0) X Putstr(dl_str); X } X} X X XHidden Procedure scr2up(yfirst, ylast, n) X int yfirst; X int ylast; X int n; X{ X Putstr(tgoto(cs_str, ylast, yfirst)); X cur_y = cur_x = Undefined; X move(ylast, 0); X while (n-- > 0) { X Putstr(sf_str); X if (has_db && ylast == lines-1) X clr_to_eol(); X } X Putstr(tgoto(cs_str, lines-1, 0)); X cur_y = cur_x = Undefined; X} X X XHidden Procedure scr2down(yfirst, ylast, n) X int yfirst; X int ylast; X int n; X{ X Putstr(tgoto(cs_str, ylast, yfirst)); X cur_y = cur_x = Undefined; X move(yfirst, 0); X while (n-- > 0) { X Putstr(sr_str); X if (has_da && yfirst == 0) X clr_to_eol(); X } X Putstr(tgoto(cs_str, lines-1, 0)); X cur_y = cur_x = Undefined; X} X X/* for dumb scrolling, uses and updates internal administration */ X XHidden Procedure scr3up(yfirst, ylast, by) X int yfirst; X int ylast; X int by; X{ X if (by > 0 && yfirst == 0) { X lf_scroll(ylast, by); X } X else if (by > 0) { X move_lines(yfirst+by, yfirst, ylast-yfirst+1-by, 1); X clear_lines(ylast-by+1, ylast); X } X else { X move_lines(ylast+by, ylast, ylast-yfirst+1+by, -1); X clear_lines(yfirst, yfirst-by-1); X } X} X XHidden Procedure lf_scroll(yto, by) X int yto; X int by; X{ X register int n = by; X X move(lines-1, 0); X while (n-- > 0) { X fputc('\n', fp); X } X scr_lines(0, lines-1, by, 1); X move_lines(lines-1-by, lines-1, lines-1-yto, -1); X clear_lines(yto-by+1, yto); X} X XHidden Procedure move_lines(yfrom, yto, n, dy) X int yfrom; X int yto; X int n; X int dy; X{ X while (n-- > 0) { X put_line(yto, 0, linedata[yfrom], linemode[yfrom], lenline[yfrom]); X yfrom += dy; X yto += dy; X } X} X X/* X * Synchronization, move cursor to given position (or previous if < 0). X */ X XVisible Procedure trmsync(y, x) X int y; X int x; X{ X#ifdef VTRMTRACE X if (vtrmfp) fprintf(vtrmfp, "\ttrmsync(%d, %d);\n", y, x); X#endif X check_started("trmsync"); X X if (0 <= y && y < lines && 0 <= x && x < cols) { X move(y, x); X if (no_cursor) { X Putstr(ve_str); X no_cursor = No; X } X } X else if (no_cursor == No) { X Putstr(vi_str); X no_cursor = Yes; X } X VOID fflush(fp); X} X X X/* X * Send a bell, visible if possible. X */ X XVisible Procedure trmbell() X{ X#ifdef VTRMTRACE X if (vtrmfp) fprintf(vtrmfp, "\ttrmbell();\n"); X#endif X check_started("trmbell"); X X Putstr(vb_str); X VOID fflush(fp); X} X X X#ifdef SHOW X X/* X * Show the current internal statuses of the screen on vtrmfp. X * For debugging only. X */ X XVisible Procedure trmshow(s) X char *s; X{ X int y, x; X X if (!vtrmfp) X return; X fprintf(vtrmfp, "<<< %s >>>\n", s); X for (y = 0; y < lines; y++) { X for (x = 0; x <= lenline[y] /*** && x < cols-1 ***/ ; x++) { X fputc(linedata[y][x], vtrmfp); X } X fputc('\n', vtrmfp); X for (x = 0; x <= lenline[y] && x < cols-1; x++) { X if (linemode[y][x]&SOBIT) X fputc('-', vtrmfp); X else X fputc(' ', vtrmfp); X } X fputc('\n', vtrmfp); X for (x = 0; x <= lenline[y] && x < cols-1; x++) { X if (linemode[y][x]&XSBIT) X fputc('+', vtrmfp); X else X fputc(' ', vtrmfp); X } X fputc('\n', vtrmfp); X } X fprintf(vtrmfp, "CUR_Y = %d, CUR_X = %d.\n", cur_y, cur_x); X VOID fflush(vtrmfp); X} X#endif X X X/* X * Return the next input character, or -1 if read fails. X * Only the low 7 bits are returned, so reading in RAW mode is permissible X * (although CBREAK is preferred if implemented). X * To avoid having to peek in the input buffer for trmavail, we use the X * 'read' system call rather than getchar(). X * (The interface allows 8-bit characters to be returned, to accomodate X * larger character sets!) X */ X XHidden int pushback= -1; X XVisible int trminput() X{ X char c; X int n; X X#ifdef CATCHINTR X if (trmintrptd) { X trmintrptd= No; X return intrchar & 0377; X } X#ifdef SETJMP X if (setjmp(readinterrupt) != 0) { X readintrcontext = No; X trmintrptd = No; X return intrchar & 0377; X } X#endif X#endif /* CATCHINTR */ X X if (pushback >= 0) { X c= pushback; X pushback= -1; X return c; X } X#ifdef CATCHINTR X readintrcontext = Yes; X#endif X X n= read(0, &c, 1); X X#ifdef CATCHINTR X readintrcontext = No; X#endif X if (n <= 0) X return -1; X return c & 0377; X} X XHidden Procedure trmpushback(c) X int c; X{ X pushback= c; X} X X X/* X * See if there's input available from the keyboard. X * The code to do this is dependent on the type of Unix you have X * (BSD, System V, ...). X * Return value: 0 -- no input; 1 -- input; -1 -- unimplementable. X * Note that each implementation form should first check pushback. X * X * TO DO: X * - Implement it for other than 4.x BSD! (notably System 5) X */ X X#ifdef HAS_SELECT X XHidden int dep_trmavail() X{ X int nfound, nfds, readfds; X static struct timeval timeout= {0, 0}; X X readfds= 1 << 0; X nfds= 0+1; X nfound= select(nfds, &readfds, (int*) 0, (int*) 0, &timeout); X return nfound > 0; X} X X#define TRMAVAIL_DEFINED X X#else /* !HAS_SELECT */ X X#ifdef HAS_TERMIO X XHidden int dep_trmavail() X{ X int n; X char c; X X stty(0, &polltty); X n= read(0, &c, 1); X if (n == 1) X trmpushback((int)c); X stty(0, &newtty); X return n > 0; X} X X#define TRMAVAIL_DEFINED X X#endif /* HAS_TERMIO */ X X#endif /* HAS_SELECT */ X X#ifndef TRMAVAIL_DEFINED X XHidden int dep_trmavail() X{ X return -1; X} X X#endif X XVisible int trmavail() X{ X#ifdef CATCHINTR X if (trmintrptd) return 1; X#endif X if (pushback >= 0) X return 1; X return dep_trmavail(); /* dependent code */ X} X X/* X * Suspend the interpreter or editor. X * Should be called only after trmend and before trmstart! X */ X XVisible int trmsuspend() X{ X#ifdef SIGTSTP X SIGTYPE (*oldsig)(); X X oldsig= signal(SIGTSTP, SIG_IGN); X if (oldsig == SIG_IGN) { X return subshell(); X } X signal(SIGTSTP, oldsig); X kill(0, SIGSTOP); X return 1; X#else /*SIGTSTP*/ X return subshell(); X#endif /*SIGTSTP*/ X} X XHidden int subshell() X{ X int r; X X r= system("exec ${SHELL-/bin/sh}"); X if (r == -1 || r == 127) X return 0; X else X return 1; X} X X X/* X * DESCRIPTION. X * X * This package uses termcap to determine the terminal capabilities. X * X * The lines and columns of our virtual terminal are numbered X * y = {0...lines-1} from top to bottom, and X * x = {0...cols-1} from left to right, X * respectively. X * X * The Visible Procedures in this package are: X * X * trmstart(&lines, &cols, &flags) X * Obligatory initialization call (sets tty modes etc.), X * Returns the height and width of the screen to the integers X * whose addresses are passed as parameters, and a flag that X * describes some capabilities (see vtrm.h). X * Function return value: 0 if all went well, an error code if there X * is any trouble. No messages are printed for errors. X * X * trmundefined() X * States that the screen contents are no longer valid. X * This is necessary for a hard redraw, for instance. X * X * trmsense(sense, format, &y, &x) X * Returns the cursor position through its parameters, for X * instance after a mouse click. Parameter 'sense' is a string X * that is sent to the terminal, if that is necessary or NULL if X * not. Parameter 'format' is a string that defines the format of X * the reply from the terminal. X * X * trmputdata(yfirst, ylast, indent, data) X * Fill lines {yfirst..ylast} with data, after skipping the initial X * 'indent' positions. It is assumed that these positions do not contain X * anything dangerous (like standout cookies or null characters). X * X * trmscrollup(yfirst, ylast, by) X * Shift lines {yfirst..ylast} up by lines (down |by| if by < 0). X * X * trmsync(y, x) X * Output data to the terminal and set cursor position to (y, x). X * X * trmbell() X * Send a (possibly visible) bell immediately. X * X * trmend() X * Obligatory termination call (resets tty modes etc.). X * X * You may call these as one or more cycles of: X * + trmstart X * + zero or more times any of the other routines X * + trmend X * Trmend may be called even in the middle of trmstart; this is necessary X * to make it possible to write an interrupt handler that resets the tty X * state before exiting the program. X * X * ADDITIONAL SPECIFICATIONS (ROUTINES FOR CHARACTER INPUT) X * X * trminput() X * Return the next input character (with its parity bit cleared X * if any). This value is a nonnegative int. Returns -1 if the X * input can't be read any more. X * X * trmavail() X * Return 1 if there is an input character immediately available, X * 0 if not. Return -1 if not implementable. X * X * trminterrupt() X * Return 1 if an interrupt has occurred since the last call to X * trminput or trmavail, 0 else. [Currently not implemented.] X * X * trmsuspend() X * When called in the proper environment (4BSD with job control X * enabled), suspends the editor, temporarily popping back to X * the calling shell. The caller should have called trmend() X * first, and must call trmstart again afterwards. X * BUG: there is a timing window where keyboard-generated X * signals (such as interrupt) can reach the program. X * In non 4BSD we try to spawn a subshell. X * Returns 1 if suspend succeeded, 0 if it failed. X * (-1 iff not implementable). X */ END_OF_FILE if test 46848 -ne `wc -c <'stdwin/Ports/vtrm/vtrm.c'`; then echo shar: \"'stdwin/Ports/vtrm/vtrm.c'\" unpacked with wrong size! fi # end of 'stdwin/Ports/vtrm/vtrm.c' fi echo shar: End of shell archive. exit 0