dbell@daisy.UUCP (David I. Bell) (03/01/85)
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! David I. Bell nsc!daisy!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: # 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
dbell@daisy.UUCP (David I. Bell) (03/01/85)
#---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, <chars) == 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