home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 3 / 3472 < prev    next >
Internet Message Format  |  1991-06-07  |  50KB

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