v08i059: A Unix/PC virtual terminal package, Part01/02
sources-request at mirror.UUCP
sources-request at mirror.UUCP
Fri Feb 13 04:17:33 AEST 1987
Submitted by: Guido van Rossum <seismo!mcvax!guido>
Mod.sources: Volume 8, Issue 59
Archive-name: vtrm/Part01
[ This package provides duplicate functionality for Unix and PC
screen-oriented programs. (Is that sentence in English?)
A Makefile doesn't make sense, and I guess I'm being nice by
not sticking to my requirement for a manpage. Comments on that,
anyone? I have not done anything to or with these programs, other
than to re-shar them. -r$ ]
As the README file mentions, there is little documentation and no
test program. Adding all the stuff to make it into a "neat" posting
would cost me a day or two, which I simply can't spare. I believe that
it is useful enough in its current state.
Guido van Rossum, CWI, Amsterdam <guido at mcvax.uucp>
#! /bin/sh
# This is a shell archive. Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
# If all goes well, you will see the message "End of archive 1 (of 2)."
# Contents: README p1trm.c trm.h MANIFEST
PATH=/bin:/usr/bin:/usr/ucb; export PATH
echo shar: extracting "'README'" '(2381 characters)'
if test -f 'README' ; then
echo shar: will not over-write existing file "'README'"
else
sed 's/^X//' >README <<'@//E*O*F README//'
XTHIS IS VTRM
X============
X
XVTRM is a terminal control package, with two implementations: one for Unix
X(only well-tested on 4.2/4.3 BSD, but supposedly running under System 5
Xas well, as long as there is a termcap database), and one for MS-DOS, to
Xbe compiled with the Microsoft C compiler (tested only with version 3.0).
XThis is a "curses replacement", which does not mean it is a curses
Xreimplementation: the interface is totally different, only the purpose
Xis more or less the same: to shield an application program from the
Xnitty-gritty detail of cursor navigation, inverse video, scrolling, etc.
XThere are also a few routines for CBREAK-mode input.
X
XUNPACKING NOTES
X
XThe shars yield five files:
X README (this file)
X trm.h (common header file)
X p1trm.c (MS-DOS version)
X vtrm.c_1
X vtrm.c_2
XThe latter two should be pasted together to get a file named vtrm.c:
X cat vtrm.c_[12] >vtrm.c
X
XAPOLOGY
X
XI must apologize for the poor documentation. Most of it has the form of
Xcomments in the source files (note the "specs" for the entire package at
Xthe end of vtrm.c). This is a library package but I do not have an
Xadequate test program for it; I usually test it with one of the two
Xapplications that use it -- these are too big to include in this posting.
X
XFUTURE DIRECTIONS
X
XThis version of VTRM is by no means an end point in its development.
XWork is under way for an implementation that provides the same interface
Xon the Macintosh. You are invided to engage in implementations for othr
Xmachines, such as as the Atari ST and the Commodore Amiga. Comments on
Xthe interface are more than welcome, and should be sent by electronic
Xmail to guido at mcvax.uucp; this is also the address for bugfixes and
Xother questions.
X
XAUTHORS
X
XThis software was written by:
X
X Timo Krijnen and Guido van Rossum
X CWI, dept. AA
X Kruislaan 413
X 1089 SJ Amsterdam
X The Netherlands
X
X Electronic mail: timo at mcvax.uucp, guido at mcvax.uucp
X Phone: ... 20 - 592 4138.
X
XCOPYRIGHT
X
XThis software is copyright (c) 1986 by Stichting Mathematisch Centrum,
XAmsterdam, The Netherlands. Its use is allowed freely for
Xnon-commercial purposes only. Use at your own risk: SMC does not take
Xresponsibility for the proper functioning of the software or for damage
Xcaused by its use. Redistribution is allowed for non-commercial
Xpurposes only, and only unchanged, in its entirety, and including this
Xcopyright notice.
@//E*O*F README//
if test 2381 -ne "`wc -c <'README'`"; then
echo shar: error transmitting "'README'" '(should have been 2381 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'p1trm.c'" '(21268 characters)'
if test -f 'p1trm.c' ; then
echo shar: will not over-write existing file "'p1trm.c'"
else
sed 's/^X//' >p1trm.c <<'@//E*O*F p1trm.c//'
X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
X
X/*
X * ibm Pc virtual TeRMinal package.
X *
X * An implementation of the VTRM interface for MS-DOS machines.
X *
X * This code supports two MODE's of accessing the screen.
X * The first one (BIOS) will be used, unless the user overwrites this
X * by setting the SCREEN environment variable.
X * This variable can also be used to convey a screen size that differs
X * from the default 25 lines and 80 columns. See below.
X *
X * The two modes are:
X *
X * 1) IBM BIOS interrupt 10 hex, video io.
X * (See IBM PC XT Technical Reference 6936833, May 1983,
X * Appendix A, pages A46-A47).
X * This is what you really want to use, since it's the only one that
X * can decently scroll. It cannot insert or delete characters, so
X * most optimisations from vtrm.c are useless and taken out.
X * Unfortunately, not every PC-compatible machine supports this BIOS
X * interrupt, so for these unlucky souls there is the following escape:
X *
X * 2) The ANSI.SYS driver.
X * (See IBM MS-DOS 6936839, Jan 1983, Version 2.00, Chapter 13.)
X * (Some compatibles don't have a separate ANSI.SYS driver but do the
X * same escape interpretation by default.)
X * This works reasonably, apart from scrolling downward, or part of
X * the screen, which is clumsy.
X * (The ANSI standard provides an escape sequence for scrolling
X * but ANSI.SYS does not support it, nor any other way of scrolling.)
X *
X * The rest of the interface is the same as described in vtrm.c,
X * with the following exceptions:
X * - to ease coding for ansi scrolls, the terminal is supposed to
X * contain blanks at positions that were not written yet;
X * the unknown rubbish that is initially on the screen can
X * only be cleared by the caller by scrolling the whole screen up
X * by one or more lines;
X * - the number of lines on the terminal is assumed to be 25;
X * the number of columns is (1) determined by a BIOS function, or
X * (2) assumed to be 80 for ANSI;
X * the user can overwrite this by setting the environment variable:
X *
X * SET SCREEN=BIOS x y
X * or
X * SET SCREEN=ANSI x y
X *
X * where x and y are the number of lines and columns respectively.
X *
X * The lines and columns of our virtual terminal are numbered
X * y = {0...lines-1} from top to bottom, and
X * x = {0...cols-1} from left to right,
X * respectively.
X *
X * The Visible Procedures in this package are as described in vtrm.c.
X *
X */
X
X/*
X * Includes and data definitions.
X */
X
X#include <stdio.h>
X#include <signal.h>
X#include <ctype.h>
X#include <dos.h>
X
Xchar *malloc();
X
X#include "trm.h"
X
X#ifdef lint
X#define VOID (void)
X#else
X#define VOID
X#endif
X
X#define Forward
X#define Visible
X#define Hidden static
X#define Procedure
X
Xtypedef short intlet;
Xtypedef char *string;
Xtypedef char bool;
X#define Yes '\1'
X#define No '\0'
X#define Undefined (-1)
X
X#define Min(a,b) ((a) <= (b) ? (a) : (b))
X
X#define MESS(number, text) text
X
X#ifdef GFX
X#include "gfx.h"
X#endif
X
X/* terminal status */
X
XHidden int started = No;
X
XHidden int scr_mode = 0;
X#define ANSI 'A'
X#define BIOS 'B'
X
X#define Nlines 25
X#define Ncols 80
XHidden int lines = Nlines;
XHidden int cols = Ncols;
XHidden int flags = 0;
X
X/* current standout mode */
X#define Off 0
X#define On 0200
XHidden int so_mode = Off;
X
X/* masks for char's and intlet's */
X#define NULCHAR '\000'
X#define CHAR 0177
X#define SOBIT On
X#define SOCHAR 0377
X
X/* current cursor position */
XHidden intlet cur_y = Undefined, cur_x = Undefined;
X
X/* "line[y][x]" holds the char on the terminal, with the SOBIT.
X * the SOBIT tells whether the character is standing out.
X * "lenline[y]" holds the length of the line.
X * (Partially) empty lines are distinghuished by "lenline[y] < cols".
X * Unknown chars will be ' ', so the scrolling routines for ANSI
X * can use "unwritten" chars (with indent > 0 in trmputdata).
X * To make the optimising compare in putline fail, lenline[y] is initially 0.
X * The latter implies that if a line is first addressed with trmputdata,
X * any rubbish that is on the screen beyond the data that gets put, will
X * remain there.
X */
XHidden char **line = 0;
XHidden intlet *lenline = 0;
X
X/* Make the cursor invisible when trmsync() tries to move outside the screen */
XHidden bool no_cursor = No;
X
X/*
X * Starting, Ending and (fatal) Error.
X */
X
X/*
X * Initialization call.
X * Determine terminal mode.
X * Start up terminal and internal administration.
X * Return Yes if succeeded, No if trouble (which doesn't apply here).
X */
XVisible int
Xtrmstart(plines, pcols, pflags)
Xint *plines;
Xint *pcols;
Xint *pflags;
X{
X static char setup = No;
X int err;
X
X#ifdef TRACE
Xif (!setup) freopen("TRACE.DAT", "a", stderr);
Xfprintf(stderr, "\ttrmstart(&li, &co, &fl);\n");
X#endif
X
X if (started)
X return TE_TWICE;
X
X#ifdef GFX
X if (gfx_mode != TEXT_MODE)
X gfx_mode= SPLIT_MODE;
X#endif
X
X if (!setup) {
X err= set_screen_up();
X if (err != TE_OK)
X return err;
X setup = Yes;
X }
X
X err= start_trm(); /* internal administration */
X if (err != TE_OK)
X return err;
X
X *plines = lines;
X *pcols = cols;
X *pflags = flags;
X
X set_handler();
X started = Yes;
X return TE_OK;
X}
X
XHidden int
Xset_screen_up()
X{
X int height;
X int width;
X int get_screen_env();
X int get_cols();
X
X height = width = 0;
X scr_mode = get_screen_env(&height, &width);
X
X switch (scr_mode) {
X case BIOS:
X case TE_OK:
X cols = get_cols();
X flags = HAS_STANDOUT|CAN_SCROLL;
X break;
X case ANSI:
X flags = HAS_STANDOUT;
X break;
X default:
X return scr_mode; /* Error flag */
X }
X
X /* allow x and y in environment variable SCREEN to override */
X if (height > 0)
X lines = height;
X if (width > 0)
X cols = width;
X return TE_OK;
X}
X
XHidden int
Xget_screen_env(pheight, pwidth)
X int *pheight, *pwidth;
X{
X string s;
X int mode;
X char screrr;
X string getenv();
X string strip();
X string skip();
X
X screrr = No;
X s = getenv("SCREEN");
X if (s == NULL)
X return BIOS;
X
X s = strip(s);
X switch (*s) {
X case '\0':
X return BIOS;
X case 'a':
X mode = ANSI;
X s = skip(s, "ansi");
X break;
X case 'A':
X mode = ANSI;
X s = skip(s, "ANSI");
X break;
X case 'b':
X mode = BIOS;
X s = skip(s, "bios");
X break;
X case 'B':
X mode = BIOS;
X s = skip(s, "BIOS");
X break;
X default:
X mode = BIOS;
X screrr = Yes;
X }
X
X /* *pheight and *pwidth were set to 0 above */
X s = strip(s);
X while (isdigit(*s)) {
X *pheight = *pheight * 10 + (*s++ - '0');
X }
X s = strip(s);
X while (isdigit(*s)) {
X *pwidth = *pwidth * 10 + (*s++ -'0');
X }
X s = strip(s);
X if (screrr || *s != '\0')
X return TE_BADTERM;
X
X return mode;
X}
X
XHidden string strip(s)
Xstring s;
X{
X while (*s == ' ' || *s == '\t')
X ++s;
X return s;
X}
X
XHidden string skip(s, pat)
Xstring s, pat;
X{
X while (*s == *pat)
X ++s, ++pat;
X return s;
X}
X
XHidden int /* initialise internal administration */
Xstart_trm()
X{
X register int y;
X
X if (line == 0) {
X if ((line = (char**) malloc(lines * sizeof(char*))) == NULL)
X return TE_NOMEM;
X for (y = 0; y < lines; y++) {
X if ((line[y] = malloc(cols * sizeof(char))) == NULL)
X return TE_NOMEM;
X }
X }
X if (lenline == 0) {
X if ((lenline = (intlet *)
X malloc(lines * sizeof(intlet))) == NULL)
X return TE_NOMEM;
X }
X
X trmundefined();
X return TE_OK;
X}
X
X/*
X * Termination call.
X * Beware that it might be called by a catched interrupt even in the middle
X * of trmstart()!
X */
X
XVisible Procedure
Xtrmend()
X{
X#ifdef TRACE
Xfprintf(stderr, "\ttrmend();\n");
X#endif
X if (started && so_mode != Off)
X standend();
X if (scr_mode == ANSI) {
X VOID fflush(stdout);
X }
X
X started = No;
X}
X
X/*
X * Set all internal statuses to undefined, especially the contents of
X * the screen, so a hard redraw will not be optimised to heaven.
X */
X
XVisible Procedure
Xtrmundefined()
X{
X register int y, x;
X#ifdef TRACE
Xfprintf(stderr, "\ttrmundefined();\n");
X#endif
X
X cur_y = cur_x = Undefined;
X so_mode = Undefined;
X
X for (y = 0; y < lines; y++) {
X for (x = 0; x < cols; x++)
X line[y][x] = ' ';
X /* they may get printed in scrolling */
X lenline[y] = 0;
X }
X}
X
X#ifdef DEBUG
XHidden Procedure
Xcheck_started(m)
X char *m;
X{
X if (!started) {
X printf("Not started: %s\n", m);
X exit(TE_TWICE);
X }
X}
X#else
X#define check_started(m) /*empty*/
X#endif
X
X/*
X * Sensing the cursor.
X * (NOT IMPLEMENTED, since there is no way to locally move the cursor.)
X */
X
X/*
X * Sense the current (y, x) cursor position, after a possible manual
X * change by the user with local cursor motions.
X * If the terminal cannot be asked for the current cursor position,
X * or if the string returned by the terminal is garbled,
X * the position is made Undefined.
X */
XVisible Procedure
Xtrmsense(py, px)
X int *py;
X int *px;
X{
X/* bool getpos(); */
X#ifdef TRACE
Xfprintf(stderr, "\ttrmsense(&yy, &xx);\n");
X#endif
X check_started(MESS(7904, "trmsense called outside trmstart/trmend"));
X
X *py = *px = Undefined;
X
X/*
X * if (flags&CAN_SENSE && getpos(py, px)) {
X * if (*py < 0 || lines <= *py || *px < 0 || cols <= *px)
X * *py = *px = Undefined;
X * }
X */
X cur_y = *py;
X cur_x = *px;
X}
X
X/*
X * Putting data on the screen.
X */
X
X/*
X * Fill screen area with given data.
X * Characters with the SO-bit (0200) set are put in standout mode.
X * (Unfortunately this makes it impossible to display accented characters.
X * The interface should change.)
X */
XVisible Procedure
Xtrmputdata(yfirst, ylast, indent, data)
Xint yfirst;
Xint ylast;
Xregister int indent;
Xregister string data;
X{
X register int y;
X int x, len, lendata, space;
X
X#ifdef TRACE
Xfprintf(stderr, "\ttrmputdata(%d, %d, %d, \"%s\");\n", yfirst, ylast, indent, data);
X#endif
X check_started(MESS(7905, "trmputdata called outside trmstart/trmend"));
X
X if (yfirst < 0)
X yfirst = 0;
X if (ylast >= lines)
X ylast = lines-1;
X space = cols*(ylast-yfirst+1) - indent;
X if (space <= 0)
X return;
X yfirst += indent/cols;
X indent %= cols;
X y = yfirst;
X if (data) {
X x = indent;
X lendata = strlen(data);
X if (ylast == lines-1 && lendata >= space)
X lendata = space - 1;
X len = Min(lendata, cols-x);
X while (y <= ylast) {
X put_line(y, x, data, len);
X y++;
X lendata -= len;
X if (lendata > 0) {
X x = 0;
X data += len;
X len = Min(lendata, cols);
X }
X else
X break;
X }
X }
X if (y <= ylast)
X clear_lines(y, ylast);
X}
X
X/*
X * We will try to get the picture:
X *
X * op>>>>>>>>>>>op oq
X * ^ ^ ^
X * <xskip><-----m1----><---------------od-------------------->
X * OLD: "You're in a maze of twisty little pieces of code, all alike"
X * NEW: "in a maze of little twisting pieces of code, all alike"
X * <-----m1----><----------------nd--------------------->
X * ^ ^ ^
X * np>>>>>>>>>>>np nq
X * where
X * op, oq, np, nq are pointers to start and end of Old and New data,
X * and
X * xskip = length of indent to be skipped,
X * m1 = length of Matching part at start,
X * od = length of Differing end on screen,
X * nd = length of Differing end in data to be put.
X */
XHidden int
Xput_line(y, xskip, data, len)
Xint y, xskip;
Xstring data;
Xint len;
X{
X register char *op, *oq, *np, *nq;
X int m1, od, nd, delta;
X
X /* calculate the magic parameters */
X op = &line[y][xskip];
X oq = &line[y][lenline[y]-1];
X np = data;
X nq = data + len - 1;
X m1 = 0;
X while ((*op&SOCHAR) == (*np&SOCHAR) && op <= oq && np <= nq)
X op++, np++, m1++;
X od = oq - op + 1;
X nd = nq - np + 1;
X /* now we have the picture above */
X
X if (od==0 && nd==0)
X return;
X
X delta = nd - od;
X move(y, xskip + m1);
X if (nd > 0) {
X put_str(np, nd);
X }
X if (delta < 0) {
X clr_to_eol();
X return;
X }
X lenline[y] = xskip + len;
X if (cur_x == cols) {
X cur_y++;
X cur_x = 0;
X }
X}
X
X/*
X * Scrolling (part of) the screen up (or down, dy<0).
X */
X
XVisible Procedure
Xtrmscrollup(yfirst, ylast, by)
Xregister int yfirst;
Xregister int ylast;
Xregister int by;
X{
X#ifdef TRACE
Xfprintf(stderr, "\ttrmscrollup(%d, %d, %d);\n", yfirst, ylast, by);
X#endif
X check_started(MESS(7906, "trmscrollup called outside trmstart/trmend"));
X
X if (by == 0)
X return;
X
X if (yfirst < 0)
X yfirst = 0;
X if (ylast >= lines)
X ylast = lines-1;
X
X if (yfirst > ylast)
X return;
X
X if (so_mode != Off)
X standend();
X
X if (by > 0 && yfirst + by > ylast
X ||
X by < 0 && yfirst - by > ylast)
X {
X clear_lines(yfirst, ylast);
X return;
X }
X
X switch (scr_mode) {
X case BIOS:
X biosscrollup(yfirst, ylast, by);
X break;
X case ANSI:
X if (by > 0 && yfirst == 0) {
X lf_scroll(ylast, by);
X }
X else if (by > 0) {
X move_lines(yfirst+by, yfirst, ylast-yfirst+1-by, 1);
X clear_lines(ylast-by+1, ylast);
X }
X else {
X move_lines(ylast+by, ylast, ylast-yfirst+1+by, -1);
X clear_lines(yfirst, yfirst-by-1);
X }
X break;
X }
X}
X
X/*
X * Synchronization, move cursor to given position (or previous if < 0).
X */
X
XVisible Procedure
Xtrmsync(y, x)
X int y;
X int x;
X{
X#ifdef TRACE
Xfprintf(stderr, "\ttrmsync(%d, %d);\n", y, x);
X#endif
X check_started(MESS(7907, "trmsync called outside trmstart/trmend"));
X
X if (0 <= y && y < lines && 0 <= x && x < cols) {
X move(y, x);
X }
X VOID fflush(stdout);
X}
X
X/*
X * Send a bell, visible if possible.
X */
X
XVisible Procedure
Xtrmbell()
X{
X#ifdef TRACE
Xfprintf(stderr, "\ttrmbell();\n");
X#endif
X check_started(MESS(7908, "trmbell called outside trmstart/trmend"));
X ring_bell();
X}
X
X/*
X * Now for the real work: here are all low level routines that really
X * differ for BIOS or ANSI mode.
X */
X
X/*
X * BIOS video io is called by generating an 8086 software interrupt,
X * using lattice's int86() function.
X * To ease coding, all routines fill in the apropriate parameters in regs,
X * and than call bios10(code), where code is to be placed in ah.
X */
X
XHidden union REGS regs, outregs;
X
X/* A macro for speed */
X#define bios10(code) (regs.h.ah = (code), int86(0x10, ®s, ®s))
X#define nbios10(code) (regs.h.ah = (code), int86(0x10, ®s, &outregs))
X
X/* Video attributes: (see the BASIC manual) (used for standout mode) */
X
XHidden int video_attr;
X#ifndef GFX
X#define V_NORMAL 7
X#else
X#define V_NORMAL (gfx_mode == TEXT_MODE ? 7 : 0)
X#endif
X#define V_STANDOUT (7<<4)
X
X/* Some BIOS only routines */
X
XHidden get_cols()
X{
X bios10(15);
X return regs.h.ah;
X}
X
X/*
X * ANSI escape sequences
X */
X#define A_CUP "\033[%d;%dH" /* cursor position */
X#define A_SGR0 "\033[0m" /* set graphics rendition to normal */
X#define A_SGR7 "\033[7m" /* set graphics rendition to standout */
X#define A_ED "\033[2J" /* erase display (and cursor home) */
X#define A_EL "\033[K" /* erase (to end of) line */
X
X/*
X * The following routine is the time bottleneck, I believe!
X */
X
XHidden Procedure
Xput_str(data, n)
Xchar *data;
Xint n;
X{
X register char c, so;
X
X so = so_mode;
X if (scr_mode == BIOS) {
X regs.x.cx = 1; /* repition count */
X regs.h.bh = 0; /* page number */
X regs.h.bl = video_attr;
X while (--n >= 0) {
X c = (*data++)&SOCHAR;
X if ((c&SOBIT) != so) {
X so = c&SOBIT;
X so ? standout() : standend();
X regs.h.bl = video_attr;
X }
X regs.h.al = c&CHAR;
X nbios10(9);
X if (cur_x >= cols-1) {
X line[cur_y][cols-1] = c;
X continue;
X }
X regs.h.dh = cur_y;
X regs.h.dl = cur_x + 1;
X nbios10(2);
X line[cur_y][cur_x] = c;
X cur_x++;
X }
X }
X else {
X while (--n >= 0) {
X c = (*data++)&SOCHAR;
X if ((c&SOBIT) != so) {
X so = c&SOBIT;
X so ? standout() : standend();
X }
X putch(c&CHAR);
X line[cur_y][cur_x] = c;
X cur_x++;
X }
X }
X}
X
X/*
X * Move to position y,x on the screen
X */
X
XHidden Procedure
Xmove(y, x)
Xint y, x;
X{
X if (scr_mode != BIOS && cur_y == y && cur_x == x)
X return;
X switch (scr_mode) {
X case BIOS:
X regs.h.dh = y;
X regs.h.dl = x;
X regs.h.bh = 0; /* Page; must be 0 for graphics */
X bios10(2);
X break;
X case ANSI:
X cprintf(A_CUP, y+1, x+1);
X break;
X }
X cur_y = y;
X cur_x = x;
X}
X
XHidden Procedure
Xstandout()
X{
X so_mode = On;
X switch (scr_mode) {
X case BIOS:
X video_attr = V_STANDOUT;
X break;
X case ANSI:
X cputs(A_SGR7);
X break;
X }
X}
X
XHidden Procedure
Xstandend()
X{
X so_mode = Off;
X switch (scr_mode) {
X case BIOS:
X video_attr = V_NORMAL;
X break;
X case ANSI:
X cputs(A_SGR0);
X break;
X }
X}
X
X#ifdef UNUSED
XHidden Procedure
Xput_c(c)
Xint c;
X{
X int ch;
X
X ch = c&CHAR;
X#ifndef NDEBUG
X if (!isprint(ch)) {
X ch = '?';
X c = (c&SOBIT)|'?';
X }
X#endif
X switch (scr_mode) {
X case BIOS:
X regs.h.al = ch;
X regs.h.bl = video_attr;
X regs.x.cx = 1; /* repition count */
X regs.h.bh = 0; /* page number */
X bios10(9);
X if (cur_x >= cols-1) {
X line[cur_y][cols-1] = c;
X return;
X }
X regs.h.dh = cur_y;
X regs.h.dl = cur_x + 1;
X bios10(2);
X break;
X case ANSI:
X putch(ch);
X break;
X }
X line[cur_y][cur_x] = c;
X cur_x++;
X}
X#endif UNUSED
X
XHidden Procedure
Xclear_lines(yfirst, ylast)
Xint yfirst, ylast ;
X{
X register int y;
X
X if (scr_mode == BIOS) {
X regs.h.al = 0; /* scroll with al = 0 means blank window */
X regs.h.ch = yfirst;
X regs.h.cl = 0;
X regs.h.dh = ylast;
X regs.h.dl = cols-1;
X regs.h.bh = V_NORMAL;
X bios10(6);
X for (y = yfirst; y <= ylast; y++)
X lenline[y] = 0;
X return;
X }
X /* scr_mode == ANSI */
X if (yfirst == 0 && ylast == lines-1) {
X if (so_mode == On)
X standend();
X move(0, 0); /* since some ANSI'd don't move */
X cputs(A_ED);
X cur_y = cur_x = 0;
X for (y = yfirst; y < ylast; y++)
X lenline[y] = 0;
X return;
X }
X for (y = yfirst; y <= ylast; y++) {
X if (lenline[y] > 0) {
X move(y, 0);
X clr_to_eol();
X }
X }
X}
X
XHidden Procedure
Xclr_to_eol()
X{
X if (so_mode == On)
X standend();
X switch (scr_mode) {
X case BIOS:
X regs.h.bh = 0; /* page */
X regs.x.cx = lenline[cur_y] - cur_x;
X regs.h.al = ' ';
X regs.h.bl = V_NORMAL;
X bios10(9);
X break;
X case ANSI:
X cputs(A_EL);
X break;
X }
X lenline[cur_y] = cur_x;
X}
X
XHidden Procedure /* scrolling for BIOS */
Xbiosscrollup(yfirst, ylast, by)
Xint yfirst;
Xint ylast;
Xint by;
X{
X regs.h.al = (by < 0 ? -by : by);
X regs.h.ch = yfirst;
X regs.h.cl = 0;
X regs.h.dh = ylast;
X regs.h.dl = cols-1;
X regs.h.bh= V_NORMAL;
X bios10(by < 0 ? 7 : 6);
X cur_y = cur_x = Undefined;
X if (by > 0)
X scr_lines(yfirst, ylast, by, 1);
X else
X scr_lines(ylast, yfirst, -by, -1);
X}
X
XHidden Procedure /* Reset internal administration accordingly */
Xscr_lines(yfrom, yto, n, dy)
Xint yfrom, yto, n, dy;
X{
X register int y, x;
X char *saveln;
X
X while (n-- > 0) {
X saveln = line[yfrom];
X for (y = yfrom; y != yto; y += dy) {
X line[y] = line[y+dy];
X lenline[y] = lenline[y+dy];
X }
X line[yto] = saveln;
X for (x = 0; x < cols; x++ )
X line[yto][x] = ' ';
X lenline[yto] = 0;
X }
X}
X
XHidden Procedure
Xlf_scroll(yto, by)
Xint yto;
Xint by;
X{
X register int n = by;
X
X move(lines-1, 0);
X while (n-- > 0) {
X putch('\n');
X }
X scr_lines(0, lines-1, by, 1);
X move_lines(lines-1-by, lines-1, lines-1-yto, -1);
X clear_lines(yto-by+1, yto);
X}
X
XHidden Procedure /* for dumb scrolling, uses and updates */
Xmove_lines(yfrom, yto, n, dy) /* internal administration */
Xint yfrom;
Xint yto;
Xint n;
Xint dy;
X{
X while (n-- > 0) {
X put_line(yto, 0, line[yfrom], lenline[yfrom]);
X yfrom += dy;
X yto += dy;
X }
X}
X
XHidden Procedure ring_bell()
X{
X switch (scr_mode) {
X case BIOS:
X regs.h.al = '\007';
X regs.h.bl = V_NORMAL;
X bios10(14);
X break;
X case ANSI:
X putch('\007');
X break;
X }
X}
X
X/*
X * Show the current internal statuses of the screen on stderr.
X * For debugging only.
X */
X
X#ifdef SHOW
XVisible Procedure
Xtrmshow(s)
Xchar *s;
X{
X int y, x;
X
X fprintf(stderr, "<<< %s >>>\n", s);
X for (y = 0; y < lines; y++) {
X for (x = 0; x <= lenline[y] /*** && x < cols ***/ ; x++) {
X fputc(line[y][x]&CHAR, stderr);
X }
X fputc('\n', stderr);
X for (x = 0; x <= lenline[y] && x < cols-1; x++) {
X if (line[y][x]&SOBIT)
X fputc('-', stderr);
X else
X fputc(' ', stderr);
X }
X fputc('\n', stderr);
X }
X fprintf(stderr, "CUR_Y = %d, CUR_X = %d.\n", cur_y, cur_x);
X VOID fflush(stderr);
X}
X#endif
X
X/*
X * Interrupt handling.
X *
X * (This has not properly been tested, nor is it clear that
X * this interface is what we want. Anyway, it's here for you
X * to experiment with. What does it do, you may ask?
X * Assume an interactive program which reads its characters
X * through trminput. Assume ^C is the interrupt character.
X * Normally, ^C is treated just like any other character: when
X * typed, it turns up in the input. The program may understand
X * input ^C as "quit from the current mode".
X * Occasionally, the program goes into a long period of computation.
X * Now it would be uninterruptible, except if it calls trminterrupt
X * at times in its computational loop. Trminterrupt magically looks
X * ahead in the input queue, and if it sees a ^C, discards all input
X * before that point and returns Yes. It also sets a flag, so that
X * the interupt "sticks around" until either trminput or trmavail
X * is called. It is undefined whether typing ^C several times in
X * a row is seen as one interrupt, or an interrupt followed by input
X * of ^C's. A program should be prepared for either.)
X */
X
Xstatic bool intrflag= No;
X
Xstatic
Xhandler(sig)
X int sig;
X{
X signal(sig, handler);
X intrflag= Yes;
X}
X
Xstatic
Xset_handler()
X{
X signal(SIGINT, handler);
X}
X
Xbool
Xtrminterrupt()
X{
X /* Force a check for Control-break which will call handler. */
X kbhit();
X return intrflag;
X}
X
X/*
X * Terminal input without echo.
X * (This is a recent addition to this module, but will soon be standard).
X */
X
Xtrminput()
X{
X intrflag= No;
X return bdos(0x7, 0, 0) & 0377; /* Input, no echo, no ^C checks */
X}
X
X/*
X * Check for character available.
X *
X * To do this properly, should call DOS function 6,
X * but the relevant bit (the Z flag) can't be checked from C.
X * For now, say we don't know.
X */
X
Xtrmavail()
X{
X intrflag= No;
X return -1;
X}
X
Xtrmsuspend()
X{
X /* Not implementable on MS-DOS */
X}
@//E*O*F p1trm.c//
if test 21268 -ne "`wc -c <'p1trm.c'`"; then
echo shar: error transmitting "'p1trm.c'" '(should have been 21268 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'trm.h'" '(879 characters)'
if test -f 'trm.h' ; then
echo shar: will not over-write existing file "'trm.h'"
else
sed 's/^X//' >trm.h <<'@//E*O*F trm.h//'
X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1986. */
X
X/*
X * Terminal capabilities. These correspond to bits set by trmstart in its
X * parameter flags parameter.
X */
X
X#define HAS_STANDOUT 1 /* Terminal has inverse video or underline */
X#define CAN_SCROLL 2 /* Terminal can insert/delete lines */
X#define CAN_OPTIMISE 4 /* Terminal can insert/delete characters */
X#define CAN_SENSE 8 /* Terminal can send cursor position */
X
X/*
X * Error codes returned by trmstart.
X */
X
X#define TE_OK 0 /* No errors */
X#define TE_TWICE 1 /* Trmstart called again */
X#define TE_NOTERM 2 /* $TERM not set or empty */
X#define TE_BADTERM 3 /* $TERM not found in termcap database */
X#define TE_DUMB 4 /* Terminal too dumb */
X#define TE_NOTTY 5 /* Stdout not a tty device */
X#define TE_NOMEM 6 /* Can't get enough memory */
X#define TE_OTHER 7 /* This and higher are reserved errors */
@//E*O*F trm.h//
if test 879 -ne "`wc -c <'trm.h'`"; then
echo shar: error transmitting "'trm.h'" '(should have been 879 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'MANIFEST'" '(270 characters)'
if test -f 'MANIFEST' ; then
echo shar: will not over-write existing file "'MANIFEST'"
else
sed 's/^X//' >MANIFEST <<'@//E*O*F MANIFEST//'
X File Name Kit # Description
X-----------------------------------------------------------
X MANIFEST 1 This shipping list
X README 1
X p1trm.c 1
X trm.h 1
X vtrm.c 2
@//E*O*F MANIFEST//
if test 270 -ne "`wc -c <'MANIFEST'`"; then
echo shar: error transmitting "'MANIFEST'" '(should have been 270 characters)'
fi
fi # end of overwriting check
echo shar: "End of archive 1 (of 2)."
cp /dev/null ark1isdone
DONE=true
for I in 1 2; do
if test -! f ark${I}isdone; then
echo "You still need to run archive ${I}."
DONE=false
fi
done
case $DONE in
true)
echo "You have run all 2 archives."
echo 'Now see the README'
;;
esac
## End of shell archive.
exit 0
More information about the Mod.sources
mailing list