rsalz@bbn.com (Rich Salz) (12/18/90)
Submitted-by: Steven Pemberton <steven@cwi.nl> Posting-number: Volume 23, Issue 81 Archive-name: abc/part02 #! /bin/sh # This is a shell archive. Remove anything before this line, then feed it # into a shell via "sh file" or similar. To overwrite existing files, # type "sh file -c". # The tool that generated this appeared in the comp.sources.unix newsgroup; # send mail to comp-sources-unix@uunet.uu.net if you want that tool. # Contents: abc/bint1/i1num.c abc/ex/hanoi/suggest.abc # abc/unix/u1trm.c # Wrapped by rsalz@litchi.bbn.com on Mon Dec 17 13:27:51 1990 PATH=/bin:/usr/bin:/usr/ucb ; export PATH echo If this archive is complete, you will see the following message: echo ' "shar: End of archive 2 (of 25)."' if test -f 'abc/bint1/i1num.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'abc/bint1/i1num.c'\" else echo shar: Extracting \"'abc/bint1/i1num.c'\" \(9745 characters\) sed "s/^X//" >'abc/bint1/i1num.c' <<'END_OF_FILE' X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1986. */ X X/* B numbers, basic external interface */ X X#include "b.h" X#include "feat.h" /* for EXT_RANGE */ X#include "bobj.h" X#include "i1num.h" X X/* X * This file contains operations on numbers that are not predefined X * B functions (the latter are defined in `i1fun.c'). X * This includes conversion of numeric B values to C `int's and X * `double's, (numval() and intval()), X * but also utilities for comparing numeric values and hashing a numeric X * value to something usable as initialization for the random generator X * without chance of overflow (so numval(v) is unusable). X * It is also possible to build numbers of all types using mk_integer, X * mk_exact (or mk_rat) and mk_approx. Note the rather irregular X * (historical!) argument structure for these: mk_approx has a X * `double' argument, where mk_exact and mk_rat have two values X * which must be `integer' (not `int's!) as arguments. X * The random number generator used by the random and choice functions X * is also in this file. X */ X X/* X * ival is used internally by intval() and large(). X * It converts an integer to double precision, yielding X * a huge value when overflow occurs (but giving no error). X */ X XHidden double ival(u) integer u; { X double x = 0; X register int i; X X if (IsSmallInt(u)) return SmallIntVal(u); X for (i = Length(u)-1; i >= 0; --i) { X if (x >= Maxreal/BASE) X return Msd(u) < 0 ? -Maxreal : Maxreal; X x = x*BASE + Digit(u, i); X } X X return x; X} X X X/* Determine if a value may be converted to an int */ X X#define NO_INTEGER MESS(1300, "number not an integer") X XVisible bool large(v) value v; { X double r; X if (!Is_number(v) || !integral(v)) { X interr(NO_INTEGER); X return No; X } X if (Rational(v)) v= (value) Numerator((rational)v); X r= ival((integer)v); X if (r > Maxint) return Yes; X return No; X} X X/* return the C `int' value of a B numeric value, if it exists. */ X X#define LARGE_INTEGER MESS(1301, "exceedingly large integer") X XVisible int intval(v) value v; { X /* v must be an Integral number or a Rational with Denominator==1 X which may result from n round x [via mk_exact]!. */ X double i; X if (IsSmallInt(v)) i= SmallIntVal(v); X else { X if (!Is_number(v)) syserr(MESS(1302, "intval on non-number")); X if (!integral(v)) { X interr(NO_INTEGER); X return 0; X } X if (Rational(v)) v= (value) Numerator((rational)v); X i= ival((integer)v); X } X if (i > Maxint || i < -Maxint) { X interr(LARGE_INTEGER); X return 0; X } X return (int) i; X} X X X/* convert an int to an intlet */ X XVisible int propintlet(i) int i; { X if (i > Maxintlet || i < -Maxintlet) { X interr(LARGE_INTEGER); X return 0; X } X return i; X} X X X/* X * determine if a number is integer X */ X XVisible bool integral(v) value v; { X if (Integral(v) || (Rational(v) && Denominator((rational)v) == int_1)) X return Yes; X else return No; X} X X/* X * mk_exact makes an exact number out of two integers. X * The third argument is the desired number of digits after the decimal X * point when the number is printed (see comments in `i1fun.c' for X * `round' and code in `i1nuc.c'). X * This printing size (if positive) is hidden in the otherwise nearly X * unused * 'Size' field of the value struct X * (cf. definition of Rational(v) etc.). X */ X XVisible value mk_exact(p, q, len) integer p, q; int len; { X rational r = mk_rat(p, q, len, Yes); X X if (Denominator(r) == int_1 && len <= 0) { X integer i = (integer) Copy(Numerator(r)); X Release(r); X return (value) i; X } X X return (value) r; X} X X#define uSMALL 1 X#define uINT 2 X#define uRAT 4 X#define uAPP 8 X#define vSMALL 16 X#define vINT 32 X#define vRAT 64 X#define vAPP 128 X XVisible relation numcomp(u, v) value u, v; { X int tu, tv; relation s; X X if (IsSmallInt(u)) tu = uSMALL; X else if (Length(u) >= 0) tu = uINT; X else if (Length(u) <= -2) tu = uRAT; X else tu = uAPP; X if (IsSmallInt(v)) tv = vSMALL; X else if (Length(v) >= 0) tv = vINT; X else if (Length(v) <= -2) tv = vRAT; X else tv = vAPP; X X switch (tu|tv) { X X case uSMALL|vSMALL: return SmallIntVal(u) - SmallIntVal(v); X X case uSMALL|vINT: X case uINT|vSMALL: X case uINT|vINT: return int_comp((integer)u, (integer)v); X X case uSMALL|vRAT: X case uINT|vRAT: X u = (value) mk_rat((integer)u, int_1, 0, Yes); X s = rat_comp((rational)u, (rational)v); X release(u); X return s; X X case uRAT|vRAT: X return rat_comp((rational)u, (rational)v); X X case uRAT|vSMALL: X case uRAT|vINT: X v = (value) mk_rat((integer)v, int_1, 0, Yes); X s = rat_comp((rational)u, (rational)v); X release(v); X return s; X X case uSMALL|vAPP: X u = approximate(u); X s = app_comp((real)u, (real)v); X release(u); X return s; X X case uINT|vAPP: X case uRAT|vAPP: X v = exactly(v); X s = numcomp(u, v); X release(v); X return s; X X case uAPP|vAPP: X return app_comp((real)u, (real)v); X X case uAPP|vSMALL: X v = approximate(v); X s = app_comp((real)u, (real)v); X release(v); X return s; X X case uAPP|vINT: X case uAPP|vRAT: X u = exactly(u); X s = numcomp(u, v); X release(u); X return s; X X default: syserr(MESS(1303, "num_comp")); /* NOTREACHED */ X X } X} X X#ifdef RANGEPRINT X/* if ranges are written as {1..10} instead of {1; 2; etc}, X * the following function is used in convert() and wri(). X */ X XVisible bool is_increment(a, b) value a, b; { X value v; X relation c; X X if (!(Is_number(a) && integral(a))) { X return No; X } X c= compare(a, v= sum(b, one)); X release(v); X return c==0; X} X#endif /* RANGEPRINT */ X X X/* X * Deliver 10**n, where n is a (maybe negative!) C integer. X * The result is a value (integer or rational, actually). X */ X XVisible value tento(n) int n; { X /* If int_tento fails, so will tento; caveat invocator */ X if (n < 0) { X integer i= int_tento(-n); value v; X if (!i) return Vnil; X v= (value) mk_exact(int_1, i, 0); X Release(i); X return v; X } X return (value) int_tento(n); X} X X X/* X * numval returns the numerical value of any numeric B value X * as a C `double'. X */ X XVisible double numval(u) value u; { X double expo, frac; X X if (!Is_number(u)) { X interr(MESS(1304, "value not a number")); X return 0.0; X } X u = approximate(u); X expo = Expo((real)u), frac = Frac((real)u); X release(u); X if (expo > Maxexpo) { X interr(MESS(1305, "approximate number too large to be handled")); X return 0.0; X } X if(expo < Minexpo) return 0.0; X return ldexp(frac, (int)expo); X} X X X/* X * Random numbers X */ X X X/* X * numhash produces a `double' number that depends on the value of X * v, useful for initializing the random generator. X * Needs rewriting, so that for instance numhash(n) never equals n. X * The magic numbers here are chosen at random. X */ X X/* The following is an auxiliary function for scrambling integers. */ X XHidden double inthash(v) double v; { X long i= ((long) v)^0x96696996; X v= 987.6543210987654321*v; X return .666*(((long) (v*.543))^((long) v)^i)+.747+v; X} X XVisible double numhash(v) value v; { X if (Integral(v)) { X double d = 0; X register int i; X X if (IsSmallInt(v)) return inthash((double)SmallIntVal(v)); X X for (i = Length(v) - 1; i >= 0; --i) { X d *= 2; X d += Digit((integer)v, i); X } X X return d; X } X X if (Rational(v)) X return .777 * numhash((value) Numerator((rational)v)) + X .123 * numhash((value) Denominator((rational)v)); X X return numval(v); /* Which fails for HUGE reals. Never mind. */ X} X X X/* Initialize the random generator */ X XHidden double lastran; X XHidden Procedure setran (seed) double seed; { X double x; X X /* Here is a change to make SETRANDOM -x differ from SETRANDOM x: */ X x = seed >= 0 ? seed : .775533-seed; X /* This gives a small speed-up: */ X while (x >= 10000) x /= 10000; X /* as before: */ X while (x >= 1) x /= 10; X lastran = floor(67108864.0*x); X} X XVisible Procedure set_random(v) value v; { X setran((double) hash(v)); X} X X X/* Return a random number in [0, 1). */ X X#define AA 29247341.0 X#define CC 66664423.0 X#define MM 67108864.0 /* 2**26 */ X X#define T21 2097152.0 /* 2**21 */ X XVisible value random() { X double p, r; X X /* Get three packets of 21 bits. X * We get the full width of a double as random bits. X * no group of bits has an obvious cyclic pattern, X * because we chop off the last 5 bits of each lastran X * (the last n bits (of the 26) go thru a 2**n cycle). X * Disadvantage: it is slow -- but someone heavy into using X * random might prefer a slower good random() over a fast one X * giving meaningless data. X */ X X p = AA * lastran + CC; X lastran = p - MM*floor(p/MM); X r= floor(lastran/32.0)/T21; X X p = AA * lastran + CC; X lastran = p - MM*floor(p/MM); X r= (floor(lastran/32.0)+r)/T21; X X p = AA * lastran + CC; X lastran = p - MM*floor(p/MM); X r= (floor(lastran/32.0)+r)/T21; X X if (r >= 1.0) return random(); X return (value) mk_approx(r, 0.0); X} X XVisible value rndm_limit; X XVisible Procedure initnum() { X rndm_limit= (value) mk_int(RNDM_LIMIT); X rat_init(); X setran((double) SEED); X initapp(); X} X XVisible Procedure endnum() { X endapp(); X endrat(); X} X X XVisible value grab_num(len) register int len; { X integer v; X register int i; X X if (len > Maxintlet) { X interr(MESS(1306, "exceptionally large number")); X return Vnil; X } X if (len < -Maxintlet) len = -2; X v = (integer) grab(Num, len); X for (i = Length(v)-1; i >= 0; --i) Digit(v, i) = 0; X return (value) v; X} X XVisible value grab_rat(len) register int len; { X if (len > 0 && len+2 <= Maxintlet); X else len= 0; X X return grab(Num, -2 - len); X} X XVisible value regrab_num(v, len) value v; register int len; { X uniql(&v); X regrab(&v, len); X return v; X} X XVisible unsigned numsyze(len, nptrs) X intlet len; X int *nptrs; X{ X register unsigned syze= 0; X *nptrs= 0; X if (len >= 0) syze= len*sizeof(digit); /* Integral */ X else if (len == -1) { X#ifdef EXT_RANGE X syze= 2*sizeof(double); /* Approximate */ X#else X syze= sizeof(double); /* Approximate */ X#endif X } X else { /* Rational */ X syze= 2*sizeof(value); X *nptrs= 2; X } X return syze; X} X END_OF_FILE if test 9745 -ne `wc -c <'abc/bint1/i1num.c'`; then echo shar: \"'abc/bint1/i1num.c'\" unpacked with wrong size! fi # end of 'abc/bint1/i1num.c' fi if test -f 'abc/ex/hanoi/suggest.abc' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'abc/ex/hanoi/suggest.abc'\" else echo shar: Extracting \"'abc/ex/hanoi/suggest.abc'\" \(8 characters\) sed "s/^X//" >'abc/ex/hanoi/suggest.abc' <<'END_OF_FILE' XHANOI ? END_OF_FILE if test 8 -ne `wc -c <'abc/ex/hanoi/suggest.abc'`; then echo shar: \"'abc/ex/hanoi/suggest.abc'\" unpacked with wrong size! fi # end of 'abc/ex/hanoi/suggest.abc' fi if test -f 'abc/unix/u1trm.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'abc/unix/u1trm.c'\" else echo shar: Extracting \"'abc/unix/u1trm.c'\" \(40794 characters\) sed "s/^X//" >'abc/unix/u1trm.c' <<'END_OF_FILE' X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1986. */ X X#define lenline len_line /* Avoid name conflict with lenline in tex.c */ 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/* X * Includes and data definitions. X */ X X#include "b.h" X X#ifndef TERMIO X#include <sgtty.h> X#else X#include <termio.h> X#endif X X#include "trm.h" X X#ifdef SIGNAL X#include <signal.h> X#endif X#ifdef SETJMP X#include <setjmp.h> X#endif X Xchar *malloc(); X Xchar *getenv(); Xint tgetent(); Xint tgetnum(); Xint tgetflag(); Xchar *tgetstr(); X X#define Min(a,b) ((a) <= (b) ? (a) : (b)) X X/* tty modes */ X#ifndef TERMIO X X/* v7/BSD tty control */ XHidden struct sgttyb oldtty, newtty; 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 X X#ifdef TIOCSLTC /* BSD -- local special chars, must all be turned off */ Xstatic struct ltchars oldltchars; Xstatic 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 */ Xstatic struct tchars oldtchars; Xstatic struct tchars newtchars; X#endif /* TIOCSETC */ X X#else /* TERMIO */ X X/* AT&T tty control */ XHidden struct termio oldtty, newtty; X#define gtty(fd,bp) ioctl(fd, TCGETA, (char *) bp) X#define stty(fd,bp) VOID ioctl(fd, TCSETAW, (char *) bp) X X#endif /* TERMIO */ X X#ifdef VTRMTRACE Xextern FILE *vtrmfp; 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= NULL; XForward int outchar(); /* procedure for termcap's tputs */ X#define Putstr(str) tputs((str), 1, outchar) Xextern char *tgoto(); 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 */ 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 */ 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) register char **parea; { 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/* current standout mode */ X#define Off 0 X#define On 0200 XHidden short so_mode = Off; X X/* masks for char's and short's */ X#define NULCHAR '\000' X#define CHAR 0177 X#define SOBIT On X#define SOCHAR 0377 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 0400 X#define SOCOOK 0600 X#define COOKBITS SOCOOK X#define UNKNOWN 1 X#define NOCOOK UNKNOWN X X/* current cursor position */ XHidden short cur_y = Undefined, cur_x = Undefined; X X/* "line[y][x]" holds the char on the terminal, with 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 short **line = 0, *lenline = 0; 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 scrolling available. (NOT YET IMPLEMENTED) X */ XHidden Procedure (*scr_up)(); XHidden Procedure (*scr_down)(); XForward Procedure scr1up(); XForward Procedure scr1down(); XForward Procedure scr2up(); XForward Procedure scr2down(); X/*Forward Procedure scr3up(); */ X/*Forward Procedure scr3down(); */ 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) int *plines, *pcols, *pflags; { X register int err; X X#ifdef VTRMTRACE X if (vtrmfp) putstr(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); X /* position for >ws message from initbws() X * on vt100's, and for alternate screen buffers X */ 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#ifdef VTRMTRACE X if (vtrmfp) putstr(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} 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 register int y, x; X#ifdef VTRMTRACE X if (vtrmfp) putstr(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 line[y][x] = 1; /* impossible char, no so bits */ X lenline[y] = cols; X } X} X X#ifdef VTRMTRACE X XHidden Procedure check_started(m) char *m; { X if (!started) { X trmend(); X if (vtrmfp) putstr(vtrmfp, "bad VTRM call\n"); X abort(); X } X} X#else X X#define check_started(m) /*empty*/ X X#endif /* NDEBUG */ X XHidden int getttyfp() { 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) char ch; { X ccc++; X} X XHidden int strcost(str) char *str; { X if (str == NULL) X return Infinity; X return str0cost(str); X} X XHidden int str0cost(str) char *str; { 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 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 return TE_DUMB; 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 /* cursor sensing (non standard) */ X if (cp_str != NULL && sp_str != NULL) X flags |= CAN_SENSE; 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 XHidden char intrchar; X#ifdef SIGTSTP XHidden char suspchar; X#endif X XHidden int setttymode() { X if (!know_ttys) { X if (gtty(0, &oldtty) != 0 || gtty(0, &newtty) != 0) X return TE_NOTTY; X#ifndef 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 /* 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#ifndef KEYS X newtty.c_lflag &= ~(ICANON|ECHO); X /* No line editing, no echo */ X newtty.c_cc[VQUIT]= 0377; /* no quit signal */ X#ifdef VSUSP X newtty.c_cc[VSUSP]= 0377; /* no susp signal */ X#endif X#else X newtty.c_lflag &= ~(ICANON|ECHO|ISIG); X /* No line editing, no echo, X * no quit, intr or susp signals */ X#endif /* KEYS */ X newtty.c_cc[VMIN]= 3; /* wait for 3 characters */ X newtty.c_cc[VTIME]= 1; /* or 0.1 sec. */ X#endif /* TERMIO */ X know_ttys = Yes; X } X stty(0, &newtty); X#ifndef TERMIO X#ifdef TIOCSLTC X newltchars.t_suspc= oldltchars.t_suspc; X#ifdef SIGTSTP X suspchar= oldltchars.t_suspc; X#endif X VOID ioctl(0, TIOCSLTC, (char *) &newltchars); X#endif X#ifdef TIOCSETC X VOID ioctl(0, TIOCGETC, (char *) &newtchars); X#ifndef KEYS X intrchar= newtchars.t_intrc; X#else X newtchars.t_intrc= -1; X#endif 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 /* TERMIO */ X return TE_OK; X} X XHidden Procedure resetttymode() { X if (know_ttys) { X stty(0, &oldtty); X#ifndef 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 /* TERMIO */ X know_ttys= No; X } X} X XHidden int start_trm() { 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 (line != NULL) { X for (y= 0; y < lines; ++y) X free((char *) line[y]); X free((char *) line); X line= 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 (line == NULL) { X if ((line = (short**) malloc(lines * sizeof(short*))) == NULL) X return TE_NOMEM; X for (y = 0; y < lines; y++) { X if ((line[y] = (short*) X malloc((cols+1) * sizeof(short))) == NULL) X return TE_NOMEM; X } X } X if (lenline == NULL) { X if ((lenline = (short*) malloc(lines * sizeof(short))) == 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, after a possible manual X * change by the user with local cursor motions. 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 */ X XVisible Procedure trmsense(py, px) int *py, *px; { X bool get_pos(); X X#ifdef VTRMTRACE X if (vtrmfp) putstr(vtrmfp, "\ttrmsense(&yy, &xx);\n"); X#endif X check_started("trmsense"); X X *py = *px = Undefined; X set_mode(Normal); X if (so_mode != Off) X standend(); X X if (flags&CAN_SENSE && get_pos(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(py, px) int *py, *px; { X char *format = cp_str; 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 Putstr(sp_str); X VOID fflush(fp); 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 '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 X * when rewriting line[y] from x_from upto x_to X */ XHidden bool rewrite_ok(y, xfrom, xto) int y, xfrom, xto; { X register short *plnyx, *plnyto; X X if (xto > lenline[y]) X return No; X X plnyto = &line[y][xto]; X for (plnyx = &line[y][xfrom]; plnyx <= plnyto; plnyx++) X if (*plnyx == UNKNOWN X || X (!has_xs && (*plnyx & SOBIT) != so_mode) X ) X return No; 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) int y, 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(line[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 with the SO-bit (0200) set are put in standout mode. X */ XVisible Procedure trmputdata(yfirst, ylast, indent, data) int yfirst, ylast; X register int indent; register string data; { X register int y; X int x, len, lendata, space; X X#ifdef VTRMTRACE X if (vtrmfp) put3DSstr(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, len); X y++; X lendata -= len; X if (lendata > 0) { X x = 0; X data += 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, bq 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, len) int y, xskip; string data; int len; { X register short *op, *oq; X register char *np, *nq, *nend; 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 line[y][lenline[y]++] = ' '; X X /* calculate the magic parameters */ X op = &line[y][xskip]; X oq = &line[y][lenline[y]-1]; X np = data; X nq = nend = data + len - 1; X m1 = m2 = 0; X while ((*op&SOCHAR) == (((short)*np)&SOCHAR) && op <= oq && np <= nq) X op++, np++, m1++; X /* calculate m2, iff we can optimise or line keeps same length: */ X if (flags & CAN_OPTIMISE || (oq-op) == (nq-np)) X while ((*oq&SOCHAR) == (((short)*nq)&SOCHAR) && op <= oq && np <= nq) X oq--, nq--, m2++; 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 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 while (p <= nend) { X while (q<=nend && *q==' ' && (op>oq || *op==' ')) X q++, op++; X if (q - p > bq1 - bp) X bp = p, bq1 = q; X p = ++q; X op++; 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 put_str(np, 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 put_str(np, dd, No); X } X X if (m2 > 0) { X if (delta > 0) { X set_mode(Insert); X ins_str(np+dd, 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 (!(line[cur_y][cur_x] & XSBIT)) { X if (so_mode != (line[cur_y][cur_x] & SOBIT)) X (so_mode ? standend() : standout()); X } X } X } X} X XHidden Procedure set_mode(m) int m; { 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 if (cur_x >= lenline[cur_y] || line[cur_y][cur_x] == UNKNOWN) X so_mode = Off; X else X so_mode = line[cur_y][cur_x] & SOBIT; X} X XHidden Procedure standout() { X Putstr(so_str); X so_mode = On; X if (has_xs) X line[cur_y][cur_x] |= SOCOOK; X} X XHidden Procedure standend() { X Putstr(se_str); X so_mode = Off; X if (has_xs) X line[cur_y][cur_x] = (line[cur_y][cur_x] & ~SOBIT) | XSBIT; X} X XHidden Procedure put_str(data, n, inserting) char *data; int n; bool inserting; { X register short c, so; X short *ln_y_x, *ln_y_end; X X so = so_mode; X if (has_xs) { X ln_y_x = &line[cur_y][cur_x]; X ln_y_end = &line[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 c = ((short)(*data++))&SOCHAR; X if ((c&SOBIT) != so) { X so = c&SOBIT; X so ? standout() : standend(); X } X if (inserting) X Putstr(ic_str); X put_c(c); X if (has_xs) X ln_y_x++; X } X} X XHidden Procedure ins_str(data, n) char *data; int n; { 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 line[cur_y][x+n] = line[cur_y][x]; X put_str(data, n, Yes); X} X XHidden Procedure del_str(n) int n; { 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 (line[cur_y][x] & XSBIT) X break; X } X if (x >= cur_x) X line[cur_y][cur_x+n] = X (line[cur_y][cur_x+n] & CHAR) X | X (line[cur_y][x] & COOKBITS); X } X for (x = cur_x; x <= xto; x++) X line[cur_y][x] = line[cur_y][x+n]; X while (n-- > 0) X Putstr(dc_str); X} X XHidden Procedure put_c(c) int c; { X char ch; X short xs_flag; X X ch = c&CHAR; X if (!isprint(ch) && ch != ' ') /* V7 isprint doesn't include blank */ X ch= '?'; X fputc(ch, fp); X if (has_xs) X xs_flag = line[cur_y][cur_x]&XSBIT; X else X xs_flag = 0; X line[cur_y][cur_x] = (c&SOCHAR)|xs_flag; X cur_x++; X} X XHidden Procedure clear_lines(yfirst, ylast) int yfirst, ylast; { 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) line[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) line[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 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 line[cur_y][0] = NOCOOK; X else if (line[cur_y][cur_x-1]&SOBIT) X standend(); X } X} X XHidden Procedure set_blanks(y, xfrom, xto) int y, xfrom, xto; { X register int x; X X for (x = xfrom; x < xto; x++) { X line[y][x] = (line[y][x]&XSBIT) | ' '; X } X} X X/* X * outchar() is used by termcap's tputs. X */ XHidden int outchar(ch) char ch; { 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) register int yfirst; X register int ylast; register int by; { X#ifdef VTRMTRACE X if (vtrmfp) put3Dstr(vtrmfp, "\ttrmscrollup(%d, %d, %d);\n", yfirst, ylast, by); X#endif X check_started("trmscrollup"); 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 (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 XHidden Procedure scr_lines(yfrom, yto, n, dy) int yfrom, yto, n, dy; { X register int y; X short *saveln; X X while (n-- > 0) { X saveln = line[yfrom]; X for (y = yfrom; y != yto; y += dy) { X line[y] = line[y+dy]; X lenline[y] = lenline[y+dy]; X } X line[yto] = saveln; X lenline[yto] = 0; X if (has_xs) line[yto][0] = NOCOOK; X } X} X XHidden Procedure scr1up(yfirst, ylast, n) int yfirst, ylast, 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) int yfirst, ylast, n; { 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) register int n; { 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) register int n; { 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) int yfirst, ylast, n; { 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) int yfirst, ylast, n; { 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 X/* X * Synchronization, move cursor to given position (or previous if < 0). X */ X XVisible Procedure trmsync(y, x) int y, x; { X#ifdef VTRMTRACE X if (vtrmfp) put2Dstr(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#ifdef VTRMTRACE X if (vtrmfp) putstr(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) char *s; { X int y, x; X X if (!vtrmfp) X return; X putSstr(vtrmfp, "<<< %s >>>\n", s); X for (y = 0; y < lines; y++) { X for (x = 0; x <= lenline[y] /*** && x < cols-1 ***/ ; x++) { X putchr(vtrmfp, line[y][x]&CHAR); X } X putnewline(vtrmfp); X for (x = 0; x <= lenline[y] && x < cols-1; x++) { X if (line[y][x]&SOBIT) X putchr(vtrmfp, '-'); X else X putchr(vtrmfp, ' '); X } X putnewline(vtrmfp); X for (x = 0; x <= lenline[y] && x < cols-1; x++) { X if (line[y][x]&XSBIT) X putchr(vtrmfp, '+'); X else X putchr(vtrmfp, ' '); X } X putnewline(vtrmfp); X } X put2Dstr(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 X#ifdef SETJMP X XVisible jmp_buf readEinterrupt; XVisible bool readEcontext; X X#endif /* SETJMP */ X Xextern bool intrflag; X#ifdef SIGTSTP Xextern bool suspflag; X#ifdef SETJMP XVisible jmp_buf readEsuspend; X#endif X#endif X XHidden int pushback= -1; X Xint trminput() { X char c; X int n; X X if (intrflag) { X intrflag= No; X return intrchar & 0377; X } X#ifdef SIGTSTP X if (suspflag) { X suspflag= No; X return suspchar & 0377; X } X#endif X if (pushback >= 0) { X c= pushback; X pushback= -1; X return c; X } X#ifdef SETJMP X if (setjmp(readEinterrupt) != 0) { X readEcontext= No; X intrflag= No; X return intrchar & 0377; X } X#ifdef SIGTSTP X if (setjmp(readEsuspend) != 0) { X readEcontext= No; X suspflag= No; X return suspchar & 0377; X } X#endif X readEcontext= Yes; X#endif /* SETJMP */ X n= read(0, &c, 1); X#ifdef SETJMP X readEcontext= No; X#endif X if (n <= 0) X return -1; X return c & 0377; X} X Xtrmpushback(c) int c; { 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 X#include <sys/time.h> X Xint dep_trmavail() { 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#endif /* HAS_SELECT */ X X#if !defined(TRMAVAIL_DEFINED) && defined(FIONREAD) X Xint dep_trmavail() { X long n; X X ioctl(0, FIONREAD, (char *) &n); X return n > 0; X} X X#define TRMAVAIL_DEFINED X X#endif /* FIONREAD */ X X#ifndef TRMAVAIL_DEFINED X Xint dep_trmavail() { X return -1; X} X X#endif X Xint trmavail() { X if (intrflag) X return 1; X if (pushback >= 0) X return 1; X return dep_trmavail(); /* dependent code */ X} X X#ifdef UNUSED X/* X * Suspend the editor. X * Should be called only after trmend and before trmstart! X */ X Xtrmsuspend() { X#ifdef SIGTSTP X SIGTYPE (*oldsig)(); X X oldsig= signal(SIGTSTP, SIG_IGN); X if (oldsig == SIG_IGN) X return; /* Could spawn a subshell here... */ X trmend(); /* Safety net */ X signal(SIGTSTP, oldsig); X kill(0, SIGSTOP); X#endif /*SIGTSTP*/ X} X#endif 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. 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 * Sets internal representation of screen and attributes to undefined. X * This is necessary for a hard redraw, which would get optimised to X * oblivion, X * X * trmsense(&y, &x) X * Returns the cursor position through its parameters X * after a possible manual change by the user. 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 * Call to output data to the terminal and set cursor position. X * X * trmbell() X * Send a (possibly visible) bell, immediately (flushing fp). 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 */ END_OF_FILE if test 40794 -ne `wc -c <'abc/unix/u1trm.c'`; then echo shar: \"'abc/unix/u1trm.c'\" unpacked with wrong size! fi # end of 'abc/unix/u1trm.c' fi echo shar: End of archive 2 \(of 25\). cp /dev/null ark2isdone MISSING="" for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 25 archives. rm -f ark[1-9]isdone ark[1-9][0-9]isdone else echo You still must unpack the following archives: echo " " ${MISSING} fi exit 0 # Just in case... -- Please send comp.sources.unix-related mail to rsalz@uunet.uu.net. Use a domain-based address or give alternate paths, or you may lose out.