home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume23 / abc / part02 < prev    next >
Encoding:
Internet Message Format  |  1991-01-08  |  54.2 KB

  1. Subject:  v23i081:  ABC interactive programming environment, Part02/25
  2. Newsgroups: comp.sources.unix
  3. Approved: rsalz@uunet.UU.NET
  4. X-Checksum-Snefru: b78c7b57 6a64e121 5532244a 29719e09
  5.  
  6. Submitted-by: Steven Pemberton <steven@cwi.nl>
  7. Posting-number: Volume 23, Issue 81
  8. Archive-name: abc/part02
  9.  
  10. #! /bin/sh
  11. # This is a shell archive.  Remove anything before this line, then feed it
  12. # into a shell via "sh file" or similar.  To overwrite existing files,
  13. # type "sh file -c".
  14. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  15. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  16. # Contents:  abc/bint1/i1num.c abc/ex/hanoi/suggest.abc
  17. #   abc/unix/u1trm.c
  18. # Wrapped by rsalz@litchi.bbn.com on Mon Dec 17 13:27:51 1990
  19. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  20. echo If this archive is complete, you will see the following message:
  21. echo '          "shar: End of archive 2 (of 25)."'
  22. if test -f 'abc/bint1/i1num.c' -a "${1}" != "-c" ; then 
  23.   echo shar: Will not clobber existing file \"'abc/bint1/i1num.c'\"
  24. else
  25.   echo shar: Extracting \"'abc/bint1/i1num.c'\" \(9745 characters\)
  26.   sed "s/^X//" >'abc/bint1/i1num.c' <<'END_OF_FILE'
  27. X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1986. */
  28. X
  29. X/* B numbers, basic external interface */
  30. X
  31. X#include "b.h"
  32. X#include "feat.h"     /* for EXT_RANGE */
  33. X#include "bobj.h"
  34. X#include "i1num.h"
  35. X
  36. X/*
  37. X * This file contains operations on numbers that are not predefined
  38. X * B functions (the latter are defined in `i1fun.c').
  39. X * This includes conversion of numeric B values to C `int's and
  40. X * `double's, (numval() and intval()),
  41. X * but also utilities for comparing numeric values and hashing a numeric
  42. X * value to something usable as initialization for the random generator
  43. X * without chance of overflow (so numval(v) is unusable).
  44. X * It is also possible to build numbers of all types using mk_integer,
  45. X * mk_exact (or mk_rat) and mk_approx.  Note the rather irregular
  46. X * (historical!) argument structure for these: mk_approx has a
  47. X * `double' argument, where mk_exact and mk_rat have two values
  48. X * which must be `integer' (not `int's!) as arguments.
  49. X * The random number generator used by the random and choice functions
  50. X * is also in this file.
  51. X */
  52. X
  53. X/*
  54. X * ival is used internally by intval() and large().
  55. X * It converts an integer to double precision, yielding
  56. X * a huge value when overflow occurs (but giving no error).
  57. X */
  58. X
  59. XHidden double ival(u) integer u; {
  60. X    double x = 0;
  61. X    register int i;
  62. X
  63. X    if (IsSmallInt(u)) return SmallIntVal(u);
  64. X    for (i = Length(u)-1; i >= 0; --i) {
  65. X        if (x >= Maxreal/BASE)
  66. X            return Msd(u) < 0 ? -Maxreal : Maxreal;
  67. X        x = x*BASE + Digit(u, i);
  68. X    }
  69. X
  70. X    return x;
  71. X}
  72. X
  73. X
  74. X/* Determine if a value may be converted to an int */
  75. X
  76. X#define NO_INTEGER    MESS(1300, "number not an integer")
  77. X
  78. XVisible bool large(v) value v; {
  79. X    double r;
  80. X    if (!Is_number(v) || !integral(v)) {
  81. X        interr(NO_INTEGER);
  82. X        return No;
  83. X    }
  84. X    if (Rational(v)) v= (value) Numerator((rational)v);
  85. X    r= ival((integer)v);
  86. X    if (r > Maxint) return Yes;
  87. X    return No;
  88. X}
  89. X
  90. X/* return the C `int' value of a B numeric value, if it exists. */
  91. X
  92. X#define LARGE_INTEGER    MESS(1301, "exceedingly large integer")
  93. X
  94. XVisible int intval(v) value v; {
  95. X    /* v must be an Integral number or a Rational with Denominator==1
  96. X        which may result from n round x [via mk_exact]!. */
  97. X    double i;
  98. X    if (IsSmallInt(v)) i= SmallIntVal(v);
  99. X    else {
  100. X        if (!Is_number(v)) syserr(MESS(1302, "intval on non-number"));
  101. X        if (!integral(v)) {
  102. X            interr(NO_INTEGER);
  103. X            return 0;
  104. X        }
  105. X        if (Rational(v)) v= (value) Numerator((rational)v);
  106. X        i= ival((integer)v);
  107. X    }
  108. X    if (i > Maxint || i < -Maxint) {
  109. X        interr(LARGE_INTEGER);
  110. X        return 0;
  111. X    }
  112. X    return (int) i;
  113. X}
  114. X
  115. X
  116. X/* convert an int to an intlet */
  117. X
  118. XVisible int propintlet(i) int i; {
  119. X    if (i > Maxintlet || i < -Maxintlet) {
  120. X        interr(LARGE_INTEGER);
  121. X        return 0;
  122. X    }
  123. X    return i;
  124. X}
  125. X
  126. X
  127. X/*
  128. X * determine if a number is integer
  129. X */
  130. X
  131. XVisible bool integral(v) value v; {
  132. X    if (Integral(v) || (Rational(v) && Denominator((rational)v) == int_1))
  133. X        return Yes;
  134. X    else return No;
  135. X}
  136. X
  137. X/*
  138. X * mk_exact makes an exact number out of two integers.
  139. X * The third argument is the desired number of digits after the decimal
  140. X * point when the number is printed (see comments in `i1fun.c' for
  141. X * `round' and code in `i1nuc.c').
  142. X * This printing size (if positive) is hidden in the otherwise nearly
  143. X * unused * 'Size' field of the value struct
  144. X * (cf. definition of Rational(v) etc.).
  145. X */
  146. X
  147. XVisible value mk_exact(p, q, len) integer p, q; int len; {
  148. X    rational r = mk_rat(p, q, len, Yes);
  149. X
  150. X    if (Denominator(r) == int_1 && len <= 0) {
  151. X        integer i = (integer) Copy(Numerator(r));
  152. X        Release(r);
  153. X        return (value) i;
  154. X    }
  155. X
  156. X    return (value) r;
  157. X}
  158. X
  159. X#define uSMALL 1
  160. X#define uINT 2
  161. X#define uRAT 4
  162. X#define uAPP 8
  163. X#define vSMALL 16
  164. X#define vINT 32
  165. X#define vRAT 64
  166. X#define vAPP 128
  167. X
  168. XVisible relation numcomp(u, v) value u, v; {
  169. X    int tu, tv; relation s;
  170. X
  171. X    if (IsSmallInt(u)) tu = uSMALL;
  172. X    else if (Length(u) >= 0) tu = uINT;
  173. X    else if (Length(u) <= -2) tu = uRAT;
  174. X    else tu = uAPP;
  175. X    if (IsSmallInt(v)) tv = vSMALL;
  176. X    else if (Length(v) >= 0) tv = vINT;
  177. X    else if (Length(v) <= -2) tv = vRAT;
  178. X    else tv = vAPP;
  179. X
  180. X    switch (tu|tv) {
  181. X
  182. X    case uSMALL|vSMALL: return SmallIntVal(u) - SmallIntVal(v);
  183. X
  184. X    case uSMALL|vINT:
  185. X    case uINT|vSMALL:
  186. X    case uINT|vINT: return int_comp((integer)u, (integer)v);
  187. X
  188. X    case uSMALL|vRAT:
  189. X    case uINT|vRAT:
  190. X        u = (value) mk_rat((integer)u, int_1, 0, Yes);
  191. X        s = rat_comp((rational)u, (rational)v);
  192. X        release(u);
  193. X        return s;
  194. X
  195. X    case uRAT|vRAT:
  196. X        return rat_comp((rational)u, (rational)v);
  197. X
  198. X    case uRAT|vSMALL:
  199. X    case uRAT|vINT:
  200. X        v = (value) mk_rat((integer)v, int_1, 0, Yes);
  201. X        s = rat_comp((rational)u, (rational)v);
  202. X        release(v);
  203. X        return s;
  204. X
  205. X    case uSMALL|vAPP:
  206. X        u = approximate(u);
  207. X        s = app_comp((real)u, (real)v);
  208. X        release(u);
  209. X        return s;
  210. X
  211. X    case uINT|vAPP:
  212. X    case uRAT|vAPP:
  213. X        v = exactly(v);
  214. X        s = numcomp(u, v);
  215. X        release(v);
  216. X        return s;
  217. X
  218. X    case uAPP|vAPP:
  219. X        return app_comp((real)u, (real)v);
  220. X
  221. X    case uAPP|vSMALL:
  222. X        v = approximate(v);
  223. X        s = app_comp((real)u, (real)v);
  224. X        release(v);
  225. X        return s;
  226. X
  227. X    case uAPP|vINT:
  228. X    case uAPP|vRAT:
  229. X        u = exactly(u);
  230. X        s = numcomp(u, v);
  231. X        release(u);
  232. X        return s;
  233. X
  234. X    default: syserr(MESS(1303, "num_comp")); /* NOTREACHED */
  235. X
  236. X    }
  237. X}
  238. X
  239. X#ifdef RANGEPRINT
  240. X/* if ranges are written as {1..10} instead of {1; 2; etc},
  241. X * the following function is used in convert() and wri().
  242. X */
  243. X
  244. XVisible bool is_increment(a, b) value a, b; {
  245. X    value v;
  246. X    relation c;
  247. X    
  248. X    if (!(Is_number(a) && integral(a))) {
  249. X        return No;
  250. X    }
  251. X    c= compare(a, v= sum(b, one));
  252. X    release(v);
  253. X    return c==0;
  254. X}
  255. X#endif /* RANGEPRINT */
  256. X
  257. X
  258. X/*
  259. X * Deliver 10**n, where n is a (maybe negative!) C integer.
  260. X * The result is a value (integer or rational, actually).
  261. X */
  262. X
  263. XVisible value tento(n) int n; {
  264. X    /* If int_tento fails, so will tento; caveat invocator */
  265. X    if (n < 0) {
  266. X        integer i= int_tento(-n); value v;
  267. X        if (!i) return Vnil;
  268. X        v= (value) mk_exact(int_1, i, 0);
  269. X        Release(i);
  270. X        return v;
  271. X    }
  272. X    return (value) int_tento(n);
  273. X}
  274. X
  275. X
  276. X/*
  277. X * numval returns the numerical value of any numeric B value
  278. X * as a C `double'.
  279. X */
  280. X
  281. XVisible double numval(u) value u; {
  282. X    double expo, frac;
  283. X
  284. X    if (!Is_number(u)) {
  285. X        interr(MESS(1304, "value not a number"));
  286. X        return 0.0;
  287. X    }
  288. X    u = approximate(u);
  289. X    expo = Expo((real)u), frac = Frac((real)u);
  290. X    release(u);
  291. X    if (expo > Maxexpo) {
  292. X        interr(MESS(1305, "approximate number too large to be handled"));
  293. X        return 0.0;
  294. X    }
  295. X    if(expo < Minexpo) return 0.0;
  296. X    return ldexp(frac, (int)expo);
  297. X}
  298. X
  299. X
  300. X/*
  301. X * Random numbers
  302. X */
  303. X
  304. X
  305. X/*
  306. X * numhash produces a `double' number that depends on the value of
  307. X * v, useful for initializing the random generator.
  308. X * Needs rewriting, so that for instance numhash(n) never equals n.
  309. X * The magic numbers here are chosen at random.
  310. X */
  311. X
  312. X/* The following is an auxiliary function for scrambling integers. */
  313. X
  314. XHidden double inthash(v) double v; {
  315. X    long i= ((long) v)^0x96696996;
  316. X    v= 987.6543210987654321*v;
  317. X    return .666*(((long) (v*.543))^((long) v)^i)+.747+v;
  318. X}
  319. X
  320. XVisible double numhash(v) value v; {
  321. X    if (Integral(v)) {
  322. X        double d = 0;
  323. X        register int i;
  324. X
  325. X        if (IsSmallInt(v)) return inthash((double)SmallIntVal(v));
  326. X        
  327. X        for (i = Length(v) - 1; i >= 0; --i) {
  328. X            d *= 2;
  329. X            d += Digit((integer)v, i);
  330. X        }
  331. X
  332. X        return d;
  333. X    }
  334. X
  335. X    if (Rational(v))
  336. X        return .777 * numhash((value) Numerator((rational)v)) +
  337. X               .123 * numhash((value) Denominator((rational)v));
  338. X
  339. X    return numval(v); /* Which fails for HUGE reals.  Never mind. */
  340. X}
  341. X
  342. X
  343. X/* Initialize the random generator */
  344. X
  345. XHidden double lastran;
  346. X
  347. XHidden Procedure setran (seed) double seed; {
  348. X    double x;
  349. X
  350. X    /* Here is a change to make SETRANDOM -x differ from SETRANDOM x: */
  351. X    x = seed >= 0 ? seed : .775533-seed;
  352. X    /* This gives a small speed-up: */
  353. X    while (x >= 10000) x /= 10000;
  354. X    /* as before: */
  355. X    while (x >= 1) x /= 10;
  356. X    lastran = floor(67108864.0*x);
  357. X}
  358. X
  359. XVisible Procedure set_random(v) value v; {
  360. X    setran((double) hash(v));
  361. X}
  362. X
  363. X
  364. X/* Return a random number in [0, 1). */
  365. X
  366. X#define AA 29247341.0
  367. X#define CC 66664423.0
  368. X#define MM 67108864.0    /* 2**26 */
  369. X
  370. X#define T21 2097152.0    /* 2**21 */
  371. X
  372. XVisible value random() {
  373. X    double p, r;
  374. X
  375. X    /* Get three packets of 21 bits.
  376. X     * We get the full width of a double as random bits.
  377. X     * no group of bits has an obvious cyclic pattern,
  378. X     * because we chop off the last 5 bits of each lastran
  379. X     * (the last n bits (of the 26) go thru a 2**n cycle).
  380. X     * Disadvantage: it is slow -- but someone heavy into using
  381. X     * random might prefer a slower good random() over a fast one
  382. X     * giving meaningless data.
  383. X     */
  384. X    
  385. X    p = AA * lastran + CC;
  386. X    lastran = p - MM*floor(p/MM);
  387. X    r= floor(lastran/32.0)/T21;
  388. X
  389. X    p = AA * lastran + CC;
  390. X    lastran = p - MM*floor(p/MM);
  391. X    r= (floor(lastran/32.0)+r)/T21;
  392. X
  393. X    p = AA * lastran + CC;
  394. X    lastran = p - MM*floor(p/MM);
  395. X    r= (floor(lastran/32.0)+r)/T21;
  396. X
  397. X    if (r >= 1.0) return random();
  398. X    return (value) mk_approx(r, 0.0);
  399. X}
  400. X
  401. XVisible value rndm_limit;
  402. X
  403. XVisible Procedure initnum() {
  404. X    rndm_limit= (value) mk_int(RNDM_LIMIT);
  405. X    rat_init();
  406. X    setran((double) SEED);
  407. X    initapp();
  408. X}
  409. X
  410. XVisible Procedure endnum() {
  411. X    endapp();
  412. X    endrat();
  413. X}
  414. X
  415. X
  416. XVisible value grab_num(len) register int len; {
  417. X    integer v;
  418. X    register int i;
  419. X
  420. X    if (len > Maxintlet) {
  421. X        interr(MESS(1306, "exceptionally large number"));
  422. X        return Vnil;
  423. X    }
  424. X    if (len < -Maxintlet) len = -2;
  425. X    v = (integer) grab(Num, len);
  426. X    for (i = Length(v)-1; i >= 0; --i) Digit(v, i) = 0;
  427. X    return (value) v;
  428. X}
  429. X
  430. XVisible value grab_rat(len) register int len; {
  431. X    if (len > 0 && len+2 <= Maxintlet);
  432. X    else len= 0;
  433. X        
  434. X    return grab(Num, -2 - len);
  435. X}
  436. X
  437. XVisible value regrab_num(v, len) value v; register int len; {
  438. X    uniql(&v);
  439. X    regrab(&v, len);
  440. X    return v;
  441. X}
  442. X
  443. XVisible unsigned numsyze(len, nptrs)
  444. X    intlet len;
  445. X    int *nptrs;
  446. X{
  447. X    register unsigned syze= 0;
  448. X    *nptrs= 0;
  449. X    if (len >= 0) syze= len*sizeof(digit);       /* Integral */
  450. X    else if (len == -1) {
  451. X#ifdef EXT_RANGE
  452. X        syze= 2*sizeof(double);        /* Approximate */
  453. X#else
  454. X        syze= sizeof(double);           /* Approximate */
  455. X#endif
  456. X    }
  457. X    else {                        /* Rational */
  458. X        syze= 2*sizeof(value);
  459. X        *nptrs= 2;
  460. X    }
  461. X    return syze;
  462. X}
  463. X
  464. END_OF_FILE
  465.   if test 9745 -ne `wc -c <'abc/bint1/i1num.c'`; then
  466.     echo shar: \"'abc/bint1/i1num.c'\" unpacked with wrong size!
  467.   fi
  468.   # end of 'abc/bint1/i1num.c'
  469. fi
  470. if test -f 'abc/ex/hanoi/suggest.abc' -a "${1}" != "-c" ; then 
  471.   echo shar: Will not clobber existing file \"'abc/ex/hanoi/suggest.abc'\"
  472. else
  473.   echo shar: Extracting \"'abc/ex/hanoi/suggest.abc'\" \(8 characters\)
  474.   sed "s/^X//" >'abc/ex/hanoi/suggest.abc' <<'END_OF_FILE'
  475. XHANOI ?
  476. END_OF_FILE
  477.   if test 8 -ne `wc -c <'abc/ex/hanoi/suggest.abc'`; then
  478.     echo shar: \"'abc/ex/hanoi/suggest.abc'\" unpacked with wrong size!
  479.   fi
  480.   # end of 'abc/ex/hanoi/suggest.abc'
  481. fi
  482. if test -f 'abc/unix/u1trm.c' -a "${1}" != "-c" ; then 
  483.   echo shar: Will not clobber existing file \"'abc/unix/u1trm.c'\"
  484. else
  485.   echo shar: Extracting \"'abc/unix/u1trm.c'\" \(40794 characters\)
  486.   sed "s/^X//" >'abc/unix/u1trm.c' <<'END_OF_FILE'
  487. X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1986. */
  488. X
  489. X#define lenline len_line /* Avoid name conflict with lenline in tex.c */
  490. X
  491. X/*
  492. X * Virtual TeRMinal package.
  493. X * (For a description see at the end of this file.)
  494. X *
  495. X * Big change:
  496. X *    output goes to /dev/tty, in case stdout is redirected to a file.
  497. X *
  498. X * TO DO:
  499. X *    - add interrupt handling (trminterrupt)
  500. X *    - adapt to changed window size when suspended or at SIGWINCH
  501. X *      (unfortunately, the calling module must be changed first --
  502. X *      it is not prepared for the changed window size...)
  503. X */
  504. X
  505. X/*
  506. X * Includes and data definitions.
  507. X */
  508. X
  509. X#include "b.h"
  510. X
  511. X#ifndef TERMIO
  512. X#include <sgtty.h>
  513. X#else
  514. X#include <termio.h>
  515. X#endif
  516. X
  517. X#include "trm.h"
  518. X
  519. X#ifdef SIGNAL
  520. X#include <signal.h>
  521. X#endif
  522. X#ifdef SETJMP
  523. X#include <setjmp.h>
  524. X#endif
  525. X
  526. Xchar *malloc();
  527. X
  528. Xchar *getenv();
  529. Xint tgetent();
  530. Xint tgetnum();
  531. Xint tgetflag();
  532. Xchar *tgetstr();
  533. X
  534. X#define Min(a,b) ((a) <= (b) ? (a) : (b))
  535. X
  536. X/* tty modes */
  537. X#ifndef TERMIO
  538. X
  539. X/* v7/BSD tty control */
  540. XHidden struct sgttyb oldtty, newtty;
  541. X#ifdef TIOCSETN
  542. X/* Redefine stty to use TIOCSETN, so type-ahead is not flushed */
  543. X#define stty(fd, bp) VOID ioctl(fd, TIOCSETN, (char *) bp)
  544. X#endif
  545. X
  546. X#ifdef TIOCSLTC /* BSD -- local special chars, must all be turned off */
  547. Xstatic struct ltchars oldltchars;
  548. Xstatic struct ltchars newltchars= {-1, -1, -1, -1, -1, -1};
  549. X#endif /* TIOCSLTC */
  550. X
  551. X#ifdef TIOCSETC /* V7 -- standard special chars, some must be turned off too */
  552. Xstatic struct tchars oldtchars;
  553. Xstatic struct tchars newtchars;
  554. X#endif /* TIOCSETC */
  555. X
  556. X#else /* TERMIO */
  557. X
  558. X/* AT&T tty control */
  559. XHidden struct termio oldtty, newtty;
  560. X#define gtty(fd,bp) ioctl(fd, TCGETA, (char *) bp)
  561. X#define stty(fd,bp) VOID ioctl(fd, TCSETAW, (char *) bp)
  562. X
  563. X#endif /* TERMIO */
  564. X
  565. X#ifdef VTRMTRACE
  566. Xextern FILE *vtrmfp;
  567. X#endif
  568. X
  569. XHidden bool know_ttys = No;
  570. X
  571. X/* visible data for termcap */
  572. Xchar PC;
  573. Xchar *BC;
  574. Xchar *UP;
  575. Xshort ospeed;
  576. X
  577. XHidden FILE *fp= NULL;
  578. XForward int outchar();         /* procedure for termcap's tputs */
  579. X#define Putstr(str)    tputs((str), 1, outchar)
  580. Xextern char *tgoto();
  581. X
  582. X/* termcap terminal capabilities */
  583. X
  584. XHidden int lines;
  585. XHidden int cols;
  586. X
  587. X/*
  588. X * String-valued capabilities are saved in one big array.
  589. X * Extend this only at the end (even though it disturbs the sorting)
  590. X * because otherwise you have to change all macros...
  591. X */
  592. X
  593. X#define par_al_str strcaps[0]    /* parametrized al (AL) */
  594. X#define cap_cm_str strcaps[1]    /* screen-relative cursor motion (CM) */
  595. X#define par_dl_str strcaps[2]    /* parametrized dl (DL) */
  596. X#define al_str strcaps[3]     /* add new blank line */
  597. X#define cd_str strcaps[4]     /* clear to end of display */
  598. X#define ce_str strcaps[5]     /* clear to end of line */
  599. X#define cl_str strcaps[6]     /* cursor home and clear screen */
  600. X#define cm_str strcaps[7]     /* cursor motion */
  601. X#define cp_str strcaps[8]    /* cursor position sense reply */
  602. X#define cr_str strcaps[9]     /* carriage return */
  603. X#define cs_str strcaps[10]     /* change scrolling region */
  604. X#define dc_str strcaps[11]     /* delete character */
  605. X#define dl_str strcaps[12]     /* delete line */
  606. X#define dm_str strcaps[13]     /* enter delete mode */
  607. X#define do_str strcaps[14]     /* cursor down one line */
  608. X#define ed_str strcaps[15]     /* end delete mode */
  609. X#define ei_str strcaps[16]     /* end insert mode */
  610. X#define ho_str strcaps[17]    /* cursor home */
  611. X#define ic_str strcaps[18]     /* insert character (if necessary; may pad) */
  612. X#define im_str strcaps[19]     /* enter insert mode */
  613. X#define nd_str strcaps[20]     /* cursor right (non-destructive space) */
  614. X#define nl_str strcaps[21]    /* newline */
  615. X#define se_str strcaps[22]     /* end standout mode */
  616. X#define sf_str strcaps[23]     /* scroll text up (from bottom of region) */
  617. X#define so_str strcaps[24]     /* begin standout mode */
  618. X#define sp_str strcaps[25]    /* sense cursor position */
  619. X#define sr_str strcaps[26]     /* scroll text down (from top of region) */
  620. X#define te_str strcaps[27]     /* end termcap */
  621. X#define ti_str strcaps[28]     /* start termcap */
  622. X#define vb_str strcaps[29]     /* visible bell */
  623. X#define ve_str strcaps[30]     /* make cursor visible again */
  624. X#define vi_str strcaps[31]     /* make cursor invisible */
  625. X#define le_str strcaps[32]     /* cursor left */
  626. X#define bc_str strcaps[33]    /* backspace character */
  627. X#define up_str strcaps[34]     /* cursor up */
  628. X#define pc_str strcaps[35]    /* pad character */
  629. X#define ks_str strcaps[36]    /* keypad mode start */
  630. X#define ke_str strcaps[37]    /* keypad mode end */
  631. X#define us_str strcaps[38]    /* start underscore mode */
  632. X#define ue_str strcaps[39]    /* end underscore mode */
  633. X/* Insert new entries here only! Don't forget to change the next line! */
  634. X#define NSTRCAPS 40 /* One more than the last entry's index */
  635. X
  636. XHidden char *strcaps[NSTRCAPS];
  637. XHidden char strcapnames[] =
  638. X"ALCMDLalcdceclcmcpcrcsdcdldmdoedeihoicimndnlsesfsospsrtetivbvevilebcuppckskeusue";
  639. X
  640. X/* Same for Boolean-valued capabilities */
  641. X
  642. X#define has_am flagcaps[0]    /* has automatic margins */
  643. X#define has_da flagcaps[1]    /* display may be retained above screen */
  644. X#define has_db flagcaps[2]    /* display may be retained below screen */
  645. X#define has_in flagcaps[3]    /* not safe to have null chars on the screen */
  646. X#define has_mi flagcaps[4]    /* move safely in insert (and delete?) mode */
  647. X#define has_ms flagcaps[5]    /* move safely in standout mode */
  648. X#define has_xs flagcaps[6]    /* standout not erased by overwriting */
  649. X#define has_bs flagcaps[7]    /* terminal can backspace */
  650. X#define hardcopy flagcaps[8]    /* hardcopy terminal */
  651. X#define has_xn flagcaps[9]    /* Vt100 / Concept glitch */
  652. X#define NFLAGS 10
  653. X
  654. XHidden char flagcaps[NFLAGS];
  655. XHidden char flagnames[]= "amdadbinmimsxsbshcxn";
  656. X
  657. XHidden Procedure getcaps(parea) register char **parea; {
  658. X    register char *capname;
  659. X    register char **capvar;
  660. X    register char *flagvar;
  661. X
  662. X    for (capname= flagnames, flagvar= flagcaps;
  663. X            *capname != '\0'; capname += 2, ++flagvar)
  664. X        *flagvar= tgetflag(capname);
  665. X
  666. X    for (capname= strcapnames, capvar= strcaps;
  667. X            *capname != '\0'; capname += 2, ++capvar)
  668. X        *capvar= tgetstr(capname, parea);
  669. X}
  670. X
  671. X/* terminal status */
  672. X
  673. X/* calling order of Visible Procs */
  674. XHidden bool started = No;
  675. X
  676. X/* to exports the capabilities mentioned in vtrm.h: */
  677. XHidden int flags = 0;
  678. X
  679. X/* cost for impossible operations */
  680. X#define Infinity 9999
  681. X    /* Allow for adding Infinity+Infinity within range */
  682. X    /* (Range is assumed at least 2**15 - 1) */
  683. X
  684. X/* The following for all sorts of undefined things (except for UNKNOWN char) */
  685. X#define Undefined (-1)
  686. X
  687. X/* current mode of putting char's */
  688. X#define Normal    0
  689. X#define Insert    1
  690. X#define    Delete    2
  691. XHidden short mode = Normal;
  692. X
  693. X/* current standout mode */
  694. X#define Off    0
  695. X#define On    0200
  696. XHidden short so_mode = Off;
  697. X
  698. X/* masks for char's and short's */
  699. X#define NULCHAR    '\000'
  700. X#define CHAR    0177
  701. X#define SOBIT    On
  702. X#define SOCHAR    0377
  703. X/* if (has_xs) record cookies placed on screen in extra bit */
  704. X/* type of cookie is determined by the SO bit */
  705. X#define XSBIT    0400
  706. X#define SOCOOK    0600
  707. X#define COOKBITS SOCOOK
  708. X#define UNKNOWN    1
  709. X#define NOCOOK    UNKNOWN
  710. X
  711. X/* current cursor position */
  712. XHidden short cur_y = Undefined, cur_x = Undefined;
  713. X
  714. X/* "line[y][x]" holds the char on the terminal, with the SOBIT and XSBIT.
  715. X * the SOBIT tells whether the character is standing out, the XSBIT whether
  716. X * there is a cookie on the screen at this position.
  717. X * In particular a standend-cookie may be recorded AFTER the line
  718. X * (just in case some trmputdata will write after that position).
  719. X * "lenline[y]" holds the length of the line.
  720. X * Unknown chars will be 1, so the optimising compare in putline will fail.
  721. X * (Partially) empty lines are distinghuished by "lenline[y] < cols".
  722. X */
  723. XHidden short **line = 0, *lenline = 0;
  724. X
  725. X/* Clear the screen initially iff only memory cursor addressing available */
  726. XHidden bool mustclear = No;
  727. X
  728. X/* Make the cursor invisible when trmsync() tries to move outside the screen */
  729. XHidden bool no_cursor = No;
  730. X
  731. X/* Optimise cursor motion */
  732. XHidden int abs_cost;         /* cost of absolute cursor motion */
  733. XHidden int cr_cost;         /* cost of carriage return */
  734. XHidden int do_cost;         /* cost of down */
  735. XHidden int le_cost;         /* cost of left */
  736. XHidden int nd_cost;         /* cost of right */
  737. XHidden int up_cost;         /* cost of up */
  738. X
  739. X/* Optimise trailing match in put_line, iff the terminal can insert and delete
  740. X * characters; the cost per n characters will be:
  741. X *     n * MultiplyFactor + OverHead
  742. X */
  743. XHidden int ins_mf, ins_oh, del_mf, del_oh;
  744. XHidden int ed_cost, ei_cost;         /* used in move() */
  745. X
  746. X/* The type of scrolling possible determines which routines get used;
  747. X * these may be:
  748. X * (1) with addline and deleteline (termcap: al_str & dl_str);
  749. X * (2) with a settable scrolling region, like VT100 (cs_str, sr_str, sf_str);
  750. X * (3) no scrolling available. (NOT YET IMPLEMENTED)
  751. X */
  752. XHidden Procedure (*scr_up)();
  753. XHidden Procedure (*scr_down)();
  754. XForward Procedure scr1up();
  755. XForward Procedure scr1down();
  756. XForward Procedure scr2up();
  757. XForward Procedure scr2down();
  758. X/*Forward Procedure scr3up(); */
  759. X/*Forward Procedure scr3down(); */
  760. X
  761. X/*
  762. X * Starting, Ending and (fatal) Error.
  763. X */
  764. X
  765. X/* 
  766. X * Initialization call.
  767. X * Determine terminal capabilities from termcap.
  768. X * Set up tty modes.
  769. X * Start up terminal and internal administration.
  770. X * Return 0 if all well, error code if in trouble.
  771. X */
  772. XVisible int trmstart(plines, pcols, pflags) int *plines, *pcols, *pflags; {
  773. X    register int err;
  774. X
  775. X#ifdef VTRMTRACE
  776. X    if (vtrmfp) putstr(vtrmfp, "\ttrmstart(&li, &co, &fl);\n");
  777. X#endif
  778. X    if (started)
  779. X        return TE_TWICE;
  780. X    err= getttyfp();
  781. X    if (err != TE_OK)
  782. X        return err;
  783. X    err= gettermcaps();
  784. X    if (err != TE_OK)
  785. X        return err;
  786. X    err= setttymode();
  787. X    if (err != TE_OK)
  788. X        return err;
  789. X    err= start_trm();
  790. X    if (err != TE_OK) {
  791. X        trmend();
  792. X        return err;
  793. X    }
  794. X
  795. X    *plines = lines;
  796. X    *pcols = cols;
  797. X    *pflags = flags;
  798. X
  799. X    started = Yes;
  800. X    
  801. X    trmsync(lines-1, 0);
  802. X        /* position for >ws message from initbws()
  803. X         * on vt100's, and for alternate screen buffers
  804. X         */
  805. X    
  806. X    return TE_OK;
  807. X}
  808. X
  809. X/*
  810. X * Termination call.
  811. X * Reset tty modes, etc.
  812. X * Beware that it might be called by a caught interrupt even in the middle
  813. X * of trmstart()!
  814. X */
  815. XVisible Procedure trmend() {
  816. X#ifdef VTRMTRACE
  817. X    if (vtrmfp) putstr(vtrmfp, "\ttrmend();\n");
  818. X#endif
  819. X    set_mode(Normal);
  820. X    if (so_mode != Off)
  821. X        standend();
  822. X    Putstr(ke_str);
  823. X    Putstr(te_str);
  824. X    VOID fflush(fp);
  825. X    resetttymode();
  826. X
  827. X    started = No;
  828. X}
  829. X
  830. X/*
  831. X * Set all internal statuses to undefined, especially the contents of
  832. X * the screen, so a hard redraw will not be optimised to heaven.
  833. X */
  834. XVisible Procedure trmundefined() {
  835. X    register int y, x;
  836. X#ifdef VTRMTRACE
  837. X    if (vtrmfp) putstr(vtrmfp, "\ttrmundefined();\n");
  838. X#endif
  839. X
  840. X    cur_y = cur_x = Undefined;
  841. X    mode = so_mode = Undefined;
  842. X    
  843. X    for (y = 0; y < lines; y++) {
  844. X        for (x = 0; x <= cols; x++)
  845. X            line[y][x] = 1; /* impossible char, no so bits */
  846. X        lenline[y] = cols;
  847. X    }
  848. X}
  849. X
  850. X#ifdef VTRMTRACE
  851. X
  852. XHidden Procedure check_started(m) char *m; {
  853. X    if (!started) {
  854. X        trmend();
  855. X        if (vtrmfp) putstr(vtrmfp, "bad VTRM call\n");
  856. X        abort();
  857. X    }
  858. X}
  859. X#else
  860. X
  861. X#define check_started(m) /*empty*/
  862. X
  863. X#endif /* NDEBUG */
  864. X
  865. XHidden int getttyfp() {
  866. X    if (fp != NULL)    /* already initialised */
  867. X        return TE_OK;
  868. X    fp= fopen("/dev/tty", "w");
  869. X    if (fp == NULL)
  870. X        return TE_NOTTY;
  871. X    return TE_OK;
  872. X}
  873. X
  874. XHidden int ccc;
  875. X
  876. X/*ARGSUSED*/
  877. XHidden Procedure countchar(ch) char ch; {
  878. X    ccc++;
  879. X}
  880. X
  881. XHidden int strcost(str) char *str; {
  882. X    if (str == NULL)
  883. X        return Infinity;
  884. X    return str0cost(str);
  885. X}
  886. X
  887. XHidden int str0cost(str) char *str; {
  888. X    ccc = 0;
  889. X    tputs(str, 1, countchar);
  890. X    return ccc;
  891. X}
  892. X
  893. X/*
  894. X * Get terminal capabilities from termcap and compute related static
  895. X * properties.  Return TE_OK if all well, error code otherwise.
  896. X */
  897. X
  898. XHidden int gettermcaps() {
  899. X    string trmname;
  900. X    char tc_buf[1024];
  901. X    static char strbuf[1024];
  902. X    char *area = strbuf;
  903. X    int sg;
  904. X    static bool tc_initialized = No;
  905. X
  906. X    if (tc_initialized)
  907. X        return TE_OK;
  908. X    
  909. X    trmname=getenv("TERM");
  910. X    if (trmname == NULL || trmname[0] == '\0')
  911. X        return TE_NOTERM;
  912. X    if (tgetent(tc_buf, trmname) != 1)
  913. X        return TE_BADTERM;
  914. X
  915. X    getcaps(&area); /* Read all flag and string type capabilities */
  916. X    if (hardcopy)
  917. X        return TE_DUMB;
  918. X    BC = le_str;
  919. X    if (BC == NULL) {
  920. X        BC = bc_str;
  921. X        if (BC == NULL) {
  922. X            if (has_bs)
  923. X                BC = "\b";
  924. X            else
  925. X                return TE_DUMB;
  926. X        }
  927. X    }
  928. X    UP = up_str;
  929. X    if (UP == NULL)
  930. X        return TE_DUMB;
  931. X    PC = (pc_str != NULL? pc_str[0] : NULCHAR);
  932. X
  933. X    if (cm_str == NULL) {
  934. X        cm_str = cap_cm_str;
  935. X        if (cm_str == NULL) {
  936. X            if (ho_str == NULL || do_str == NULL || nd_str == NULL)
  937. X                return TE_DUMB;
  938. X        }
  939. X        else
  940. X            mustclear = Yes;
  941. X    }
  942. X    if (al_str && dl_str) {
  943. X        scr_up = scr1up;
  944. X        scr_down = scr1down;
  945. X        flags |= CAN_SCROLL;
  946. X    }
  947. X    else {
  948. X        if (sf_str == NULL)
  949. X            sf_str = "\n";
  950. X        if (cs_str && sr_str) {
  951. X            scr_up = scr2up;
  952. X            scr_down = scr2down;
  953. X            flags |= CAN_SCROLL;
  954. X        }
  955. X        else
  956. X            return TE_DUMB;
  957. X    }
  958. X        
  959. X    lines = tgetnum("li");
  960. X    cols = tgetnum("co");
  961. X    if (lines <= 0) lines = 24;
  962. X    if (cols <= 0) cols = 80;
  963. X    
  964. X    if (!ce_str)
  965. X        return TE_DUMB;
  966. X    if (cr_str == NULL) cr_str = "\r";
  967. X    if (do_str == NULL) {
  968. X        do_str = nl_str;
  969. X        if (do_str == NULL) do_str = "\n";
  970. X    }
  971. X    le_str = BC;
  972. X    up_str = UP;
  973. X    if (vb_str == NULL)     /* then we will do with the audible bell */
  974. X        vb_str = "\007";
  975. X    
  976. X    /* cursor sensing (non standard) */
  977. X    if (cp_str != NULL && sp_str != NULL)
  978. X        flags |= CAN_SENSE;
  979. X
  980. X    if (so_str != NULL && se_str != NULL && (sg=tgetnum("sg")) <= 0) {
  981. X        if (sg == 0)
  982. X            has_xs = Yes;
  983. X        flags |= HAS_STANDOUT;
  984. X    }
  985. X    else if (us_str != NULL && ue_str != NULL) {
  986. X        so_str = us_str; se_str = ue_str;
  987. X        flags |= HAS_STANDOUT;
  988. X    }
  989. X    else
  990. X        return TE_DUMB;
  991. X
  992. X    /* calculate costs of local and absolute cursor motions */
  993. X    if (cm_str == NULL)
  994. X        abs_cost = Infinity;
  995. X    else
  996. X        abs_cost = strcost(tgoto(cm_str, 0, 0));
  997. X    cr_cost = strcost(cr_str);
  998. X    do_cost = strcost(do_str);
  999. X    le_cost = strcost(le_str);
  1000. X    nd_cost = strcost(nd_str);
  1001. X    up_cost = strcost(up_str);
  1002. X
  1003. X    /* cost of leaving insert or delete mode, used in move() */
  1004. X    ei_cost = str0cost(ei_str);
  1005. X    ed_cost = str0cost(ed_str);
  1006. X    
  1007. X    /* calculate insert and delete cost multiply_factor and overhead */
  1008. X    if (((im_str && ei_str) || ic_str) && dc_str) {
  1009. X        flags |= CAN_OPTIMISE;
  1010. X        ins_mf = 1 + str0cost(ic_str);
  1011. X        ins_oh = str0cost(im_str) + ei_cost;
  1012. X        del_mf = str0cost(dc_str);
  1013. X        del_oh = str0cost(dm_str) + ed_cost;
  1014. X    }
  1015. X        
  1016. X    tc_initialized = Yes;
  1017. X    return TE_OK;
  1018. X}
  1019. X
  1020. XHidden char intrchar;
  1021. X#ifdef SIGTSTP
  1022. XHidden char suspchar;
  1023. X#endif
  1024. X
  1025. XHidden int setttymode() {
  1026. X    if (!know_ttys) {
  1027. X        if (gtty(0, &oldtty) != 0 || gtty(0, &newtty) != 0)
  1028. X            return TE_NOTTY;
  1029. X#ifndef TERMIO
  1030. X        ospeed = oldtty.sg_ospeed;
  1031. X        newtty.sg_flags = (newtty.sg_flags & ~ECHO & ~CRMOD & ~XTABS)
  1032. X                  | CBREAK;
  1033. X#ifdef TIOCSLTC
  1034. X        VOID ioctl(0, TIOCGLTC, (char *) &oldltchars);
  1035. X#endif
  1036. X#ifdef TIOCSETC
  1037. X        VOID ioctl(0, TIOCGETC, (char *) &oldtchars);
  1038. X#endif
  1039. X
  1040. X#else /* TERMIO */
  1041. X        ospeed= oldtty.c_lflag & CBAUD;
  1042. X        newtty.c_iflag &= ~ICRNL; /* No CR->NL mapping on input */
  1043. X        newtty.c_oflag &= ~ONLCR; /* NL doesn't output CR */
  1044. X#ifndef KEYS
  1045. X        newtty.c_lflag &= ~(ICANON|ECHO);
  1046. X                /* No line editing, no echo */
  1047. X        newtty.c_cc[VQUIT]= 0377; /* no quit signal */
  1048. X#ifdef VSUSP
  1049. X        newtty.c_cc[VSUSP]= 0377; /* no susp signal */
  1050. X#endif
  1051. X#else
  1052. X        newtty.c_lflag &= ~(ICANON|ECHO|ISIG);
  1053. X                /* No line editing, no echo, 
  1054. X                 * no quit, intr or susp signals */
  1055. X#endif /* KEYS */
  1056. X        newtty.c_cc[VMIN]= 3; /* wait for 3 characters */
  1057. X        newtty.c_cc[VTIME]= 1; /* or 0.1 sec. */
  1058. X#endif /* TERMIO */
  1059. X        know_ttys = Yes;
  1060. X    }
  1061. X    stty(0, &newtty);
  1062. X#ifndef TERMIO
  1063. X#ifdef TIOCSLTC
  1064. X    newltchars.t_suspc= oldltchars.t_suspc;
  1065. X#ifdef SIGTSTP
  1066. X    suspchar= oldltchars.t_suspc;
  1067. X#endif
  1068. X    VOID ioctl(0, TIOCSLTC, (char *) &newltchars);
  1069. X#endif
  1070. X#ifdef TIOCSETC
  1071. X    VOID ioctl(0, TIOCGETC, (char *) &newtchars);
  1072. X#ifndef KEYS
  1073. X    intrchar= newtchars.t_intrc;
  1074. X#else
  1075. X    newtchars.t_intrc= -1;
  1076. X#endif
  1077. X    newtchars.t_quitc= -1;
  1078. X    newtchars.t_eofc= -1;
  1079. X    newtchars.t_brkc= -1;
  1080. X    VOID ioctl(0, TIOCSETC, (char *) &newtchars);
  1081. X#endif /* TIOCSETC */
  1082. X#endif /* TERMIO */
  1083. X    return TE_OK;
  1084. X}
  1085. X
  1086. XHidden Procedure resetttymode() {
  1087. X    if (know_ttys) {
  1088. X        stty(0, &oldtty);
  1089. X#ifndef TERMIO
  1090. X#ifdef TIOCSLTC
  1091. X        VOID ioctl(0, TIOCSLTC, (char *) &oldltchars);
  1092. X#endif
  1093. X#ifdef TIOCSETC
  1094. X        VOID ioctl(0, TIOCSETC, (char *) &oldtchars);
  1095. X#endif
  1096. X#endif /* TERMIO */
  1097. X        know_ttys= No;
  1098. X    }
  1099. X}
  1100. X
  1101. XHidden int start_trm() {
  1102. X    register int y;
  1103. X#ifdef TIOCGWINSZ
  1104. X    struct winsize win;
  1105. X
  1106. X    if (ioctl(0, TIOCGWINSZ, (char*)&win) == 0) {
  1107. X        if (win.ws_col > 0 && ((int) win.ws_col) != cols
  1108. X            ||
  1109. X            win.ws_row > 0 && ((int) win.ws_row) != lines) {
  1110. X            /* Window size has changed.
  1111. X               Release previously allocated buffers. */
  1112. X            if (line != NULL) {
  1113. X                for (y= 0; y < lines; ++y)
  1114. X                    free((char *) line[y]);
  1115. X                free((char *) line);
  1116. X                line= NULL;
  1117. X            }
  1118. X            if (lenline != NULL) {
  1119. X                free((char *) lenline);
  1120. X                lenline= NULL;
  1121. X            }
  1122. X        }
  1123. X        if (((int)win.ws_col) > 0)
  1124. X            cols = win.ws_col;
  1125. X        if (((int)win.ws_row) > 0)
  1126. X            lines = win.ws_row;
  1127. X    }
  1128. X#endif
  1129. X    if (line == NULL) {
  1130. X        if ((line = (short**) malloc(lines * sizeof(short*))) == NULL)
  1131. X            return TE_NOMEM;
  1132. X        for (y = 0; y < lines; y++) {
  1133. X            if ((line[y] = (short*)
  1134. X                malloc((cols+1) * sizeof(short))) == NULL)
  1135. X                return TE_NOMEM;
  1136. X        }
  1137. X    }
  1138. X    if (lenline == NULL) {
  1139. X        if ((lenline = (short*) malloc(lines * sizeof(short))) == NULL)
  1140. X            return TE_NOMEM;
  1141. X    }
  1142. X
  1143. X    trmundefined();
  1144. X
  1145. X    Putstr(ti_str);
  1146. X    Putstr(ks_str);
  1147. X    if (cs_str)
  1148. X        Putstr(tgoto(cs_str, lines-1, 0));
  1149. X    if (mustclear)
  1150. X        clear_lines(0, lines-1);
  1151. X    VOID fflush(fp);
  1152. X    
  1153. X    return TE_OK;
  1154. X}
  1155. X
  1156. X
  1157. X/*
  1158. X * Sensing and moving the cursor.
  1159. X */
  1160. X
  1161. X/*
  1162. X * Sense the current (y, x) cursor position, after a possible manual
  1163. X * change by the user with local cursor motions.
  1164. X * If the terminal cannot be asked for the current cursor position,
  1165. X * or if the string returned by the terminal is garbled,
  1166. X * the position is made Undefined.
  1167. X */
  1168. X
  1169. XVisible Procedure trmsense(py, px) int *py, *px; {
  1170. X    bool get_pos();
  1171. X
  1172. X#ifdef VTRMTRACE
  1173. X    if (vtrmfp) putstr(vtrmfp, "\ttrmsense(&yy, &xx);\n");
  1174. X#endif
  1175. X    check_started("trmsense");
  1176. X
  1177. X    *py = *px = Undefined;
  1178. X    set_mode(Normal);
  1179. X    if (so_mode != Off)
  1180. X        standend();
  1181. X    
  1182. X    if (flags&CAN_SENSE && get_pos(py, px)) {
  1183. X        if (*py < 0 || lines <= *py || *px < 0 || cols <= *px)
  1184. X            *py = *px = Undefined;
  1185. X    }
  1186. X    cur_y = Undefined;
  1187. X    cur_x = Undefined;
  1188. X}
  1189. X
  1190. XHidden bool get_pos(py, px) int *py, *px; {
  1191. X    char *format = cp_str;
  1192. X    int fc;         /* current format character */
  1193. X    int ic;         /* current input character */
  1194. X    int num;
  1195. X    int on_y = 1;
  1196. X    bool incr_orig = No;
  1197. X    int i, ni;
  1198. X
  1199. X    Putstr(sp_str);
  1200. X    VOID fflush(fp);
  1201. X
  1202. X    while (fc = *format++) {
  1203. X        if (fc != '%') {
  1204. X            if (trminput() != fc)
  1205. X                return No;
  1206. X        }
  1207. X        else {
  1208. X            switch (fc = *format++) {
  1209. X            case '%':
  1210. X                if (trminput() != '%')
  1211. X                    return No;
  1212. X                continue;
  1213. X            case 'r':
  1214. X                on_y = 1 - on_y;
  1215. X                continue;
  1216. X            case 'i':
  1217. X                incr_orig = Yes;
  1218. X                continue;
  1219. X            case 'd':
  1220. X                ic = trminput();
  1221. X                if (!isdigit(ic))
  1222. X                    return No;
  1223. X                num = ic - '0';
  1224. X                while (isdigit(ic=trminput()))
  1225. X                    num = 10*num + ic - '0';
  1226. X                trmpushback(ic);
  1227. X                break;
  1228. X            case '2':
  1229. X            case '3':
  1230. X                ni = fc - '0';
  1231. X                    num = 0;
  1232. X                for (i=0; i<ni; i++) {
  1233. X                    ic = trminput();
  1234. X                    if (isdigit(ic))
  1235. X                        num = 10*num + ic - '0';
  1236. X                    else
  1237. X                        return No;
  1238. X                }
  1239. X                break;
  1240. X            case '+':
  1241. X                num = trminput() - *format++;
  1242. X                break;
  1243. X            case '-':
  1244. X                num = trminput() + *format++;
  1245. X                break;
  1246. X            default:
  1247. X                return No;
  1248. X            }
  1249. X            /* assign num to parameter */
  1250. X            if (incr_orig)
  1251. X                num--;
  1252. X            if (on_y)
  1253. X                *py = num;
  1254. X            else
  1255. X                *px = num;
  1256. X            on_y = 1 - on_y;
  1257. X        }
  1258. X    }
  1259. X
  1260. X    return Yes;
  1261. X}
  1262. X        
  1263. X/* 
  1264. X * To move over characters by rewriting them, we have to check:
  1265. X * (1) that the screen has been initialised on these positions;
  1266. X * (2) we do not screw up characters
  1267. X * when rewriting line[y] from x_from upto x_to
  1268. X */
  1269. XHidden bool rewrite_ok(y, xfrom, xto) int y, xfrom, xto; {
  1270. X    register short *plnyx, *plnyto;
  1271. X    
  1272. X    if (xto > lenline[y])
  1273. X        return No;
  1274. X
  1275. X    plnyto = &line[y][xto];
  1276. X    for (plnyx = &line[y][xfrom]; plnyx <= plnyto; plnyx++)
  1277. X        if (*plnyx == UNKNOWN
  1278. X            ||
  1279. X            (!has_xs && (*plnyx & SOBIT) != so_mode)
  1280. X           )
  1281. X            return No;
  1282. X    return Yes;
  1283. X}
  1284. X        
  1285. X/*
  1286. X * Move to position y,x on the screen
  1287. X */
  1288. X/* possible move types for y and x respectively: */
  1289. X#define None    0
  1290. X#define Down    1
  1291. X#define Up    2
  1292. X#define Right    1
  1293. X#define ReWrite    2
  1294. X#define Left    3
  1295. X#define CrWrite    4
  1296. X
  1297. XHidden Procedure move(y, x) int y, x; {
  1298. X    int dy, dx;
  1299. X    int y_cost, x_cost, y_move, x_move;
  1300. X    int mode_cost;
  1301. X    int xi;
  1302. X    
  1303. X    if (cur_y == y && cur_x == x)
  1304. X        return;
  1305. X    
  1306. X    if (!has_mi || mode == Undefined)
  1307. X        set_mode(Normal);
  1308. X    if (!has_xs && ((!has_ms && so_mode != Off) || so_mode == Undefined))
  1309. X        standend();
  1310. X    
  1311. X    if (cur_y == Undefined || cur_x == Undefined)
  1312. X        goto absmove;
  1313. X    
  1314. X    dy = y - cur_y;
  1315. X    dx = x - cur_x;
  1316. X
  1317. X    if (dy > 0) {
  1318. X        y_move = Down;
  1319. X        y_cost = dy * do_cost;
  1320. X    }
  1321. X    else if (dy < 0) {
  1322. X        y_move = Up;
  1323. X        y_cost = -dy * up_cost;
  1324. X    }
  1325. X    else {
  1326. X        y_move = None;
  1327. X        y_cost = 0;
  1328. X    }
  1329. X    if (y_cost < abs_cost) {
  1330. X        switch (mode) {
  1331. X        case Normal:
  1332. X            mode_cost = 0;
  1333. X            break;
  1334. X        case Insert:
  1335. X            mode_cost = ei_cost;
  1336. X            break;
  1337. X        case Delete:
  1338. X            mode_cost = ed_cost;
  1339. X            break;
  1340. X        }
  1341. X        if (dx > 0) {
  1342. X            x_cost = dx + mode_cost;
  1343. X            if (dx*nd_cost < x_cost || !rewrite_ok(y, cur_x, x)) {
  1344. X                x_cost = dx * nd_cost;
  1345. X                x_move = Right;
  1346. X            }
  1347. X            else
  1348. X                x_move = ReWrite;
  1349. X        }
  1350. X        else if (dx < 0) {
  1351. X            x_cost = -dx * le_cost;
  1352. X            x_move = Left;
  1353. X        }
  1354. X        else {
  1355. X            x_cost = 0;
  1356. X            x_move = None;
  1357. X        }
  1358. X        if (cr_cost + x + mode_cost < x_cost && rewrite_ok(y, 0, x)) {
  1359. X            x_move = CrWrite;
  1360. X            x_cost = cr_cost + x + mode_cost;
  1361. X        }
  1362. X    }
  1363. X    else
  1364. X        x_cost = abs_cost;
  1365. X
  1366. X    if (y_cost + x_cost < abs_cost) {
  1367. X        switch (y_move) {
  1368. X        case Down:
  1369. X            while (dy-- > 0) Putstr(do_str);
  1370. X            break;
  1371. X        case Up:
  1372. X            while (dy++ < 0) Putstr(up_str);
  1373. X            break;
  1374. X        }
  1375. X        switch (x_move) {
  1376. X        case Right:
  1377. X            while (dx-- > 0) Putstr(nd_str);
  1378. X            break;
  1379. X        case Left:
  1380. X            while (dx++ < 0) Putstr(le_str);
  1381. X            break;
  1382. X        case CrWrite:
  1383. X            Putstr(cr_str);
  1384. X            cur_x = 0;
  1385. X            /* FALL THROUGH */
  1386. X        case ReWrite:
  1387. X            set_mode(Normal);
  1388. X            for (xi = cur_x; xi < x; xi++)
  1389. X                fputc(line[y][xi], fp);
  1390. X            break;
  1391. X        }
  1392. X    }
  1393. X    else
  1394. X    {
  1395. X    absmove:
  1396. X        if (cm_str == NULL) {
  1397. X            Putstr(ho_str);
  1398. X            for (cur_y = 0; cur_y < y; ++cur_y)
  1399. X                Putstr(do_str);
  1400. X            /* Should try to use tabs here: */
  1401. X            for (cur_x = 0; cur_x < x; ++cur_x)
  1402. X                Putstr(nd_str);
  1403. X        }
  1404. X        else
  1405. X            Putstr(tgoto(cm_str, x, y));
  1406. X    }
  1407. X    
  1408. X    cur_y = y;
  1409. X    cur_x = x;
  1410. X}
  1411. X
  1412. X
  1413. X/*
  1414. X * Putting data on the screen.
  1415. X */
  1416. X
  1417. X/*
  1418. X * Fill screen area with given data.
  1419. X * Characters with the SO-bit (0200) set are put in standout mode.
  1420. X */
  1421. XVisible Procedure trmputdata(yfirst, ylast, indent, data) int yfirst, ylast;
  1422. X        register int indent; register string data; {
  1423. X    register int y;
  1424. X    int x, len, lendata, space;
  1425. X
  1426. X#ifdef VTRMTRACE
  1427. X    if (vtrmfp) put3DSstr(vtrmfp, "\ttrmputdata(%d, %d, %d, \"%s\");\n", yfirst, ylast, indent, data);
  1428. X#endif
  1429. X    check_started("trmputdata");
  1430. X    
  1431. X    if (yfirst < 0)
  1432. X        yfirst = 0;
  1433. X    if (ylast >= lines)
  1434. X        ylast = lines-1;
  1435. X    space = cols*(ylast-yfirst+1) - indent;
  1436. X    if (space <= 0)
  1437. X        return;
  1438. X    yfirst += indent/cols;
  1439. X    indent %= cols;
  1440. X    y= yfirst;
  1441. X    if (!data)
  1442. X        data= ""; /* Safety net */
  1443. X    x = indent;
  1444. X    lendata = strlen(data);
  1445. X    if (ylast == lines-1 && lendata >= space)
  1446. X        lendata = space - 1;
  1447. X    len = Min(lendata, cols-x);
  1448. X    while (y <= ylast) {
  1449. X        put_line(y, x, data, len);
  1450. X        y++;
  1451. X        lendata -= len;
  1452. X        if (lendata > 0) {
  1453. X            x = 0;
  1454. X            data += len;
  1455. X            len = Min(lendata, cols);
  1456. X        }
  1457. X        else
  1458. X            break;
  1459. X    }
  1460. X    if (y <= ylast)
  1461. X        clear_lines(y, ylast);
  1462. X}
  1463. X
  1464. X/* 
  1465. X * We will first try to get the picture:
  1466. X *
  1467. X *                  op>>>>>>>>>>>op          oq<<<<<<<<<<<<<<<<<<<<<<<<oq
  1468. X *                  ^            ^           ^                         ^
  1469. X *           <xskip><-----m1----><----od-----><-----------m2----------->
  1470. X *   OLD:   "You're in a maze of twisty little pieces of code, all alike"
  1471. X *   NEW:          "in a maze of little twisting pieces of code, all alike"
  1472. X *                  <-----m1----><-----nd------><-----------m2----------->
  1473. X *                  ^            ^             ^                         ^
  1474. X *                  np>>>>>>>>>>>np            nq<<<<<<<<<<<<<<<<<<<<<<<<nq
  1475. X * where
  1476. X *    op, oq, np, nq are pointers to start and end of Old and New data,
  1477. X * and
  1478. X *    xskip = length of indent to be skipped,
  1479. X *    m1 = length of Matching part at start,
  1480. X *    od = length of Differing mid on screen,
  1481. X *    nd = length of Differing mid in data to be put,
  1482. X *    m2 = length of Matching trail.
  1483. X *
  1484. X * Then we will try to find a long blank-or-cleared piece in <nd+m2>:
  1485. X *
  1486. X *    <---m1---><---d1---><---nb---><---d2---><---m2--->
  1487. X *              ^         ^         ^        ^         ^
  1488. X *              np        bp        bq1      nq        nend
  1489. X * where
  1490. X *    bp, bq are pointers to start and AFTER end of blank piece,
  1491. X * and
  1492. X *    d1 = length of differing part before blank piece,
  1493. X *    nb = length of blank piece to be skipped,
  1494. X *    d2 = length of differing part after blank piece.
  1495. X * Remarks:
  1496. X *    d1 + nb + d2 == nd,
  1497. X * and
  1498. X *    d2 maybe less than 0.
  1499. X */
  1500. XHidden int put_line(y, xskip, data, len) int y, xskip; string data; int len; {
  1501. X    register short *op, *oq;
  1502. X    register char *np, *nq, *nend;
  1503. X    char *bp, *bq1, *p, *q;
  1504. X    int m1, m2, od, nd, delta, dd, d1, nb, d2;
  1505. X    bool skipping;
  1506. X    int cost, o_cost;     /* normal and optimising cost */
  1507. X    
  1508. X    /* Bugfix GvR 19-June-87: */
  1509. X    while (lenline[y] < xskip)
  1510. X        line[y][lenline[y]++] = ' ';
  1511. X    
  1512. X    /* calculate the magic parameters */
  1513. X    op = &line[y][xskip];
  1514. X    oq = &line[y][lenline[y]-1];
  1515. X    np = data;
  1516. X    nq = nend = data + len - 1;
  1517. X    m1 = m2 = 0;
  1518. X    while ((*op&SOCHAR) == (((short)*np)&SOCHAR) && op <= oq && np <= nq)
  1519. X        op++, np++, m1++;
  1520. X    /* calculate m2, iff we can optimise or line keeps same length: */
  1521. X    if (flags & CAN_OPTIMISE || (oq-op) == (nq-np))
  1522. X        while ((*oq&SOCHAR) == (((short)*nq)&SOCHAR) && op <= oq && np <= nq)
  1523. X            oq--, nq--, m2++;
  1524. X    od = oq - op + 1;
  1525. X    nd = nq - np + 1;
  1526. X    /* now we have the first picture above */
  1527. X
  1528. X    if (od==0 && nd==0)
  1529. X        return;
  1530. X    delta = nd - od;
  1531. X
  1532. X    /* find the blank piece */
  1533. X    p = q = bp = bq1 = np;
  1534. X    oq += m2;         /* back to current eol */
  1535. X    if (delta == 0) /* if no change in linelength */
  1536. X        nend -= m2;    /* don't find blanks in m2 */
  1537. X    if (!has_in) {
  1538. X        while (p <= nend) {
  1539. X            while (q<=nend && *q==' ' && (op>oq || *op==' '))
  1540. X                q++, op++;
  1541. X            if (q - p > bq1 - bp)
  1542. X                bp = p, bq1 = q;
  1543. X            p = ++q;
  1544. X            op++;
  1545. X        }
  1546. X    }
  1547. X    d1 = bp - np;
  1548. X    nb = bq1 - bp;
  1549. X    d2 = nq - bq1 + 1;
  1550. X    
  1551. X    /* what is cheapest:
  1552. X     * ([+m2] means: leave m2 alone if same linelength)
  1553. X     *  normal: put nd[+m2];                       (dd = nd[+m2])
  1554. X     *  skipping: put d1, skip nb, put d2[+m2];    (dd = d2[+m2])
  1555. X     *  optimise: put dd, insert or delete delta.  (dd = min(od,nd))
  1556. X     */
  1557. X    cost = nd + (delta == 0 ? 0 : m2);     /* normal cost */
  1558. X    if (nb > abs_cost || (d1 == 0 && nb > 0)) {
  1559. X        skipping = Yes;
  1560. X        cost -= nb - (d1>0 ? abs_cost : 0); /* skipping cost */
  1561. X        dd = d2;
  1562. X    }
  1563. X    else {
  1564. X        skipping = No;
  1565. X        dd = nd;
  1566. X    }
  1567. X    
  1568. X    if (m2 != 0 && delta != 0) {
  1569. X        /* try optimising */
  1570. X        o_cost = Min(od, nd);
  1571. X        if (delta > 0)
  1572. X            o_cost += delta * ins_mf + ins_oh;
  1573. X        else if (delta < 0)
  1574. X            o_cost += -delta * del_mf + del_oh;
  1575. X        if (o_cost >= cost) {
  1576. X            /* discard m2, no optimise */
  1577. X            dd += m2;
  1578. X            m2 = 0;
  1579. X        }
  1580. X        else {
  1581. X            dd = Min(od, nd);
  1582. X            skipping = No;
  1583. X        }
  1584. X    }
  1585. X
  1586. X    /* and now for the real work */
  1587. X    if (!skipping || d1 > 0)
  1588. X        move(y, xskip + m1);
  1589. X
  1590. X    if (has_xs)
  1591. X        get_so_mode();
  1592. X    
  1593. X    if (skipping) {
  1594. X        if (d1 > 0) {
  1595. X            set_mode(Normal);
  1596. X            put_str(np, d1, No);
  1597. X        }
  1598. X        if (has_xs && so_mode != Off)
  1599. X            standend();
  1600. X        set_blanks(y, xskip+m1+d1, xskip+m1+d1+nb);
  1601. X        if (dd != 0 || delta < 0) {
  1602. X            move(y, xskip+m1+d1+nb);
  1603. X            np = bq1;
  1604. X        }
  1605. X    }
  1606. X    
  1607. X    if (dd > 0) {
  1608. X        set_mode(Normal);
  1609. X        put_str(np, dd, No);
  1610. X    }
  1611. X    
  1612. X    if (m2 > 0) {
  1613. X        if (delta > 0) {
  1614. X            set_mode(Insert);
  1615. X            ins_str(np+dd, delta);
  1616. X        }
  1617. X        else if (delta < 0) {
  1618. X            if (so_mode != Off)
  1619. X                standend();
  1620. X                /* Some terminals fill with standout spaces! */
  1621. X            set_mode(Delete);
  1622. X            del_str(-delta);
  1623. X        }
  1624. X    }
  1625. X    else {
  1626. X        if (delta < 0) {
  1627. X            clr_to_eol();
  1628. X            return;
  1629. X        }
  1630. X    }
  1631. X    
  1632. X    lenline[y] = xskip + len;
  1633. X    if (cur_x == cols) {
  1634. X        if (!has_mi)
  1635. X            set_mode(Normal);
  1636. X        if (!has_ms)
  1637. X            so_mode = Undefined;
  1638. X        if (has_am) {
  1639. X            if (has_xn)
  1640. X                cur_y= Undefined;
  1641. X            else
  1642. X                cur_y++;
  1643. X        }
  1644. X        else
  1645. X            Putstr(cr_str);
  1646. X        cur_x = 0;
  1647. X    }
  1648. X    else if (has_xs) {
  1649. X        if (m2 == 0) {
  1650. X            if (so_mode == On)
  1651. X                standend();
  1652. X        }
  1653. X        else {
  1654. X            if (!(line[cur_y][cur_x] & XSBIT)) {
  1655. X                if (so_mode != (line[cur_y][cur_x] & SOBIT))
  1656. X                    (so_mode ? standend() : standout());
  1657. X            }
  1658. X        }
  1659. X    }
  1660. X}
  1661. X
  1662. XHidden Procedure set_mode(m) int m; {
  1663. X    if (m == mode)
  1664. X        return;
  1665. X    switch (mode) {
  1666. X    case Insert:
  1667. X        Putstr(ei_str);
  1668. X        break;
  1669. X    case Delete:
  1670. X        Putstr(ed_str);
  1671. X        break;
  1672. X    case Undefined:
  1673. X        Putstr(ei_str);
  1674. X        Putstr(ed_str);
  1675. X        break;
  1676. X    }
  1677. X    switch (m) {
  1678. X    case Insert:
  1679. X        Putstr(im_str);
  1680. X        break;
  1681. X    case Delete:
  1682. X        Putstr(dm_str);
  1683. X        break;
  1684. X    }
  1685. X    mode = m;
  1686. X}
  1687. X
  1688. XHidden Procedure get_so_mode() {
  1689. X    if (cur_x >= lenline[cur_y] || line[cur_y][cur_x] == UNKNOWN)
  1690. X        so_mode = Off;
  1691. X    else
  1692. X        so_mode = line[cur_y][cur_x] & SOBIT;
  1693. X}
  1694. X
  1695. XHidden Procedure standout() {
  1696. X    Putstr(so_str);
  1697. X    so_mode = On;
  1698. X    if (has_xs)
  1699. X        line[cur_y][cur_x] |= SOCOOK;
  1700. X}
  1701. X
  1702. XHidden Procedure standend() {
  1703. X    Putstr(se_str);
  1704. X    so_mode = Off;
  1705. X    if (has_xs)
  1706. X        line[cur_y][cur_x] = (line[cur_y][cur_x] & ~SOBIT) | XSBIT;
  1707. X}
  1708. X
  1709. XHidden Procedure put_str(data, n, inserting) char *data; int n; bool inserting; {
  1710. X    register short c, so;
  1711. X    short *ln_y_x, *ln_y_end;
  1712. X    
  1713. X    so = so_mode;
  1714. X    if (has_xs) {
  1715. X        ln_y_x = &line[cur_y][cur_x];
  1716. X        ln_y_end = &line[cur_y][lenline[cur_y]];
  1717. X    }
  1718. X    while (n-- > 0) {
  1719. X        if (has_xs && ln_y_x <= ln_y_end && ((*ln_y_x)&XSBIT))
  1720. X            so = so_mode = (*ln_y_x)&SOBIT;
  1721. X            /* this also checks for the standend cookie AFTER */
  1722. X            /* the line because off the equals sign in <= */
  1723. X        c = ((short)(*data++))&SOCHAR;
  1724. X        if ((c&SOBIT) != so) {
  1725. X            so = c&SOBIT;
  1726. X            so ? standout() : standend();
  1727. X         }
  1728. X        if (inserting)
  1729. X            Putstr(ic_str);
  1730. X        put_c(c);
  1731. X        if (has_xs)
  1732. X            ln_y_x++;
  1733. X    }
  1734. X}
  1735. X
  1736. XHidden Procedure ins_str(data, n) char *data; int n; {
  1737. X    int x;
  1738. X    
  1739. X    /* x will start AFTER the line, because there might be a cookie */
  1740. X    for (x = lenline[cur_y]; x >= cur_x; x--)
  1741. X        line[cur_y][x+n] = line[cur_y][x];
  1742. X    put_str(data, n, Yes);
  1743. X}
  1744. X
  1745. XHidden Procedure del_str(n) int n; {
  1746. X    int x, xto;
  1747. X    
  1748. X    xto = lenline[cur_y] - n; /* again one too far because of cookie */
  1749. X    if (has_xs) {
  1750. X        for (x = cur_x + n; x >= cur_x; x--) {
  1751. X            if (line[cur_y][x] & XSBIT)
  1752. X                break;
  1753. X        }
  1754. X        if (x >= cur_x)
  1755. X            line[cur_y][cur_x+n] =
  1756. X                (line[cur_y][cur_x+n] & CHAR)
  1757. X                |
  1758. X                (line[cur_y][x] & COOKBITS);
  1759. X    }
  1760. X    for (x = cur_x; x <= xto; x++)
  1761. X        line[cur_y][x] = line[cur_y][x+n];
  1762. X    while (n-- > 0)
  1763. X        Putstr(dc_str);
  1764. X}
  1765. X
  1766. XHidden Procedure put_c(c) int c; {
  1767. X    char ch;
  1768. X    short xs_flag;
  1769. X    
  1770. X    ch = c&CHAR;
  1771. X    if (!isprint(ch) && ch != ' ') /* V7 isprint doesn't include blank */
  1772. X        ch= '?';
  1773. X    fputc(ch, fp);
  1774. X    if (has_xs)
  1775. X        xs_flag = line[cur_y][cur_x]&XSBIT;
  1776. X    else
  1777. X        xs_flag = 0;
  1778. X    line[cur_y][cur_x] = (c&SOCHAR)|xs_flag;
  1779. X    cur_x++;
  1780. X}
  1781. X
  1782. XHidden Procedure clear_lines(yfirst, ylast) int yfirst, ylast; {
  1783. X    register int y;
  1784. X    
  1785. X    if (!has_xs && so_mode != Off)
  1786. X        standend();
  1787. X    if (cl_str && yfirst == 0 && ylast == lines-1) {
  1788. X        Putstr(cl_str);
  1789. X        cur_y = cur_x = 0;
  1790. X        for (y = 0; y < lines; ++y) {
  1791. X            lenline[y] = 0;
  1792. X            if (has_xs) line[y][0] = NOCOOK;
  1793. X        }
  1794. X        return;
  1795. X    }
  1796. X    for (y = yfirst; y <= ylast; y++) {
  1797. X        if (lenline[y] > 0) {
  1798. X            move(y, 0);
  1799. X            if (ylast == lines-1 && cd_str) {
  1800. X                Putstr(cd_str);
  1801. X                while (y <= ylast) {
  1802. X                    if (has_xs) line[y][0] = NOCOOK;
  1803. X                    lenline[y++] = 0;
  1804. X                }
  1805. X                break;
  1806. X            }
  1807. X            else {
  1808. X                clr_to_eol();
  1809. X            }
  1810. X        }
  1811. X    }
  1812. X}
  1813. X
  1814. XHidden Procedure clr_to_eol() {
  1815. X    lenline[cur_y] = cur_x;
  1816. X    if (!has_xs && so_mode != Off)
  1817. X        standend();
  1818. X    Putstr(ce_str);
  1819. X    if (has_xs) {
  1820. X        if (cur_x == 0)
  1821. X            line[cur_y][0] = NOCOOK;
  1822. X        else if (line[cur_y][cur_x-1]&SOBIT)
  1823. X            standend();
  1824. X    }
  1825. X}
  1826. X
  1827. XHidden Procedure set_blanks(y, xfrom, xto) int y, xfrom, xto; {
  1828. X    register int x;
  1829. X    
  1830. X    for (x = xfrom; x < xto; x++) {
  1831. X        line[y][x] = (line[y][x]&XSBIT) | ' ';
  1832. X    }
  1833. X}
  1834. X
  1835. X/* 
  1836. X * outchar() is used by termcap's tputs.
  1837. X */
  1838. XHidden int outchar(ch) char ch; {
  1839. X    fputc(ch, fp);
  1840. X}
  1841. X
  1842. X/*
  1843. X * Scrolling (part of) the screen up (or down, by<0).
  1844. X */
  1845. X
  1846. XVisible Procedure trmscrollup(yfirst, ylast, by) register int yfirst;
  1847. X        register int ylast; register int by; {
  1848. X#ifdef VTRMTRACE
  1849. X    if (vtrmfp) put3Dstr(vtrmfp, "\ttrmscrollup(%d, %d, %d);\n", yfirst, ylast, by);
  1850. X#endif
  1851. X    check_started("trmscrollup");
  1852. X    
  1853. X    if (yfirst < 0)
  1854. X        yfirst = 0;
  1855. X    if (ylast >= lines)
  1856. X        ylast = lines-1;
  1857. X
  1858. X    if (yfirst > ylast)
  1859. X        return;
  1860. X
  1861. X    if (!has_xs && so_mode != Off)
  1862. X        standend();
  1863. X    
  1864. X    if (by > 0 && yfirst + by > ylast
  1865. X        ||
  1866. X        by < 0 && yfirst - by > ylast)
  1867. X    {
  1868. X        clear_lines(yfirst, ylast);
  1869. X        return;
  1870. X    }
  1871. X    
  1872. X    if (by > 0) {
  1873. X        (*scr_up)(yfirst, ylast, by);
  1874. X        scr_lines(yfirst, ylast, by, 1);
  1875. X    }
  1876. X    else if (by < 0) {
  1877. X        (*scr_down)(yfirst, ylast, -by);
  1878. X        scr_lines(ylast, yfirst, -by, -1);
  1879. X    }
  1880. X}
  1881. X
  1882. XHidden Procedure scr_lines(yfrom, yto, n, dy) int yfrom, yto, n, dy; {
  1883. X    register int y;
  1884. X    short *saveln;
  1885. X    
  1886. X    while (n-- > 0) {
  1887. X        saveln = line[yfrom];
  1888. X        for (y = yfrom; y != yto; y += dy) {
  1889. X            line[y] = line[y+dy];
  1890. X            lenline[y] = lenline[y+dy];
  1891. X        }
  1892. X        line[yto] = saveln;
  1893. X        lenline[yto] = 0;
  1894. X        if (has_xs) line[yto][0] = NOCOOK;
  1895. X    }
  1896. X}
  1897. X
  1898. XHidden Procedure scr1up(yfirst, ylast, n) int yfirst, ylast, n; {
  1899. X
  1900. X    move(yfirst, 0);
  1901. X    dellines(n);
  1902. X    if (ylast < lines-1) {
  1903. X        move(ylast-n+1, 0);
  1904. X        addlines(n);
  1905. X    }
  1906. X}
  1907. X
  1908. X
  1909. XHidden Procedure scr1down(yfirst, ylast, n) int yfirst, ylast, n; {
  1910. X    if (ylast == lines-1) {
  1911. X        clear_lines(ylast-n+1, ylast);
  1912. X    }
  1913. X    else {
  1914. X        move(ylast-n+1, 0);
  1915. X        dellines(n);
  1916. X    }
  1917. X    move(yfirst, 0);
  1918. X    addlines(n);
  1919. X}
  1920. X
  1921. X
  1922. XHidden Procedure addlines(n) register int n; {
  1923. X    if (par_al_str && n > 1)
  1924. X            Putstr(tgoto(par_al_str, n, n));
  1925. X    else {
  1926. X        while (n-- > 0)
  1927. X            Putstr(al_str);
  1928. X    }
  1929. X}
  1930. X
  1931. X
  1932. XHidden Procedure dellines(n) register int n; {
  1933. X    if (par_dl_str && n > 1)
  1934. X        Putstr(tgoto(par_dl_str, n, n));
  1935. X    else {
  1936. X        while (n-- > 0)
  1937. X            Putstr(dl_str);
  1938. X    }
  1939. X}
  1940. X
  1941. X
  1942. XHidden Procedure scr2up(yfirst, ylast, n) int yfirst, ylast, n; {
  1943. X    Putstr(tgoto(cs_str, ylast, yfirst));
  1944. X    cur_y = cur_x = Undefined;
  1945. X    move(ylast, 0);
  1946. X    while (n-- > 0) {
  1947. X        Putstr(sf_str);
  1948. X        if (has_db && ylast == lines-1)
  1949. X            clr_to_eol();
  1950. X    }
  1951. X    Putstr(tgoto(cs_str, lines-1, 0));
  1952. X    cur_y = cur_x = Undefined;
  1953. X}
  1954. X
  1955. X
  1956. XHidden Procedure scr2down(yfirst, ylast, n) int yfirst, ylast, n; {
  1957. X    Putstr(tgoto(cs_str, ylast, yfirst));
  1958. X    cur_y = cur_x = Undefined;
  1959. X    move(yfirst, 0);
  1960. X    while (n-- > 0) {
  1961. X        Putstr(sr_str);
  1962. X        if (has_da && yfirst == 0)
  1963. X            clr_to_eol();
  1964. X    }
  1965. X    Putstr(tgoto(cs_str, lines-1, 0));
  1966. X    cur_y = cur_x = Undefined;
  1967. X}
  1968. X
  1969. X
  1970. X/*
  1971. X * Synchronization, move cursor to given position (or previous if < 0).
  1972. X */
  1973. X
  1974. XVisible Procedure trmsync(y, x) int y, x; {
  1975. X#ifdef VTRMTRACE
  1976. X    if (vtrmfp) put2Dstr(vtrmfp, "\ttrmsync(%d, %d);\n", y, x);
  1977. X#endif
  1978. X    check_started("trmsync");
  1979. X    
  1980. X    if (0 <= y && y < lines && 0 <= x && x < cols) {
  1981. X        move(y, x);
  1982. X        if (no_cursor) {
  1983. X            Putstr(ve_str);
  1984. X            no_cursor = No;
  1985. X        }
  1986. X    }
  1987. X    else if (no_cursor == No) {
  1988. X        Putstr(vi_str);
  1989. X        no_cursor = Yes;
  1990. X    }
  1991. X    VOID fflush(fp);
  1992. X}
  1993. X
  1994. X
  1995. X/*
  1996. X * Send a bell, visible if possible.
  1997. X */
  1998. X
  1999. XVisible Procedure trmbell() {
  2000. X#ifdef VTRMTRACE
  2001. X    if (vtrmfp) putstr(vtrmfp, "\ttrmbell();\n");
  2002. X#endif
  2003. X    check_started("trmbell");
  2004. X    
  2005. X    Putstr(vb_str);
  2006. X    VOID fflush(fp);
  2007. X}
  2008. X
  2009. X
  2010. X#ifdef SHOW
  2011. X
  2012. X/*
  2013. X * Show the current internal statuses of the screen on vtrmfp.
  2014. X * For debugging only.
  2015. X */
  2016. X
  2017. XVisible Procedure trmshow(s) char *s; {
  2018. X    int y, x;
  2019. X    
  2020. X    if (!vtrmfp)
  2021. X        return;
  2022. X    putSstr(vtrmfp, "<<< %s >>>\n", s);
  2023. X    for (y = 0; y < lines; y++) {
  2024. X        for (x = 0; x <= lenline[y] /*** && x < cols-1 ***/ ; x++) {
  2025. X            putchr(vtrmfp, line[y][x]&CHAR);
  2026. X        }
  2027. X        putnewline(vtrmfp);
  2028. X        for (x = 0; x <= lenline[y] && x < cols-1; x++) {
  2029. X            if (line[y][x]&SOBIT)
  2030. X                putchr(vtrmfp, '-');
  2031. X            else
  2032. X                putchr(vtrmfp, ' ');
  2033. X        }
  2034. X        putnewline(vtrmfp);
  2035. X        for (x = 0; x <= lenline[y] && x < cols-1; x++) {
  2036. X            if (line[y][x]&XSBIT)
  2037. X                putchr(vtrmfp, '+');
  2038. X            else
  2039. X                putchr(vtrmfp, ' ');
  2040. X        }
  2041. X        putnewline(vtrmfp);
  2042. X    }
  2043. X    put2Dstr(vtrmfp, "CUR_Y = %d, CUR_X = %d.\n", cur_y, cur_x);
  2044. X    VOID fflush(vtrmfp);
  2045. X}
  2046. X#endif
  2047. X
  2048. X
  2049. X/*
  2050. X * Return the next input character, or -1 if read fails.
  2051. X * Only the low 7 bits are returned, so reading in RAW mode is permissible
  2052. X * (although CBREAK is preferred if implemented).
  2053. X * To avoid having to peek in the input buffer for trmavail, we use the
  2054. X * 'read' system call rather than getchar().
  2055. X * (The interface allows 8-bit characters to be returned, to accomodate
  2056. X * larger character sets!)
  2057. X */
  2058. X
  2059. X#ifdef SETJMP
  2060. X
  2061. XVisible jmp_buf readEinterrupt;
  2062. XVisible bool readEcontext;
  2063. X
  2064. X#endif /* SETJMP */
  2065. X
  2066. Xextern bool intrflag;
  2067. X#ifdef SIGTSTP
  2068. Xextern bool suspflag;
  2069. X#ifdef SETJMP
  2070. XVisible jmp_buf readEsuspend;
  2071. X#endif
  2072. X#endif
  2073. X
  2074. XHidden int pushback= -1;
  2075. X
  2076. Xint trminput() {
  2077. X    char c;
  2078. X    int n;
  2079. X
  2080. X    if (intrflag) {
  2081. X        intrflag= No;
  2082. X        return intrchar & 0377;
  2083. X    }
  2084. X#ifdef SIGTSTP
  2085. X    if (suspflag) {
  2086. X        suspflag= No;
  2087. X        return suspchar & 0377;
  2088. X    }
  2089. X#endif
  2090. X    if (pushback >= 0) {
  2091. X        c= pushback;
  2092. X        pushback= -1;
  2093. X        return c;
  2094. X    }
  2095. X#ifdef SETJMP
  2096. X    if (setjmp(readEinterrupt) != 0) {
  2097. X        readEcontext= No;
  2098. X        intrflag= No;
  2099. X        return intrchar & 0377;
  2100. X    }
  2101. X#ifdef SIGTSTP
  2102. X    if (setjmp(readEsuspend) != 0) {
  2103. X        readEcontext= No;
  2104. X            suspflag= No;
  2105. X            return suspchar & 0377;
  2106. X    }
  2107. X#endif
  2108. X    readEcontext= Yes;
  2109. X#endif /* SETJMP */
  2110. X    n= read(0, &c, 1);
  2111. X#ifdef SETJMP
  2112. X    readEcontext= No;
  2113. X#endif
  2114. X    if (n <= 0)
  2115. X        return -1;
  2116. X    return c & 0377;
  2117. X}
  2118. X
  2119. Xtrmpushback(c) int c; {
  2120. X    pushback= c;
  2121. X}
  2122. X
  2123. X
  2124. X/*
  2125. X * See if there's input available from the keyboard.
  2126. X * The code to do this is dependent on the type of Unix you have
  2127. X * (BSD, System V, ...).
  2128. X * Return value: 0 -- no input; 1 -- input; -1 -- unimplementable.
  2129. X * Note that each implementation form should first check pushback.
  2130. X *
  2131. X * TO DO:
  2132. X *    - Implement it for other than 4.x BSD! (notably System 5)
  2133. X */
  2134. X
  2135. X#ifdef HAS_SELECT
  2136. X
  2137. X#include <sys/time.h>
  2138. X
  2139. Xint dep_trmavail() {
  2140. X    int nfound, nfds, readfds;
  2141. X    static struct timeval timeout= {0, 0};
  2142. X
  2143. X    readfds= 1 << 0;
  2144. X    nfds= 0+1;
  2145. X    nfound= select(nfds, &readfds, (int*) 0, (int*) 0, &timeout);
  2146. X    return nfound > 0;
  2147. X}
  2148. X
  2149. X#define TRMAVAIL_DEFINED
  2150. X
  2151. X#endif /* HAS_SELECT */
  2152. X
  2153. X#if !defined(TRMAVAIL_DEFINED) && defined(FIONREAD)
  2154. X
  2155. Xint dep_trmavail() {
  2156. X    long n;
  2157. X
  2158. X    ioctl(0, FIONREAD, (char *) &n);
  2159. X    return n > 0;
  2160. X}
  2161. X
  2162. X#define TRMAVAIL_DEFINED
  2163. X
  2164. X#endif /* FIONREAD */
  2165. X
  2166. X#ifndef TRMAVAIL_DEFINED
  2167. X
  2168. Xint dep_trmavail() {
  2169. X    return -1;
  2170. X}
  2171. X
  2172. X#endif
  2173. X
  2174. Xint trmavail() {
  2175. X    if (intrflag)
  2176. X        return 1;
  2177. X    if (pushback >= 0)
  2178. X        return 1;
  2179. X    return dep_trmavail(); /* dependent code */
  2180. X}    
  2181. X
  2182. X#ifdef UNUSED
  2183. X/*
  2184. X * Suspend the editor.
  2185. X * Should be called only after trmend and before trmstart!
  2186. X */
  2187. X
  2188. Xtrmsuspend() {
  2189. X#ifdef SIGTSTP
  2190. X    SIGTYPE (*oldsig)();
  2191. X    
  2192. X    oldsig= signal(SIGTSTP, SIG_IGN);
  2193. X    if (oldsig == SIG_IGN)
  2194. X        return; /* Could spawn a subshell here... */
  2195. X    trmend(); /* Safety net */
  2196. X    signal(SIGTSTP, oldsig);
  2197. X    kill(0, SIGSTOP);
  2198. X#endif /*SIGTSTP*/
  2199. X}
  2200. X#endif
  2201. X
  2202. X/*
  2203. X * DESCRIPTION.
  2204. X *
  2205. X * This package uses termcap to determine the terminal capabilities.
  2206. X *
  2207. X * The lines and columns of our virtual terminal are numbered 
  2208. X *    y = {0...lines-1} from top to bottom, and
  2209. X *    x = {0...cols-1} from left to right,
  2210. X * respectively.
  2211. X *
  2212. X * The Visible Procedures in this package are:
  2213. X *
  2214. X * trmstart(&lines, &cols, &flags)
  2215. X *     Obligatory initialization call (sets tty modes etc.),
  2216. X *     Returns the height and width of the screen to the integers
  2217. X *     whose addresses are passed as parameters, and a flag that
  2218. X *    describes some capabilities.
  2219. X *    Function return value: 0 if all went well, an error code if there
  2220. X *    is any trouble.  No messages are printed for errors.
  2221. X *
  2222. X * trmundefined()
  2223. X *    Sets internal representation of screen and attributes to undefined.
  2224. X *    This is necessary for a hard redraw, which would get optimised to
  2225. X *    oblivion,
  2226. X *
  2227. X * trmsense(&y, &x)
  2228. X *    Returns the cursor position through its parameters
  2229. X *    after a possible manual change by the user.
  2230. X *
  2231. X * trmputdata(yfirst, ylast, indent, data)
  2232. X *     Fill lines {yfirst..ylast} with data, after skipping the initial
  2233. X *    'indent' positions. It is assumed that these positions do not contain
  2234. X *    anything dangerous (like standout cookies or null characters).
  2235. X *
  2236. X * trmscrollup(yfirst, ylast, by)
  2237. X *     Shift lines {yfirst..ylast} up by lines (down |by| if by < 0).
  2238. X *
  2239. X * trmsync(y, x)
  2240. X *     Call to output data to the terminal and set cursor position.
  2241. X *
  2242. X * trmbell()
  2243. X *    Send a (possibly visible) bell, immediately (flushing fp).
  2244. X *
  2245. X * trmend()
  2246. X *     Obligatory termination call (resets tty modes etc.).
  2247. X *
  2248. X * You may call these as one or more cycles of:
  2249. X *     + trmstart
  2250. X *     +    zero or more times any of the other routines
  2251. X *     + trmend
  2252. X * Trmend may be called even in the middle of trmstart; this is necessary
  2253. X * to make it possible to write an interrupt handler that resets the tty
  2254. X * state before exiting the program.
  2255. X *
  2256. X * ADDITIONAL SPECIFICATIONS (ROUTINES FOR CHARACTER INPUT)
  2257. X *
  2258. X * trminput()
  2259. X *    Return the next input character (with its parity bit cleared
  2260. X *    if any).  This value is a nonnegative int.  Returns -1 if the
  2261. X *    input can't be read any more.
  2262. X *
  2263. X * trmavail()
  2264. X *    Return 1 if there is an input character immediately available,
  2265. X *    0 if not.  Return -1 if not implementable.
  2266. X *
  2267. X * trminterrupt()
  2268. X *    Return 1 if an interrupt has occurred since the last call to
  2269. X *    trminput or trmavail, 0 else.  [Currently not implemented.]
  2270. X *
  2271. X * trmsuspend()
  2272. X *    When called in the proper environment (4BSD with job control
  2273. X *    enabled), suspends the editor, temporarily popping back to
  2274. X *    the calling shell.  The caller should have called trmend()
  2275. X *    first, and must call trmstart again afterwards.
  2276. X *    BUG: there is a timing window where keyboard-generated
  2277. X *    signals (such as interrupt) can reach the program.
  2278. X */
  2279. END_OF_FILE
  2280.   if test 40794 -ne `wc -c <'abc/unix/u1trm.c'`; then
  2281.     echo shar: \"'abc/unix/u1trm.c'\" unpacked with wrong size!
  2282.   fi
  2283.   # end of 'abc/unix/u1trm.c'
  2284. fi
  2285. echo shar: End of archive 2 \(of 25\).
  2286. cp /dev/null ark2isdone
  2287. MISSING=""
  2288. 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
  2289.     if test ! -f ark${I}isdone ; then
  2290.     MISSING="${MISSING} ${I}"
  2291.     fi
  2292. done
  2293. if test "${MISSING}" = "" ; then
  2294.     echo You have unpacked all 25 archives.
  2295.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2296. else
  2297.     echo You still must unpack the following archives:
  2298.     echo "        " ${MISSING}
  2299. fi
  2300. exit 0 # Just in case...
  2301.