chris@umcp-cs.UUCP (07/06/83)
: Run this shell script with "sh" not "csh" PATH=:/bin:/usr/bin:/usr/ucb export PATH all=FALSE if [ $1x = -ax ]; then all=TRUE fi /bin/echo 'Extracting xac' sed 's/^X//' <<'//go.sysin dd *' >xac X.\"Wood.R.J.-1982-05-3 X.ds [F Wood 82 X.]- X.ds [L Wood 82 X.ds [A Wood, R.J. X.ds [T A Window Based Display Management System X.ds [R Univ. of Maryland, TR (in preparation) X.ds [D May 1982 X.nr [T 0 X.nr [A 1 X.nr [O 0 X.][ 4 tech-report X.]> X.ls 2 X.AP "Technical description" X.pp XThese are listings of the files that are to be #\fIinclude\fRd to use the Xwindow library. The first file should be included in any program using Xwindows; it includes the second file automatically. X.sp X.ce X\fB<local/window.h>\fR X.sp X.nf X.ls 1 X#include <local/win.h> X X#define Wwrap(w,on) ((w)->w_status &= ~WWRAPOFF, \\ X (w)->w_status |= (on)?0:WWRAPOFF, 0) X#define Wnewline(w,on) ((w)->w_status &= ~WNEWLINE, \\ X (w)->w_status |= (on)?WNEWLINE:0, 0) X#define Wsetmode(w,m) ((w)->w_mode &= ~MODEMASK, \\ X (w)->w_mode |= m & MODEMASK, 0) X#define Wsetpopup(w,p) ((w)->w_popup = (p), 0) X#define Wcurup(w,n) (WAcursor (w, \\ X (w)->w_cursor.row+(w)->w_bstart.row-(n),\\ X (w)->w_cursor.col+(w)->w_bstart.col)) X#define Wcurdown(w,n) (WAcursor (w, \\ X (w)->w_cursor.row+(w)->w_bstart.row+(n),\\ X (w)->w_cursor.col+(w)->w_bstart.col)) X#define Wcurleft(w,n) (WAcursor (w, \\ X (w)->w_cursor.row+(w)->w_bstart.row,\\ X (w)->w_cursor.col+(w)->w_bstart.col-(n))) X#define Wcurright(w,n) (WAcursor (w, \\ X (w)->w_cursor.row+(w)->w_bstart.row,\\ X (w)->w_cursor.col+(w)->w_bstart.col+(n))) X#define WWtoBcursor(w) (WAcursor (w, \\ X (w)->w_textbuf->b_cursor.row, \\ X (w)->w_textbuf->b_cursor.col)) X X/* NOTE: THESE MACROS MAY BE SYSTEM DEPENDENT */ X#define WCHAROF(c) ((c)&0377) X#define WMODEOF(c) ((c)>>NBPB) X X/* Function types for non-integer functions */ XWin *Wopen (), *Wlink (), *Wfind (), *Wboxfind (); X.ls X.fi X.bp X.ce X\fB<local/win.h>\fR X.sp X.nf X.ls 1 X#define NBPB 8 /* Number of bits per byte */ X Xunion chr { X struct { X char ch; /* NOTE: this is known to be low byte */ X char mode; X } ch_two; X short ch_all; X}; X X/* ch_all is set to ' ' or (' '|(WBUF<<NBPB)) so Char must be low byte, and X Mode must be high byte. */ X X#define Char ch_two.ch X#define Mode ch_two.mode X Xtypedef struct { X int row, col; X} Pos; X Xtypedef struct { X int xorigin, yorigin; X int xextent, yextent; X} Rect; X Xstruct coverlist { X struct coverlist *c_next; X struct window *c_top, /* Window on top */ X *c_bot; /* Window on bottom */ X Rect c_area; /* Area of intersection */ X}; X Xtypedef union chr Ch; X Xstruct buffer { X Ch *b_contents; X int b_nwins; /* Number of windows using this buffer */ X int b_nrows, /* Number of rows of text */ X b_ncols; /* Number of cols */ X Pos b_cursor; /* Buffer cursor (WBputc ()) */ X int b_nmodw; /* If zero buffer not modified [see disp.c] */ X}; X Xtypedef struct coverlist Cov; Xtypedef struct buffer Buf; Xtypedef struct window Win; X Xstruct window { X Win *w_next; /* Next window in list */ X int w_id; /* Window ID */ X Rect w_outside; /* Describes whole window */ X Rect w_inside; /* Describes inner part of window */ X Buf *w_textbuf; /* Pointer to buffer containing text */ X Ch *w_winbuf; /* Pointer to window chars */ X Pos w_bstart; /* Coordinates of win projection on w_buf */ X Pos w_cursor; /* Coordinates of cursor */ X Pos w_auxcursor; /* Coordinates of aux cursor */ X Ch *w_bcursor; /* Cursor ptr into text [w_textbuf] */ X Ch *w_wcursor; /* Cursor ptr into window [w_auxcursor] */ X int w_popup; /* Number of lines to scroll */ X char w_mode; /* Current text-writing mode */ X char w_status; /* Status bits */ X}; X X#define OXO w_outside.xorigin X#define OXE w_outside.xextent X#define OYO w_outside.yorigin X#define OYE w_outside.yextent X X#define IXO w_inside.xorigin X#define IXE w_inside.xextent X#define IYO w_inside.yorigin X#define IYE w_inside.yextent X X/* Mode bits (w_mode, ch_two.mode) */ X#define WBOLD 0x01 /* Bold */ X#define WULINE 0x02 /* Underlined */ X#define WBLINK 0x04 /* Blinking */ X#define WINVERSE 0x08 /* Inverse video */ X#define MODEMASK (WBOLD|WULINE|WBLINK|WINVERSE) /* [all chars] */ X#define WINVIS 0x10 /* Invisible [windows only] */ X#define WBUF 0x20 /* From buffer [windows only] */ X X/* Status bits (w_status) */ X#define WWRAPOFF 0x01 /* Auto-wrap is off */ X#define WHIDDEN 0x02 /* Window is hidden */ X#define WNEWLINE 0x04 /* \\r, \\n act like \\r\\n */ X#define WCURSOR 0x08 /* Cursor is hidden */ X#define WDUMP 0x10 /* Window contents need dumping to screen */ X#define WCOVERED 0x20 /* Window is covered */ X#define WCOVERING 0x40 /* Window is covering others */ X#define WBORDERED 0x80 /* Window has been bordered (framed) */ X Xextern Win *WinList; /* Base of window list */ Xextern Win *CurWin; /* Current window */ Xextern Cov *WCovList; /* Base of coverings list */ Xextern Rect WBox; /* Information on the (single) box */ Xextern int MajorUpdate; /* True iff maximum optimization wanted */ Xextern int SigMagic; /* True iff sigset() magic is wanted */ Xextern int InputPending; /* True iff keyboard input is pending */ Xextern int LastRedisplayPaused; /* True iff last redisplay paused */ Xextern int ScreenGarbaged; /* True iff screen contents uncertain */ Xextern int WBoxActive; /* True iff box is active */ Xextern int WSetRealCursor; /* True iff want terminal cursor positioning */ Xextern int WRCurRow; /* Set real cursor to this row, */ Xextern int WRCurCol; /* ... this col [both 0 origin] */ Xextern int VisibleBell; /* True iff want ^G to flash */ Xextern int WindowsActive; /* Set while windows (stty settings) active */ X X#define Max(a,b) ((a)>(b)?(a):(b)) X#define Min(a,b) ((a)<(b)?(a):(b)) X.ls X.fi X.bp X.sp X.ce X\fIWhat they mean\fR X.pp X\fBUnion chr\fR is the union used to access characters. All characters are Xstored as 16 bits, with the low eight being the character, and the next Xfour being the mode. Two more bits are used in window buffers. ch_all Xis a way to get to all 16 bits quickly. X.pp X.pp X\fBPos\fR and \fBRect\fR are coordinate holders. \fBPos\fR is a position; \fBRect\fR Xis a position and size (i.e. a rectangular region). \fBStruct Xcoverlist\fR (aka \fBCov\fR) is an element of the window covering information Xlist. Each entry has a pointer to the next, two pointers to windows X(one is on top and the other on bottom), and an area of intersection. XThis list can be used to quickly find out which windows cover or are Xcovered by another. X.pp X\fBStruct window\fR (aka \fBWin\fR) is the window descriptor structure. It Xholds a pointer to the next window in the window list, the window's ID, Xthe position and size of the winbuf, the position and size of the Xin-margins area, a pointer to the window's text buffer, a pointer to Xthe window's winbuf, the position over the text buffer (the X\fBWrelscroll\fRed position), the coordinates of the cursor and aux cursor, Xpointers for the cursor and the aux cursor, the window's popup, the Xwindow's current mode for printing characters, and the status bits. X.pp XA text buffer (\fBstruct buffer\fR or \fBBuf\fR) contains a pointer to the Xactual text, the number of windows linked to this buffer, the size (in Xrows and columns) of the buffer, the position of the buffer cursor, and Xa special value that if -1 means that windows using the buffer need to Xbe redrawn on the screen. (In the redrawing algorithm, b_nmodw is used Xto count down the number of remaining windows, so that b_nmodw becomes Xzero when there are no more windows using the buffer that need to be Xredrawn.) X.pp XThere are some shorthand #\fIdefine\fRs, then the mode and status bits are Xdefined. WBOLD, WULINE, WBLINK, and WINVERSE are the four standard Xmodes that any character has. MODEMASK selects just those four. XWINVIS is set on characters that are covered (thus "invisible"). WBUF Xis set on characters in the winbuf that are to come from the text Xbuffer. WWRAPOFF is true if auto-wrap is off; WHIDDEN is true if the Xwindow is hidden. WNEWLINE is the CR/LF mapping bit. WCURSOR is set Xif the cursor is hidden. WDUMP is set whenever major changes are made Xto a window; it specifies that at \fBWrefresh\fR time, the window should be Xdumped to the virtual screen. WCOVERED is true if the window might be Xcovered (it occasionally gets out of date); WCOVERING is true if the Xwindow might be covering others. WBORDERED is set if labels should Xavoid the left and right corners. These are followed by the global Xvariables listed below. X.ip \fBWinList\fR XThe base of the windows list. The depth of a particular window is Xdetermined by its position in the \fBWinList\fR: the first window is the Xfront window; each successive window is a little bit deeper. X.ip \fBCurWin\fR XThe current window, maintained for those who don't want to hang on to Xeach \fBWin\fR pointer. X.ip \fBWCovList\fR XThe base of the cover information list. X.ip \fBWBox\fR XDescribes the position and size of the box. X.ip \fBMajorUpdate\fR XSet whenever something that might make it wise to check for line Xinsertion/deletion optimization occurs; if not set a lot of computation Xis avoided. X.ip \fBSigMagic\fR XSet if \fBWinit\fR is called with zero as the second parameter. When set, XSIGINT and SIGTSTP signals are held during critical sections of code. X.ip \fBInputPending\fR X\fBInputPending\fR is the object of the \fBioctl\fR calls that look for pending Xinput, so is the number of characters that can be read from file Xdescriptor 0. X.ip \fBLastRedisplayPaused\fR XFor internal use; this forces a clear of the virtual screen and a dump Xof every window at \fBWrefresh\fR time. X.ip \fBScreenGarbaged\fR XWhen set, forces a complete update of the terminal's screen; typically Xit should be set when a user types a special character (e.g. ^L). X.ip \fBWBoxActive\fR XSet when the box should be displayed. To remove the box, set X\fBWBoxActive\fR to zero. X.ip \fBWSetRealCursor\fR XMay be set to force the real terminal's cursor to be positioned at Xsomeplace in particular if this is desired; the place should be filled Xinto \fBWRCurRow\fR and \fBWRCurCol\fR. X.ip \fBVisibleBell\fR XShould be set if the user wants his terminal to flash instead of Xfeeping when an ASCII 7 (BELL) is printed (or when \fBDing\fR is called). X.ip \fBWindowsActive\fR XSet while windows are "active" (i.e. whenever windows stty settings Xare active) and is checked by \fBWrefresh\fR, since a refresh will often Xcore dump quite mysteriously if windows are not active. X.sp 2 X.ce X\fIInternal Representation\fR X.pp XAll characters are stored as \fBunion chr\fR. The lower four bits of the Xmode apply to all characters and are the standard modes. The next two Xbits are only used in winbufs. WINVIS is set on characters that are Xcovered. This is used during \fBWrefresh\fR to decide when characters Xshould be displayed. If WINVIS is set, the character (be it from the Xtextbuf or winbuf) is not displayed. WBUF, if set, means the character Xshould be displayed from the textbuf. X.pp XCharacters that are covered are never visible. Whenever a window is Xhidden or unhidden, or moved, or fronted, or a new window is opened, Xthe covering relationships of windows need to be recomputed. To Xrecompute the cover relationships of a window, all existing cover Xinformation regarding the window must be removed. This can be done by Xrunning down the cover list looking for the appropriate window, and Xuncovering covered characters. Unfortunately, if the window is on top Xof another, the characters uncovered in the other window may still be Xcovered by still other windows, so all bottom windows that are Xuncovered must also be recomputed. X.pp XOnce the covering information is removed, new information can be Xcomputed. This is done by running down the window list, looking for Xwindows that intersect. If two windows intersect, the "topness" of one Xover the other is determined by their relative positions in the window Xlist. The first window covers all others; successive windows are each Xa bit deeper. All that is actually necessary is to cover windows that Xcome after the window being computed ("this window"), and to cover the Xwindow being computed by those that come before it. Thus only one flag Xis needed, namely, whether this window has been encountered on the Xlist. If so, this window covers the other; if not, the other covers Xthis. X.pp XWith the windows computed, there remains the task of getting them onto Xthe physical display. To do this, two copies of the terminal screen Xare kept. One is the current "physical screen". This holds the actual Xstate of the display, as last \fBWrefresh\fRed. The other is the "virtual Xscreen", holding the desired state. When \fBWrefresh\fR is called, it Xmakes sure that all the windows are correctly in the virtual screen, Xthen updates the physical screen to match the virtual screen. This Xupdate can be done simply by updating each line, or it can be done with Xan algorithm that compares lines and uses line insert and delete to Xmove physical display lines around. The decision to use the more Xdifficult insert-and-delete is made depending on whether any window Xmoves or scrolls have occurred. This information is kept in the Xvariable \fBMajorUpdate\fR. If set, the extra work will be done. X.pp XMost terminals are not able to turn off their cursors, so the variable X\fBWSetRealCursor\fR may be set to make the window library position the Xterminal's cursor to a particular row and column after an update is Xcomplete. If not set, the cursor will be left after the last character Xwritten. Often this is immediately following the window cursor, thus Xmaking a window appear to have two cursors. If set, the terminal's Xcursor will be moved to line \fBWRCurRow\fR, column \fBWRCurCol\fR. In fact, Xit is sometimes useful to hide the window's cursor and use the real Xterminal's cursor. The following macro may be used to set the Xvariables \fBWRCurRow\fR and \fBWRCurCol\fR to \fIw\fR's window cursor position: X.sp X.nf X.ls 1 X#define SetReal(w) (WRCurRow = (w)->OYE+(w)->IYE+(w)->w_cursor.row, \\ X WRCurCol = (w)->OXE+(w)->IXE+(w)->w_cursor.col) X.ls X.sp X.fi X.AP "Alphabetical List of Functions" X.lp XFunctions marked with "-" are actually macros. X.sp X.nf X.ls 1 X Ding () X- Max (a, b) X- Min (a, b) X WAcursor (w, row, col) X WAread (w, charonly) X WBclear (w, howto) X WBclearline (w, howto) X WBcursor (w, row, col) X WBdelchars (w, n) X WBdelcols (w, n) X WBdellines (w, n) X WBinschars (w, n) X WBinscols (w, n) X WBinslines (w, n) X WBputc (c, w) X WBputs (s, w) X WBread (w, charonly) X WBscroll (w, rows) X WBtoWcursor (w) X- WCHAROF (c) X- WMODEOF (c) X WWcursor (w, row, col) X- WWtoBcursor (w) X Waputc (c, m, w) X Waputs (s, m, w) X Wauxcursor (w, row, col) X Wback (w) X Wborder (w, ulc, top, urc, left, right, llc, bottom, lrc) X Wbox (xorg, yorg, xext, yext) X Wboxfind () X Wcleanup () X Wclear (w, howto) X Wclearline (w, howto) X Wclose (w) X Wcloseall () X- Wcurdown (w, n) X- Wcurleft (w, n) X- Wcurright (w, n) X- Wcurup (w, n) X Wdelchars (w, n) X Wdelcols (w, n) X Wdellines (w, n) X Wexit (code) X Wfiledump (file) X Wfind (id) X Wframe (W) X Wfront (w) X Wgetframe (ulc, top, urc, left, right, llc, bottom, lrc) X Whide (w) X Winit (settings, nomagic) X Winschars (w, n) X Winscols (w, n) X Winslines (w, n) X Wlabel (w, label, bottom, center) X Wlink (ew, id, xorg, yorg, xext, yext, bcols, brows) X Wmove (w, xorg, yorg) X- Wnewline (w, on) X Woncursor (w, on) X Wopen (id, xorg, yorg, xext, yext, bcols, brows) X Wputc (c, w) X Wputs (s, w) X Wread (w, charonly, winonly) X Wrefresh (SkipInputCheck) X Wrelscroll (w, rows, cols, cwin) X Wretroline (w, mode) X Wscreensize (rows, cols) X Wscroll (w) X Wsetbuf (w, bcols, brows) X Wsetframe (ulc, top, urc, left, right, llc, bottom, LRC) X Wsetmargins (w, inxorg, inxext, inyorg, inyext) X- Wsetmode (w, m) X- Wsetpopup (w, p) X Wsize (w, xext, yext) X Wsuspend () X Wunhide (w) X- Wwrap (w, on) X bcopy (from, to, count) X.ls X.fi X.AP "Signals" X.pp XThese routines emulate the Berkeley jobs library using the Version 7 XUnix signal mechanism. They have not been extensively tested; no Xguarantee is made that they will work in all cases. X.sp 2 X.nf X.ls 1 X#include <signal.h> X X/* X * Jobs library emulator using old signal mechanism X * X * 26 March 1983 ACT X * X * held_sigs == the signals held via sighold() X * executing_sigs == the signals held because the signal handler is already X * running X * pending_sigs == the signals pending, for sigrelse() or whatever X */ X Xstatic long held_sigs, pending_sigs, executing_sigs; Xstatic int (*sigfuncs[32])(); Xint sigcatch(); X Xint (*sigset (signo, f))() Xregister signo; Xint (*f)(); X{ X int (*rv)() = sigfuncs[signo]; X X if (f == SIG_DFL || f == SIG_IGN) { /* these are just zap-em-ins */ X sigfuncs[signo] = f; X signal (signo, f); X pending_sigs &= ~(1<<signo); X return rv; X } X sigfuncs[signo] = f; X signal (signo, sigcatch); /* sigcatch() does the real work */ X return rv; X} X Xint (*sigignore (signo))() Xint signo; X{ X sigset (signo, SIG_IGN); X} X X/* This is easy too ... */ Xsighold (signo) Xint signo; X{ X held_sigs |= 1 << signo; X} X Xsigrelse (signo) Xint signo; X{ X register sigbit = 1 << signo; X X held_sigs &= ~sigbit; X if (pending_sigs & sigbit) X sigcatch (signo); /* sigcatch() does the real work */ X} X X/* RACE CONDITIONS ABOUND! */ X/* This code assumes that if a second signal occurs it will be during X the user's function. That isn't quite true, but... that's the way X it goes. */ Xstatic Xsigcatch (signo) Xregister signo; X{ X register sigbit; X X signal (signo, sigcatch); X sigbit = 1 << signo; Xresig: X /* If it's already executing, or if the user asked to hold it, X then don't call the function yet. */ X if ((executing_sigs|held_sigs) & sigbit) { X pending_sigs |= sigbit; X return; X } X pending_sigs &= ~sigbit; /* Clear pending signals */ X executing_sigs |= sigbit; /* Say this one is executing */ X (*sigfuncs[signo]) (signo); /* Call user function */ X executing_sigs &= ~sigbit; /* Not executing anymore */ X if (pending_sigs & sigbit) X goto resig; X} X.ls X.fi X.AP "Sample Program(s)/Routine(s)" X.pp XThis routine will get input from the user's terminal, echoing in a Xwindow. It handles backspace and line kill, and redrawing the Xentire screen. X.sp 2 X.nf X.ls 1 X#include <stdio.h> X#include <local/window.h> X X/* X * gets (s, n, w) X * X * A simple input routine; get at most n characters into string s, X * echoing in Win *w. X * X * Does not know about control characters and such. X */ X X#define CTRL(c) ((c)&0x1f) X Xgets (s, n, w) Xchar *s; Xregister n; Xregister Win *w; X{ X register c; X register char *cp = s; X X for (;;) { X Wrefresh (0); /* Update screen */ X c = getchar () & 0x7f; X if (c == '\\b') { /* Backspace */ X if (cp == s) /* nothing to backspace over */ X continue; X Wputc (c, w); X --cp; X n++; X continue; X } X if (c == CTRL('X')) { /* Line kill */ X Wputs ("\\r\\n", w); X n += cp - s; X cp = s; X continue; X } X if (c == CTRL('L')) { /* Redraw screen */ X ScreenGarbaged++; X continue; X } X if (c == '\\r' || c == '\\n') {/* Enter */ X *cp = 0; X Wputs ("\\r\\n", w); X return; X } X if (n < 2) { /* Not enough space for char, */ X Ding (); /* ring bell */ X continue; /* and ignore */ X } X *cp++ = c; /* Stuff in char */ X n--; /* Less room */ X Wputc (c, w); /* Echo char in window */ X } X} X.ls X.sp X.fi X.pp XMore program(s)... if I ever write them. X.AP "Format of File Dumps" X.pp XFile dumps are made using stdio. The format is a series of hex digits Xas printed by "%02x", separated by newlines. The first line contains Xfour hex digits. The first two represent the screen width and the last Xtwo the screen height. There follow screen height lines of (screen Xwidth * 4) hex digits each, in groups of four. Positions on the screen Xthat are not occupied by windows are dumped as 0000. In any other Xcase, the first two digits are the mode, of which the low five bits may Xbe set. These bits are as defined in <local/win.h>. The last two Xdigits are the ASCII code of the character. Figure \n(Fn represents a Xten (decimal) by six screen with one 6 by 5 empty window. X.Bf X0a06 X0000002b002d002d002d002d002b000000000000 X0000007d0020002000200020007d000000000000 X0000007d0020002000200020007d000000000000 X0000007d0020002000200020007d000000000000 X0000002b002d002d002d002d002b000000000000 X0000000000000000000000000000000000000000 X.Ef "Dump of 10 x 6 Screen" X.AP "Reserved Names Not Listed Elsewhere" X.pp XThe following symbols may not be listed elsewhere in this document, but Xare used internally and should be avoided by programmers using the XMaryland Windows Library. This list includes only names Xnot starting with capital W. All names starting with W should be avoided Xto prevent conflicts. X.sp X.nf X.ls 1 XCurWin XDing XInputPending XInverseVideo XLastRedisplayPaused XMajorUpdate XNoOperation XScreenGarbaged XSigMagic XTrmAmb XTrmBitG XTrmTEK4025 XTrmTERM XTrmVT100 XVisibleBell Xbcopy X.ls X.fi X.he '''' X.bp X.ls 2 X.\" for use with -me macros X.\" assumes that macro defined by stoc.nr exists X.de Im X.In \\$1 X.ti -\\$2n X.. X.de In X'ba \\$1n X'in \\n($iu + \\n(pou X.. X.de BI X.xl -\\$1n X.IN \\$1n X.. X.de BO X.xl +\\$1n X.IN -\\$1n X.. X.de Tc X.if \\n(.$-2 .if \\$3=9 .Im 90 18 X.if \\n(.$-2 .if \\$3=8 .Im 72 16 X.if \\n(.$-2 .if \\$3=7 .Im 56 14 X.if \\n(.$-2 .if \\$3=6 .Im 42 12 X.if \\n(.$-2 .if \\$3=5 .Im 30 10 X.if \\n(.$-2 .if \\$3=4 .Im 20 8 X.if \\n(.$-2 .if \\$3=3 .Im 12 6 X.if \\n(.$-2 .if \\$3=2 .Im 6 4 X.if \\n(.$-2 .if \\$3=1 .Im 2 2 X.if \\n(.$-2 \\$2 \\$1 X.if 2-\\n(.$ \\$1 X.if \\n(.$-2 .if \\$3=9 .In -90 X.if \\n(.$-2 .if \\$3=8 .In -72 X.if \\n(.$-2 .if \\$3=7 .In -56 X.if \\n(.$-2 .if \\$3=6 .In -42 X.if \\n(.$-2 .if \\$3=5 .In -30 X.if \\n(.$-2 .if \\$3=4 .In -20 X.if \\n(.$-2 .if \\$3=3 .In -12 X.if \\n(.$-2 .if \\$3=2 .In -6 X.if \\n(.$-2 .if \\$3=1 .In -2 X.. X.fo '''' X.eh '''' X.oh '''' X.lp X.bp X.(l C XTable of Contents X.)l X.sp 3 X.na X.xp t X.ad b //go.sysin dd * made=TRUE if [ $made = TRUE ]; then /bin/chmod 644 xac /bin/echo -n ' '; /bin/ls -ld xac fi -- UUCP: {seismo,allegra,brl-bmd}!umcp-cs!chris CSNet: chris@umcp-cs ARPA: chris.umcp-cs@UDel-Relay