[net.sources] REPORTING for DBell - DPY

chongo@nsc.UUCP (Landon Noll) (04/12/85)

In net.sources:
  I am reposting DBell's DPY sources in response to all the folks who
  needed them for his LIFE and WAR progs.  DBell is no longer on the
  net (in fact in a few days he will no longer be in this hemisphere)
  otherwise he would have done this himself.

In net.sources.games:
  I am reposting DBell's LIFE sources complete with the changes noted
  below.  Both LIFE and WAR (posted to net.sources.games by DBell not long ago)
  require the use of DPY so be sure and GRAB IT FROM NET.SOURCES NOW!!!

---------------------begin DBell's comments-------------------------------
This is a new version of the DPY module that I posted a while ago.  This
new version runs on both 4.2 BSD and System V.  Because of this, there are
some simple changes visible to the callers of the module, all of which were
made in order to make the interfaces system-independent.  The README file
explains these changes in more detail.  There is also a bug fix for padding
characters on certain terminals.

In particular, if you have obtained the LIFE program that I recently posted
to the net, you must make the following changes to the LIFE sources in order
to load it with this new release.  In main.c, delete the include of 'sgtty.h'
and replace the 'dpyinit' call with 'dpyinit((char *)0, (char *)0)'.  In io.c
and view.c, replace all 'dpyclearwindow' calls with 'dpyclrwindow' and all
'dpyclearline' calls with 'dpyclrline'.  These are 'official' changes and so
don't require any notices by the copyright notices.  Enjoy!  (This fix
has been made to the reposted LIFE sources. Ed.)

			David I. Bell
			nsc!daisy!dbell  <--No longer at this address  Ed.
---------------------------------------------------------------------------
#---Cut here and place in it's own directory, then feed to Bourne shell---
# This is a shell archive.  Remove anything before this line, then
# unpack it by saving it in a file and typing "sh file".  (Files
# unpacked will be owned by you and have default permissions.)
# This archive contains:
#   README (1807 chars)
#   dpy.doc (15578 chars)
#   makefile.bsd (1270 chars)
#   makefile.usg (1816 chars)
#   test1.c (553 chars)
#   test2.c (1446 chars)
#   dpy.h (3445 chars)
#
echo x - README
sed -e 's/^X//' > "README" << '//E*O*F README//'
X			DPY (release 2)
X
XThe DPY module was originally written for a 4.2 BSD UNIX system running on a
XVAX 750.  It now also runs under System V.  There are two makefiles supplied
Xwith this release, with the following names:
X
X	makefile.bsd	for 4.2 BSD.
X	makefile.usg	for System V.
X
XYou should copy the appropriate makefile to the file "makefile" in order to
Xbuild the library that is suitable for your system.
X
XThis is the second release of the DPY module.  There have been some changes
Xin some of the dpy routines since the previous release.  If you have any
Xprograms written for the previous release, you will need to modify them
Xas follows in order to use the new DPY:
X
X	Dpyclearline is now called dpyclrline.
X	Dpyclearwindow is now called dpyclrwindow.
X	Dpyinit is called with different arguments.
X
XThe file dpy.doc describes the new calling formats.  These changes were made
Xin order to make DPY less system dependent.  There are also several bug fixes
Xin this new release.
X
XIf you are running under a different machine, you have to change the makefile
Xto use gensubs.c instead of vaxsubs.s (this contains generic subroutines which
Xrun on all machines).  If you are ambitious, you can speed up dpy by writing
Xyour own assembly level routines to duplicate what gensubs.c does.  Not much
Xassembly code is needed.  (If you are real lucky, you are on a 32016, and the
Xnecessary routines are already written in ns32ksubs.s.)  I am willing to
Xcollect and distribute such subroutines for some other machines.
X
XI have included two toy programs (test1.c and test2.c) which demonstrate some
Xof the capabilities of dpy.  Along with dpy.doc, they should show you how to
Xuse the module.  I am still sorry that dpy.doc is not formatted.  Someday...
X
XComments and bug fixes are welcome.
X			David I. Bell
X			nsc!daisy!dbell
//E*O*F README//
echo x - dpy.doc
sed -e 's/^X//' > "dpy.doc" << '//E*O*F dpy.doc//'
X		DPY - New Screen Updating Routines
X			by David I. Bell
X
X
XDpy is a terminal display package much like curses(3).  Dpy does not
Xprovide all of the capabilities of curses, but instead tries to focus on
Xthe following two goals:
X1.	Allow the programmer to easily define and update many different
X	rectangles of data on the screen at the same time.
X2.	Be as fast as possible.
X
XThe routines in the dpy library are called directly by the user program.
XNone of these routines are a macro, so that there is no need to include a
Xheader file to use dpy.  These routines use the termlib (or curses) library
Xroutines to obtain the proper terminal escape sequences.  Therefore, you
Xload your program as in the following examples:
X
X	cc -o yourprog yourprog.c -ldpy -ltermlib	for BSD
Xor:
X	cc -o yourprog yourprog.c -ldpy -lcurses	for System V
X
XDpy keeps two arrays which hold images of the terminal screen.  The first
Xarray (the "current screen") is a copy of what the terminal screen really
Xlooks like.  The second array (the "future screen") is a copy of what the
Xcalling program wants the screen to look like.  The use of dpy proceeds in
Xtwo phases under the control of the calling program, as follows:
X
XIn the first phase, only the future screen is manipulated.  The calling
Xprogram positions the "current write location" as desired within the future
Xscreen, and writes new information within it.  During this phase, no actual
XI/O occurs and the terminal screen remains unchanged.
X
XIn the second phase, the calling program asks dpy to update the screen.
XDpy compares the future screen contents with the current screen contents,
Xand does whatever terminal I/O is required in order to make the current
Xscreen look like the future screen.  After this is done, the two screen
Ximages are identical.
X
XThe calling program usually uses dpy by looping between the above two
Xphases.  First, it defines what the screen should look like, and then
Xthe screen is updated, then it defines the screen again, and so on.  In
Xdoing so, the program can be "dumb" or "smart".  A dumb program rewrites
Xall of the data in its windows each iteration of the loop, and depends on
Xdpy to prevent terminal I/O for unchanging data.  Thus a dumb program
Xcan be very trivial, and doesn't have to know anything about what is
Xhappening on the screen.  A smart program knows the exact locations of the
Xdesired screen changes each iteration of the loop, and only rewrites those
Xlocations.  This runs somewhat faster than a dumb program, but has the
Xdisadvantage of introducing complexity and possible bugs into the program.
XIf generating a new screen of data is too much work for each iteration,
Xa good compromise is to keep an internal copy of the screen in the program,
Xupdate that appropriately, and give that whole screen to dpy each iteration.
X
XPutting data into the future screen is much like writing to a real terminal.
XThere is a "current write location", which is similar to the cursor of the
Xterminal.  Like a terminal, characters written to dpy appear at the current
Xwrite location, and automatically advance its location.  When the rightmost
Xlocation on a line is reached, the current write location is automatically
Xmoved to the leftmost location on the next line.  Finally, some control
Xcharacters have special effects like on a terminal.  In particular, linefeed
Xmoves to the beginning of the next line, return moves back to the beginning
Xof the current line, tab moves to the next tab stop as if the corresponding
Xnumber of spaces were given, and backspace backs up by one location.  Other
Xcontrol characters appear in ^X format.
X
XThere are some differences between writing to the future screen and most real
Xterminals, however.  Firstly, scrolling does not usually occur.  If the end of
Xthe screen is reached, any further characters are ignored.  Secondly, it is
Xpossible to limit output to a "window", which is a rectangle of any size on
Xthe screen.  The location and size of a window is specified by the program
Xwhen it wants to limit output to a rectangle.  This window acts just like
Xa regular terminal screen of the appropriate size.  Furthermore, coordinates
Xare relative to the window's upper left corner, so a routine which writes
Xin the window does not need to know where it is.  Data in the future screen
Xwhich lies outside of the window is untouched, no matter what is done within
Xthe window.  Typically, a program divides the screen up into several windows
Xwhich do not overlap.  Data can then be written to each window independently,
Xwithout regard to where each window is.  For example, a linefeed character
Xmoves to the beginning of the next line in the current window, instead of
Xto the beginning of the next line of the screen.
X
XThe following is a description of the procedures available in the dpy library:
X
X
Xdpyinit(ttytype, modestring)
Xchar *ttytype, *modestring;
X
X	This routine must be called before any other call to dpy (except for
X	dpyclose).  It allocates memory for the two screen images for dpy,
X	defines the current window to be the whole screen, sets the current
X	write location to the upper left corner of the screen, uses signal(2)
X	to cause the terminal stop character to trap to dpystop for pretty
X	program stopping (only under BSD systems), and sets terminal modes
X	for input of various kinds.  The actual terminal screen is not cleared
X	until the first dpyupdate call is made, so that you can initialize
X	your program based upon the terminal size before deciding to continue.
X	Returns nonzero with an error message typed if cannot initialize.
X
X	The 'ttytype' argument is the terminal type string (example: "vt100"),
X	or NULL to use the TERM environment variable value.  'Modestring' is
X	a string specifying how input is to be treated from the terminal.
X	Each mode is specified by a single letter, preceeded by an (optional)
X	plus sign to enable the mode, or preceeded by a minus sign to disable
X	the mode.  Modes can be separated by spaces.  Modes not mentioned in
X	the string are unchanged.  The currently defined modes letters are:
X		e  (echo)   Echoing of input characters occurs.
X		c  (cbreak) Characters are returned without waiting for
X			    a newline and tty signals are processed.
X		r  (raw)    Characters are returned exactly as typed and
X			    tty signals are disabled.
X	Thus the normal terminal modes before starting dpy are described
X	by the mode string "e -c -r".  If the mode string specified is a
X	NULL pointer, then the default mode string of "-e c" is used.
X	If the dpyread call is to be used in your program, then you must
X	specify that echoing is disabled, and either cbreak or raw mode
X	is enabled.
X
X
Xdpyclose()
X	Homes down to the lower left corner and clears the last line of the
X	terminal screen, frees the memory allocated by dpyinit, and resets
X	the original terminal modes.  Useful when exiting your program.
X	If dpyinit has not yet been called, nothing is done, so it is safe
X	to call dpyclose at any time.
X
X
Xdpywrite(buf, count)
Xchar *buf;
Xint count;
X
X	Writes 'count' characters from location 'buf' to the future screen
X	image at the current write location in the current window, and updates
X	the current write location appropriately.  This call does not do any
X	actual I/O to the terminal.  Control characters are handled reasonably,
X	as is running off the end of a line or the window.  This routine is
X	called by dpychar, dpystr, and dpyprintf, and is therefore the most
X	efficient way to give characters to dpy.  Returns nonzero if not all
X	the characters fit in the window.
X
X
Xdpychar(ch)
Xchar ch;
X
X	Writes a single character to the future screen image.  Returns nonzero
X	if the character couldn't fit in the window.
X
X
Xdpystr(str)
Xchar *str;
X
X	Writes a null terminated string to the future screen image.  Returns
X	nonzero if any of string couldn't fit in the window.
X
X
Xdpyprintf(fmt [,args] ...)
Xchar *fmt;
X
X	Writes a formated string to the future screen image, in the
X	manner of printf.  Returns nonzero if any of the string couldn't
X	fit in the window.
X
X
Xdpyclrline()
X
X	Clears the rest of the line in the future screen image (by changing
X	the characters to spaces), but does not change the current write
X	location.  Writing a linefeed to the future screen performs this
X	function, in addition to moving the write location to the next line.
X
X
Xdpyclrwindow()
X
X	Clears the rest of the window in the future screen image, but
X	does not change the current write location.  When rewriting a
X	window completely, this should be called when done so that any
X	old contents of the window will be sure to be cleared out.
X
X
Xdpyhome()
X
X	Moves the current write location to the top left corner of the window.
X	When being a dumb program which rewrites the whole window, this needs
X	to be called between iterations.
X
X
Xdpygetrow()
X
X	Returns the row number of the current write location.  This is
X	the row number where the next character written would go.  If the
X	next character written would not fit in the window, -1 is returned.
X	This number is relative to the first line of the current window.
X	For example, if the current write location is at the beginning of
X	the top line of the window, this function returns zero.
X
X
Xdpygetcol()
X
X	Returns the column number of the current write location.  This is
X	the column number where is next character written would go.  If the
X	next character written would not fit in the window, -1 is returned.
X	This number is relative to the current window.  For example, if
X	the current write location is at the beginning of a line in the
X	window, this function returns zero.
X
X
Xdpyupdate()
X
X	Makes the terminal screen look like the future screen image,
X	using a minimal amount of terminal I/O.  The cursor is positioned
X	at the current write location when this function is done.
X
X
Xdpyredraw()
X
X	Redraws the screen to make it look like the current screen image.
X	Used to fix the screen when it becomes trashed due to glitches or
X	other programs also writing to the screen.  This does not change
X	the current or future screen images.
X
X
Xdpystop()
X
X	Suspends execution of the process in a nice way.  Homes down to
X	the lower left corner, clears the last line, resets terminal modes,
X	and then stops the process.  If the process is continued, terminal
X	modes are restored, the screen is redrawn, and execution proceeds.
X	This is called automatically when the terminal stop character is
X	typed by the user.  This call is a nop for non-BSD systems.
X
X
Xdpymove(row, col)
Xint row, col;
X
X	Changes the current write location to the given row and column
X	numbers, relative to the upper left corner of the current window.
X	Coordinates start at zero.  Negative numbers measure from the last
X	row or column of the window.  For example, dpymove(-1, 0) positions
X	to the beginning of the last line of the window.  This does not set
X	the actual terminal's cursor location, unless this is also followed
X	by a call to dpyupdate.  Returns nonzero if the coordinates are
X	illegal.
X
X
Xdpyplace(row, col, ch)
Xint row, col;
Xchar ch;
X
X	Place the given character at the given coordinates within the
X	current window, without changing the current write location.  The
X	character placed should not be a control character.  The coordinates
X	can be negative to measure from the last row or column of the window.
X	Like dpywrite and similar routines, this routine only affects the
X	future screen image, and does no terminal I/O.  Returns nonzero if
X	the coordinates are illegal.
X
X
Xdpyget(row, col)
Xint row, col;
X
X	Returns the character which is at the given coordinates within the
X	current window, without changing the current write location.  The
X	coordinates can be negative to measure from the last row or column of
X	the window.  The character returned is from the future screen image,
X	not the current screen image.  Returns negative if the coordinates
X	are illegal.
X
X
Xdpyread(prompt, routine, buf, count)
Xchar *prompt;
Xint (*routine)();
Xchar *buf;
Xint count;
X
X	This is used to read data from the user, while showing the input
X	data on the screen.  The current window is used for this purpose.
X	Editing of the input and updating of the screen is automatically
X	performed by dpy.  To use this feature properly do the following:
X
X	1.	Set a window to the region where you want input to occur.
X		Usually this is one line at the top or bottom of the screen.
X	2.	Call dpyread to read the input.
X
X	If the prompt string pointer is not NULL, then the prompt string will
X	appear at the top of the window, followed by the data typed by the user.
X	To display the user's input without any prompt, use a pointer to a
X	null string.  If the prompt pointer is NULL, then no terminal I/O at
X	all will be performed (useful when input is from a script or file).
X	The buf and count specify the area in the calling program where the
X	data being read is stored.  The data will be what was typed by the
X	user, not what is seen on the screen (for example, control characters
X	appear on the screen as ^X, but appear in the buffer as themselves).
X	If more data is typed than fits in the window, the data in the window
X	is automatically scrolled to keep the current input location visible.
X	Routine is a function variable which specifies a routine which will
X	provide the input characters for dpy.  The routine is called with the
X	previous character read (-1 on the first call).  It returns the
X	next character read, or -1 to return from dpyread.  Providing the
X	previous character as an argument allows a routine to easily return
X	a break character as input, and then end the input on the next call.
X	If 0 is supplied as a routine, a default routine will be used which
X	reads from the standard input until an end of file or newline is typed
X	(which is included in the buffer).  If the character count is exceeded,
X	dpyread will warn the user with a bell and discard further input.
X	Dpyread returns the number of characters read into the buffer, which
X	is not guaranteed to contain a terminating null or newline character.
X
X
Xdpywindow(minrow, maxrow, mincol, maxcol)
Xint minrow, maxrow, mincol, maxcol;
X
X	Specifies a rectangle where characters will be placed in the future
X	screen image, and sets the current write location to the top left
X	corner of the rectangle.  The rectangle is specified by the minimum
X	and maximum row numbers, and minimum and maximum column numbers,
X	where the top left corner of the screen is row 0 and column 0.
X	The coordinates are specified in absolute screen coordinates, and
X	negative numbers specify row or column numbers from the bottom or
X	right edges of the screen.  For example, dpywindow(0, -1, 0, -1)
X	defines a window which is the whole screen.  Returns nonzero if the
X	coordinates are illegal.
X
X
XFinal hints:
X
XA window can be filled with a background character by simply writing that
Xcharacter to the window until a nonzero return value is obtained, meaning
Xthe window is full.
X
XIf a region of the screen is never changed (such as a help text), then that
Xregion should be in its own window.  Then it only needs to be written once.
X
XThe terminal size can be found after calling dpyinit by simply calling
Xdpymove(-1, -1) to move to the lower right of the screen, and then calling
Xdpygetrow and dpygetcol to return the row and column numbers.
X
XWhile writing data to the window, dpygetrow and dpygetcol are useful to
Xremember the location of a particular position in the window, so that
Xthe terminal cursor can be positioned back to that location when all the
Xdata is written.  In this way, you don't have worry about line wrapping
Xand tab and other control character expansions when computing how to
Xposition the cursor on a particular character.
//E*O*F dpy.doc//
echo x - makefile.bsd
sed -e 's/^X//' > "makefile.bsd" << '//E*O*F makefile.bsd//'
X# @(#)makefile.bsd	1.6	2/27/85
X# Makefile for BSD systems
X
X.SUFFIXES: .c .o .s
X
XCFLAGS = -O -DBSD
XCC = cc
XAS = as
XRANLIB = ranlib
XLIBDIR = /usr/lib
X
XCFILES = dpy.c dpymove.c dpyplace.c dpyget.c dpyread.c dpywindow.c
XOFILES = dpy.o dpymove.o dpyplace.o dpyget.o dpyread.o dpywindow.o
XSOURCES = ${CFILES} dpy.h vaxsubs.s ns32ksubs.s gensubs.c
X
X# Machine dependent assembly routines.  Define MACHINEFILES appropriately
X# to select the target machine.  Gensubs is a portable version of the
X# subroutines applicable to any machine (but slower than the assembly ones).
X
XGENFILES = gensubs.o		# generic subroutines
XNS32KFILES= ns32ksubs.o		# National Semiconductor 32032 subroutines
XVAXFILES = vaxsubs.o		# VAX subroutines
XMACHINEFILES = ${VAXFILES}	# subroutines to be used
X
X
Xlibdpy.a: ${OFILES} ${MACHINEFILES}
X	ar rc libdpy.a ${OFILES} ${MACHINEFILES}
X	${RANLIB} libdpy.a
X
Xsources: ${SOURCES}
X
X${SOURCES}:
X	sccs get $@
X
X${OFILES}: dpy.h
X
Xinstall: libdpy.a
X	cp libdpy.a ${LIBDIR}
X	${RANLIB} ${LIBDIR}/libdpy.a
X	chmod 644 ${LIBDIR}/libdpy.a
X
Xtest1:	test1.o libdpy.a
X	${CC} -o test1 test1.o libdpy.a -ltermlib
X
Xtest2:	test2.o libdpy.a
X	${CC} -o test2 test2.o libdpy.a -ltermlib
X
Xclean:
X	rm -f *.o libdpy.a test1 test2
X
X.s.o:
X	${AS} -o $*.o $*.s
X
X.c.o:
X	${CC} -c ${CFLAGS} $*.c
//E*O*F makefile.bsd//
echo x - makefile.usg
sed -e 's/^X//' > "makefile.usg" << '//E*O*F makefile.usg//'
X# @(#)makefile.usg	1.5	2/27/85
X# Makefile for USG systems
X
X.SUFFIXES: .c .o .s
X
XCC = cc
XOFLAG = -O
XDFLAG =
XSYSTEM = -DUSG
XCFLAGS = $(OFLAG) $(DFLAG) $(SYSTEM)
XAS = as
XLIBDIR = /usr/lib
XLIB = libdpy.a
X
XCFILES = dpy.c dpymove.c dpyplace.c dpyget.c dpyread.c dpywindow.c
XOFILES = dpy.o dpymove.o dpyplace.o dpyget.o dpyread.o dpywindow.o
X
XLIBOBJS =	$(LIB)(dpy.o) \
X		$(LIB)(dpymove.o) \
X		$(LIB)(dpyplace.o) \
X		$(LIB)(dpyget.o) \
X		$(LIB)(dpyread.o) \
X		$(LIB)(dpywindow.o)
X
XSOURCES = dpy.h ${CFILES} vaxsubs.s ns32ksubs.s gensubs.c
X
X# Machine dependent assembly routines.  Define MACHINEFILES appropriately
X# to select the target machine.  Gensubs is a portable version of the
X# subroutines applicable to any machine (but slower than the assembly ones).
X
XGENFILES = gensubs.o		# generic subroutines
XNS32KFILES = ns32ksubs.o	# National Semiconductor 32032 subroutines
XVAXFILES = vaxsubs.o		# VAX subroutines
XMACHINEFILES = ${VAXFILES}	# subroutines to be used
X
X
Xlibdpy.a: ${LIBOBJS} $(MACHINEFILES)
X	$(MAKE) -$(MAKEFLAGS) -f dpy.mk.usg $? OFLAG=$(OFLAG) \
X		DFLAG=$(DFLAG) SYSTEM=$(SYSTEM)
X	ar rv libdpy.a $?
X	/bin/rm $?
X
X$(LIB)(vaxsubs.o) vaxsubs.o : vaxsubs.s
X
X$(LIB)(gensubs.o) gensubs.o : gensubs.s
X
X$(LIB)(ns32ksubs.o) ns32ksubs.o : ns32ksubs.s
X
Xsources: ${SOURCES}
X
X$(LIBOBJS) ${OFILES}: dpy.h
X
Xinstall: libdpy.a
X	cp libdpy.a ${LIBDIR}
X	chmod 644 ${LIBDIR}/libdpy.a
X
Xtest1:	test1.o libdpy.a
X	$(CC) test1.o $(LDFLAGS) -o test1 libdpy.a -lcurses
X
Xtest2:	test2.o libdpy.a
X	$(CC) test2.o $(LDFLAGS) -o test2 libdpy.a -lcurses
X
Xprint:	${SOURCES} makefile
X	pr -w120 -n ${SOURCES} makefile >dpy.lst
X	@echo dpy.lst finished
X
Xclean:
X	rm -f *.o libdpy.a test1 test2
X
XPRECIOUS:	libdpy.a
X
X.c.a:
X	@echo $*.c
X
X.s.a:
X	@echo $*.s
X
X.s.o:
X	${AS} -o $*.o $*.s
X
X.c.o:
X	${CC} -c ${CFLAGS} $*.c
X
X.s~.s:
X	$(GET) $(GFLAGS) -p $< > $*.s
//E*O*F makefile.usg//
echo x - test1.c
sed -e 's/^X//' > "test1.c" << '//E*O*F test1.c//'
X/*
X * Example program.  Randomly fill up the screen with numbers until
X * it all turns to asterisks.
X */
X
X#ifdef USG
X#define	random	rand
X#endif USG
X
Xmain()
X{
X	register int row, col, ch;
X	register int rows, cols;
X
X	if (dpyinit((char *)0, "e")) exit(1);
X	dpymove(-1, -1);
X	rows = dpygetrow() + 1;
X	cols = dpygetcol() + 1;
X	dpyhome();
X	while (1) {
X		dpyupdate();
X		row = random() % rows;
X		col = random() % cols;
X		ch = dpyget(row, col);
X		if (ch == ' ') ch = '1';
X		else if (ch == '9') ch = '*';
X		else if (ch != '*') ch++;
X		dpyplace(row, col, ch);
X	}
X}
//E*O*F test1.c//
echo x - test2.c
sed -e 's/^X//' > "test2.c" << '//E*O*F test2.c//'
X/*
X * Example program.  Split the screen into three windows, input using the
X * top window until an escape is typed, and show it in the bottom window.
X * The middle window is just a border.  Continue until a ^E is typed.
X */
X
X#include <signal.h>
X
X#define	BOARDER	10		/* row for boarder window */
X#define	BUFSIZE	1000		/* maximum chars which can be input */
X#define	ESC	'\033'		/* escape character */
X#define	QUIT	'\005'		/* quit character (^E) */
X
Xint	grabchar();		/* routine to read tty chars */
Xint	quit();			/* interrupt routine */
X
Xmain()
X{
X	register int	i;		/* character count */
X	char	buf[BUFSIZE];		/* input buffer */
X
X	signal(SIGINT, quit);
X	if (dpyinit((char *)0, "-ec"))
X		exit(1);
X	dpywindow(BOARDER, BOARDER, 0, -1);
X	while (dpywrite("-----", 5) == 0) ;
X	while (1) {
X		dpywindow(0, BOARDER - 1, 0, -1);
X		i = dpyread("Input: ", grabchar, buf, sizeof(buf));
X		if ((i > 0) && (buf[i-1] == QUIT)) break;
X		dpywindow(BOARDER + 1, -1, 0, -1);
X		dpyprintf("Read %d chars:\n", i);
X		dpywrite(buf, i);
X		dpyclrwindow();
X		dpyupdate();
X	}
X	dpyclose();
X}
X
X
X/*
X * Read next char from tty, quitting on an end of file or escape character.
X * The escape character is removed from the buffer, but the end of file
X * character is kept.
X */
Xgrabchar(oldch)
X{
X	unsigned char	newch;
X
X	if ((oldch == QUIT) || (read(0, &newch, 1) != 1) || (newch == ESC))
X		return(-1);
X	return(newch);
X}
X
X
X/*
X * Here on an interrupt.
X */
Xquit()
X{
X	dpyclose();
X	exit(0);
X}
//E*O*F test2.c//
echo x - dpy.h
sed -e 's/^X//' > "dpy.h" << '//E*O*F dpy.h//'
X/*
X * @(#)dpy.h	1.12	2/27/85
X * @(#)Copyright (C) 1985 by D Bell
X * Modified for USG by Alan P.W. Hewett
X */
X
X#ifdef	BSD
X#include <sys/ioctl.h>
X#endif	BSD
X
X#ifdef	USG
X#include <sys/termio.h>
X#define	CTRL(c)	('c'&037)
X#undef	CERASE
X#define	CERASE	CTRL(h)
X#define	CRPRNT	CTRL(r)
X#define	CWERASE	CTRL(w)
X#define	CLNEXT	CTRL(v)
X#define	bcopy(from,to,size)	memcpy(to,from,size)
X#endif	USG
X
X#define	STDIN	0		/* standard descriptors */
X#define	STDOUT	1
X#define	STDERR	2
X
X/*
X * The window structure contains data describing the state of the screen.
X * The following picture shows a typical screen and window, and shows the
X * relationship of each of the character pointers in the structure.
X *
X *	A----------------------|
X *	|                      |
X *	|    C--------|        |
X *	|    |        |        |
X *	|    E     G  |F       |
X *	|    |        |        |
X *	|    D--------|        |
X *	|                      |
X *	|----------------------|
X *	B
X */
Xstruct	window	{
X	char	*begdata;		/* A: beginning of new screen image */
X	char	*enddata;		/* B: end of screen image */
X	char	*begwin;		/* C: beginning of current window */
X	char	*endwin;		/* D: last row of current window */
X	char	*begrow;		/* E: beginning of current row */
X	char	*endrow;		/* F: end of current row */
X	char	*cp;			/* G: current character pointer */
X	char	*begchange;		/* beginning of changed region */
X	char	*endchange;		/* end of changed region */
X	char	*screen;		/* the actual screen image */
X	int	nrows;			/* number of rows on screen */
X	int	ncols;			/* number of columns on screen */
X	int	delta;			/* distance between rows */
X	int	currow;			/* current row column */
X	int	curcol;			/* cursor column column */
X	int	tabsize;		/* current tab size */
X	char	nocrlf;			/* don't do automatic crlfs */
X	char	noctrl;			/* don't show control characters */
X	char	nomove;			/* don't move cursor when done */
X	char	scroll;			/* scroll screen when end reached */
X	char	inited;			/* we are initialized */
X	char	output;			/* we have output to screen */
X	char	full;			/* window is full */
X	char	c_kill;			/* line erase character */
X	char	c_erase;		/* character erase character */
X	char	c_werase;		/* word erase character */
X	char	c_rprnt;		/* retype line character */
X	char	c_eof;			/* end of file character */
X	char	c_lnext;		/* literal input character */
X	char	tc_am;			/* cursor wraps on last column */
X	char	tc_hocc;		/* character count for tc_ho */
X	char	tc_cecc;		/* character count for tc_ce */
X	char	tc_cdcc;		/* character count for tc_cd */
X	char	*tc_ho;			/* home capability */
X	char	*tc_ce;			/* clear to end of line */
X	char	*tc_cd;			/* clear to end of display */
X	char	*tc_cm;			/* move cursor */
X	char	*tptr;			/* pointer into termcap strings */
X#ifdef	BSD
X	struct	sgttyb	old0ttyblk;	/* original tty parameters for stdin */
X	struct	sgttyb	new0ttyblk;	/* new terminal parameters for stdin */
X	struct	sgttyb	old1ttyblk;	/* original tty parameters for stdout */
X	struct	sgttyb	new1ttyblk;	/* new terminal parameters for stdout */
X#endif	BSD
X#ifdef	USG
X	struct	termio	old0ttyblk;	/* original tty parameters for stdin */
X	struct	termio	new0ttyblk;	/* new terminal parameters for stdin */
X	struct	termio	old1ttyblk;	/* original tty parameters for stdout */
X	struct	termio	new1ttyblk;	/* new terminal parameters for stdout */
X#endif	USG
X	char	tdata[1024];		/* buffer for termcap data */
X	char	tbuf[200];		/* strings for termcap */
X};
X
Xextern	struct	window	window;		/* window structure */
//E*O*F dpy.h//
echo done
-- 
no comment is a comment.

chongo@nsc.UUCP (Landon Noll) (04/12/85)

In net.sources:
  I am reposting DBell's DPY sources in response to all the folks who
  needed them for his LIFE and WAR progs.  DBell is no longer on the
  net (in fact in a few days he will no longer be in this hemisphere)
  otherwise he would have done this himself.

In net.sources.games:
  I am reposting DBell's LIFE sources complete with the changes for the
  new DPY.  Both LIFE and WAR (which was posted by DBell not long ago)
  require the use of DPY so be sure and GRAB IT FROM net.sources NOW!!!

#---Cut here and place in it's own directory, then feed to Bourne shell---
# This is a shell archive.  Remove anything before this line, then
# unpack it by saving it in a file and typing "sh file".  (Files
# unpacked will be owned by you and have default permissions.)
# This archive contains:
#   dpy.c (22206 chars)
#   dpyget.c (1117 chars)
#   dpymove.c (1069 chars)
#   dpyplace.c (1297 chars)
#   dpyread.c (3564 chars)
#   dpywindow.c (1170 chars)
#   gensubs.c (1183 chars)
#   vaxsubs.s (332 chars)
#   ns32ksubs.s (812 chars)
#
echo x - dpy.c
sed -e 's/^X//' > "dpy.c" << '//E*O*F dpy.c//'
Xstatic char *sccsid = "@(#)dpy.c	1.46	2/27/85";
Xstatic char *cpyrid = "@(#)Copyright (C) 1985 by D Bell";
X
X
X/*
X * Different curses package (by David I. Bell).
X * Modified to run under System V by Alan P.W. Hewett.
X * These dpy module sources are in the public domain, and can be copied
X * or used as desired, with the following restrictions:
X * 1.	All copyright notices (and this notice) must be preserved.
X * 2.	The dpy sources (even if modified) cannot be sold for profit.
X * 3.	If any sources are modified, a sentence must exist by the
X *	copyright notice of each modified source file which says that
X *	the file has been modified.
X */
X
X
X#include <stdio.h>		/* standard I/O */
X#include <signal.h>		/* signals */
X#include "dpy.h"		/* window definitions */
X
X#define	DEL	0177		/* delete character */
X#define	EOL	'\n'		/* end of line character */
X#define	RET	'\r'		/* return character */
X#define	BS	'\b'		/* backspace character */
X#define	TAB	'\t'		/* tab character */
X#define	SPACE	' '		/* space character */
X#define	TRUE	1		/* true value */
X#define	FALSE	0		/* false value */
X#define	INTSIZ	(sizeof(int))	/* size of an integer */
X
Xextern	short	ospeed;		/* output speed for tputs to use */
Xextern	char	PC;		/* pad character for tputs to use */
Xstruct	window	window;		/* the window */
Xstatic	int	dpytputs();	/* called by tputs to type to terminal */
Xstatic	int	dpysputs();	/* called by tputs to save characters */
Xint	dpystop();		/* stop routine */
Xchar	*tgetstr();		/* return termcap string */
Xchar	*malloc();		/* allocate memory */
Xchar	*getenv();		/* return environment variable */
X
X
X/*
X * Initialize the window structure.  Returns nonzero on failure with a
X * message already typed.  The ttytype argument is the terminal type string,
X * or NULL if the TERM environment variable is to be used.  Modes is a
X * string whose characters describe the desired state of the terminal.
X * These are:
X * 	+	turn on mode indicated by next character (default)
X *	-	turn off mode indicated by next character.
X *	c	cbreak mode (return each character as typed, without waiting
X *		for an end of line, and leave signal processing on).
X *	e	echoing of typed-in characters is enabled.
X *	r	raw mode (return each character as typed, no canonical or
X *		signal processing of any kind).
X *	<SP>	spaces are ignored
X * So the terminal modes before dpy runs are normally "e -c -r".
X * A NULL modes pointer defaults the modes to "-e c".
X */
Xdpyinit(ttytype, modes)
X	register char	*ttytype;	/* terminal type, or NULL for default */
X	char	*modes;			/* terminal modes */
X{
X	register struct	window	*wp;	/* window pointer */
X	register char	*cp;		/* character pointer */
X	register char	*sp;		/* pointer for spaces */
X	register int	size;		/* size of character array */
X	int on;				/* whether or not mode is on */
X#ifdef BSD
X	struct	ltchars	ltchars;	/* local terminal characters */
X	struct	tchars	tchars;		/* terminal characters */
X#endif BSD
X
X	wp = &window;
X	wp->inited = FALSE;
X	wp->output = FALSE;
X	if (ttytype == NULL) {
X		ttytype = getenv("TERM");
X		if (ttytype == NULL) {
X			fprintf(stderr, "dpyinit: TERM not defined\n");
X			return(1);
X		}
X	}
X	size = tgetent(wp->tdata, ttytype);
X	if (size <= 0) {
X		fprintf(stderr, size ? "dpyinit: cannot open termcap file\n"
X			: "dpyinit: unknown terminal type %s\n", ttytype);
X		return(1);
X	}
X	/*
X	 * Collect current tty modes, and remember editing characters
X	 */
X	wp->c_kill = CKILL;		/* init in case stdin is not a tty */
X	wp->c_erase = CERASE;
X	wp->c_werase = CWERASE;
X	wp->c_lnext = CLNEXT;
X	wp->c_rprnt = CRPRNT;
X	wp->c_eof = CEOF;
X#ifdef	BSD
X	if (ioctl(STDIN, TIOCGETP, &wp->old0ttyblk) == 0) {
X		wp->c_erase = wp->old0ttyblk.sg_erase;
X		wp->c_kill = wp->old0ttyblk.sg_kill;
X	}
X	if (ioctl(STDIN, TIOCGLTC, &ltchars) == 0) {
X		wp->c_werase = ltchars.t_werasc;
X		wp->c_rprnt = ltchars.t_rprntc;
X		wp->c_lnext = ltchars.t_lnextc;
X	}
X	if (ioctl(STDIN, TIOCGETC, &tchars) == 0) {
X		wp->c_eof = tchars.t_eofc;
X	}
X	wp->old1ttyblk.sg_ospeed = 0;
X	ioctl(STDOUT, TIOCGETP, &wp->old1ttyblk);
X	ospeed = wp->old1ttyblk.sg_ospeed;	/* save speed for tputs */
X#endif	BSD
X#ifdef	USG
X	if (ioctl(STDIN, TCGETA, &wp->old0ttyblk) == 0) {
X		wp->c_erase = wp->old0ttyblk.c_cc[VERASE];
X		wp->c_kill = wp->old0ttyblk.c_cc[VKILL];
X		wp->c_eof = wp->old0ttyblk.c_cc[VEOF];
X	}
X	ioctl(STDOUT, TCGETA, &wp->old1ttyblk);
X#endif	USG
X	/*
X	 * Collect terminal capability strings
X	 */
X	wp->nrows = tgetnum("li");
X	wp->ncols = tgetnum("co");
X	wp->tc_am = tgetflag("am");
X	wp->tbuf[0] = '\0';
X	wp->tptr = wp->tbuf;
X	(void) tgetstr("pc", &wp->tptr);
X	PC = wp->tbuf[0];
X	wp->tptr = wp->tbuf;
X	wp->tc_ho = tgetstr("ho", &wp->tptr);
X	wp->tc_hocc = wp->tptr - wp->tbuf - 1;
X	wp->tc_ce = tgetstr("ce", &wp->tptr);
X	wp->tc_cd = tgetstr("cd", &wp->tptr);
X	wp->tc_cm = tgetstr("cm", &wp->tptr);
X	if ((wp->nrows <= 0) || (wp->ncols <= 0) || (wp->tc_ce == NULL)
X		|| (wp->tc_cd == NULL) || (wp->tc_cm == NULL)) {
X			fprintf(stderr, "dpyinit: missing termcap entry\n");
X			return(1);
X	}
X	sp = wp->tptr;			/* apply padding to clear screen */
X	tputs(wp->tc_cd, wp->nrows, dpysputs);
X	wp->tc_cd = sp;
X	wp->tc_cdcc = wp->tptr - sp;
X	sp = wp->tptr;			/* and to clear line string */
X	tputs(wp->tc_ce, 1, dpysputs);
X	wp->tc_ce = sp;
X	wp->tc_cecc = wp->tptr - sp;
X	if (wp->tc_ho == NULL) {	/* make home up string if not defined */
X		sp = wp->tptr;
X		tputs(tgoto(wp->tc_cm, 0, 0), 1, dpysputs);
X		wp->tc_ho = sp;
X		wp->tc_hocc = wp->tptr - sp;
X	}
X	wp->delta = (wp->ncols + INTSIZ) &~ (INTSIZ-1);	/* round up */
X	size = wp->nrows * wp->delta;
X	cp = malloc(2 * (size + INTSIZ));
X	if (cp == NULL) {
X		fprintf(stderr, "dpyinit: failed to allocate memory\n");
X		return(1);
X	}
X	wp->begdata = cp;
X	wp->enddata = cp + size;
X	wp->begwin = cp;
X	wp->endwin = cp + size - wp->delta;
X	wp->begrow = cp;
X	wp->endrow = cp + wp->ncols;
X	wp->cp = cp;
X	wp->screen = cp + size + INTSIZ;
X	for (sp = cp + (2 * (size + INTSIZ)) - 1; sp >= cp; sp--) *sp = SPACE;
X	*((int *)(cp + size)) = 0;	/* terminate end of screens */
X	*((int *)(wp->screen + size)) = 0;
X	wp->currow = 0;
X	wp->curcol = 0;
X	wp->noctrl = 0;
X	wp->nocrlf = 0;
X	wp->nomove = 0;
X	wp->scroll = 0;
X	wp->full = 0;
X	wp->tabsize = 8;
X	wp->begchange = wp->enddata;
X	wp->endchange = wp->begdata;
X	/*
X	 * Copy old tty modes to new ones, and modify them as specified
X	 */
X	wp->new0ttyblk = wp->old0ttyblk;
X	wp->new1ttyblk = wp->old1ttyblk;
X	if (modes == (char*)NULL) modes = "-e c";
X	on = TRUE;
X	for (cp = modes; *cp ; cp++) {		/* scan mode string */
X		switch (*cp) {
X		case ' ':			/* spaces (ignored) */
X			continue;
X		case '+':			/* turn on next mode */
X			on = TRUE;
X			continue;
X		case '-':			/* turn off next mode */
X			on = FALSE;
X			continue;
X#ifdef	BSD
X		case 'e':			/* enable echoing */
X			if (on) {
X				wp->new0ttyblk.sg_flags |= ECHO;
X				wp->new1ttyblk.sg_flags |= ECHO;
X			} else {
X				wp->new0ttyblk.sg_flags &= ~ECHO;
X				wp->new1ttyblk.sg_flags &= ~ECHO;
X			}
X			break;
X
X		case 'c':			/* enable character mode */
X			if (on) {
X				wp->new0ttyblk.sg_flags |= CBREAK;
X				wp->new1ttyblk.sg_flags |= CBREAK;
X			} else {
X				wp->new0ttyblk.sg_flags &= ~CBREAK;
X				wp->new1ttyblk.sg_flags &= ~CBREAK;
X			}
X			break;
X
X		case 'r':			/* enable raw mode */
X			if (on) {
X				wp->new0ttyblk.sg_flags |= RAW;
X				wp->new1ttyblk.sg_flags |= RAW;
X			} else {
X				wp->new0ttyblk.sg_flags &= ~RAW;
X				wp->new1ttyblk.sg_flags &= ~RAW;
X			}
X			break;
X#endif	BSD
X#ifdef	USG
X		case 'e':			/* enable echoing */
X			if (on) {
X				wp->new0ttyblk.c_lflag |= ECHO | ECHOE | ECHOK ;
X				wp->new1ttyblk.c_lflag |= ECHO | ECHOE | ECHOK ;
X			} else {
X				wp->new0ttyblk.c_lflag &= ~(ECHO|ECHOE|ECHOK) ;
X				wp->new1ttyblk.c_lflag &= ~(ECHO|ECHOE|ECHOK) ;
X			}
X			break ;
X
X		case 'c':			/* enable character mode */
X			if (on) {
X				wp->new0ttyblk.c_iflag |= ISTRIP ;
X				wp->new0ttyblk.c_lflag &= ~ICANON ;
X				wp->new0ttyblk.c_cc[VMIN] = 1 ;
X				wp->new0ttyblk.c_cc[VTIME] = 0 ;
X				wp->new1ttyblk.c_iflag |= ISTRIP ;
X				wp->new1ttyblk.c_lflag &= ~ICANON ;
X				wp->new1ttyblk.c_cc[VMIN] = 1 ;
X				wp->new1ttyblk.c_cc[VTIME] = 0 ;
X			} else {
X	    			wp->new0ttyblk.c_iflag |= (ICRNL|IUCLC) ;
X	    			wp->new0ttyblk.c_lflag |= ICANON ;
X	    			wp->new0ttyblk.c_cc[VEOF] =
X					wp->old0ttyblk.c_cc[VEOF] ;
X	    			wp->new0ttyblk.c_cc[VEOL] =
X					wp->old0ttyblk.c_cc[VEOL] ;
X	    			wp->new1ttyblk.c_iflag |= (ICRNL|IUCLC) ;
X	    			wp->new1ttyblk.c_lflag |= ICANON ;
X	    			wp->new1ttyblk.c_cc[VEOF] =
X					wp->old1ttyblk.c_cc[VEOF] ;
X	    			wp->new1ttyblk.c_cc[VEOL] =
X					wp->old1ttyblk.c_cc[VEOL] ;
X			}
X			break ;
X
X		case 'r':			/* enable raw mode */
X			if (on) {
X	    			wp->new0ttyblk.c_iflag &=
X					~(BRKINT|IGNPAR|ISTRIP|IXON|IXANY) ;
X	    			wp->new0ttyblk.c_oflag &= ~OPOST ;
X	    			wp->new0ttyblk.c_cflag =
X					(wp->new0ttyblk.c_cflag|CS8) & ~PARENB ;
X	    			wp->new0ttyblk.c_lflag &= ~ICANON ;
X	    			wp->new0ttyblk.c_cc[VMIN] = 1 ;
X	    			wp->new0ttyblk.c_cc[VTIME] = 0 ;
X	    			wp->new1ttyblk.c_iflag &=
X					~(BRKINT|IGNPAR|ISTRIP|IXON|IXANY) ;
X	    			wp->new1ttyblk.c_oflag &= ~OPOST ;
X	    			wp->new1ttyblk.c_cflag =
X					(wp->new1ttyblk.c_cflag|CS8) & ~PARENB ;
X	    			wp->new1ttyblk.c_lflag &= ~ICANON ;
X	    			wp->new1ttyblk.c_cc[VMIN] = 1 ;
X	    			wp->new1ttyblk.c_cc[VTIME] = 0 ;
X			} else {
X	    			wp->new0ttyblk.c_iflag |=
X					(BRKINT|IGNPAR|ISTRIP|IXON
X					|IXANY|ICRNL|IUCLC) ;
X	    			wp->new0ttyblk.c_oflag |= OPOST ;
X	    			wp->new0ttyblk.c_cflag =
X					(wp->new0ttyblk.c_cflag & ~CSIZE) |
X					CS7 | PARENB ;
X	    			wp->new0ttyblk.c_lflag |= ICANON | ISIG ;
X	    			wp->new0ttyblk.c_cc[VEOF] = CEOF ;
X	    			wp->new0ttyblk.c_cc[VEOL] = 0 ;
X	    			wp->new0ttyblk.c_cc[VEOL2] = 0 ;
X	    			wp->new1ttyblk.c_iflag |=
X					(BRKINT|IGNPAR|ISTRIP|IXON|
X					IXANY|ICRNL|IUCLC) ;
X	    			wp->new1ttyblk.c_oflag |= OPOST ;
X	    			wp->new1ttyblk.c_cflag =
X					(wp->new1ttyblk.c_cflag & ~CSIZE) |
X					CS7 | PARENB ;
X	    			wp->new1ttyblk.c_lflag |= ICANON | ISIG ;
X	    			wp->new1ttyblk.c_cc[VEOF] = CEOF ;
X	    			wp->new1ttyblk.c_cc[VEOL] = 0 ;
X	    			wp->new1ttyblk.c_cc[VEOL2] = 0 ;
X			}
X			break;
X#endif	USG
X		default:
X			fprintf(stderr, "dpyinit: illegal flag: %c%c\n",
X				(on ? '+' : '-'), *cp);
X			return(1);
X		}
X		on = TRUE;		/* reset mode */
X	}
X	/*
X	 * Set the new modes for real
X	 */
X#ifdef	BSD
X	wp->new1ttyblk.sg_flags &= ~XTABS;
X	signal(SIGTSTP, dpystop);
X	ioctl(STDIN, TIOCSETP, &wp->new0ttyblk);
X	ioctl(STDOUT, TIOCSETP, &wp->new1ttyblk);
X#endif	BSD
X#ifdef	USG
X	wp->new1ttyblk.c_oflag &= ~TAB3 ;
X	ioctl(STDIN,TCSETAW,&wp->new0ttyblk) ;
X	ioctl(STDOUT,TCSETAW,&wp->new1ttyblk) ;
X#endif	USG	
X	wp->inited = TRUE;
X	return(0);
X}
X
X
X/*
X * Terminate the window, home down to the bottom of the screen, and reset
X * the terminal modes to their original state.
X */
Xdpyclose()
X{
X	register struct	window	*wp;	/* window pointer */
X
X	wp = &window;
X	if (wp->inited) {
X		wp->inited = FALSE;
X		if (wp->output) {
X			domove(wp->nrows - 1, 0, (char *)NULL);
X			fwrite(wp->tc_ce, 1, wp->tc_cecc, stdout);
X			fflush(stdout);
X		}
X		free(wp->begdata);
X#ifdef	BSD
X		ioctl(STDIN, TIOCSETP, &wp->old0ttyblk);
X		ioctl(STDOUT, TIOCSETP, &wp->old1ttyblk);
X#endif	BSD
X#ifdef	USG
X		ioctl(STDIN, TCSETAW, &wp->old0ttyblk);
X		ioctl(STDOUT, TCSETAW, &wp->old1ttyblk);
X#endif	USG
X	}
X	return(0);
X}
X
X
X/*
X * Put a given number of characters to the window at the current write location.
X * Certain control characters have effects, others print as ^X or are ignored.
X * Automatic wrapping to the next line is possible, and scrolling when the last
X * line is full. Returns nonzero if the window cannot hold the whole buffer.
X */
Xdpywrite(buf, count)
X	register char	*buf;		/* buffer address */
X	int	count;			/* number of characters */
X{
X	register struct	window	*wp;	/* window pointer */
X	register char	*endbuf;	/* end of buffer to write */
X	register char	*cp;		/* current character pointer */
X	register int	ch;		/* character to store */
X
X	wp = &window;
X	if (wp->full) return(1);
X	cp = wp->cp;
X	if (cp < wp->begchange) wp->begchange = cp;
X	for (endbuf = buf + count; buf < endbuf; buf++) {
X		ch = *buf;
X		if (ch < ' ') {			/* control character */
X			if (ch == EOL) {	/* new line */
X				clear(cp, wp->endrow);
X				if (cp >= wp->endwin) {	/* window full */
X					wp->endchange = wp->endrow;
X					if (wp->scroll == 0) {
X						wp->full = 1;
X						wp->cp = wp->begrow;
X						return(1);
X					}
X					wp->cp = cp;
X					dpyscroll();
X					cp = wp->begrow;
X					continue;
X				}
X				wp->begrow += wp->delta;
X				wp->endrow += wp->delta;
X				cp = wp->begrow;
X				continue;
X			}
X			if (ch == TAB) {	/* tab */
X				wp->cp = cp;
X				do {
X					if (dpywrite(" ", 1)) return(1);
X				} while ((wp->cp - wp->begrow) % wp->tabsize);
X				cp = wp->cp;
X				continue;
X			}
X			if (ch == BS) {		/* backspace */
X				if (cp > wp->begrow) cp--;
X				continue;
X			}
X			if (ch == RET) {	/* return character */
X				cp = wp->begrow;
X				continue;
X			}
X			/*
X			 * Obscure control character, show as ^X
X			 */
X			if (wp->noctrl) continue;
X			wp->cp = cp;
X			if (dpywrite("^", 1) || dpychar(ch + '@')) return(1);
X			cp = wp->cp;
X			continue;
X		}
X		if (ch == DEL) {		/* delete character */
X			if (wp->noctrl) continue;
X			wp->cp = cp;
X			if (dpywrite("^?", 2)) return(1);
X			cp = wp->cp;
X			continue;
X		}
X		/*
X		 * Normal printing character
X		 */
X		if (cp >= wp->endrow) {		/* end of row, see if do crlf */
X			wp->cp = cp;
X			if (cp > wp->endchange) wp->endchange = cp;
X			if (wp->nocrlf) return(1);
X			if (cp >= wp->endwin) {
X				if (wp->scroll == 0) return(1);
X				dpyscroll();
X				cp = wp->begrow;
X				*cp++ = ch;
X				continue;
X			}
X			wp->begrow += wp->delta;
X			wp->endrow += wp->delta;
X			cp = wp->begrow;
X		}
X		*cp++ = ch;
X	}
X	wp->cp = cp;
X	if (cp > wp->endchange) wp->endchange = cp;
X	return(0);
X}
X
X
X/*
X * Put a single character to the window.
X * Returns nonzero if full.
X */
Xdpychar(ch)
X	char	ch;
X{
X	return(dpywrite(&ch, 1));
X}
X
X
X/*
X * Put a null-terminated string to the window.
X * Returns nonzero if full.
X */
Xdpystr(str)
X	char	*str;
X{
X	return(dpywrite(str, strlen(str)));
X}
X
X
X
X/*
X * Print a formatted string to the window.  Returns nonzero if full.
X * This routine is a ripped off version of sprintf.  This routine is
X * machine-dependent!!
X */
X#ifdef	BSD
Xdpyprintf(fmt, args)
X	char	*fmt;			/* format string */
X{
X	FILE	_strbuf;		/* file header */
X	char	buf[5000];		/* data storage */
X
X	_strbuf._flag = _IOWRT+_IOSTRG;
X	_strbuf._ptr = buf;
X	_strbuf._cnt = 32767;
X	_doprnt(fmt, &args, &_strbuf);
X	return(dpywrite(buf, _strbuf._ptr - buf));
X}
X#endif	BSD
X#ifdef	USG
X
X#include <varargs.h>
X
Xdpyprintf(format, va_alist)
Xchar *format;
Xva_dcl
X{
X	register int count;
X	FILE siop;
X	va_list ap;
X	unsigned char	buf[5000];		/* data storage */
X
X	siop._cnt = sizeof(buf) ;
X	siop._base = siop._ptr = &buf[0] ;
X	siop._flag = _IOWRT;
X	siop._file = _NFILE;
X	va_start(ap);
X	count = _doprnt(format, ap, &siop);
X	va_end(ap);
X	*siop._ptr = '\0'; /* plant terminating null character */
X	return(dpywrite(buf, siop._ptr - buf));
X}
X#endif	USG
X
X
X/* Clear to the end of the current row without changing the write location */
Xdpyclrline()
X{
X	register struct	window	*wp;	/* window pointer */
X	register char	*cp;		/* current character */
X	register char	*endcp;		/* ending character */
X
X	wp = &window;
X	if (wp->full) return;
X	cp = wp->cp;
X	endcp = wp->endrow;
X	if (cp < wp->begchange) wp->begchange = cp;
X	if (endcp > wp->endchange) wp->endchange = cp;
X	clear(cp, endcp);
X}
X
X
X/* Clear to the end of the window without changing the write location */
Xdpyclrwindow()
X{
X	register struct	window	*wp;	/* window pointer */
X	register char	*begcp;		/* beginning character */
X	register char	*cp;		/* current character */
X	register char	*endcp;		/* ending character */
X
X	wp = &window;
X	if (wp->full) return;
X	begcp = wp->begrow;
X	endcp = wp->endrow;
X	cp = wp->cp;
X	if (cp < wp->begchange) wp->begchange = cp;
X	while (1) {
X		clear(cp, endcp);
X		if (begcp >= wp->endwin) break;
X		begcp += wp->delta;
X		endcp += wp->delta;
X		cp = begcp;
X	}
X	if (endcp > wp->endchange) wp->endchange = endcp;
X}
X
X
X/* Set the current write position to the top left corner of the window */
Xdpyhome()
X{
X	register struct	window	*wp;	/* window pointer */
X
X	wp = &window;
X	wp->endrow += wp->begwin - wp->begrow;
X	wp->begrow = wp->begwin;
X	wp->cp = wp->begrow;
X	wp->full = 0;
X}
X
X
X/* Scroll the current window upwards a line to make room for more data. */
Xdpyscroll()
X{
X	register struct	window	*wp;	/* window pointer */
X	register char	*currow;	/* beginning of current row */
X	register char	*nextrow;	/* beginning of next row */
X	register int	cols;		/* columns in window */
X
X	wp = &window;
X	cols = wp->endrow - wp->begrow;
X	currow = wp->begwin;
X	nextrow = currow + wp->delta;
X	while (currow < wp->endwin) {		/* move each line up */
X		bcopy(nextrow, currow, cols);
X		currow += wp->delta;
X		nextrow += wp->delta;
X	}
X	clear(currow, currow + cols);		/* clear last line */
X	wp->begchange = wp->begwin;
X	wp->endchange = wp->endwin + cols;
X}
X
X
X/*
X * Return the row number being written to, or -1 if out of the window.
X * The row number is relative to the beginning of the window.
X */
Xdpygetrow()
X{
X	register struct	window	*wp;	/* window pointer */
X
X	wp = &window;
X	if (wp->full) return(-1);
X	return((wp->cp - wp->begwin) / wp->delta);
X}
X
X
X/*
X * Return the column number being written to, or -1 if out of the window.
X * The column number is relative to the current window.
X */
Xdpygetcol()
X{
X	register struct	window	*wp;	/* window pointer */
X
X	wp = &window;
X	if (wp->full) return(-1);
X	if (wp->cp < wp->endrow) return(wp->cp - wp->begrow);
X	if (wp->nocrlf) return(-1);
X	return(0);
X}
X
X
X/* Make the screen match the data as previously written by the user */
Xdpyupdate()
X{
X	register struct	window	*wp;	/* window pointer */
X	register char	*scp;		/* screen character pointer */
X	register char	*cp;		/* current character */
X	register char	*spcp;		/* cp where spaces remain in row */
X	register char	*endrow;	/* end of row */
X	register char	*begrow;	/* beginning of row */
X	register int	row;		/* current row number */
X	int	diff;
X
X	wp = &window;
X	if (wp->output == 0) {		/* first output, clear screen */
X		wp->output = TRUE;
X		fwrite(wp->tc_ho, 1, wp->tc_hocc, stdout);
X		fwrite(wp->tc_cd, 1, wp->tc_cdcc, stdout);
X	}
X	cp = wp->begchange;
X	scp = wp->screen + (cp - wp->begdata);
X	endrow = 0;
X	while (cp < wp->endchange) {	/* look for a difference */
X		diff = strdif(cp, scp, wp->endchange - cp);
X		cp += diff;
X		scp += diff;
X		if (cp >= wp->endchange) break;
X		if (cp >= endrow) {
X			row = (cp - wp->begdata) / wp->delta;
X			begrow = wp->begdata + (row * wp->delta);
X			endrow = begrow + wp->ncols;
X			spcp = endrow - 1;
X			while ((spcp >= begrow) && (*spcp == SPACE))
X				spcp--;
X			spcp++;
X		}
X		domove(row, cp - begrow, begrow);
X		if (cp >= spcp) {		/* clear rest of line */
X			fwrite(wp->tc_ce, 1, wp->tc_cecc, stdout);
X			while (cp < endrow) {
X				*scp++ = SPACE;
X				cp++;
X			}
X			continue;
X		}
X		putchar(*cp);
X		*scp++ = *cp++;
X		if (++wp->curcol >= wp->ncols) {	/* fixup last column */
X			wp->curcol--;
X			if (wp->tc_am) {
X				wp->currow++;
X				wp->curcol = 0;
X			}
X		}
X	}
X	wp->begchange = wp->enddata;
X	wp->endchange = wp->begdata;
X	if (wp->nomove == 0) dpycursor();
X	fflush(stdout);
X}
X
X
X/*
X * Set the terminal cursor at the current write location.
X * If the window is full, the cursor is placed at the front of the
X * last line in the window.  If lines are not being wrapped and the
X * line is full, the cursor is placed at the end of the line.
X * Otherwise, the cursor is placed at the location being written to next.
X */
Xstatic
Xdpycursor()
X{
X	register struct	window	*wp;	/* window pointer */
X	register char	*cp;		/* current write location */
X	register char	*begrow;	/* beginning of current row */
X	register int	row;		/* row number */
X
X	wp = &window;
X	cp = wp->cp;
X	if (wp->full)
X		cp = wp->endwin;
X	else if (cp >= wp->endrow) {
X		if (wp->nocrlf || (wp->begrow >= wp->endwin))
X			cp = wp->endrow - 1;
X		else
X			cp = wp->begrow + wp->delta;
X	}
X	row = (cp - wp->begdata) / wp->delta;
X	begrow = wp->begdata + (row * wp->delta);
X	domove(row, cp - begrow, begrow);
X}
X
X
X/*
X * Subroutine to move to the given location on the screen.  The third argument
X * is a pointer to beginning of the desired row in case we find it is faster
X * to type the intervening characters.  If NULL, we must use addressing.
X */
Xstatic
Xdomove(row, col, cp)
X	register int	row;		/* desired row */
X	register int	col;		/* desired column */
X	register char	*cp;		/* data on desired row */
X{
X	register struct	window	*wp;	/* window structure */
X
X	wp = &window;
X	if (cp && (row == wp->currow) && (col >= wp->curcol)
X		&& (col < wp->curcol + 6)) {		/* a few ahead */
X			cp += wp->curcol;
X			while (wp->curcol < col) {
X				putchar(*cp);
X				cp++;
X				wp->curcol++;
X			}
X			return;
X	}
X	if ((col == 0) && (row == wp->currow + 1)) {	/* next row */
X		putchar('\n');
X		wp->currow++;
X		wp->curcol = 0;
X		return;
X	}
X	tputs(tgoto(wp->tc_cm, col, row), 1, dpytputs);	/* arbitrary */
X	wp->currow = row;
X	wp->curcol = col;
X}
X
X
X/* Local routine called by tputs to print a character */
Xstatic
Xdpytputs(ch)
X	char	ch;
X{
X	putchar(ch);
X}
X
X
X/* Local routine called by tputs to save a character */
Xstatic
Xdpysputs(ch)
X	char	ch;
X{
X	*window.tptr++ = c

chongo@nsc.UUCP (Landon Noll) (04/12/85)

In net.sources:
  I am reposting DBell's DPY sources in response to all the folks who
  needed them for his LIFE and WAR progs.  DBell is no longer on the
  net (in fact in a few days he will no longer be in this hemisphere)
  otherwise he would have done this himself.

In net.sources.games:
  I am reposting DBell's LIFE sources complete with the changes for the
  new DPY.  Both LIFE and WAR (which was posted by DBell not long ago)
  require the use of DPY so be sure and GRAB IT FROM net.sources NOW!!!

#---Cut here and place in it's own directory, then feed to Bourne shell---
# This is a shell archive.  Remove anything before this line, then
# unpack it by saving it in a file and typing "sh file".  (Files
# unpacked will be owned by you and have default permissions.)
# This archive contains:
#   dpy.c (22206 chars)
#   dpyget.c (1117 chars)
#   dpymove.c (1069 chars)
#   dpyplace.c (1297 chars)
#   dpyread.c (3564 chars)
#   dpywindow.c (1170 chars)
#   gensubs.c (1183 chars)
#   vaxsubs.s (332 chars)
#   ns32ksubs.s (812 chars)
#
echo x - dpy.c
sed -e 's/^X//' > "dpy.c" << '//E*O*F dpy.c//'
Xstatic char *sccsid = "@(#)dpy.c	1.46	2/27/85";
Xstatic char *cpyrid = "@(#)Copyright (C) 1985 by D Bell";
X
X
X/*
X * Different curses package (by David I. Bell).
X * Modified to run under System V by Alan P.W. Hewett.
X * These dpy module sources are in the public domain, and can be copied
X * or used as desired, with the following restrictions:
X * 1.	All copyright notices (and this notice) must be preserved.
X * 2.	The dpy sources (even if modified) cannot be sold for profit.
X * 3.	If any sources are modified, a sentence must exist by the
X *	copyright notice of each modified source file which says that
X *	the file has been modified.
X */
X
X
X#include <stdio.h>		/* standard I/O */
X#include <signal.h>		/* signals */
X#include "dpy.h"		/* window definitions */
X
X#define	DEL	0177		/* delete character */
X#define	EOL	'\n'		/* end of line character */
X#define	RET	'\r'		/* return character */
X#define	BS	'\b'		/* backspace character */
X#define	TAB	'\t'		/* tab character */
X#define	SPACE	' '		/* space character */
X#define	TRUE	1		/* true value */
X#define	FALSE	0		/* false value */
X#define	INTSIZ	(sizeof(int))	/* size of an integer */
X
Xextern	short	ospeed;		/* output speed for tputs to use */
Xextern	char	PC;		/* pad character for tputs to use */
Xstruct	window	window;		/* the window */
Xstatic	int	dpytputs();	/* called by tputs to type to terminal */
Xstatic	int	dpysputs();	/* called by tputs to save characters */
Xint	dpystop();		/* stop routine */
Xchar	*tgetstr();		/* return termcap string */
Xchar	*malloc();		/* allocate memory */
Xchar	*getenv();		/* return environment variable */
X
X
X/*
X * Initialize the window structure.  Returns nonzero on failure with a
X * message already typed.  The ttytype argument is the terminal type string,
X * or NULL if the TERM environment variable is to be used.  Modes is a
X * string whose characters describe the desired state of the terminal.
X * These are:
X * 	+	turn on mode indicated by next character (default)
X *	-	turn off mode indicated by next character.
X *	c	cbreak mode (return each character as typed, without waiting
X *		for an end of line, and leave signal processing on).
X *	e	echoing of typed-in characters is enabled.
X *	r	raw mode (return each character as typed, no canonical or
X *		signal processing of any kind).
X *	<SP>	spaces are ignored
X * So the terminal modes before dpy runs are normally "e -c -r".
X * A NULL modes pointer defaults the modes to "-e c".
X */
Xdpyinit(ttytype, modes)
X	register char	*ttytype;	/* terminal type, or NULL for default */
X	char	*modes;			/* terminal modes */
X{
X	register struct	window	*wp;	/* window pointer */
X	register char	*cp;		/* character pointer */
X	register char	*sp;		/* pointer for spaces */
X	register int	size;		/* size of character array */
X	int on;				/* whether or not mode is on */
X#ifdef BSD
X	struct	ltchars	ltchars;	/* local terminal characters */
X	struct	tchars	tchars;		/* terminal characters */
X#endif BSD
X
X	wp = &window;
X	wp->inited = FALSE;
X	wp->output = FALSE;
X	if (ttytype == NULL) {
X		ttytype = getenv("TERM");
X		if (ttytype == NULL) {
X			fprintf(stderr, "dpyinit: TERM not defined\n");
X			return(1);
X		}
X	}
X	size = tgetent(wp->tdata, ttytype);
X	if (size <= 0) {
X		fprintf(stderr, size ? "dpyinit: cannot open termcap file\n"
X			: "dpyinit: unknown terminal type %s\n", ttytype);
X		return(1);
X	}
X	/*
X	 * Collect current tty modes, and remember editing characters
X	 */
X	wp->c_kill = CKILL;		/* init in case stdin is not a tty */
X	wp->c_erase = CERASE;
X	wp->c_werase = CWERASE;
X	wp->c_lnext = CLNEXT;
X	wp->c_rprnt = CRPRNT;
X	wp->c_eof = CEOF;
X#ifdef	BSD
X	if (ioctl(STDIN, TIOCGETP, &wp->old0ttyblk) == 0) {
X		wp->c_erase = wp->old0ttyblk.sg_erase;
X		wp->c_kill = wp->old0ttyblk.sg_kill;
X	}
X	if (ioctl(STDIN, TIOCGLTC, &ltchars) == 0) {
X		wp->c_werase = ltchars.t_werasc;
X		wp->c_rprnt = ltchars.t_rprntc;
X		wp->c_lnext = ltchars.t_lnextc;
X	}
X	if (ioctl(STDIN, TIOCGETC, &tchars) == 0) {
X		wp->c_eof = tchars.t_eofc;
X	}
X	wp->old1ttyblk.sg_ospeed = 0;
X	ioctl(STDOUT, TIOCGETP, &wp->old1ttyblk);
X	ospeed = wp->old1ttyblk.sg_ospeed;	/* save speed for tputs */
X#endif	BSD
X#ifdef	USG
X	if (ioctl(STDIN, TCGETA, &wp->old0ttyblk) == 0) {
X		wp->c_erase = wp->old0ttyblk.c_cc[VERASE];
X		wp->c_kill = wp->old0ttyblk.c_cc[VKILL];
X		wp->c_eof = wp->old0ttyblk.c_cc[VEOF];
X	}
X	ioctl(STDOUT, TCGETA, &wp->old1ttyblk);
X#endif	USG
X	/*
X	 * Collect terminal capability strings
X	 */
X	wp->nrows = tgetnum("li");
X	wp->ncols = tgetnum("co");
X	wp->tc_am = tgetflag("am");
X	wp->tbuf[0] = '\0';
X	wp->tptr = wp->tbuf;
X	(void) tgetstr("pc", &wp->tptr);
X	PC = wp->tbuf[0];
X	wp->tptr = wp->tbuf;
X	wp->tc_ho = tgetstr("ho", &wp->tptr);
X	wp->tc_hocc = wp->tptr - wp->tbuf - 1;
X	wp->tc_ce = tgetstr("ce", &wp->tptr);
X	wp->tc_cd = tgetstr("cd", &wp->tptr);
X	wp->tc_cm = tgetstr("cm", &wp->tptr);
X	if ((wp->nrows <= 0) || (wp->ncols <= 0) || (wp->tc_ce == NULL)
X		|| (wp->tc_cd == NULL) || (wp->tc_cm == NULL)) {
X			fprintf(stderr, "dpyinit: missing termcap entry\n");
X			return(1);
X	}
X	sp = wp->tptr;			/* apply padding to clear screen */
X	tputs(wp->tc_cd, wp->nrows, dpysputs);
X	wp->tc_cd = sp;
X	wp->tc_cdcc = wp->tptr - sp;
X	sp = wp->tptr;			/* and to clear line string */
X	tputs(wp->tc_ce, 1, dpysputs);
X	wp->tc_ce = sp;
X	wp->tc_cecc = wp->tptr - sp;
X	if (wp->tc_ho == NULL) {	/* make home up string if not defined */
X		sp = wp->tptr;
X		tputs(tgoto(wp->tc_cm, 0, 0), 1, dpysputs);
X		wp->tc_ho = sp;
X		wp->tc_hocc = wp->tptr - sp;
X	}
X	wp->delta = (wp->ncols + INTSIZ) &~ (INTSIZ-1);	/* round up */
X	size = wp->nrows * wp->delta;
X	cp = malloc(2 * (size + INTSIZ));
X	if (cp == NULL) {
X		fprintf(stderr, "dpyinit: failed to allocate memory\n");
X		return(1);
X	}
X	wp->begdata = cp;
X	wp->enddata = cp + size;
X	wp->begwin = cp;
X	wp->endwin = cp + size - wp->delta;
X	wp->begrow = cp;
X	wp->endrow = cp + wp->ncols;
X	wp->cp = cp;
X	wp->screen = cp + size + INTSIZ;
X	for (sp = cp + (2 * (size + INTSIZ)) - 1; sp >= cp; sp--) *sp = SPACE;
X	*((int *)(cp + size)) = 0;	/* terminate end of screens */
X	*((int *)(wp->screen + size)) = 0;
X	wp->currow = 0;
X	wp->curcol = 0;
X	wp->noctrl = 0;
X	wp->nocrlf = 0;
X	wp->nomove = 0;
X	wp->scroll = 0;
X	wp->full = 0;
X	wp->tabsize = 8;
X	wp->begchange = wp->enddata;
X	wp->endchange = wp->begdata;
X	/*
X	 * Copy old tty modes to new ones, and modify them as specified
X	 */
X	wp->new0ttyblk = wp->old0ttyblk;
X	wp->new1ttyblk = wp->old1ttyblk;
X	if (modes == (char*)NULL) modes = "-e c";
X	on = TRUE;
X	for (cp = modes; *cp ; cp++) {		/* scan mode string */
X		switch (*cp) {
X		case ' ':			/* spaces (ignored) */
X			continue;
X		case '+':			/* turn on next mode */
X			on = TRUE;
X			continue;
X		case '-':			/* turn off next mode */
X			on = FALSE;
X			continue;
X#ifdef	BSD
X		case 'e':			/* enable echoing */
X			if (on) {
X				wp->new0ttyblk.sg_flags |= ECHO;
X				wp->new1ttyblk.sg_flags |= ECHO;
X			} else {
X				wp->new0ttyblk.sg_flags &= ~ECHO;
X				wp->new1ttyblk.sg_flags &= ~ECHO;
X			}
X			break;
X
X		case 'c':			/* enable character mode */
X			if (on) {
X				wp->new0ttyblk.sg_flags |= CBREAK;
X				wp->new1ttyblk.sg_flags |= CBREAK;
X			} else {
X				wp->new0ttyblk.sg_flags &= ~CBREAK;
X				wp->new1ttyblk.sg_flags &= ~CBREAK;
X			}
X			break;
X
X		case 'r':			/* enable raw mode */
X			if (on) {
X				wp->new0ttyblk.sg_flags |= RAW;
X				wp->new1ttyblk.sg_flags |= RAW;
X			} else {
X				wp->new0ttyblk.sg_flags &= ~RAW;
X				wp->new1ttyblk.sg_flags &= ~RAW;
X			}
X			break;
X#endif	BSD
X#ifdef	USG
X		case 'e':			/* enable echoing */
X			if (on) {
X				wp->new0ttyblk.c_lflag |= ECHO | ECHOE | ECHOK ;
X				wp->new1ttyblk.c_lflag |= ECHO | ECHOE | ECHOK ;
X			} else {
X				wp->new0ttyblk.c_lflag &= ~(ECHO|ECHOE|ECHOK) ;
X				wp->new1ttyblk.c_lflag &= ~(ECHO|ECHOE|ECHOK) ;
X			}
X			break ;
X
X		case 'c':			/* enable character mode */
X			if (on) {
X				wp->new0ttyblk.c_iflag |= ISTRIP ;
X				wp->new0ttyblk.c_lflag &= ~ICANON ;
X				wp->new0ttyblk.c_cc[VMIN] = 1 ;
X				wp->new0ttyblk.c_cc[VTIME] = 0 ;
X				wp->new1ttyblk.c_iflag |= ISTRIP ;
X				wp->new1ttyblk.c_lflag &= ~ICANON ;
X				wp->new1ttyblk.c_cc[VMIN] = 1 ;
X				wp->new1ttyblk.c_cc[VTIME] = 0 ;
X			} else {
X	    			wp->new0ttyblk.c_iflag |= (ICRNL|IUCLC) ;
X	    			wp->new0ttyblk.c_lflag |= ICANON ;
X	    			wp->new0ttyblk.c_cc[VEOF] =
X					wp->old0ttyblk.c_cc[VEOF] ;
X	    			wp->new0ttyblk.c_cc[VEOL] =
X					wp->old0ttyblk.c_cc[VEOL] ;
X	    			wp->new1ttyblk.c_iflag |= (ICRNL|IUCLC) ;
X	    			wp->new1ttyblk.c_lflag |= ICANON ;
X	    			wp->new1ttyblk.c_cc[VEOF] =
X					wp->old1ttyblk.c_cc[VEOF] ;
X	    			wp->new1ttyblk.c_cc[VEOL] =
X					wp->old1ttyblk.c_cc[VEOL] ;
X			}
X			break ;
X
X		case 'r':			/* enable raw mode */
X			if (on) {
X	    			wp->new0ttyblk.c_iflag &=
X					~(BRKINT|IGNPAR|ISTRIP|IXON|IXANY) ;
X	    			wp->new0ttyblk.c_oflag &= ~OPOST ;
X	    			wp->new0ttyblk.c_cflag =
X					(wp->new0ttyblk.c_cflag|CS8) & ~PARENB ;
X	    			wp->new0ttyblk.c_lflag &= ~ICANON ;
X	    			wp->new0ttyblk.c_cc[VMIN] = 1 ;
X	    			wp->new0ttyblk.c_cc[VTIME] = 0 ;
X	    			wp->new1ttyblk.c_iflag &=
X					~(BRKINT|IGNPAR|ISTRIP|IXON|IXANY) ;
X	    			wp->new1ttyblk.c_oflag &= ~OPOST ;
X	    			wp->new1ttyblk.c_cflag =
X					(wp->new1ttyblk.c_cflag|CS8) & ~PARENB ;
X	    			wp->new1ttyblk.c_lflag &= ~ICANON ;
X	    			wp->new1ttyblk.c_cc[VMIN] = 1 ;
X	    			wp->new1ttyblk.c_cc[VTIME] = 0 ;
X			} else {
X	    			wp->new0ttyblk.c_iflag |=
X					(BRKINT|IGNPAR|ISTRIP|IXON
X					|IXANY|ICRNL|IUCLC) ;
X	    			wp->new0ttyblk.c_oflag |= OPOST ;
X	    			wp->new0ttyblk.c_cflag =
X					(wp->new0ttyblk.c_cflag & ~CSIZE) |
X					CS7 | PARENB ;
X	    			wp->new0ttyblk.c_lflag |= ICANON | ISIG ;
X	    			wp->new0ttyblk.c_cc[VEOF] = CEOF ;
X	    			wp->new0ttyblk.c_cc[VEOL] = 0 ;
X	    			wp->new0ttyblk.c_cc[VEOL2] = 0 ;
X	    			wp->new1ttyblk.c_iflag |=
X					(BRKINT|IGNPAR|ISTRIP|IXON|
X					IXANY|ICRNL|IUCLC) ;
X	    			wp->new1ttyblk.c_oflag |= OPOST ;
X	    			wp->new1ttyblk.c_cflag =
X					(wp->new1ttyblk.c_cflag & ~CSIZE) |
X					CS7 | PARENB ;
X	    			wp->new1ttyblk.c_lflag |= ICANON | ISIG ;
X	    			wp->new1ttyblk.c_cc[VEOF] = CEOF ;
X	    			wp->new1ttyblk.c_cc[VEOL] = 0 ;
X	    			wp->new1ttyblk.c_cc[VEOL2] = 0 ;
X			}
X			break;
X#endif	USG
X		default:
X			fprintf(stderr, "dpyinit: illegal flag: %c%c\n",
X				(on ? '+' : '-'), *cp);
X			return(1);
X		}
X		on = TRUE;		/* reset mode */
X	}
X	/*
X	 * Set the new modes for real
X	 */
X#ifdef	BSD
X	wp->new1ttyblk.sg_flags &= ~XTABS;
X	signal(SIGTSTP, dpystop);
X	ioctl(STDIN, TIOCSETP, &wp->new0ttyblk);
X	ioctl(STDOUT, TIOCSETP, &wp->new1ttyblk);
X#endif	BSD
X#ifdef	USG
X	wp->new1ttyblk.c_oflag &= ~TAB3 ;
X	ioctl(STDIN,TCSETAW,&wp->new0ttyblk) ;
X	ioctl(STDOUT,TCSETAW,&wp->new1ttyblk) ;
X#endif	USG	
X	wp->inited = TRUE;
X	return(0);
X}
X
X
X/*
X * Terminate the window, home down to the bottom of the screen, and reset
X * the terminal modes to their original state.
X */
Xdpyclose()
X{
X	register struct	window	*wp;	/* window pointer */
X
X	wp = &window;
X	if (wp->inited) {
X		wp->inited = FALSE;
X		if (wp->output) {
X			domove(wp->nrows - 1, 0, (char *)NULL);
X			fwrite(wp->tc_ce, 1, wp->tc_cecc, stdout);
X			fflush(stdout);
X		}
X		free(wp->begdata);
X#ifdef	BSD
X		ioctl(STDIN, TIOCSETP, &wp->old0ttyblk);
X		ioctl(STDOUT, TIOCSETP, &wp->old1ttyblk);
X#endif	BSD
X#ifdef	USG
X		ioctl(STDIN, TCSETAW, &wp->old0ttyblk);
X		ioctl(STDOUT, TCSETAW, &wp->old1ttyblk);
X#endif	USG
X	}
X	return(0);
X}
X
X
X/*
X * Put a given number of characters to the window at the current write location.
X * Certain control characters have effects, others print as ^X or are ignored.
X * Automatic wrapping to the next line is possible, and scrolling when the last
X * line is full. Returns nonzero if the window cannot hold the whole buffer.
X */
Xdpywrite(buf, count)
X	register char	*buf;		/* buffer address */
X	int	count;			/* number of characters */
X{
X	register struct	window	*wp;	/* window pointer */
X	register char	*endbuf;	/* end of buffer to write */
X	register char	*cp;		/* current character pointer */
X	register int	ch;		/* character to store */
X
X	wp = &window;
X	if (wp->full) return(1);
X	cp = wp->cp;
X	if (cp < wp->begchange) wp->begchange = cp;
X	for (endbuf = buf + count; buf < endbuf; buf++) {
X		ch = *buf;
X		if (ch < ' ') {			/* control character */
X			if (ch == EOL) {	/* new line */
X				clear(cp, wp->endrow);
X				if (cp >= wp->endwin) {	/* window full */
X					wp->endchange = wp->endrow;
X					if (wp->scroll == 0) {
X						wp->full = 1;
X						wp->cp = wp->begrow;
X						return(1);
X					}
X					wp->cp = cp;
X					dpyscroll();
X					cp = wp->begrow;
X					continue;
X				}
X				wp->begrow += wp->delta;
X				wp->endrow += wp->delta;
X				cp = wp->begrow;
X				continue;
X			}
X			if (ch == TAB) {	/* tab */
X				wp->cp = cp;
X				do {
X					if (dpywrite(" ", 1)) return(1);
X				} while ((wp->cp - wp->begrow) % wp->tabsize);
X				cp = wp->cp;
X				continue;
X			}
X			if (ch == BS) {		/* backspace */
X				if (cp > wp->begrow) cp--;
X				continue;
X			}
X			if (ch == RET) {	/* return character */
X				cp = wp->begrow;
X				continue;
X			}
X			/*
X			 * Obscure control character, show as ^X
X			 */
X			if (wp->noctrl) continue;
X			wp->cp = cp;
X			if (dpywrite("^", 1) || dpychar(ch + '@')) return(1);
X			cp = wp->cp;
X			continue;
X		}
X		if (ch == DEL) {		/* delete character */
X			if (wp->noctrl) continue;
X			wp->cp = cp;
X			if (dpywrite("^?", 2)) return(1);
X			cp = wp->cp;
X			continue;
X		}
X		/*
X		 * Normal printing character
X		 */
X		if (cp >= wp->endrow) {		/* end of row, see if do crlf */
X			wp->cp = cp;
X			if (cp > wp->endchange) wp->endchange = cp;
X			if (wp->nocrlf) return(1);
X			if (cp >= wp->endwin) {
X				if (wp->scroll == 0) return(1);
X				dpyscroll();
X				cp = wp->begrow;
X				*cp++ = ch;
X				continue;
X			}
X			wp->begrow += wp->delta;
X			wp->endrow += wp->delta;
X			cp = wp->begrow;
X		}
X		*cp++ = ch;
X	}
X	wp->cp = cp;
X	if (cp > wp->endchange) wp->endchange = cp;
X	return(0);
X}
X
X
X/*
X * Put a single character to the window.
X * Returns nonzero if full.
X */
Xdpychar(ch)
X	char	ch;
X{
X	return(dpywrite(&ch, 1));
X}
X
X
X/*
X * Put a null-terminated string to the window.
X * Returns nonzero if full.
X */
Xdpystr(str)
X	char	*str;
X{
X	return(dpywrite(str, strlen(str)));
X}
X
X
X
X/*
X * Print a formatted string to the window.  Returns nonzero if full.
X * This routine is a ripped off version of sprintf.  This routine is
X * machine-dependent!!
X */
X#ifdef	BSD
Xdpyprintf(fmt, args)
X	char	*fmt;			/* format string */
X{
X	FILE	_strbuf;		/* file header */
X	char	buf[5000];		/* data storage */
X
X	_strbuf._flag = _IOWRT+_IOSTRG;
X	_strbuf._ptr = buf;
X	_strbuf._cnt = 32767;
X	_doprnt(fmt, &args, &_strbuf);
X	return(dpywrite(buf, _strbuf._ptr - buf));
X}
X#endif	BSD
X#ifdef	USG
X
X#include <varargs.h>
X
Xdpyprintf(format, va_alist)
Xchar *format;
Xva_dcl
X{
X	register int count;
X	FILE siop;
X	va_list ap;
X	unsigned char	buf[5000];		/* data storage */
X
X	siop._cnt = sizeof(buf) ;
X	siop._base = siop._ptr = &buf[0] ;
X	siop._flag = _IOWRT;
X	siop._file = _NFILE;
X	va_start(ap);
X	count = _doprnt(format, ap, &siop);
X	va_end(ap);
X	*siop._ptr = '\0'; /* plant terminating null character */
X	return(dpywrite(buf, siop._ptr - buf));
X}
X#endif	USG
X
X
X/* Clear to the end of the current row without changing the write location */
Xdpyclrline()
X{
X	register struct	window	*wp;	/* window pointer */
X	register char	*cp;		/* current character */
X	register char	*endcp;		/* ending character */
X
X	wp = &window;
X	if (wp->full) return;
X	cp = wp->cp;
X	endcp = wp->endrow;
X	if (cp < wp->begchange) wp->begchange = cp;
X	if (endcp > wp->endchange) wp->endchange = cp;
X	clear(cp, endcp);
X}
X
X
X/* Clear to the end of the window without changing the write location */
Xdpyclrwindow()
X{
X	register struct	window	*wp;	/* window pointer */
X	register char	*begcp;		/* beginning character */
X	register char	*cp;		/* current character */
X	register char	*endcp;		/* ending character */
X
X	wp = &window;
X	if (wp->full) return;
X	begcp = wp->begrow;
X	endcp = wp->endrow;
X	cp = wp->cp;
X	if (cp < wp->begchange) wp->begchange = cp;
X	while (1) {
X		clear(cp, endcp);
X		if (begcp >= wp->endwin) break;
X		begcp += wp->delta;
X		endcp += wp->delta;
X		cp = begcp;
X	}
X	if (endcp > wp->endchange) wp->endchange = endcp;
X}
X
X
X/* Set the current write position to the top left corner of the window */
Xdpyhome()
X{
X	register struct	window	*wp;	/* window pointer */
X
X	wp = &window;
X	wp->endrow += wp->begwin - wp->begrow;
X	wp->begrow = wp->begwin;
X	wp->cp = wp->begrow;
X	wp->full = 0;
X}
X
X
X/* Scroll the current window upwards a line to make room for more data. */
Xdpyscroll()
X{
X	register struct	window	*wp;	/* window pointer */
X	register char	*currow;	/* beginning of current row */
X	register char	*nextrow;	/* beginning of next row */
X	register int	cols;		/* columns in window */
X
X	wp = &window;
X	cols = wp->endrow - wp->begrow;
X	currow = wp->begwin;
X	nextrow = currow + wp->delta;
X	while (currow < wp->endwin) {		/* move each line up */
X		bcopy(nextrow, currow, cols);
X		currow += wp->delta;
X		nextrow += wp->delta;
X	}
X	clear(currow, currow + cols);		/* clear last line */
X	wp->begchange = wp->begwin;
X	wp->endchange = wp->endwin + cols;
X}
X
X
X/*
X * Return the row number being written to, or -1 if out of the window.
X * The row number is relative to the beginning of the window.
X */
Xdpygetrow()
X{
X	register struct	window	*wp;	/* window pointer */
X
X	wp = &window;
X	if (wp->full) return(-1);
X	return((wp->cp - wp->begwin) / wp->delta);
X}
X
X
X/*
X * Return the column number being written to, or -1 if out of the window.
X * The column number is relative to the current window.
X */
Xdpygetcol()
X{
X	register struct	window	*wp;	/* window pointer */
X
X	wp = &window;
X	if (wp->full) return(-1);
X	if (wp->cp < wp->endrow) return(wp->cp - wp->begrow);
X	if (wp->nocrlf) return(-1);
X	return(0);
X}
X
X
X/* Make the screen match the data as previously written by the user */
Xdpyupdate()
X{
X	register struct	window	*wp;	/* window pointer */
X	register char	*scp;		/* screen character pointer */
X	register char	*cp;		/* current character */
X	register char	*spcp;		/* cp where spaces remain in row */
X	register char	*endrow;	/* end of row */
X	register char	*begrow;	/* beginning of row */
X	register int	row;		/* current row number */
X	int	diff;
X
X	wp = &window;
X	if (wp->output == 0) {		/* first output, clear screen */
X		wp->output = TRUE;
X		fwrite(wp->tc_ho, 1, wp->tc_hocc, stdout);
X		fwrite(wp->tc_cd, 1, wp->tc_cdcc, stdout);
X	}
X	cp = wp->begchange;
X	scp = wp->screen + (cp - wp->begdata);
X	endrow = 0;
X	while (cp < wp->endchange) {	/* look for a difference */
X		diff = strdif(cp, scp, wp->endchange - cp);
X		cp += diff;
X		scp += diff;
X		if (cp >= wp->endchange) break;
X		if (cp >= endrow) {
X			row = (cp - wp->begdata) / wp->delta;
X			begrow = wp->begdata + (row * wp->delta);
X			endrow = begrow + wp->ncols;
X			spcp = endrow - 1;
X			while ((spcp >= begrow) && (*spcp == SPACE))
X				spcp--;
X			spcp++;
X		}
X		domove(row, cp - begrow, begrow);
X		if (cp >= spcp) {		/* clear rest of line */
X			fwrite(wp->tc_ce, 1, wp->tc_cecc, stdout);
X			while (cp < endrow) {
X				*scp++ = SPACE;
X				cp++;
X			}
X			continue;
X		}
X		putchar(*cp);
X		*scp++ = *cp++;
X		if (++wp->curcol >= wp->ncols) {	/* fixup last column */
X			wp->curcol--;
X			if (wp->tc_am) {
X				wp->currow++;
X				wp->curcol = 0;
X			}
X		}
X	}
X	wp->begchange = wp->enddata;
X	wp->endchange = wp->begdata;
X	if (wp->nomove == 0) dpycursor();
X	fflush(stdout);
X}
X
X
X/*
X * Set the terminal cursor at the current write location.
X * If the window is full, the cursor is placed at the front of the
X * last line in the window.  If lines are not being wrapped and the
X * line is full, the cursor is placed at the end of the line.
X * Otherwise, the cursor is placed at the location being written to next.
X */
Xstatic
Xdpycursor()
X{
X	register struct	window	*wp;	/* window pointer */
X	register char	*cp;		/* current write location */
X	register char	*begrow;	/* beginning of current row */
X	register int	row;		/* row number */
X
X	wp = &window;
X	cp = wp->cp;
X	if (wp->full)
X		cp = wp->endwin;
X	else if (cp >= wp->endrow) {
X		if (wp->nocrlf || (wp->begrow >= wp->endwin))
X			cp = wp->endrow - 1;
X		else
X			cp = wp->begrow + wp->delta;
X	}
X	row = (cp - wp->begdata) / wp->delta;
X	begrow = wp->begdata + (row * wp->delta);
X	domove(row, cp - begrow, begrow);
X}
X
X
X/*
X * Subroutine to move to the given location on the screen.  The third argument
X * is a pointer to beginning of the desired row in case we find it is faster
X * to type the intervening characters.  If NULL, we must use addressing.
X */
Xstatic
Xdomove(row, col, cp)
X	register int	row;		/* desired row */
X	register int	col;		/* desired column */
X	register char	*cp;		/* data on desired row */
X{
X	register struct	window	*wp;	/* window structure */
X
X	wp = &window;
X	if (cp && (row == wp->currow) && (col >= wp->curcol)
X		&& (col < wp->curcol + 6)) {		/* a few ahead */
X			cp += wp->curcol;
X			while (wp->curcol < col) {
X				putchar(*cp);
X				cp++;
X				wp->curcol++;
X			}
X			return;
X	}
X	if ((col == 0) && (row == wp->currow + 1)) {	/* next row */
X		putchar('\n');
X		wp->currow++;
X		wp->curcol = 0;
X		return;
X	}
X	tputs(tgoto(wp->tc_cm, col, row), 1, dpytputs);	/* arbitrary */
X	wp->currow = row;
X	wp->curcol = col;
X}
X
X
X/* Local routine called by tputs to print a character */
Xstatic
Xdpytputs(ch)
X	char	ch;
X{
X	putchar(ch);
X}
X
X
X/* Local routine called by tputs to save a character */
Xstatic
Xdpysputs(ch)
X	char	ch;
X{
X	*window.tptr++ = ch;
X}
X
X
X/* Redraw the screen to fix glitches */
Xdpyredraw()
X{
X	register struct	window	*wp;	/* window pointer */
X	register char	*cp;		/* current character */
X	register char	*endcp;		/* ending character */
X
X	wp = &window;
X	cp = wp->screen;
X	endcp = cp + (wp->nrows * wp->delta);
X	clear(cp, endcp);
X	wp->currow = 0;
X	wp->curcol = 0;
X	wp->begchange = wp->begdata;
X	wp->endchange = wp->enddata;
X	fwrite(wp->tc_ho, 1, wp->tc_hocc, stdout);
X	fwrite(wp->tc_cd, 1, wp->tc_cdcc, stdout);
X	dpyupdate();
X}
X
X
X/*
X * Routine called on a terminal stop signal.  Restore the original terminal
X * state, home down to the bottom, and really stop.  If continued, restore
X * the new terminal state and redraw the screen.
X */
Xdpystop()
X{
X#ifdef	BSD
X	register struct	window	*wp;	/* window pointer */
X
X	wp = &window;
X	if (wp->output) {
X		domove(wp->nrows - 1, 0, (char *)NULL);
X		fflush(stdout);
X	}
X	ioctl(STDIN, TIOCSETP, &wp->old0ttyblk);
X	ioctl(STDOUT, TIOCSETP, &wp->old1ttyblk);
X	kill(getpid(), SIGSTOP);	/* really stop */
X	ioctl(STDIN, TIOCSETP, &wp->new0ttyblk);
X	ioctl(STDOUT, TIOCSETP, &wp->new1ttyblk);
X	if (wp->output) dpyredraw();
X#endif	BSD
X}
//E*O*F dpy.c//
echo x - dpyget.c
sed -e 's/^X//' > "dpyget.c" << '//E*O*F dpyget.c//'
X#ifdef SCCS
Xstatic char *sccsid = "@(#)dpyget.c	1.1	1/28/85";
Xstatic char *cpyrid = "@(#)Copyright (C) 1985 by D Bell";
X#endif
X
X#include "dpy.h"
X
X/* Return the character which is at the specified location in the current
X * window.  The character returned is the one in our internal screen image,
X * not what is actually on the screen (these will be identical if dpyupdate
X * was just called).  Returns negative if the coordinates are illegal.
X */
Xdpyget(row, col)
X	register int	row;		/* row to get character from */
X	register int	col;		/* column to get character from */
X{
X	register struct	window	*wp;	/* window pointer */
X	register char	*cp;		/* character pointer */
X	register int	winrows;	/* number of rows in window */
X	register int	wincols;	/* number of columns in window */
X
X	wp = &window;
X	winrows = ((wp->endwin - wp->begwin) / wp->delta) + 1;
X	wincols = wp->endrow - wp->begrow;
X	if (row < 0) row += winrows;
X	if (col < 0) col += wincols;
X	if (((unsigned)row >= winrows) || ((unsigned)col >= wincols)) {
X		return(-1);		/* out of window */
X	}
X	cp = wp->begwin + (row * wp->delta) + col;
X	return(*cp & 0xff);
X}
//E*O*F dpyget.c//
echo x - dpymove.c
sed -e 's/^X//' > "dpymove.c" << '//E*O*F dpymove.c//'
X#ifdef SCCS
Xstatic char *sccsid = "@(#)dpymove.c	1.3	1/17/85";
Xstatic char *cpyrid = "@(#)Copyright (C) 1985 by D Bell";
X#endif
X
X#include "dpy.h"
X
X/* Set the current write location to the given row and column.
X * The position given is relative to the current window.
X * Negative numbers indicate backwards from last row or column.
X * Returns nonzero if arguments are out of bounds.
X */
Xdpymove(row, col)
X	register int	row;		/* desired row number */
X	register int	col;		/* desired column number */
X{
X	register struct	window	*wp;	/* window pointer */
X	register int	winrows;	/* number of rows in window */
X	register int	wincols;	/* number of columns in window */
X
X	wp = &window;
X	winrows = ((wp->endwin - wp->begwin) / wp->delta) + 1;
X	wincols = wp->endrow - wp->begrow;
X	if (row < 0) row += winrows;
X	if (col < 0) col += wincols;
X	if (((unsigned)row >= winrows) || ((unsigned)col >= wincols)) {
X		return(1);		/* out of window */
X	}
X	wp->begrow = wp->begwin + (row * wp->delta);
X	wp->endrow = wp->begrow + wincols;
X	wp->cp = wp->begrow + col;
X	wp->full = 0;
X	return(0);
X}
//E*O*F dpymove.c//
echo x - dpyplace.c
sed -e 's/^X//' > "dpyplace.c" << '//E*O*F dpyplace.c//'
X#ifdef SCCS
Xstatic char *sccsid = "@(#)dpyplace.c	1.5	1/28/85";
Xstatic char *cpyrid = "@(#)Copyright (C) 1985 by D Bell";
X#endif
X
X#include "dpy.h"
X
X/* Place a single character to the window at a particular location.
X * The change will not be seen until a call to dpyupdate.
X * The current write location is unaffected.
X * Returns nonzero if coordinates are illegal.
X * The coordinates are relative to the current window.
X */
Xdpyplace(row, col, ch)
X	register int	row;		/* row to place character at */
X	register int	col;		/* column to place character at */
X	char	ch;			/* character to be placed */
X{
X	register struct	window	*wp;	/* window pointer */
X	register char	*cp;		/* character pointer */
X	register int	winrows;	/* number of rows in window */
X	register int	wincols;	/* number of columns in window */
X
X	wp = &window;
X	winrows = ((wp->endwin - wp->begwin) / wp->delta) + 1;
X	wincols = wp->endrow - wp->begrow;
X	if (row < 0) row += winrows;
X	if (col < 0) col += wincols;
X	if (((unsigned)row >= winrows) || ((unsigned)col >= wincols)) {
X		return(1);		/* out of window */
X	}
X	cp = wp->begwin + (row * wp->delta) + col;
X	if (*cp != ch) {		/* do only if char needs changing */
X		if (cp < wp->begchange) wp->begchange = cp;
X		*cp++ = ch;
X		if (cp > wp->endchange) wp->endchange = cp;
X	}
X	return(0);
X}
//E*O*F dpyplace.c//
echo x - dpyread.c
sed -e 's/^X//' > "dpyread.c" << '//E*O*F dpyread.c//'
X#ifdef SCCS
Xstatic char *sccsid = "@(#)dpyread.c	1.13	2/16/85";
Xstatic char *cpyrid = "@(#)Copyright (C) 1985 by D Bell";
X#endif
X
X#include "dpy.h"		/* window definitions */
X
Xstatic int readline();		/* default read routine */
X
X/* Read some input while possibly showing it in the current window.
X * If the prompt string is NULL, then editing is performed without
X * any windowing activity (useful when reading commands from scripts).
X * Otherwise, the prompt is shown in the window along with any input.
X * The given routine is called for each character, with an argument
X * which is the previous character (or -1 on the first call).
X * The routine returns the next input character, or -1 to stop reading.
X * A null routine defaults to one which reads until an end of line.
X * Scrolling of the window is automatically performed when necessary.
X * Editing of the input is handled.  If the buffer fills up, the user
X * is warned with beeps and further input is ignored.
X * Returns number of bytes of data read.
X */
Xdpyread(prompt, routine, buf, count)
X	register char	*prompt;	/* prompt string (if any) */
X	int	(*routine)();		/* routine to call to get character */
X	register char	*buf;		/* address of the storage buffer */
X	int	count;			/* maximum number of bytes allowed */
X{
X	register struct	window	*wp;	/* window pointer */
X	register int	ch;		/* character which was read */
X	register char	*bp;		/* current buffer pointer location */
X	char	*endbp;			/* end of buffer */
X	char	redraw;			/* need to redisplay input */
X	char	oldscroll;		/* old scrolling flag */
X	int	promptlen;		/* length of prompt string */
X
X	wp = &window;
X	promptlen = 0;
X	if (prompt) promptlen = strlen(prompt);
X	if ((int)routine == 0) routine = readline;
X	bp = buf;
X	endbp = bp + count - 1;
X	redraw = 1;
X	ch = -1;
X	oldscroll = wp->scroll;
X	wp->scroll = 1;
X	while (1) {
X		if (prompt && redraw) {		/* recompute window data */
X			redraw = 0;
X			dpyhome();
X			dpywrite(prompt, promptlen);
X			dpywrite(buf, bp - buf);
X			dpyclrwindow();
X		}
X		if (prompt) dpyupdate();
X		ch = routine(ch);
X		if (ch < 0) {				/* end of file */
X			wp->scroll = oldscroll;
X			return(bp - buf);
X		}
X		if (ch == wp->c_lnext) {		/* literal input */
X			ch = routine(ch);
X			if (ch < 0) {
X				wp->scroll = oldscroll;
X				return(bp - buf);
X			}
X			if (bp >= endbp) {		/* buffer is full */
X				write(STDERR, "\07", 1);
X				continue;
X			}
X			*bp = ch;
X			if (prompt) dpywrite(bp, 1);
X			bp++;
X			continue;
X		}
X		if (ch == wp->c_eof) {			/* end of file */
X			wp->scroll = oldscroll;
X			return(bp - buf);
X		}
X		if (ch == wp->c_erase) {		/* character erase */
X			if (bp <= buf) continue;
X			bp--;
X			redraw = 1;
X			continue;
X		}
X		if (ch == wp->c_werase) {		/* word erase */
X			if (bp <= buf) continue;
X			while ((bp > buf) && ((bp[-1] == '\n')
X				|| (bp[-1] == ' ') || (bp[-1] == '\t'))) bp--;
X			while ((bp > buf) && (bp[-1] != '\n')
X				&& (bp[-1] != ' ') && (bp[-1] != '\t')) bp--;
X			redraw = 1;
X			continue;
X		}
X		if (ch == wp->c_kill) {			/* line erase */
X			if (bp <= buf) continue;
X			if (bp[-1] == '\n') bp--;
X			while ((bp > buf) && (bp[-1] != '\n')) bp--;
X			redraw = 1;
X			continue;
X		}
X		if (ch == wp->c_rprnt) {		/* retype line */
X			if (prompt) dpyredraw();
X			continue;
X		}
X		if (bp >= endbp) {			/* buffer is full */
X			write(STDERR, "\07", 1);
X			continue;
X		}
X		*bp = ch;				/* normal character */
X		if (prompt) dpywrite(bp, 1);
X		bp++;
X	}
X}
X
X
X/* Local routine to read until end of line character is reached */
Xstatic
Xreadline(ch)
X{
X	if ((ch == '\n') || (read(STDIN, &ch, 1) < 1)) return(-1);
X	return(ch & 0xff);
X}
//E*O*F dpyread.c//
echo x - dpywindow.c
sed -e 's/^X//' > "dpywindow.c" << '//E*O*F dpywindow.c//'
X#ifdef SCCS
Xstatic char *sccsid = "@(#)dpywindow.c	1.3	1/17/85";
Xstatic char *cpyrid = "@(#)Copyright (C) 1985 by D Bell";
X#endif
X
X#include "dpy.h"
X
X/* Set the row and column boundaries of the current window.
X * Negative numbers indicate backwards from last row or column.
X * The write location is set to the top left of the window.
X * Returns nonzero if arguments are out of bounds.
X */
Xdpywindow(minrow, maxrow, mincol, maxcol)
X	register int	minrow, maxrow;		/* range of rows */
X	register int	mincol, maxcol;		/* range of columns */
X{
X	register struct	window	*wp;		/* window pointer */
X
X	wp = &window;
X	if (minrow < 0) minrow += wp->nrows;
X	if (maxrow < 0) maxrow += wp->nrows;
X	if (mincol < 0) mincol += wp->ncols;
X	if (maxcol < 0) maxcol += wp->ncols;
X	if (((unsigned) minrow > maxrow)
X		|| ((unsigned) maxrow >= wp->nrows)
X		|| ((unsigned) mincol > maxcol)
X		|| (maxcol >= wp->ncols)) {
X			return(1);		/* illegal */
X	}
X	wp->begwin = wp->begdata + (minrow * wp->delta) + mincol;
X	wp->endwin = wp->begwin + ((maxrow - minrow) * wp->delta);
X	wp->begrow = wp->begwin;
X	wp->endrow = wp->begrow + (maxcol - mincol + 1);
X	wp->cp = wp->begrow;
X	wp->full = 0;
X	return(0);
X}
//E*O*F dpywindow.c//
echo x - gensubs.c
sed -e 's/^X//' > "gensubs.c" << '//E*O*F gensubs.c//'
X#ifdef SCCS
Xstatic char *sccsid = "@(#)gensubs.c	1.3	1/17/85";
Xstatic char *cpyrid = "@(#)Copyright (C) 1985 by D Bell";
X#endif
X
X/*
X * Generic subroutines usable on any machine.  These subroutines should
X * be replaced by assembly-level routines if possible, to make dpy run
X * as fast as possible.
X */
X
X
X/*
X * Compare two strings of a given length, and return the number of leading
X * bytes which are identical, or the length if the strings are identical.
X * Nulls are not treated specially.  Examples:
X *	strdif("hi mom", "hi pop", 6) returns 3.
X *	strdif("aaaa1", "aaaa2", 2) returns 2.
X */
Xstrdif(s1, s2, len)
X	register char	*s1;		/* first string */
X	register char	*s2;		/* second string */
X{
X	register char	*end;		/* ending character */
X	char	*beg;			/* beginning character */
X
X	beg = s1;
X	end = s1 + len;
X	while ((s1 < end) && (*s1 == *s2)) {
X		s1++;
X		s2++;
X	}
X	return(s1 - beg);
X}
X
X
X
X/*
X * Clear a number of bytes to spaces, from the original character location
X * up to but not including the ending location.
X */
Xclear(beg, end)
X	register char	*beg;		/* beginning of string to clear */
X	register char	*end;		/* end of string to clear */
X{
X	while (beg < end) *beg++ = ' ';
X}
//E*O*F gensubs.c//
echo x - vaxsubs.s
sed -e 's/^X//' > "vaxsubs.s" << '//E*O*F vaxsubs.s//'
X# @(#)vaxsubs.s	1.5	1/17/85
X# @(#)Copyright (C) 1985 by D Bell
X
X
X	.text
X	.globl	_strdif
X	.globl	_clear
X
X_strdif:
X	.word	0x0
X	cmpc3	12(ap),*4(ap),*8(ap)	#compare the strings
X	subl3	4(ap),r1,r0		#return difference
X	ret
X
X_clear:
X	.word	0x0
X	subl3	4(ap),8(ap),r0		#number of bytes to fill
X	movc5	$0,0,$32,r0,*4(ap)	#fill the bytes
X	ret
//E*O*F vaxsubs.s//
echo x - ns32ksubs.s
sed -e 's/^X//' > "ns32ksubs.s" << '//E*O*F ns32ksubs.s//'
X; @(#)m16subs.s	1.4	1/28/85
X; @(#)Copyright (C) 1985 by D Bell
X;
X;machine dependent subroutines for the National 32032 microprocessor.
X;strdif - return number of bytes until two strings differ or count is reached.
X;clear	- from first address up till last address, make memory spaces.
X
X	.program
X
X_strdif::
X	movd	16(sp),r0	;byte count
X	movd	8(sp),r1	;first string
X	movd	12(sp),r2	;second string
X	cmpsb			;compare bytes
X	subd	8(sp),r1	;get length of search
X	movd	r1,r0		;make return value
X	rxp	0		;return
X
X
X_clear::
X	movd	12(sp),r0	;ending address
X	movd	8(sp),r1	;beginning address
X	subd	r1,r0		;compute byte count
X	cmpqd	0,r0		;see if any to do
X	bge	done		;nope
X	addqd	-1,r0		;fix count
X	addr	1(r1),r2	;destination address
X	movb	32,0(r1)	;start with a blank
X	movsb			;fill rest too
Xdone:	rxp	0		;return
X
X	.endseg
//E*O*F ns32ksubs.s//
echo done
-- 
no comment is a comment.

chongo@nsc.UUCP (Landon Noll) (04/12/85)

In net.sources:
  I am reposting DBell's DPY sources in responce to all the folks who
  needed them for his LIFE and WAR progs.  DBell is no longer on the
  net (in fact in a few days he will no longer be in this hemisphere)
  otherwise he would have done this himself.

In net.sources.games:
  I am reposting DBell's LIFE sources complete with the changes for the
  new DPY.  Both LIFE and WAR (which was posted by DBell not long ago)
  require the use of DPY so be sure and GRAB IT FROM net.sources NOW!!!

---------------------begin DBell's comments-------------------------------

I have finally created a manual page for DPY (which was posted recently).
The following contains the original nroff input file, and also the final
output file in case you can't run it off yourself.  Enjoy.
		- dbell -

#---Cut here and place in it's own directory, then feed to Bourne shell---
# This is a shell archive.  Remove anything before this line, then
# unpack it by saving it in a file and typing "sh file".  (Files
# unpacked will be owned by you and have default permissions.)
# This archive contains:
#   dpy.3 (17265 chars)
#   dpy.doc (20751 chars)
#
echo x - dpy.3
sed -e 's/^X//' > "dpy.3" << '//E*O*F dpy.3//'
X.TH DPY 3 "7 March 1985"
X.UC 4
X.SH NAME
Xdpy \- new screen updating routines
X.SH SYNOPSIS
X.nf
X.ft B
Xdpyinit(ttytype, modestring)
Xchar *ttytype, *modestring;
X
Xdpywindow(minrow, maxrow, mincol, maxcol)
Xint minrow, maxrow, mincol, maxcol;
X
Xdpyread(prompt, routine, buf, count)
Xchar *prompt;
Xint (*routine)();
Xchar *buf;
Xint count;
X
Xdpymove(row, col)
Xint row, col;
X
Xdpyplace(row, col, ch)
Xint row, col;
Xchar ch;
X
Xdpywrite(buf, count)
Xchar *buf;
Xint count;
X
Xdpyprintf(fmt [,args] ...)
Xchar *fmt;
X
Xdpychar(ch)
Xchar ch;
X
Xdpystr(str)
Xchar *str;
X
Xdpyget(row, col)
Xint row, col;
X
Xdpyclrline()
X
Xdpyclrwindow()
X
Xdpyhome()
X
Xdpygetrow()
X
Xdpygetcol()
X
Xdpyupdate()
X
Xdpyredraw()
X
Xdpystop()
X
Xdpyclose()
X.ft R
X.fi
X.SH DESCRIPTION
X.I
XDpy
Xis a terminal display package much like
X.IR curses (3).
XHowever,
X.I dpy
Xdoes not provide all of the capabilities of
X.IR curses ,
Xbut instead tries to focus on the following two goals:
X.TP 5n
X1.
XAllow the programmer to easily define and update many different
Xrectangles of data on the screen at the same time.
X.TP
X2.
XBe as fast as possible.
X.PP
XA tutorial on the usage of
X.I dpy
Xappears later in this document.
XThe remainder of this section describes the procedures.
X
X.I Dpyinit
Xmust be called before any other call to
X.I dpy (except for
X.IR dpyclose ).
XIt allocates memory for two screen images,
Xdefines the current window to be the whole screen,
Xsets the current write location to the upper left corner of the screen,
Xuses
X.IR signal (2)
Xto cause the terminal stop character to trap to
X.I dpystop
Xfor pretty program stopping (only on BSD systems), and sets the terminal
Xmodes to allow for terminal input of various kinds.
XThe actual terminal screen is not cleared until the first
X.I dpyupdate
Xcall is made, so that you can initialize your program based upon the
Xterminal size before deciding to continue.
X.I Ttytype
Xis a string specifying the terminal type (example: "vt100"),
Xor NULL to use the value specified by the
X.I TERM
Xenvironment variable.
X.I Modestring
Xis a string specifying how input is to be treated from the terminal.
XEach mode is specified by a single letter, preceeded by an (optional) plus
Xsign to enable the mode, or preceeded by a minus sign to disable the mode.
XModes can be separated by spaces.
XModes not mentioned in the string are unchanged.
XThe currently defined mode letters are:
X.TP 5n
X.B e
X(echo) Echoing of input characters occurs.
X.TP
X.B c
X(cbreak) Characters are returned without waiting for a newline and tty
Xsignals are processed.
X.TP
X.B r
X(raw) Characters are returned exactly as typed and tty signals are disabled.
X.PP
XThus the normal terminal modes before starting
X.I dpy
Xare described by the string "e -c -r".
XIf
X.I modestring
Xis a NULL pointer, then the default modes of "-e c" are used.
XIf the
X.I dpyread
Xcall is to be used in your program, then you must specify that echoing
Xis disabled, and that either cbreak or raw mode is enabled.
X.I Dpyinit
Xreturns nonzero with an error message typed if it cannot initialize.
X
X.I Dpyclose
Xhomes down to the lower left corner of the terminal screen, clears the last
Xline of the screen, frees the memory allocated by
X.IR dpyinit,
Xand restores the original terminal modes.
XThis is useful just before exiting from your program.
X.I Dpyclose
Xis guaranteed to do nothing if
X.I dpyinit
Xhas not yet been completed, so that it is safe to call
X.I dpyclose
Xat any time.
X
X.I Dpyupdate
Xmakes the terminal screen look like the future screen image,
Xusing a minimal amount of terminal I/O.
XThe cursor is also positioned to the current write location.
XThis routine must be called when you have completed your writing of data to
Xthe future screen image, in order to make those changes visible to the user.
X
X.I Dpywindow
Xspecifies the rectangle where characters will be placed in the future
Xscreen image, and sets the current write location to the top left
Xcorner of the rectangle.
XThe upper left corner of the window has the coordinates specified by
X.I minrow
Xand
X.IR mincol ,
Xand the lower right corner has the coordinates specified by
X.I maxrow
Xand
X.IR maxcol .
XThese coordinates are the absolute screen coordinates, where
Xthe upper left corner of the screen is row 0 and column 0.
XNegative numbers specify row or column numbers from the bottom or
Xright edges of the screen.
XFor example,
X.nf
X	dpywindow(0, -1, 0, -1);
X.fi
Xdefines a window which fills the whole screen.
XReturns nonzero if the coordinates are illegal.
X
X.I Dpywrite
Xwrites
X.I count
Xcharacters from location
X.I buf
Xto the future screen image at the current write location in the current
Xwindow, and updates the current write location appropriately.
XThis call does not do any actual I/O to the terminal.
XControl characters are handled reasonably, as is running off the end
Xof a line or the window.
XThis routine is called by
X.IR dpychar,
X.IR dpystr,
Xand
X.IR dpyprintf,
Xand is therefore the most efficient way to give characters to
X.IR dpy .
XReturns nonzero if not all the characters fit in the window.
X
X.I Dpychar
Xwrites the single character
X.I ch
Xto the future screen image.
XReturns nonzero if the character couldn't fit in the window.
X
X.I Dpystr
Xwrites the null terminated string
X.I str
Xto the future screen image.
XReturns nonzero if any of the string couldn't fit in the window.
X
X.I Dpyprintf
Xwrites a formated string to the future screen image in the manner of
X.IR printf (3).
X.I Fmt
Xis the format string, and
X.I args
Xare arguments to the format string.
XReturns nonzero if any of the string couldn't fit in the window.
X
X.I Dpyclrline
Xclears the rest of the line in the future screen image (by changing
Xthe characters to spaces), but does not change the current write location.
XWriting a linefeed to the future screen performs this function,
Xin addition to moving the write location to the next line.
X
X.I Dpyclrwindow
Xclears the rest of the window in the future screen image, but
Xdoes not change the current write location.
XWhen rewriting a window completely, this should be called when done so
Xthat any old contents of the window will be sure to be cleared out.
X
X.I Dpymove
Xchanges the current write location to the specified
X.I row
Xand
X.I column
Xnumbers, relative to the upper left corner of the current window.
XThe upper left corner of the window is row 0 and column 0.
XNegative numbers measure from the last row or column of the window.
XFor example,
X.nf
X	dpymove(-1, 0);
X.fi
Xpositions to the beginning of the last line of the window.
XThis does not set the actual terminal's cursor location unless it is
Xalso followed by a call to
X.IR dpyupdate .
XReturns nonzero if the coordinates are illegal.
X
X.I Dpyhome
Xmoves the current write location to the top left corner of the window.
XThis function is useful between updates if your program iteratively
Xrewrites the whole screen as one window.
X
X.I Dpygetrow
Xreturns the row number of the current write location.
XThis is the row number where the next character written would go.
XIf the next character written would not fit in the window, -1 is returned.
XThis number is relative to the first line of the current window.
XFor example, if the current write location is at the beginning of
Xthe top line of the window, this function returns zero.
X
X.I Dpygetcol
Xreturns the column number of the current write location.
XThis is the column number where is next character written would go.
XIf the next character written would not fit in the window, -1 is returned.
XThis number is relative to the current window.
XFor example, if the current write location is at the beginning of a line
Xin the window, this function returns zero.
X
X.I Dpyredraw
Xredraws the screen to make it look like the current screen image.
XThis is used to fix the screen when it becomes trashed due to glitches or
Xother programs also writing to the screen.
XThis does not change the current or future screen images.
X
X.I Dpystop
Xsuspends execution of the process in a nice way by homing down to the lower
Xleft corner of the terminal screen, clearing the last line of the screen,
Xrestoring the original terminal modes, and then stopping the process.
XIf the process is continued, terminal modes are restored,
Xthe screen is redrawn, and execution proceeds.
XThis is called automatically when the terminal's stop character (usually ^Z)
Xis typed by the user.
X.I Dpystop
Xis a null routine for non-BSD systems.
X
X.I Dpyplace
Xplaces the character
X.I ch
Xwithin the current window at the coordinates specified by
X.I row
Xand
X.IR col .
XThe character should not be a control character.
XThe coordinates can be negative to measure from the last row or column
Xof the window.
XThe current write location is unchanged.
XLike
X.I dpywrite
Xand similar routines, this routine only affects the
Xfuture screen image, and does no terminal I/O.
XReturns nonzero if the coordinates are illegal.
X
X.I Dpyget
XReturns the character from the current window which is at the coordinates
Xspecified by
X.I row
Xand
X.IR col.
XThe coordinates can be negative to measure from the last row or column of
Xthe window.
XThe character returned is from the future screen image, not the current
Xscreen image.
XThe current write location is unchanged.
XReturns negative if the coordinates are illegal.
X
X.I Dpyread
Xreads input from the user while showing the input
Xdata on the screen.
XEditing of the input and updating of the screen is automatically
Xperformed by
X.IR dpy .
XThe entire current window is used to display the input, and therefore
Xyou must set the window to your desired input location before calling
X.IR dpyread .
XTypically, you specify the window to be a single line at the top or bottom
Xof the screen.
XIf the
X.I prompt
Xstring pointer is not NULL, then the prompt string will appear at the
Xbeginning of the window, followed by the data typed by the user.
XTo display the user's input without any prompt, specify a pointer to a
Xnull string.
XIf
X.I prompt
Xis NULL, then the window will be untouched and no terminal I/O at all will
Xbe performed (useful when input is from a script or file).
X.I Buf
Xand
X.I count
Xspecify the area in the calling program where the
Xdata being read is stored, in the manner of
X.IR read (2).
XThe data will be what was typed by the
Xuser, not what is seen on the screen (i.e. control characters appear
Xon the screen as ^X, but appear in the buffer as themselves).
XIf more data is typed than fits in the window, the data in the window
Xis automatically scrolled to keep the current input location visible.
X.I Routine
Xis a function variable which specifies a routine which is called to
Xprovide the input characters for
X.IR dpyread .
X.I Routine
Xis called with the previous character read (-1 on the first call).
XIt must return the next character read, or -1 to end input and cause
X.I dpyread
Xto return.
XProviding the previous character as an argument allows a routine to easily
Xreturn a break character as input, and then end the input on the next call.
XIf
X.I routine
Xis 0, then a default routine will be used which reads from the standard input
Xuntil an end of file or newline is typed (which is included in the buffer).
XWhenever the character count would be exceeded, then
X.I dpyread
Xwill warn the user with a bell and discard the input character.
X.I Dpyread
Xreturns the number of characters read into the buffer, which is not
Xguaranteed to contain a terminating null or newline character.
X.SH "TUTORIAL"
XThe routines in the
X.I dpy
Xlibrary are called directly by the user program.
XNone of these routines are a macro, so that there is no need to include a
Xheader file to use
X.IR dpy .
XThese routines use the
X.I termlib
X(or
X.I curses
Xunder System V) library routines to obtain the proper terminal escape sequences.
XTherefore, you load your program as in the following examples:
X.nf
X
X	cc -o yourprog yourprog.c -ldpy -ltermlib	for BSD
Xor:
X	cc -o yourprog yourprog.c -ldpy -lcurses	for System V
X
X.fi
X.I Dpy
Xkeeps two arrays which hold images of the terminal screen.
XThe first array (the "current screen") is a copy of what the terminal
Xscreen really looks like.
XThe second array (the "future screen") is a copy of what the
Xcalling program wants the screen to look like.
XThe use of
X.I dpy
Xproceeds in two phases under the control of the calling program, as follows:
X
XIn the first phase, only the future screen is manipulated.
XThe calling program positions the "current write location" as desired
Xwithin the future screen, and writes new information within it.
XThe
X.IR dpywrite ,
X.IR dpychar ,
X.IR dpystr ,
X.IR dpyprintf ,
Xand
X.I dpyplace
Xroutines are used for this purpose.
XDuring this phase, no actual I/O occurs and the terminal screen remains
Xunchanged.
X
XIn the second phase, the calling program uses the
X.I dpyupdate
Xroutine to update the screen.
X.I Dpy
Xcompares the future screen contents with the current screen contents,
Xand does whatever terminal I/O is required in order to make the current
Xscreen look like the future screen.
XAfter this is done, the two screen images are identical.
XIn addition, the terminal's cursor is positioned to the current write position.
X
XThe calling program usually uses
X.I dpy
Xby looping between the above two phases.
XIt defines what the screen should look like, updates the screen,
Xdefines the screen again, updates it again, and so on.
XIn doing so, the program can be "dumb" or "smart".
XA dumb program rewrites all of the data in its windows each iteration of
Xthe loop, and depends on
X.I dpy
Xto prevent terminal I/O for unchanging data.
XThus a dumb program can be very trivial, and doesn't have to know anything
Xabout what is happening on the screen.
X
XIf generating a new screenful of data from scratch is too much work for
Xthe program to do for each iteration, then a good compromise is to keep an
Xinternal copy of the screen in the program, update that copy appropriately,
Xand then execute one
X.I dpywrite
Xcall to give
X.I dpy
Xthe new data.
X
XA smart program knows the exact locations of the desired screen changes
Xeach iteration of the loop, and only rewrites the necessary locations
Xby using appropriate
X.I dpymove
Xand
X.I dpyplace
Xcalls.
XThis runs faster than a dumb program, but has the disadvantage of
Xintroducing complexity and possible bugs into the program.
X
XPutting data into the future screen is much like writing to a real terminal.
XThere is a "current write location", which is similar to the cursor of the
Xterminal.
XLike a terminal, characters written to
X.I dpy
Xappear at the current write location, and automatically advance its location.
XWhen the rightmost location on a line is reached, the current write location
Xis automatically moved to the leftmost location on the next line.
X
XPrinting characters are stored as is, and will later be visible.
XBut control characters have special effects like on a terminal.
XIn particular, linefeed moves to the beginning of the next line, return
Xmoves back to the beginning of the current line, tab moves to the next
Xtab stop as if the corresponding number of spaces were given, and backspace
Xbacks up by one location.
XOther control characters appear in ^X format.
X
XWriting to the future screen differs from writing to most real terminals
Xin a couple of ways.
XFirstly, scrolling does not occur.
XIf the end of the screen is reached, any further characters are ignored.
XThe
X.I dpyread
Xcall is an exception, and does provide for scrolling.
X
XSecondly, it is possible to limit output to a
X.IR window,
Xwhich is a rectangle of any size on the screen.
XThe location and size of a window is specified by the program when it wants to
Xlimit output to a rectangle.
XThis window acts just like a regular terminal screen of the appropriate size.
XFurthermore, coordinates are relative to the window's upper left corner,
Xso a routine which writes in the window does not need to know where it is.
XData in the future screen which lies outside of the window is untouched,
Xno matter what is done within the window.
X
XTypically, a program divides the screen up into several windows
Xwhich do not overlap.
XData can then be written to each window independently,
Xwithout regard to where each window is.
XFor example, a linefeed character moves to the beginning of the next line in
Xthe current window, instead of to the beginning of the next line of the screen.
XMultiple writes to the same location do not cause any problems.
XTherefore, when windows do overlap and then
X.I dpyupdate
Xis called, each screen location just displays the character which was
Xlast written there.
X
XFinal hints:
X
XA window can be filled with a background character by simply writing that
Xcharacter to the window until a nonzero return value is obtained, meaning
Xthe window is full.
X
XIf a region of the screen is never changed (such as a help text), then that
Xregion should be in its own window.
XThen it only needs to be written once.
X
XThe terminal size can be found after calling
X.I dpyinit
Xby calling
X.nf
X	dpymove(-1, -1);
X.fi
Xto move to the lower right corner of the screen, and then calling
X.I
Xdpygetrow
Xand
X.I dpygetcol
Xto return the row and column numbers.
X
XWhile writing data to the window,
X.I dpygetrow
Xand
X.I dpygetcol
Xare useful in order to
Xremember the location of a particular position in the window.
XWhen all of the data has been written, then
X.I dpymove
Xcan be used to position the cursor back to that location.
XIn this way, you don't have to worry about line wrapping or control character
Xexpansions when computing how to position the cursor on a particular
Xcharacter of your data.
X.SH AUTHOR
XDavid I. Bell
//E*O*F dpy.3//
echo x - dpy.doc
sed -e 's/^X//' > "dpy.doc" << '//E*O*F dpy.doc//'
X
X
X
XDPY(3)		    UNIX Programmer's Manual		   DPY(3)
X
X
X
XNAME
X     dpy - new screen updating routines
X
XSYNOPSIS
X     dpyinit(ttytype, modestring)
X     char *ttytype, *modestring;
X
X     dpywindow(minrow, maxrow, mincol, maxcol)
X     int minrow, maxrow, mincol, maxcol;
X
X     dpyread(prompt, routine, buf, count)
X     char *prompt;
X     int (*routine)();
X     char *buf;
X     int count;
X
X     dpymove(row, col)
X     int row, col;
X
X     dpyplace(row, col,	ch)
X     int row, col;
X     char ch;
X
X     dpywrite(buf, count)
X     char *buf;
X     int count;
X
X     dpyprintf(fmt [,args] ...)
X     char *fmt;
X
X     dpychar(ch)
X     char ch;
X
X     dpystr(str)
X     char *str;
X
X     dpyget(row, col)
X     int row, col;
X
X     dpyclrline()
X
X     dpyclrwindow()
X
X     dpyhome()
X
X     dpygetrow()
X
X     dpygetcol()
X
X     dpyupdate()
X
X     dpyredraw()
X
X
X
XPrinted	3/7/85		  7 March 1985				1
X
X
X
X
X
X
XDPY(3)		    UNIX Programmer's Manual		   DPY(3)
X
X
X
X     dpystop()
X
X     dpyclose()
X
XDESCRIPTION
X     _D_p_y is a terminal display package much like _c_u_r_s_e_s(3).  How-
X     ever, _d_p_y does not	provide	all of the capabilities	of
X     _c_u_r_s_e_s, but instead tries to focus	on the following two
X     goals:
X
X     1.	  Allow	the programmer to easily define	and update many
X	  different rectangles of data on the screen at	the same
X	  time.
X
X     2.	  Be as	fast as	possible.
X
X     A tutorial	on the usage of	_d_p_y appears later in this docu-
X     ment.  The	remainder of this section describes the	pro-
X     cedures.
X
X     _D_p_y_i_n_i_t must be called before any other call to _d_p_y (_e_x_c_e_p_t
X     _f_o_r _d_p_y_c_l_o_s_e).  It	allocates memory for two screen	images,
X     defines the current window	to be the whole	screen,	sets the
X     current write location to the upper left corner of	the
X     screen, uses _s_i_g_n_a_l(2) to cause the terminal stop character
X     to	trap to	_d_p_y_s_t_o_p	for pretty program stopping (only on BSD
X     systems), and sets	the terminal modes to allow for	terminal
X     input of various kinds.  The actual terminal screen is not
X     cleared until the first _d_p_y_u_p_d_a_t_e call is made, so	that you
X     can initialize your program based upon the	terminal size
X     before deciding to	continue.  _T_t_y_t_y_p_e is a	string specifying
X     the terminal type (example: "vt100"), or NULL to use the
X     value specified by	the _T_E_R_M environment variable.	_M_o_d_e_-
X     _s_t_r_i_n_g is a string	specifying how input is	to be treated
X     from the terminal.	 Each mode is specified	by a single
X     letter, preceeded by an (optional)	plus sign to enable the
X     mode, or preceeded	by a minus sign	to disable the mode.
X     Modes can be separated by spaces.	Modes not mentioned in
X     the string	are unchanged.	The currently defined mode
X     letters are:
X
X     e	  (echo) Echoing of input characters occurs.
X
X     c	  (cbreak) Characters are returned without waiting for a
X	  newline and tty signals are processed.
X
X     r	  (raw)	Characters are returned	exactly	as typed and tty
X	  signals are disabled.
X
X     Thus the normal terminal modes before starting _d_p_y	are
X     described by the string "e	-c -r".	 If _m_o_d_e_s_t_r_i_n_g is a NULL
X     pointer, then the default modes of	"-e c" are used.  If the
X
X
X
XPrinted	3/7/85		  7 March 1985				2
X
X
X
X
X
X
XDPY(3)		    UNIX Programmer's Manual		   DPY(3)
X
X
X
X     _d_p_y_r_e_a_d call is to	be used	in your	program, then you must
X     specify that echoing is disabled, and that	either cbreak or
X     raw mode is enabled.  _D_p_y_i_n_i_t returns nonzero with	an error
X     message typed if it cannot	initialize.
X
X     _D_p_y_c_l_o_s_e homes down to the	lower left corner of the terminal
X     screen, clears the	last line of the screen, frees the memory
X     allocated by _d_p_y_i_n_i_t, and restores	the original terminal
X     modes.  This is useful just before	exiting	from your pro-
X     gram.  _D_p_y_c_l_o_s_e is	guaranteed to do nothing if _d_p_y_i_n_i_t has
X     not yet been completed, so	that it	is safe	to call	_d_p_y_c_l_o_s_e
X     at	any time.
X
X     _D_p_y_u_p_d_a_t_e makes the terminal screen look like the future
X     screen image, using a minimal amount of terminal I/O.  The
X     cursor is also positioned to the current write location.
X     This routine must be called when you have completed your
X     writing of	data to	the future screen image, in order to make
X     those changes visible to the user.
X
X     _D_p_y_w_i_n_d_o_w specifies the rectangle where characters	will be
X     placed in the future screen image,	and sets the current
X     write location to the top left corner of the rectangle.  The
X     upper left	corner of the window has the coordinates speci-
X     fied by _m_i_n_r_o_w and	_m_i_n_c_o_l,	and the	lower right corner has
X     the coordinates specified by _m_a_x_r_o_w and _m_a_x_c_o_l.  These coor-
X     dinates are the absolute screen coordinates, where	the upper
X     left corner of the	screen is row 0	and column 0.  Negative
X     numbers specify row or column numbers from	the bottom or
X     right edges of the	screen.	 For example,
X	  dpywindow(0, -1, 0, -1);
X     defines a window which fills the whole screen.  Returns
X     nonzero if	the coordinates	are illegal.
X
X     _D_p_y_w_r_i_t_e writes _c_o_u_n_t characters from location _b_u_f	to the
X     future screen image at the	current	write location in the
X     current window, and updates the current write location
X     appropriately.  This call does not	do any actual I/O to the
X     terminal.	Control	characters are handled reasonably, as is
X     running off the end of a line or the window.  This	routine
X     is	called by _d_p_y_c_h_a_r, _d_p_y_s_t_r, and _d_p_y_p_r_i_n_t_f, and is there-
X     fore the most efficient way to give characters to _d_p_y.
X     Returns nonzero if	not all	the characters fit in the window.
X
X     _D_p_y_c_h_a_r writes the	single character _c_h to the future screen
X     image.  Returns nonzero if	the character couldn't fit in the
X     window.
X
X     _D_p_y_s_t_r writes the null terminated string _s_t_r to the future
X     screen image.  Returns nonzero if any of the string couldn't
X     fit in the	window.
X
X
X
X
XPrinted	3/7/85		  7 March 1985				3
X
X
X
X
X
X
XDPY(3)		    UNIX Programmer's Manual		   DPY(3)
X
X
X
X     _D_p_y_p_r_i_n_t_f writes a	formated string	to the future screen
X     image in the manner of _p_r_i_n_t_f(3).	_F_m_t is the format string,
X     and _a_r_g_s are arguments to the format string.  Returns
X     nonzero if	any of the string couldn't fit in the window.
X
X     _D_p_y_c_l_r_l_i_n_e	clears the rest	of the line in the future screen
X     image (by changing	the characters to spaces), but does not
X     change the	current	write location.	 Writing a linefeed to
X     the future	screen performs	this function, in addition to
X     moving the	write location to the next line.
X
X     _D_p_y_c_l_r_w_i_n_d_o_w clears the rest of the window	in the future
X     screen image, but does not	change the current write loca-
X     tion.  When rewriting a window completely,	this should be
X     called when done so that any old contents of the window will
X     be	sure to	be cleared out.
X
X     _D_p_y_m_o_v_e changes the current write location	to the specified
X     _r_o_w and _c_o_l_u_m_n numbers, relative to the upper left	corner of
X     the current window.  The upper left corner	of the window is
X     row 0 and column 0.  Negative numbers measure from	the last
X     row or column of the window.  For example,
X	  dpymove(-1, 0);
X     positions to the beginning	of the last line of the	window.
X     This does not set the actual terminal's cursor location
X     unless it is also followed	by a call to _d_p_y_u_p_d_a_t_e.	 Returns
X     nonzero if	the coordinates	are illegal.
X
X     _D_p_y_h_o_m_e moves the current write location to the top left
X     corner of the window.  This function is useful between
X     updates if	your program iteratively rewrites the whole
X     screen as one window.
X
X     _D_p_y_g_e_t_r_o_w returns the row number of the current write loca-
X     tion.  This is the	row number where the next character writ-
X     ten would go.  If the next	character written would	not fit
X     in	the window, -1 is returned.  This number is relative to
X     the first line of the current window.  For	example, if the
X     current write location is at the beginning	of the top line
X     of	the window, this function returns zero.
X
X     _D_p_y_g_e_t_c_o_l returns the column number of the	current	write
X     location.	This is	the column number where	is next	character
X     written would go.	If the next character written would not
X     fit in the	window,	-1 is returned.	 This number is	relative
X     to	the current window.  For example, if the current write
X     location is at the	beginning of a line in the window, this
X     function returns zero.
X
X     _D_p_y_r_e_d_r_a_w redraws the screen to make it look like the
X     current screen image.  This is used to fix	the screen when
X     it	becomes	trashed	due to glitches	or other programs also
X
X
X
XPrinted	3/7/85		  7 March 1985				4
X
X
X
X
X
X
XDPY(3)		    UNIX Programmer's Manual		   DPY(3)
X
X
X
X     writing to	the screen.  This does not change the current or
X     future screen images.
X
X     _D_p_y_s_t_o_p suspends execution	of the process in a nice way by
X     homing down to the	lower left corner of the terminal screen,
X     clearing the last line of the screen, restoring the original
X     terminal modes, and then stopping the process.  If	the pro-
X     cess is continued,	terminal modes are restored, the screen
X     is	redrawn, and execution proceeds.  This is called automat-
X     ically when the terminal's	stop character (usually	^Z) is
X     typed by the user.	 _D_p_y_s_t_o_p is a null routine for non-BSD
X     systems.
X
X     _D_p_y_p_l_a_c_e places the character _c_h within the current window
X     at	the coordinates	specified by _r_o_w and _c_o_l.  The character
X     should not	be a control character.	 The coordinates can be
X     negative to measure from the last row or column of	the win-
X     dow.  The current write location is unchanged.  Like
X     _d_p_y_w_r_i_t_e and similar routines, this routine only affects the
X     future screen image, and does no terminal I/O.  Returns
X     nonzero if	the coordinates	are illegal.
X
X     _D_p_y_g_e_t Returns the	character from the current window which
X     is	at the coordinates specified by	_r_o_w and	_c_o_l.  The coordi-
X     nates can be negative to measure from the last row	or column
X     of	the window.  The character returned is from the	future
X     screen image, not the current screen image.  The current
X     write location is unchanged.  Returns negative if the coor-
X     dinates are illegal.
X
X     _D_p_y_r_e_a_d reads input from the user while showing the input
X     data on the screen.  Editing of the input and updating of
X     the screen	is automatically performed by _d_p_y.  The	entire
X     current window is used to display the input, and therefore
X     you must set the window to	your desired input location
X     before calling _d_p_y_r_e_a_d.  Typically, you specify the window
X     to	be a single line at the	top or bottom of the screen.  If
X     the _p_r_o_m_p_t	string pointer is not NULL, then the prompt
X     string will appear	at the beginning of the	window,	followed
X     by	the data typed by the user.  To	display	the user's input
X     without any prompt, specify a pointer to a	null string.  If
X     _p_r_o_m_p_t is NULL, then the window will be untouched and no
X     terminal I/O at all will be performed (useful when	input is
X     from a script or file).  _B_u_f and _c_o_u_n_t specify the	area in
X     the calling program where the data	being read is stored, in
X     the manner	of _r_e_a_d(2).  The data will be what was typed by
X     the user, not what	is seen	on the screen (i.e. control char-
X     acters appear on the screen as ^X,	but appear in the buffer
X     as	themselves).  If more data is typed than fits in the win-
X     dow, the data in the window is automatically scrolled to
X     keep the current input location visible.  _R_o_u_t_i_n_e is a func-
X     tion variable which specifies a routine which is called to
X
X
X
XPrinted	3/7/85		  7 March 1985				5
X
X
X
X
X
X
XDPY(3)		    UNIX Programmer's Manual		   DPY(3)
X
X
X
X     provide the input characters for _d_p_y_r_e_a_d.	_R_o_u_t_i_n_e	is called
X     with the previous character read (-1 on the first call).  It
X     must return the next character read, or -1	to end input and
X     cause _d_p_y_r_e_a_d to return.  Providing the previous character
X     as	an argument allows a routine to	easily return a	break
X     character as input, and then end the input	on the next call.
X     If	_r_o_u_t_i_n_e	is 0, then a default routine will be used which
X     reads from	the standard input until an end	of file	or new-
X     line is typed (which is included in the buffer).  Whenever
X     the character count would be exceeded, then _d_p_y_r_e_a_d will
X     warn the user with	a bell and discard the input character.
X     _D_p_y_r_e_a_d returns the number	of characters read into	the
X     buffer, which is not guaranteed to	contain	a terminating
X     null or newline character.
X
XTUTORIAL
X     The routines in the _d_p_y library are called	directly by the
X     user program.  None of these routines are a macro,	so that
X     there is no need to include a header file to use _d_p_y.  These
X     routines use the _t_e_r_m_l_i_b (or _c_u_r_s_e_s under System V) library
X     routines to obtain	the proper terminal escape sequences.
X     Therefore,	you load your program as in the	following exam-
X     ples:
X
X	  cc -o	yourprog yourprog.c -ldpy -ltermlib    for BSD
X     or:
X	  cc -o	yourprog yourprog.c -ldpy -lcurses     for System V
X
X     _D_p_y keeps two arrays which	hold images of the terminal
X     screen.  The first	array (the "current screen") is	a copy of
X     what the terminal screen really looks like.  The second
X     array (the	"future	screen") is a copy of what the calling
X     program wants the screen to look like.  The use of	_d_p_y
X     proceeds in two phases under the control of the calling pro-
X     gram, as follows:
X
X     In	the first phase, only the future screen	is manipulated.
X     The calling program positions the "current	write location"
X     as	desired	within the future screen, and writes new informa-
X     tion within it.  The _d_p_y_w_r_i_t_e, _d_p_y_c_h_a_r, _d_p_y_s_t_r, _d_p_y_p_r_i_n_t_f,
X     and _d_p_y_p_l_a_c_e routines are used for	this purpose.  During
X     this phase, no actual I/O occurs and the terminal screen
X     remains unchanged.
X
X     In	the second phase, the calling program uses the _d_p_y_u_p_d_a_t_e
X     routine to	update the screen.  _D_p_y	compares the future
X     screen contents with the current screen contents, and does
X     whatever terminal I/O is required in order	to make	the
X     current screen look like the future screen.  After	this is
X     done, the two screen images are identical.	 In addition, the
X     terminal's	cursor is positioned to	the current write posi-
X     tion.
X
X
X
XPrinted	3/7/85		  7 March 1985				6
X
X
X
X
X
X
XDPY(3)		    UNIX Programmer's Manual		   DPY(3)
X
X
X
X     The calling program usually uses _d_p_y by looping between the
X     above two phases.	It defines what	the screen should look
X     like, updates the screen, defines the screen again, updates
X     it	again, and so on.  In doing so,	the program can	be "dumb"
X     or	"smart".  A dumb program rewrites all of the data in its
X     windows each iteration of the loop, and depends on	_d_p_y to
X     prevent terminal I/O for unchanging data.	Thus a dumb pro-
X     gram can be very trivial, and doesn't have	to know	anything
X     about what	is happening on	the screen.
X
X     If	generating a new screenful of data from	scratch	is too
X     much work for the program to do for each iteration, then a
X     good compromise is	to keep	an internal copy of the	screen in
X     the program, update that copy appropriately, and then exe-
X     cute one _d_p_y_w_r_i_t_e call to give _d_p_y	the new	data.
X
X     A smart program knows the exact locations of the desired
X     screen changes each iteration of the loop,	and only rewrites
X     the necessary locations by	using appropriate _d_p_y_m_o_v_e and
X     _d_p_y_p_l_a_c_e calls.  This runs	faster than a dumb program, but
X     has the disadvantage of introducing complexity and	possible
X     bugs into the program.
X
X     Putting data into the future screen is much like writing to
X     a real terminal.  There is	a "current write location", which
X     is	similar	to the cursor of the terminal.	Like a terminal,
X     characters	written	to _d_p_y appear at the current write loca-
X     tion, and automatically advance its location.  When the
X     rightmost location	on a line is reached, the current write
X     location is automatically moved to	the leftmost location on
X     the next line.
X
X     Printing characters are stored as is, and will later be
X     visible.  But control characters have special effects like
X     on	a terminal.  In	particular, linefeed moves to the begin-
X     ning of the next line, return moves back to the beginning of
X     the current line, tab moves to the	next tab stop as if the
X     corresponding number of spaces were given,	and backspace
X     backs up by one location.	Other control characters appear
X     in	^X format.
X
X     Writing to	the future screen differs from writing to most
X     real terminals in a couple	of ways.  Firstly, scrolling does
X     not occur.	 If the	end of the screen is reached, any further
X     characters	are ignored.  The _d_p_y_r_e_a_d call is an exception,
X     and does provide for scrolling.
X
X     Secondly, it is possible to limit output to a _w_i_n_d_o_w, which
X     is	a rectangle of any size	on the screen.	The location and
X     size of a window is specified by the program when it wants
X     to	limit output to	a rectangle.  This window acts just like
X     a regular terminal	screen of the appropriate size.
X
X
X
XPrinted	3/7/85		  7 March 1985				7
X
X
X
X
X
X
XDPY(3)		    UNIX Programmer's Manual		   DPY(3)
X
X
X
X     Furthermore, coordinates are relative to the window's upper
X     left corner, so a routine which writes in the window does
X     not need to know where it is.  Data in the	future screen
X     which lies	outside	of the window is untouched, no matter
X     what is done within the window.
X
X     Typically,	a program divides the screen up	into several win-
X     dows which	do not overlap.	 Data can then be written to each
X     window independently, without regard to where each	window
X     is.  For example, a linefeed character moves to the begin-
X     ning of the next line in the current window, instead of to
X     the beginning of the next line of the screen.  Multiple
X     writes to the same	location do not	cause any problems.
X     Therefore,	when windows do	overlap	and then _d_p_y_u_p_d_a_t_e is
X     called, each screen location just displays	the character
X     which was last written there.
X
X     Final hints:
X
X     A window can be filled with a background character	by simply
X     writing that character to the window until	a nonzero return
X     value is obtained,	meaning	the window is full.
X
X     If	a region of the	screen is never	changed	(such as a help
X     text), then that region should be in its own window.  Then
X     it	only needs to be written once.
X
X     The terminal size can be found after calling _d_p_y_i_n_i_t by cal-
X     ling
X	  dpymove(-1, -1);
X     to	move to	the lower right	corner of the screen, and then
X     calling _d_p_y_g_e_t_r_o_w and _d_p_y_g_e_t_c_o_l to	return the row and column
X     numbers.
X
X     While writing data	to the window, _d_p_y_g_e_t_r_o_w and _d_p_y_g_e_t_c_o_l
X     are useful	in order to remember the location of a particular
X     position in the window.  When all of the data has been writ-
X     ten, then _d_p_y_m_o_v_e can be used to position the cursor back to
X     that location.  In	this way, you don't have to worry about
X     line wrapping or control character	expansions when	computing
X     how to position the cursor	on a particular	character of your
X     data.
X
XAUTHOR
X     David I. Bell
X
X
X
X
X
X
X
X
X
X
XPrinted	3/7/85		  7 March 1985				8
X
X
X
//E*O*F dpy.doc//
echo done
-- 
no comment is a comment.