home *** CD-ROM | disk | FTP | other *** search
- From: ustel@well.UUCP (Mark Hargrove)
- Newsgroups: comp.sources.misc
- Subject: v02i053: Unify TEXT fields from ACCELL Part 4/5
- Message-ID: <7221@ncoast.UUCP>
- Date: 11 Feb 88 00:52:50 GMT
- Approved: allbery@ncoast.UUCP
-
- Comp.sources.misc: Volume 2, Issue 53
- Submitted-By: "Mark Hargrove" <ustel@well.UUCP>
- Archive-Name: accell-text/Part4
-
- [Beware of substandard shar. I saw a man page ripe for chomping. ++bsa]
-
- #!/bin/sh
- # to extract, remove the header and type "sh filename"
- if `test ! -s ./README`
- then
- echo "writing ./README"
- cat > ./README << '\Rogue\Monster\'
- To change the function key bindings in mgx:
-
- The actual function key bindings are in the file "ttykbd.c", in the
- function "ttykeymapinit". All other keys are bound in the "key" array in
- the file "symbol.c". If the function you are binding to has already been
- mapped (in the "key" array definition), then you only need to use the
- function "keydup( KEY fkey, char *function_name)". If you are adding a
- function that has NOT been previously defined in the "key" array, you
- must use the function "keyadd( KEY fkey, int (*func)(), char
- *function_name)". Things bomb spectacularly if you mess up here!
-
- The "help" line for function key usage is done using the functions
- "modeline" and "rotatmode" in the file "display.c", which is not really
- the correct place for a user-accessible function, but I didn't want to
- make another global variable, and rebuild the whole program again!. The
- help usage attempts to model after the ACCELL function key help, and
- should be updated when the function key bindings are changed.
-
- \Rogue\Monster\
- else
- echo "will not over write ./README"
- fi
- if `test ! -s ./Makefile`
- then
- echo "writing ./Makefile"
- cat > ./Makefile << '\Rogue\Monster\'
- # Makefile for TinyMG.
- # This is a very small word-processor, designed to be called from Accell
- # that is based upon MicroGnuEmacs V.1b, but without multi-window support
- # or run-time configurability. (It really ain't emacs anymore!)
-
- SHELL = /bin/sh
- # This program needs termcap, not terminfo (not enough function keys)
- # On our NCR Tower, libtermcap.a is linked to libterminfo.a, however
- # accell comes with a termcap library, which I copied over into
- # /usr/lib/libscotterm.a (name it as you will - but order is IMPORTANT,
- # as on the Tower, libcurses.a includes terminfo)
- LIBS = -lscottterm -lcurses
- BIN = /usr/lbin
- # NCR's implementation of SysV defaults to non-shareable text segments
- # this option forces the link of a shareable text segment
- LDFLAGS = -Wl,-n
- # CDEFS gets defines, and gets passed to lint. CFLAGS gets flags, and doesn't
- # get passed to lint.
- #
- # (Common) compile-time options:
- #
- # DO_METAKEY -- if bit 7 is set for a key, treat like a META key
- # STARTUP -- look for and handle initialization file
- # XKEYS -- use termcap function key definitions
- # BACKUP -- enable "make-backup-files"
- # PREFIXREGION -- enable function "prefix-region"
- # BIT7EVEN -- 7-bits/even parity. should be XOR with DO_METAKEY
- # TINY -- very small version
- #
- CDEFS = -DXKEYS -DNOTAB -DMISLOG -DTINY
- CFLAGS = -g $(CDEFS)
-
- OBJ = basic.o buffer.o cinfo.o display.o echo.o extend.o file.o kbd.o \
- line.o main.o random.o region.o search.o symbol.o version.o \
- window.o paragraph.o word.o fileio.o ttyio.o tty.o ttykbd.o spawn.o \
- newlog.o
- SRCS = basic.c buffer.c cinfo.c display.c echo.c extend.c file.c kbd.c \
- line.c main.c random.c region.c search.c symbol.c version.c \
- window.c word.c paragraph.c fileio.c ttyio.c tty.c ttykbd.c spawn.c \
- newlog.c
- INCS = ttydef.h sysdef.h def.h
-
- .c.o :
- $(CC) $(CFLAGS) -c $<
-
- mgx : $(OBJ)
- cc $(CFLAGS) $(LDFLAGS) -o mgx $(OBJ) $(LIBS)
-
- lin : $(SRCS)
- lint $(CDEFS) $(SRCS)
-
- $(OBJ) : $(INCS)
-
- clean :
- rm -f $(OBJ)
-
- install : mgx
- cp mgx $(BIN)
- strip $(BIN)/mgx
- \Rogue\Monster\
- else
- echo "will not over write ./Makefile"
- fi
- if `test ! -s ./def.h`
- then
- echo "writing ./def.h"
- cat > ./def.h << '\Rogue\Monster\'
- /*
- * This file is the general header file for all parts
- * of the MicroEMACS display editor. It contains all of the
- * general definitions and macros. It also contains some
- * conditional compilation flags. All of the per-system and
- * per-terminal definitions are in special header files.
- * The most common reason to edit this file would be to zap
- * the definition of CVMVAS or BACKUP.
- */
- #include "sysdef.h" /* Order is critical. */
- #include "ttydef.h"
- #include <stdio.h>
-
- /*
- * If your system and/or compiler does not support the "void" type
- * then define NO_VOID_TYPE in sysdef.h. In the absence of some
- * other definition for VOID, the default in that case will be to
- * turn it into an int, which works with most compilers that don't
- * support void. In the absence of any definition of VOID or
- * NO_VOID_TYPE, the default is to assume void is supported, which
- * should be the case for most modern C compilers.
- */
-
- #ifdef NO_VOID_TYPE
- # undef VOID
- # define VOID int /* Default for no void is int */
- #else
- #ifndef VOID
- # define VOID void /* Just use normal void */
- #endif /* VOID */
- #endif /* NO_VOID_TYPE */
-
- /*
- * Table sizes, etc.
- */
- #ifdef HASH
- #define NSHASH 31 /* Symbol table hash size. */
- #endif
- #define NFILEN 80 /* Length, file name. */
- #define NBUFN 24 /* Length, buffer name. */
- #ifndef NLINE /* allow it to be defined in makefile */
- #define NLINE 256 /* Length, line. */
- #endif
- #define NKBDM 256 /* Length, keyboard macro. */
- #define NPAT 80 /* Length, pattern. */
- #define HUGE 1000 /* A rather large number. */
- #define NSRCH 128 /* Undoable search commands. */
- #define NXNAME 64 /* Length, extended command. */
- #define NKNAME 20 /* Length, key names */
- /*
- * Universal.
- */
- #define FALSE 0 /* False, no, bad, etc. */
- #define TRUE 1 /* True, yes, good, etc. */
- #define ABORT 2 /* Death, ^G, abort, etc. */
-
- /*
- * These flag bits keep track of
- * some aspects of the last command. The CFCPCN
- * flag controls goal column setting. The CFKILL
- * flag controls the clearing versus appending
- * of data in the kill buffer.
- */
- #define CFCPCN 0x0001 /* Last command was C-P, C-N */
- #define CFKILL 0x0002 /* Last command was a kill */
-
- /*
- * File I/O.
- */
- #define FIOSUC 0 /* Success. */
- #define FIOFNF 1 /* File not found. */
- #define FIOEOF 2 /* End of file. */
- #define FIOERR 3 /* Error. */
-
- /*
- * Directory I/O.
- */
- #define DIOSUC 0 /* Success. */
- #define DIOEOF 1 /* End of file. */
- #define DIOERR 2 /* Error. */
-
- /*
- * Display colors.
- */
- #define CNONE 0 /* Unknown color. */
- #define CTEXT 1 /* Text color. */
- #define CMODE 2 /* Mode line color. */
-
- /*
- * global mode
- */
- #define MBSMAP 0x0001 /* Map bs<->del */
- #define MFLOW 0x0002 /* Use ^^ for ^Q and ^/ for ^S */
- #define MINDENT 0x0004 /* autoindent */
- #define MFILL 0x0008 /* fill mode */
- #ifdef NOTAB
- #define MNOTAB 0x0010 /* no tab mode */
- #endif
- #define MOVRSTK 0x0020 /* insert / over-strike mode */
-
- /*
- * Flags for "eread".
- */
- #define EFFUNC 0x0001 /* Autocomplete functions. */
- #define EFBUF 0x0002 /* Autocomplete buffers. */
- #define EFFILE 0x0004 /* " files (maybe someday) */
- #define EFAUTO 0x0007 /* Some autocompleteion on */
- #define EFNEW 0x0008 /* New prompt. */
- #define EFCR 0x0010 /* Echo CR at end; last read. */
-
- /*
- * Flags for "getkey".
- */
- #define KQUOTE 0x0001 /* Get raw character */
- #define KNOMAC 0x0002 /* Don't record for macros */
- #define KPROMPT 0x0004 /* do delayed prompting */
-
- /*
- * Flags for "ldelete"/"kinsert"
- */
-
- #define KNONE 0
- #define KFORW 1
- #define KBACK 2
-
- /*
- * Keys are represented inside using an 11 bit
- * keyboard code. The transformation between the keys on
- * the keyboard and 11 bit code is done by terminal specific
- * code in the "kbd.c" file. The actual character is stored
- * in 8 bits (DEC multinationals work); there is also a control
- * flag KCTRL, a meta flag KMETA, and a control-X flag KCTLX.
- * ASCII control characters are always represented using the
- * KCTRL form. Although the C0 control set is free, it is
- * reserved for C0 controls because it makes the communication
- * between "getkey" and "getkbd" easier. The funny keys get
- * mapped into the C1 control area. The KEY type is typedefed in
- * sysdef.h, as it may depeond on compiler/machine.
- */
- #define NKEYS 2048 /* 11 bit code. */
-
- #define METACH 0x1B /* M- prefix, Control-[, ESC */
- #define CTMECH 0x1C /* C-M- prefix, Control-\ */
- #define EXITCH 0x1D /* Exit level, Control-] */
- #define CTRLCH 0x1E /* C- prefix, Control-^ */
- #define HELPCH 0x1F /* Help key, Control-_ */
-
- #define KCHAR 0x00FF /* The basic character code. */
- #define KCTRL 0x0100 /* Control flag. */
- #define KMETA 0x0200 /* Meta flag. */
- #define KCTLX 0x0400 /* Control-X flag. */
-
- #define KFIRST 0x0080 /* First special. */
- #define KLAST 0x009F /* Last special. */
-
- #define KRANDOM 0x0080 /* A "no key" code. */
- #define K01 0x0081 /* Use these names to define */
- #define K02 0x0082 /* the special keys on your */
- #define K03 0x0083 /* terminal. */
- #define K04 0x0084
- #define K05 0x0085
- #define K06 0x0086
- #define K07 0x0087
- #define K08 0x0088
- #define K09 0x0089
- #define K0A 0x008A
- #define K0B 0x008B
- #define K0C 0x008C
- #define K0D 0x008D
- #define K0E 0x008E
- #define K0F 0x008F
- #define K10 0x0090
- #define K11 0x0091
- #define K12 0x0092
- #define K13 0x0093
- #define K14 0x0094
- #define K15 0x0095
- #define K16 0x0096
- #define K17 0x0097
- #define K18 0x0098
- #define K19 0x0099
- #define K1A 0x009A
- #define K1B 0x009B
- #define K1C 0x009C
- #define K1D 0x009D
- #define K1E 0x009E
- #define K1F 0x009F
-
- #ifndef SEOL /* needed for OSK, where '\r' == '\n' */
- # define SEOL '\n'
- #endif
-
- /*
- * These flags, and the macros below them,
- * make up a do-it-yourself set of "ctype" macros that
- * understand the DEC multinational set, and let me ask
- * a slightly different set of questions.
- */
- #define _W 0x01 /* Word. */
- #define _U 0x02 /* Upper case letter. */
- #define _L 0x04 /* Lower case letter. */
- #define _C 0x08 /* Control. */
- #define _P 0x10 /* end of sentence punctuation */
-
- #define ISWORD(c) ((cinfo[(c)]&_W)!=0)
- #define ISCTRL(c) ((cinfo[(c)]&_C)!=0)
- #define ISUPPER(c) ((cinfo[(c)]&_U)!=0)
- #define ISLOWER(c) ((cinfo[(c)]&_L)!=0)
- #define ISEOSP(c) ((cinfo[(c)]&_P)!=0)
- #define TOUPPER(c) ((c)-0x20)
- #define TOLOWER(c) ((c)+0x20)
-
- /*
- * generally useful thing for chars
- */
- #define CCHR(x) ((x)-'@')
-
- /*
- * All repeated structures are kept as linked lists of structures.
- * All of these start with a LIST structure (except lines, which
- * have their own abstraction). This will allow for
- * later conversion to generic list manipulation routines should
- * I decide to do that. it does mean that there are four extra
- * bytes per window. I feel that this is an acceptable price,
- * considering that there are usually only one or two windows.
- */
- typedef struct LIST {
- union {
- struct SYMBOL *l_sp;
- struct WINDOW *l_wp;
- struct BUFFER *l_bp;
- struct LIST *l_nxt;
- } l_p;
- char *l_name;
- } LIST;
- /*
- * Usual hack - to keep from uglifying the code with lotsa
- * references through the union, we #define something for it.
- */
- #define l_next l_p.l_nxt
-
- /*
- * The symbol table links editing functions
- * to names. Entries in the key map point at the symbol
- * table entry.
- */
- typedef struct SYMBOL {
- LIST s_list; /* List chain. */
- int (*s_funcp)(); /* Function. */
- #ifdef HASH
- short s_flags; /* Flags for this symbol */
- #endif
- } SYMBOL;
- #define s_symp s_list.l_p.l_sp
- #define s_name s_list.l_name
- #ifdef HASH
- #define SFEND 0x001 /* End of has list */
- #endif
-
- /*
- * There is a window structure allocated for
- * every active display window. The windows are kept in a
- * big list, in top to bottom screen order, with the listhead at
- * "wheadp". Each window contains its own values of dot and mark.
- * The flag field contains some bits that are set by commands
- * to guide redisplay; although this is a bit of a compromise in
- * terms of decoupling, the full blown redisplay is just too
- * expensive to run for every input character.
- */
- typedef struct WINDOW {
- LIST w_list; /* List header */
- struct BUFFER *w_bufp; /* Buffer displayed in window */
- struct LINE *w_linep; /* Top line in the window */
- struct LINE *w_dotp; /* Line containing "." */
- struct LINE *w_markp; /* Line containing "mark" */
- short w_doto; /* Byte offset for "." */
- short w_marko; /* Byte offset for "mark" */
- char w_toprow; /* Origin 0 top row of window */
- char w_ntrows; /* # of rows of text in window */
- char w_force; /* If NZ, forcing row. */
- char w_flag; /* Flags. */
- } WINDOW;
- #define w_wndp w_list.l_p.l_wp
- #define w_name w_list.l_name
-
- /*
- * Window flags are set by command processors to
- * tell the display system what has happened to the buffer
- * mapped by the window. Setting "WFHARD" is always a safe thing
- * to do, but it may do more work than is necessary. Always try
- * to set the simplest action that achieves the required update.
- * Because commands set bits in the "w_flag", update will see
- * all change flags, and do the most general one.
- */
- #define WFFORCE 0x01 /* Force reframe. */
- #define WFMOVE 0x02 /* Movement from line to line. */
- #define WFEDIT 0x04 /* Editing within a line. */
- #define WFHARD 0x08 /* Better to a full display. */
- #define WFMODE 0x10 /* Update mode line. */
-
- /*
- * Text is kept in buffers. A buffer header, described
- * below, exists for every buffer in the system. The buffers are
- * kept in a big list, so that commands that search for a buffer by
- * name can find the buffer header. There is a safe store for the
- * dot and mark in the header, but this is only valid if the buffer
- * is not being displayed (that is, if "b_nwnd" is 0). The text for
- * the buffer is kept in a circularly linked list of lines, with
- * a pointer to the header line in "b_linep".
- */
- typedef struct BUFFER {
- LIST b_list; /* buffer list pointer */
- struct BUFFER *b_altb; /* Link to alternate buffer */
- struct LINE *b_dotp; /* Link to "." LINE structure */
- struct LINE *b_markp; /* The same as the above two, */
- struct LINE *b_linep; /* Link to the header LINE */
- short b_doto; /* Offset of "." in above LINE */
- short b_marko; /* but for the "mark" */
- char b_nwnd; /* Count of windows on buffer */
- char b_flag; /* Flags */
- char b_fname[NFILEN]; /* File name */
- } BUFFER;
- #define b_bufp b_list.l_p.l_bp
- #define b_bname b_list.l_name
-
- #define BFCHG 0x01 /* Changed. */
- #define BFBAK 0x02 /* Need to make a backup. */
-
- /*
- * This structure holds the starting position
- * (as a line/offset pair) and the number of characters in a
- * region of a buffer. This makes passing the specification
- * of a region around a little bit easier.
- */
- typedef struct {
- struct LINE *r_linep; /* Origin LINE address. */
- short r_offset; /* Origin LINE offset. */
- RSIZE r_size; /* Length in characters. */
- } REGION;
-
- /*
- * All text is kept in circularly linked
- * lists of "LINE" structures. These begin at the
- * header line (which is the blank line beyond the
- * end of the buffer). This line is pointed to by
- * the "BUFFER". Each line contains a the number of
- * bytes in the line (the "used" size), the size
- * of the text array, and the text. The end of line
- * is not stored as a byte; it's implied. Future
- * additions will include update hints, and a
- * list of marks into the line.
- */
- typedef struct LINE {
- struct LINE *l_fp; /* Link to the next line */
- struct LINE *l_bp; /* Link to the previous line */
- short l_size; /* Allocated size */
- short l_used; /* Used size */
- #ifdef PCC
- char l_text[1]; /* A bunch of characters. */
- #else
- char l_text[]; /* A bunch of characters. */
- #endif
- } LINE;
-
- /*
- * The rationale behind these macros is that you
- * could (with some editing, like changing the type of a line
- * link from a "LINE *" to a "REFLINE", and fixing the commands
- * like file reading that break the rules) change the actual
- * storage representation of lines to use something fancy on
- * machines with small address spaces.
- */
- #define lforw(lp) ((lp)->l_fp)
- #define lback(lp) ((lp)->l_bp)
- #define lgetc(lp, n) ((lp)->l_text[(n)]&0xFF)
- #define lputc(lp, n, c) ((lp)->l_text[(n)]=(c))
- #define llength(lp) ((lp)->l_used)
- #define ltext(lp) ((lp)->l_text)
-
- /*
- * Externals.
- */
- extern int thisflag;
- extern int lastflag;
- extern int curgoal;
- extern int epresf;
- extern int sgarbf;
- extern int mode;
- extern WINDOW *curwp;
- extern BUFFER *curbp;
- extern WINDOW *wheadp;
- extern BUFFER *bheadp;
- extern KEY kbdm[];
- extern KEY *kbdmip;
- extern KEY *kbdmop;
- extern KEY getkey();
- extern char pat[];
- extern SYMBOL *symbol[];
- extern SYMBOL *binding[];
- extern BUFFER *bfind();
- extern WINDOW *popbuf();
- extern WINDOW *wpopup();
- extern LINE *lalloc();
- extern int nrow;
- extern int ncol;
- extern char *version;
- extern int ttrow;
- extern int ttcol;
- extern int tceeol;
- extern int tcinsl;
- extern int tcdell;
- extern char cinfo[];
- extern char *keystrings[];
- extern SYMBOL *symlookup();
- VOID update();
- VOID keyname();
- /*
- * Standard I/O.
- */
- extern char *strcpy();
- extern char *strcat();
- extern char *malloc();
- \Rogue\Monster\
- else
- echo "will not over write ./def.h"
- fi
- if `test ! -s ./sysdef.h`
- then
- echo "writing ./sysdef.h"
- cat > ./sysdef.h << '\Rogue\Monster\'
- /*
- * Name: MicroEMACS
- * Ultrix-32 system header file same for System V.
- * Version: 29
- * Last edit: 05-Feb-86
- * By: rex::conroy
- * decvax!decwrl!dec-rhea!dec-rex!conroy
- */
- #define PCC 1 /* "[]" gets an error. */
- #define KBLOCK 8192 /* Kill grow. */
- #define GOOD 0 /* Good exit status. */
-
- typedef int RSIZE; /* Type for file/region sizes */
- typedef short KEY; /* Type for internal keystrokes */
-
- /*
- * Macros used by the buffer name making code.
- * Start at the end of the file name, scan to the left
- * until BDC1 (or BDC2, if defined) is reached. The buffer
- * name starts just to the right of that location, and
- * stops at end of string (or at the next BDC3 character,
- * if defined). BDC2 and BDC3 are mainly for VMS.
- */
- #define BDC1 '/' /* Buffer names. */
- \Rogue\Monster\
- else
- echo "will not over write ./sysdef.h"
- fi
- if `test ! -s ./ttydef.h`
- then
- echo "writing ./ttydef.h"
- cat > ./ttydef.h << '\Rogue\Monster\'
- /*
- * Termcap terminal file, nothing special, just make it big
- * enough for windowing systems.
- */
-
- #define GOSLING /* Compile in fancy display. */
- /* #define MEMMAP */ /* Not memory mapped video. */
-
- #define NROW 66 /* Rows. */
- #define NCOL 132 /* Columns. */
- /* #define MOVE_STANDOUT /* don't move in standout mode */
- #define STANDOUT_GLITCH /* possible standout glitch */
- #define TERMCAP /* for possible use in ttyio.c */
-
- /*
- * Termcap function keys. The last 10 keys correspond to the
- * non-standard termcap entries K0-K9 (instead of k0-k9).
- */
- #ifdef XKEYS
- /*
- #define KFIRST K01
- #define KLAST K1A
- */
- #define KHOME K01
- #define KDOWN K02
- #define KUP K03
- #define KLEFT K04
- #define KRIGHT K05
- #define KF0 K06
- #define KF1 K07
- #define KF2 K08
- #define KF3 K09
- #define KF4 K0A
- #define KF5 K0B
- #define KF6 K0C
- #define KF7 K0D
- #define KF8 K0E
- #define KF9 K0F
- #define KF10 K10
- #define KF11 K11
- #define KF12 K12
- #define KF13 K13
- #define KF14 K14
- #define KF15 K15
- #define KF16 K16
- #define KF17 K17
- #define KF18 K18
- #define KF19 K19
- #define KF20 K1A
-
- #define NFKEYS 20 /* # of function keys (k0-k9, K0-K9) */
- #endif
- \Rogue\Monster\
- else
- echo "will not over write ./ttydef.h"
- fi
- if `test ! -s ./basic.c`
- then
- echo "writing ./basic.c"
- cat > ./basic.c << '\Rogue\Monster\'
- /*
- * Basic cursor motion commands.
- *
- * The routines in this file are the basic
- * command functions for moving the cursor around on
- * the screen, setting mark, and swapping dot with
- * mark. Only moves between lines, which might make the
- * current buffer framing bad, are hard.
- */
- #include "def.h"
-
- VOID setgoal();
-
- /*
- * Go to beginning of line.
- */
- /*ARGSUSED*/
- gotobol(f, n, k)
- {
- curwp->w_doto = 0;
- return (TRUE);
- }
-
- /*
- * Move cursor backwards. Do the
- * right thing if the count is less than
- * 0. Error if you try to move back from
- * the beginning of the buffer.
- */
- /*ARGSUSED*/
- backchar(f, n, k) register int n;
- {
- register LINE *lp;
-
- if (n < 0)
- return (forwchar(f, -n, k));
- while (n--)
- {
- if (curwp->w_doto == 0)
- {
- if ((lp=lback(curwp->w_dotp)) == curbp->b_linep)
- {
- if (k != KRANDOM)
- ewprintf("Beginning of buffer");
- return (FALSE);
- }
- curwp->w_dotp = lp;
- curwp->w_doto = llength(lp);
- curwp->w_flag |= WFMOVE;
- }
- else
- curwp->w_doto--;
- }
- return (TRUE);
- }
-
- /*
- * Go to end of line.
- */
- /*ARGSUSED*/
- gotoeol(f, n, k)
- {
- curwp->w_doto = llength(curwp->w_dotp);
- return (TRUE);
- }
-
- /*
- * Move cursor forwards. Do the
- * right thing if the count is less than
- * 0. Error if you try to move forward
- * from the end of the buffer.
- */
- /*ARGSUSED*/
- forwchar(f, n, k) register int n;
- {
- if (n < 0)
- return (backchar(f, -n, k));
- while (n--)
- {
- if (curwp->w_doto == llength(curwp->w_dotp))
- {
- if (curwp->w_dotp == curbp->b_linep)
- {
- if (k != KRANDOM)
- ewprintf("End of buffer");
- return (FALSE);
- }
- curwp->w_dotp = lforw(curwp->w_dotp);
- curwp->w_doto = 0;
- curwp->w_flag |= WFMOVE;
- }
- else
- curwp->w_doto++;
- }
- return (TRUE);
- }
-
- /*
- * Go to the beginning of the
- * buffer. Setting WFHARD is conservative,
- * but almost always the case.
- */
- gotobob(f, n, k)
- {
- (VOID) setmark(f, n, k) ;
- curwp->w_dotp = lforw(curbp->b_linep);
- curwp->w_doto = 0;
- curwp->w_flag |= WFHARD;
- return (TRUE);
- }
-
- /*
- * Go to the end of the buffer.
- * Setting WFHARD is conservative, but
- * almost always the case.
- */
- gotoeob(f, n, k)
- {
- (VOID) setmark(f, n, k) ;
- curwp->w_dotp = curbp->b_linep;
- curwp->w_doto = 0;
- curwp->w_flag |= WFHARD;
- return (TRUE);
- }
-
- /*
- * Move forward by full lines.
- * If the number of lines to move is less
- * than zero, call the backward line function to
- * actually do it. The last command controls how
- * the goal column is set.
- */
- /*ARGSUSED*/
- forwline(f, n, k)
- {
- register LINE *dlp;
-
- if (n < 0)
- return (backline(f, -n, KRANDOM));
- if ((lastflag&CFCPCN) == 0) /* Fix goal. */
- setgoal();
- thisflag |= CFCPCN;
- dlp = curwp->w_dotp;
- while (n-- && dlp!=curbp->b_linep)
- dlp = lforw(dlp);
- curwp->w_dotp = dlp;
- curwp->w_doto = getgoal(dlp);
- curwp->w_flag |= WFMOVE;
- return (TRUE);
- }
-
- /*
- * This function is like "forwline", but
- * goes backwards. The scheme is exactly the same.
- * Check for arguments that are less than zero and
- * call your alternate. Figure out the new line and
- * call "movedot" to perform the motion.
- */
- /*ARGSUSED*/
- backline(f, n, k)
- {
- register LINE *dlp;
-
- if (n < 0)
- return (forwline(f, -n, KRANDOM));
- if ((lastflag&CFCPCN) == 0) /* Fix goal. */
- setgoal();
- thisflag |= CFCPCN;
- dlp = curwp->w_dotp;
- while (n-- && lback(dlp)!=curbp->b_linep)
- dlp = lback(dlp);
- curwp->w_dotp = dlp;
- curwp->w_doto = getgoal(dlp);
- curwp->w_flag |= WFMOVE;
- return (TRUE);
- }
-
- /*
- * Set the current goal column,
- * which is saved in the external variable "curgoal",
- * to the current cursor column. The column is never off
- * the edge of the screen; it's more like display then
- * show position.
- */
- VOID
- setgoal()
- {
-
- curgoal = getcolpos() - 1; /* Get the position. */
- if (curgoal >= ncol) /* Chop to tty width. */
- curgoal = ncol-1;
- }
-
- /*
- * This routine looks at a line (pointed
- * to by the LINE pointer "dlp") and the current
- * vertical motion goal column (set by the "setgoal"
- * routine above) and returns the best offset to use
- * when a vertical motion is made into the line.
- */
- getgoal(dlp) register LINE *dlp;
- {
- register int c;
- register int col;
- register int newcol;
- register int dbo;
-
- col = 0;
- dbo = 0;
- while (dbo != llength(dlp))
- {
- c = lgetc(dlp, dbo);
- newcol = col;
- if (
- #ifdef NOTAB
- !(mode&MNOTAB) &&
- #endif
- c == '\t')
- newcol |= 0x07;
- else if (ISCTRL(c) != FALSE)
- ++newcol;
- ++newcol;
- if (newcol > curgoal)
- break;
- col = newcol;
- ++dbo;
- }
- return (dbo);
- }
-
- #ifndef TINY
- /*
- * Scroll forward by a specified number
- * of lines, or by a full page if no argument.
- * The "2" is the window overlap (this is the default
- * value from ITS EMACS). Because the top line in
- * the window is zapped, we have to do a hard
- * update and get it back.
- */
- /*ARGSUSED*/
- forwpage(f, n, k) register int n;
- {
- register LINE *lp;
-
- if (f == FALSE)
- {
- n = curwp->w_ntrows - 2; /* Default scroll. */
- if (n <= 0) /* Forget the overlap */
- n = 1; /* if tiny window. */
- }
- else if (n < 0)
- return (backpage(f, -n, KRANDOM));
- #ifdef CVMVAS
- else /* Convert from pages */
- n *= curwp->w_ntrows; /* to lines. */
- #endif
- lp = curwp->w_linep;
- while (n-- && lp!=curbp->b_linep)
- lp = lforw(lp);
- curwp->w_linep = lp;
- curwp->w_dotp = lp;
- curwp->w_doto = 0;
- curwp->w_flag |= WFHARD;
- return (TRUE);
- }
-
- /*
- * This command is like "forwpage",
- * but it goes backwards. The "2", like above,
- * is the overlap between the two windows. The
- * value is from the ITS EMACS manual. The
- * hard update is done because the top line in
- * the window is zapped.
- */
- /*ARGSUSED*/
- backpage(f, n, k) register int n;
- {
- register LINE *lp;
-
- if (f == FALSE)
- {
- n = curwp->w_ntrows - 2; /* Default scroll. */
- if (n <= 0) /* Don't blow up if the */
- n = 1; /* window is tiny. */
- }
- else if (n < 0)
- return (forwpage(f, -n, KRANDOM));
- #ifdef CVMVAS
- else /* Convert from pages */
- n *= curwp->w_ntrows; /* to lines. */
- #endif
- lp = curwp->w_linep;
- while (n-- && lback(lp)!=curbp->b_linep)
- lp = lback(lp);
- curwp->w_linep = lp;
- curwp->w_dotp = lp;
- curwp->w_doto = 0;
- curwp->w_flag |= WFHARD;
- return (TRUE);
- }
-
- #endif
-
- /*
- * Internal set mark routine, used by other functions (daveb).
- */
- VOID
- isetmark()
- {
- curwp->w_markp = curwp->w_dotp;
- curwp->w_marko = curwp->w_doto;
- }
-
- /*
- * Set the mark in the current window
- * to the value of dot. A message is written to
- * the echo line unless we are running in a keyboard
- * macro, when it would be silly.
- */
- /*ARGSUSED*/
- setmark(f, n, k)
- {
- isetmark();
- if (kbdmop == NULL)
- ewprintf("Mark set");
- return (TRUE);
- }
-
- /*
- * Swap the values of "dot" and "mark" in
- * the current window. This is pretty easy, because
- * all of the hard work gets done by the standard routine
- * that moves the mark about. The only possible
- * error is "no mark".
- */
-
- #ifndef TINY
- /*ARGSUSED*/
- swapmark(f, n, k)
- {
- register LINE *odotp;
- register int odoto;
-
- if (curwp->w_markp == NULL)
- {
- ewprintf("No mark in this window");
- return (FALSE);
- }
- odotp = curwp->w_dotp;
- odoto = curwp->w_doto;
- curwp->w_dotp = curwp->w_markp;
- curwp->w_doto = curwp->w_marko;
- curwp->w_markp = odotp;
- curwp->w_marko = odoto;
- curwp->w_flag |= WFMOVE;
- return (TRUE);
- }
-
- /*
- * Go to a specific line, mostly for
- * looking up errors in C programs, which give the
- * error a line number. If an argument is present, then
- * it is the line number, else prompt for a line number
- * to use.
- */
- /*ARGSUSED*/
- gotoline(f, n, k) register int n;
- {
- register LINE *clp;
- register int s;
- char buf[32];
-
- if (f == FALSE)
- {
- if ((s=ereply("Goto line: ", buf, sizeof(buf))) != TRUE)
- return (s);
- n = atoi(buf);
- }
-
- clp = lforw(curbp->b_linep); /* "clp" is first line */
- while (n > 1)
- {
- if (lforw(clp) == curbp->b_linep) break;
- clp = lforw(clp);
- --n;
- }
- curwp->w_dotp = clp;
- curwp->w_doto = 0;
- curwp->w_flag |= WFMOVE;
- return (TRUE);
- }
- #endif
- \Rogue\Monster\
- else
- echo "will not over write ./basic.c"
- fi
- if `test ! -s ./buffer.c`
- then
- echo "writing ./buffer.c"
- cat > ./buffer.c << '\Rogue\Monster\'
- /*
- * Buffer handling.
- */
- #include "def.h"
-
- static itor();
-
- #ifndef TINY
- /*
- * Attach a buffer to a window. The
- * values of dot and mark come from the buffer
- * if the use count is 0. Otherwise, they come
- * from some other window.
- */
- /*ARGSUSED*/
- usebuffer(f, n, k)
- {
- register BUFFER *bp;
- register int s;
- char bufn[NBUFN];
-
- /* Get buffer to use from user */
- if (curbp->b_altb != NULL)
- s=eread("Switch to buffer: (default %s) ", bufn, NBUFN,
- EFNEW|EFBUF,
- #ifdef VARARGS
- curbp->b_altb->b_bname
- #else
- &(curbp->b_altb->b_bname), (char *) NULL
- #endif
- ) ;
- else
- s=eread("Switch to buffer: ", bufn, NBUFN, EFNEW|EFBUF
- #ifndef VARARGS
- ,(char *) NULL
- #endif
- );
- if (s == ABORT)
- return (s);
- if (s == FALSE && curbp->b_altb != NULL)
- bp = curbp->b_altb ;
- else if ((bp=bfind(bufn, TRUE)) == NULL)
- return (FALSE);
-
- /* and put it in current window */
- curbp = bp;
- return showbuffer(bp, curwp, WFFORCE|WFHARD);
- }
-
- /*
- * pop to buffer asked for by the user.
- */
- /*ARGSUSED*/
- poptobuffer(f, n, k)
- {
- register BUFFER *bp;
- register WINDOW *wp;
- register int s;
- char bufn[NBUFN];
- WINDOW *popbuf();
-
- /* Get buffer to use from user */
- if (curbp->b_altb != NULL)
- s=eread("Switch to buffer in other window: (default %s) ",
- bufn, NBUFN, EFNEW|EFBUF,
- #ifdef VARARGS
- curbp->b_altb->b_bname
- #else
- &(curbp->b_altb->b_bname) ,(char *) NULL
- #endif
- ) ;
- else
- s=eread("Switch to buffer in other window: ", bufn, NBUFN,
- EFNEW|EFBUF
- #ifndef VARARGS
- , (char *) NULL
- #endif
- ) ;
- if (s == ABORT)
- return (s);
- if (s == FALSE && curbp->b_altb != NULL)
- bp = curbp->b_altb ;
- else if ((bp=bfind(bufn, TRUE)) == NULL)
- return (FALSE);
-
- /* and put it in a new window */
- if ((wp = popbuf(bp)) == NULL)
- return FALSE;
- curbp = bp;
- curwp = wp;
- return TRUE;
- }
-
- /*
- * Dispose of a buffer, by name.
- * Ask for the name. Look it up (don't get too
- * upset if it isn't there at all!). Clear the buffer (ask
- * if the buffer has been changed). Then free the header
- * line and the buffer header. Bound to "C-X K".
- */
- /*ARGSUSED*/
- killbuffer(f, n, k)
- {
- register BUFFER *bp;
- register BUFFER *bp1;
- register BUFFER *bp2;
- WINDOW *wp;
- register int s;
- char bufn[NBUFN];
-
- if ((s=eread("Kill buffer: (default %s) ", bufn, NBUFN, EFNEW|EFBUF,
- #ifdef VARARGS
- curbp->b_bname
- #else
- &(curbp->b_bname)
- #endif
- )) == ABORT) return (s);
- else if (s == FALSE)
- bp = curbp ;
- else if ((bp=bfind(bufn, FALSE)) == NULL)
- return FALSE;
-
- if (bp->b_nwnd != 0)
- {
- if ((bp1 = bp->b_altb) == NULL) return FALSE;
- if (bclear(bp) != TRUE) return TRUE;
- for (wp = wheadp; bp->b_nwnd > 0; wp = wp->w_wndp)
- {
- /* Special case - could use showbuf, but don't */
- if (wp->w_bufp == bp)
- {
- --bp->b_nwnd;
- ++bp1->b_nwnd;
- wp->w_bufp = bp1 ;
- wp->w_dotp = bp1->b_dotp;
- wp->w_doto = bp1->b_doto;
- wp->w_markp = bp1->b_markp;
- wp->w_marko = bp1->b_marko;
- wp->w_linep = bp1->b_linep;
- wp->w_flag |= WFMODE|WFFORCE|WFHARD;
- }
- }
- }
- else if (bclear(bp) != TRUE)
- return TRUE;
- if (bp == curbp)
- curbp = bp->b_altb;
- free((char *) bp->b_linep); /* Release header line. */
- bp1 = NULL; /* Find the header. */
- bp2 = bheadp;
- while (bp2 != bp)
- {
- if (bp2->b_altb == bp)
- bp2->b_altb = (bp->b_altb == bp2) ? NULL : bp->b_altb;
- bp1 = bp2;
- bp2 = bp2->b_bufp;
- }
- bp2 = bp2->b_bufp; /* Next one in chain. */
- if (bp1 == NULL) /* Unlink it. */
- bheadp = bp2;
- else
- bp1->b_bufp = bp2;
- while (bp2 != NULL)
- { /* Finish with altb's */
- if (bp2->b_altb == bp)
- bp2->b_altb = (bp->b_altb == bp2) ? NULL : bp->b_altb;
- bp2 = bp2->b_bufp;
- }
- free(bp->b_bname); /* Release name block */
- free((char *) bp); /* Release buffer block */
- return (TRUE);
- }
- #endif
-
- /*
- * Save some buffers - just call anycb with the arg flag.
- */
- /*ARGSUSED*/
- savebuffers(f, n, k)
- {
- if (anycb(f) == ABORT) return ABORT;
- return TRUE;
- }
-
- #ifndef TINY
- /*
- * Display the buffer list. This is done
- * in two parts. The "makelist" routine figures out
- * the text, and puts it in a buffer. "popbuf"
- * then pops the data onto the screen. Bound to
- * "C-X C-B".
- */
- /*ARGSUSED*/
- listbuffers(f, n, k)
- {
- register BUFFER *bp;
- register WINDOW *wp;
- BUFFER *makelist();
- WINDOW *popbuf();
-
- if ((bp=makelist()) == NULL
- #ifndef TINY
- || (wp=popbuf(bp)) == NULL
- #endif
- )
- return FALSE;
- wp->w_dotp = bp->b_dotp; /* fix up if window already on screen */
- wp->w_doto = bp->b_doto;
- return TRUE;
- }
-
- /*
- * This routine rebuilds the text for the
- * list buffers command. Return TRUE if
- * everything works. Return FALSE if there
- * is an error (if there is no memory).
- */
- BUFFER *
- makelist()
- {
- register char *cp1;
- register char *cp2;
- register int c;
- register BUFFER *bp;
- LINE *lp;
- register RSIZE nbytes;
- BUFFER *blp;
- char b[6+1];
- char line[128];
-
- if ((blp = bfind("*Buffer List*", TRUE)) == NULL) return NULL;
- if (bclear(blp) != TRUE) return NULL;
- blp->b_flag &= ~BFCHG; /* Blow away old. */
-
- (VOID) strcpy(line, " MR Buffer");
- cp1 = line + 10;
- while(cp1 < line + 4 + NBUFN + 1) *cp1++ = ' ';
- (VOID) strcpy(cp1, "Size File");
- if (addline(blp, line) == FALSE) return NULL;
- (VOID) strcpy(line, " -- ------");
- cp1 = line + 10;
- while(cp1 < line + 4 + NBUFN + 1) *cp1++ = ' ';
- (VOID) strcpy(cp1, "---- ----");
- if (addline(blp, line) == FALSE) return NULL;
- bp = bheadp; /* For all buffers */
- while (bp != NULL)
- {
- cp1 = &line[0]; /* Start at left edge */
- *cp1++ = (bp == curbp) ? '.' : ' ';
- *cp1++ = ((bp->b_flag&BFCHG) != 0) ? '*' : ' ';
- *cp1++ = ' '; /* Gap. */
- *cp1++ = ' ';
- cp2 = &bp->b_bname[0]; /* Buffer name */
- while ((c = *cp2++) != 0)
- *cp1++ = c;
- while (cp1 < &line[4+NBUFN+1])
- *cp1++ = ' ';
- nbytes = 0; /* Count bytes in buf. */
- if (bp != blp)
- {
- lp = lforw(bp->b_linep);
- while (lp != bp->b_linep)
- {
- nbytes += llength(lp)+1;
- lp = lforw(lp);
- }
- }
- (VOID) itor(b, 6, nbytes); /* 6 digit buffer size. */
- cp2 = &b[0];
- while ((c = *cp2++) != 0)
- *cp1++ = c;
- *cp1++ = ' '; /* Gap.. */
- cp2 = &bp->b_fname[0]; /* File name */
- if (*cp2 != 0)
- {
- while ((c = *cp2++) != 0)
- {
- if (cp1 < &line[128-1])
- *cp1++ = c;
- }
- }
- *cp1 = 0; /* Add to the buffer. */
- if (addline(blp, line) == FALSE)
- return NULL;
- bp = bp->b_bufp;
- }
- blp->b_dotp = lforw(blp->b_linep); /* put dot at beginning of buffer */
- blp->b_doto = 0;
- return blp; /* All done */
- }
-
- /*
- * Used above.
- */
- static itor(buf, width, num)
- register char buf[]; register int width; register RSIZE num;
- {
- register RSIZE r;
-
- if (num / 10 == 0)
- {
- buf[0] = (num % 10) + '0';
- for (r = 1; r < width; buf[r++] = ' ')
- ;
- buf[width] = '\0';
- return 1;
- }
- else
- {
- buf[r = itor(buf, width, num / (RSIZE)10)] =
- (num % (RSIZE)10) + '0';
- return r + 1;
- }
- /*NOTREACHED*/
- }
-
- /*
- * The argument "text" points to
- * a string. Append this line to the
- * buffer. Handcraft the EOL
- * on the end. Return TRUE if it worked and
- * FALSE if you ran out of room.
- */
- addline(bp, text) register BUFFER *bp; char *text;
- {
- register LINE *lp;
- register int i;
- register int ntext;
-
- ntext = strlen(text);
- if ((lp=lalloc((RSIZE) ntext)) == NULL)
- return (FALSE);
- for (i=0; i<ntext; ++i)
- lputc(lp, i, text[i]);
- bp->b_linep->l_bp->l_fp = lp; /* Hook onto the end */
- lp->l_bp = bp->b_linep->l_bp;
- bp->b_linep->l_bp = lp;
- lp->l_fp = bp->b_linep;
- if (bp->b_dotp == bp->b_linep) /* If "." is at the end */
- bp->b_dotp = lp; /* move it to new line */
- if (bp->b_markp == bp->b_linep) /* ditto for mark */
- bp->b_markp = lp;
- return (TRUE);
- }
- #endif
-
- /*
- * Look through the list of buffers, giving the user
- * a chance to save them. Return TRUE if there are
- * any changed buffers afterwards. Buffers that don't
- * have an associated file don't count. Return FALSE
- * if there are no changed buffers.
- */
- anycb(f)
- {
- register BUFFER *bp;
- register int s = FALSE, save = FALSE;
- char prompt[NFILEN + 11];
-
- for (bp = bheadp; bp != NULL; bp = bp->b_bufp)
- {
- if (*(bp->b_fname) != '\0'
- && (bp->b_flag&BFCHG) != 0)
- {
- (VOID) strcpy(prompt, "Save text before exiting?");
- if ((f == TRUE || (save = eyorn(prompt)) == TRUE)
- && writeout(bp, bp->b_fname) == TRUE)
- {
- bp->b_flag &= ~BFCHG;
- upmodes(bp);
- }
- else
- s = TRUE;
- if (save == ABORT)
- return (save);
- save = TRUE;
- }
- }
-
- return s;
- }
-
- /*
- * Search for a buffer, by name.
- * If not found, and the "cflag" is TRUE,
- * create a buffer and put it in the list of
- * all buffers. Return pointer to the BUFFER
- * block for the buffer.
- */
- BUFFER *
- bfind(bname, cflag) register char *bname;
- {
- register BUFFER *bp;
- char *malloc();
- register LINE *lp;
-
- bp = bheadp;
- while (bp != NULL)
- {
- if (strcmp(bname, bp->b_bname) == 0)
- return (bp);
- bp = bp->b_bufp;
- }
- if (cflag!=TRUE) return NULL;
- /*NOSTRICT*/
- if ((bp=(BUFFER *)malloc(sizeof(BUFFER))) == NULL)
- {
- ewprintf("Can't get %d bytes", sizeof(BUFFER));
- return NULL;
- }
- if ((bp->b_bname=malloc(strlen(bname)+1)) == NULL)
- {
- ewprintf("Can't get %d bytes", strlen(bname)+1);
- free((char *) bp);
- return NULL;
- }
- if ((lp=lalloc((RSIZE) 0)) == NULL)
- {
- free(bp->b_bname);
- free((char *) bp);
- return NULL;
- }
- bp->b_altb = bp->b_bufp = NULL;
- bp->b_dotp = lp;
- bp->b_doto = 0;
- bp->b_markp = NULL;
- bp->b_marko = 0;
- bp->b_flag = 0;
- bp->b_nwnd = 0;
- bp->b_linep = lp;
- (VOID) strcpy(bp->b_fname, "");
- (VOID) strcpy(bp->b_bname, bname);
- lp->l_fp = lp;
- lp->l_bp = lp;
- bp->b_bufp = bheadp;
- bheadp = bp;
- return (bp);
- }
-
- /*
- * This routine blows away all of the text
- * in a buffer. If the buffer is marked as changed
- * then we ask if it is ok to blow it away; this is
- * to save the user the grief of losing text. The
- * window chain is nearly always wrong if this gets
- * called; the caller must arrange for the updates
- * that are required. Return TRUE if everything
- * looks good.
- */
- bclear(bp) register BUFFER *bp;
- {
- register LINE *lp;
- register int s;
-
- if ((bp->b_flag&BFCHG) != 0 /* Changed. */
- && (s=eyesno("Text modified -- are you sure")) != TRUE)
- return (s);
- bp->b_flag &= ~BFCHG; /* Not changed */
- while ((lp=lforw(bp->b_linep)) != bp->b_linep)
- lfree(lp);
- bp->b_dotp = bp->b_linep; /* Fix "." */
- bp->b_doto = 0;
- bp->b_markp = NULL; /* Invalidate "mark" */
- bp->b_marko = 0;
- return (TRUE);
- }
-
- /*
- * Display the given buffer in the given window. Flags indicated
- * action on redisplay.
- */
- showbuffer(bp, wp, flags) register BUFFER *bp; register WINDOW *wp;
- {
- register BUFFER *obp;
- WINDOW *owp;
-
- if (wp->w_bufp == bp)
- { /* Easy case! */
- wp->w_flag |= flags;
- return TRUE ;
- }
-
- /* First, dettach the old buffer from the window */
- if ((bp->b_altb = obp = wp->w_bufp) != NULL)
- {
- if (--obp->b_nwnd == 0)
- {
- obp->b_dotp = wp->w_dotp;
- obp->b_doto = wp->w_doto;
- obp->b_markp = wp->w_markp;
- obp->b_marko = wp->w_marko;
- }
- }
-
- /* Now, attach the new buffer to the window */
- wp->w_bufp = bp;
-
- if (bp->b_nwnd++ == 0)
- { /* First use. */
- wp->w_dotp = bp->b_dotp;
- wp->w_doto = bp->b_doto;
- wp->w_markp = bp->b_markp;
- wp->w_marko = bp->b_marko;
- }
- else
- /* already on screen, steal values from other window */
- for (owp = wheadp; owp != NULL; owp = wp->w_wndp)
- if (wp->w_bufp == bp && owp != wp)
- {
- wp->w_dotp = owp->w_dotp;
- wp->w_doto = owp->w_doto;
- wp->w_markp = owp->w_markp;
- wp->w_marko = owp->w_marko;
- break;
- }
- wp->w_flag |= WFMODE|flags;
- return TRUE;
- }
-
- /*
- * Turn off the dirty bit on this buffer.
- */
- /*ARGSUSED*/
- notmodified(f, n, k)
- {
- register WINDOW *wp;
-
- curbp->b_flag &= ~BFCHG;
- wp = wheadp; /* Update mode lines. */
- while (wp != NULL)
- {
- if (wp->w_bufp == curbp)
- wp->w_flag |= WFMODE;
- wp = wp->w_wndp;
- }
-
- return (TRUE);
- }
- \Rogue\Monster\
- else
- echo "will not over write ./buffer.c"
- fi
- echo "Finished archive 4 of 5"
- exit
- --
- =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
- Mark A. Hargrove U.S. TeleCenters
- Voice: 408-496-1800 Santa Clara, CA
- uucp : {dual, hoptoad, hplabs, portal, ptsfa}!well!ustel
-