home *** CD-ROM | disk | FTP | other *** search
- From: ustel@well.UUCP (Mark Hargrove)
- Newsgroups: comp.sources.misc
- Subject: v02i050: Unify TEXT fields from ACCELL Part 1/5
- Message-ID: <7218@ncoast.UUCP>
- Date: 11 Feb 88 00:43:57 GMT
- Approved: allbery@ncoast.UUCP
-
- Comp.sources.misc: Volume 2, Issue 50
- Submitted-By: "Mark Hargrove" <ustel@well.UUCP>
- Archive-Name: accell-text/Part1
-
- [Sendlist gave me a size warning; this may get truncated. ++bsa]
-
- The following collection of stuff allows you to access
- and use UNIFY Text (and by extension, Binary) fields
- from within the Accell environment. Also included is
- a deliberately crippled version of micro-gnu emacs that
- has been mangled into presenting a very Accell-like
- "look and feel" to the user. On an NCR Tower, the resulting
- executable is only about 55K. For casual users, this
- has turned out to be a better editor than say, vi or
- ed :-) As with UNIFY, your choice of editors is
- available via the EDIT environment variable.
-
- The C-hooks which write the text out to the database
- HAVE been modified to work around the recently discovered
- (and rather gruesome) UNIFY bug which frequently led to
- corruption of file.dbv. Remember that using ENTER to
- edit a text field WILL STILL CAUSE CORRUPTION OF FILE.DBV.
-
- [If you don't know about this bug and you are using text
- fields from either C or via ENTER -- call Unify TS TODAY
- and get a description of the problem ]
-
- Bug reports would be appreciated.
-
- -Mark Hargrove
-
- #!/bin/sh
- # to extract, remove the header and type "sh filename"
- if `test ! -s ./region.c`
- then
- echo "writing ./region.c"
- cat > ./region.c << '\Rogue\Monster\'
- /*
- * Region based commands.
- * The routines in this file
- * deal with the region, that magic space
- * between "." and mark. Some functions are
- * commands. Some functions are just for
- * internal use.
- */
- #include "def.h"
-
- /*
- * Kill the region. Ask "getregion"
- * to figure out the bounds of the region.
- * Move "." to the start, and kill the characters.
- */
- /*ARGSUSED*/
- killregion(f, n, k)
- {
- register int s;
- REGION region;
-
- if ((s=getregion(®ion)) != TRUE)
- return (s);
- if ((lastflag&CFKILL) == 0) /* This is a kill type */
- kdelete(); /* command, so do magic */
- thisflag |= CFKILL; /* kill buffer stuff. */
- curwp->w_dotp = region.r_linep;
- curwp->w_doto = region.r_offset;
- return (ldelete(region.r_size, KFORW));
- }
-
-
- /*
- * This routine figures out the bound of the region
- * in the current window, and stores the results into the fields
- * of the REGION structure. Dot and mark are usually close together,
- * but I don't know the order, so I scan outward from dot, in both
- * directions, looking for mark. The size is kept in a long. At the
- * end, after the size is figured out, it is assigned to the size
- * field of the region structure. If this assignment loses any bits,
- * then we print an error. This is "type independent" overflow
- * checking. All of the callers of this routine should be ready to
- * get an ABORT status, because I might add a "if regions is big,
- * ask before clobberring" flag.
- */
- getregion(rp) register REGION *rp;
- {
- register LINE *flp;
- register LINE *blp;
- register long fsize; /* Long now. */
- register long bsize;
-
- if (curwp->w_markp == NULL)
- {
- ewprintf("No mark set in this window");
- return (FALSE);
- }
- if (curwp->w_dotp == curwp->w_markp)
- { /* "r_size" always ok. */
- rp->r_linep = curwp->w_dotp;
- if (curwp->w_doto < curwp->w_marko)
- {
- rp->r_offset = curwp->w_doto;
- rp->r_size = (RSIZE) (curwp->w_marko-curwp->w_doto);
- }
- else
- {
- rp->r_offset = curwp->w_marko;
- rp->r_size = (RSIZE) (curwp->w_doto-curwp->w_marko);
- }
- return (TRUE);
- }
- blp = curwp->w_dotp; /* Get region size. */
- flp = curwp->w_dotp;
- bsize = curwp->w_doto;
- fsize = llength(flp)-curwp->w_doto+1;
- while (flp!=curbp->b_linep || lback(blp)!=curbp->b_linep)
- {
- if (flp != curbp->b_linep)
- {
- flp = lforw(flp);
- if (flp == curwp->w_markp)
- {
- rp->r_linep = curwp->w_dotp;
- rp->r_offset = curwp->w_doto;
- return (setsize(rp,
- (RSIZE) (fsize+curwp->w_marko)));
- }
- fsize += llength(flp)+1;
- }
- if (lback(blp) != curbp->b_linep)
- {
- blp = lback(blp);
- bsize += llength(blp)+1;
- if (blp == curwp->w_markp)
- {
- rp->r_linep = blp;
- rp->r_offset = curwp->w_marko;
- return (setsize(rp,
- (RSIZE) (bsize-curwp->w_marko)));
- }
- }
- }
- ewprintf("Bug: lost mark"); /* Gak! */
- return (FALSE);
- }
-
- /*
- * Set size, and check for overflow.
- */
- setsize(rp, size)
- register REGION *rp;
- register RSIZE size;
- {
-
- rp->r_size = size;
- if (rp->r_size != size)
- {
- ewprintf("Region is too large");
- return (FALSE);
- }
- return (TRUE);
- }
-
- #ifdef PREFIXREGION
- /*
- * Implements one of my favorite keyboard macros; put a string at the
- * beginning of a number of lines in a buffer. The quote string is
- * settable by using set-prefix-string. Great for quoting mail, which
- * is the real reason I wrote it, but also has uses for creating bar
- * comments (like the one you're reading) in C code.
- */
-
- #define PREFIXLENGTH 40
- static char prefix_string[PREFIXLENGTH] = { '>', '\0' };
-
- /*
- * Prefix the region with whatever is in prefix_string.
- * Leaves dot at the beginning of the line after the end
- * of the region. If an argument is given, prompts for the
- * line prefix string.
- */
-
- /*ARGSUSED*/
- prefixregion(f, n, k)
- {
- register int s;
- register LINE *first, *last;
- register int nline;
- REGION region;
- char *prefix = prefix_string;
-
- if ((f == TRUE) && ((s = setprefix(FALSE, 1, KRANDOM)) != TRUE))
- return (s);
-
- /* get # of lines to affect */
- if ((s = getregion(®ion)) != TRUE)
- return (s);
- first = region.r_linep;
- last = (first == curwp->w_dotp) ? curwp->w_markp : curwp->w_dotp;
- for (nline = 1; first != last; nline++)
- first = lforw(first);
-
- /*move to beginning of region */
- curwp->w_dotp = region.r_linep;
- curwp->w_doto = region.r_offset;
-
- /* for each line, go to beginning and insert the prefix string */
- while (nline--)
- {
- gotobol();
- for (prefix = prefix_string; *prefix; prefix++)
- (VOID) linsert((RSIZE) 1, *prefix);
- forwline(FALSE, 1, KRANDOM);
- }
- gotobol();
- return (TRUE);
- }
-
- /*
- * Set prefix string.
- */
-
- /*ARGSUSED*/
- setprefix(f, n, k)
- {
- char buf[PREFIXLENGTH];
- register int s;
-
- if (prefix_string[0] == '\0')
- s = ereply("Prefix string: ",buf,sizeof buf);
- else
- s = ereply("Prefix string (default %s): ",
- buf,sizeof buf,prefix_string);
- if (s == TRUE)
- (VOID) strcpy(prefix_string, buf);
- if ((s == FALSE) && (prefix_string[0] != '\0')) /* CR -- use old one */
- s = TRUE;
- return (s);
- }
- #endif
- \Rogue\Monster\
- else
- echo "will not over write ./region.c"
- fi
- if `test ! -s ./search.c`
- then
- echo "writing ./search.c"
- cat > ./search.c << '\Rogue\Monster\'
- /*
- * Search commands.
- * The functions in this file implement the
- * search commands (both plain and incremental searches
- * are supported) and the query-replace command.
- *
- * The plain old search code is part of the original
- * MicroEMACS "distribution". The incremental search code,
- * and the query-replace code, is by Rich Ellison.
- */
- #include "def.h"
-
- #define SRCH_BEGIN (0) /* Search sub-codes. */
- #define SRCH_FORW (-1)
- #define SRCH_BACK (-2)
- #define SRCH_NOPR (-3)
- #define SRCH_ACCM (-4)
- #define SRCH_MARK (-5)
-
- typedef struct {
- int s_code;
- LINE *s_dotp;
- int s_doto;
- } SRCHCOM;
-
- static SRCHCOM cmds[NSRCH];
- static int cip;
-
- int srch_lastdir = SRCH_NOPR; /* Last search flags. */
-
- VOID is_cpush();
- VOID is_lpush();
- VOID is_pop();
- VOID is_prompt();
- VOID is_dspl();
-
- /*
- * Search forward.
- * Get a search string from the user, and search for it,
- * starting at ".". If found, "." gets moved to just after the
- * matched characters, and display does all the hard stuff.
- * If not found, it just prints a message.
- */
- /*ARGSUSED*/
- forwsearch(f, n, k)
- {
- register int s;
-
- if ((s=readpattern("Search")) != TRUE)
- return (s);
- if (forwsrch() == FALSE)
- {
- ewprintf("Search failed: \"%s\"", pat);
- return (FALSE);
- }
- srch_lastdir = SRCH_FORW;
- return (TRUE);
- }
-
- /*
- * Reverse search.
- * Get a search string from the user, and search, starting at "."
- * and proceeding toward the front of the buffer. If found "." is left
- * pointing at the first character of the pattern [the last character that
- * was matched].
- */
- /*ARGSUSED*/
- backsearch(f, n, k)
- {
- register int s;
-
- if ((s=readpattern("Search backward")) != TRUE)
- return (s);
- if (backsrch() == FALSE)
- {
- ewprintf("Search failed: \"%s\"", pat);
- return (FALSE);
- }
- srch_lastdir = SRCH_BACK;
- return (TRUE);
- }
-
- /*
- * Search again, using the same search string
- * and direction as the last search command. The direction
- * has been saved in "srch_lastdir", so you know which way
- * to go.
- */
- /*ARGSUSED*/
- searchagain(f, n, k)
- {
- if (srch_lastdir == SRCH_FORW)
- {
- if (forwsrch() == FALSE)
- {
- ewprintf("Search failed: \"%s\"", pat);
- return (FALSE);
- }
- return (TRUE);
- }
- if (srch_lastdir == SRCH_BACK)
- {
- if (backsrch() == FALSE)
- {
- ewprintf("Search failed: \"%s\"", pat);
- return (FALSE);
- }
- return (TRUE);
- }
- ewprintf("No last search");
- return (FALSE);
- }
-
-
- /*
- * This routine does the real work of a
- * forward search. The pattern is sitting in the external
- * variable "pat". If found, dot is updated, the window system
- * is notified of the change, and TRUE is returned. If the
- * string isn't found, FALSE is returned.
- */
- forwsrch()
- {
- register LINE *clp;
- register int cbo;
- register LINE *tlp;
- register int tbo;
- register char *pp;
- register int c;
-
- clp = curwp->w_dotp;
- cbo = curwp->w_doto;
- while (clp != curbp->b_linep)
- {
- if (cbo == llength(clp))
- {
- clp = lforw(clp);
- cbo = 0;
- c = SEOL;
- } else
- c = lgetc(clp, cbo++);
- if (eq(c, pat[0]) != FALSE)
- {
- tlp = clp;
- tbo = cbo;
- pp = &pat[1];
- while (*pp != 0)
- {
- if (tlp == curbp->b_linep)
- goto fail;
- if (tbo == llength(tlp))
- {
- tlp = lforw(tlp);
- if (tlp == curbp->b_linep)
- goto fail;
- tbo = 0;
- c = SEOL;
- } else
- c = lgetc(tlp, tbo++);
- if (eq(c, *pp++) == FALSE)
- goto fail;
- }
- curwp->w_dotp = tlp;
- curwp->w_doto = tbo;
- curwp->w_flag |= WFMOVE;
- return (TRUE);
- }
- fail: ;
- }
- return (FALSE);
- }
-
- /*
- * This routine does the real work of a
- * backward search. The pattern is sitting in the external
- * variable "pat". If found, dot is updated, the window system
- * is notified of the change, and TRUE is returned. If the
- * string isn't found, FALSE is returned.
- */
- backsrch()
- {
- register LINE *clp;
- register int cbo;
- register LINE *tlp;
- register int tbo;
- register int c;
- register char *epp;
- char *pp;
-
- for (epp = &pat[0]; epp[1] != 0; ++epp)
- ;
- clp = curwp->w_dotp;
- cbo = curwp->w_doto;
- for (;;)
- {
- if (cbo == 0)
- {
- clp = lback(clp);
- if (clp == curbp->b_linep)
- return (FALSE);
- cbo = llength(clp)+1;
- }
- if (--cbo == llength(clp))
- c = SEOL;
- else
- c = lgetc(clp,cbo);
- if (eq(c, *epp) != FALSE)
- {
- tlp = clp;
- tbo = cbo;
- pp = epp;
- while (pp != &pat[0])
- {
- if (tbo == 0)
- {
- tlp = lback(tlp);
- if (tlp == curbp->b_linep)
- goto fail;
- tbo = llength(tlp)+1;
- }
- if (--tbo == llength(tlp))
- c = SEOL;
- else
- c = lgetc(tlp,tbo);
- if (eq(c, *--pp) == FALSE)
- goto fail;
- }
- curwp->w_dotp = tlp;
- curwp->w_doto = tbo;
- curwp->w_flag |= WFMOVE;
- return (TRUE);
- }
- fail: ;
- }
- /* NOTREACHED*/
- }
-
- /*
- * Compare two characters.
- * The "bc" comes from the buffer.
- * It has its case folded out. The
- * "pc" is from the pattern.
- */
- eq(bc, pc)
- {
- register int ibc;
- register int ipc;
-
- ibc = bc & 0xFF;
- ipc = pc & 0xFF;
- if (ISLOWER(ibc) != FALSE)
- ibc = TOUPPER(ibc);
- if (ISLOWER(ipc) != FALSE)
- ipc = TOUPPER(ipc);
- if (ibc == ipc)
- return (TRUE);
- return (FALSE);
- }
-
- /*
- * Read a pattern.
- * Stash it in the external variable "pat". The "pat" is
- * not updated if the user types in an empty line. If the user typed
- * an empty line, and there is no old pattern, it is an error.
- * Display the old pattern, in the style of Jeff Lomicka. There is
- * some do-it-yourself control expansion.
- */
- readpattern(prompt) char *prompt;
- {
- register int s;
- char tpat[NPAT];
-
- if (tpat[0] == '\0') s = ereply("%s: ", tpat, NPAT, prompt);
- else s = ereply("%s: (default %s) ", tpat, NPAT, prompt, pat);
-
- if (s == TRUE) /* Specified */
- (VOID) strcpy(pat, tpat);
- else if (s==FALSE && pat[0]!=0) /* CR, but old one */
- s = TRUE;
- return (s);
- }
- \Rogue\Monster\
- else
- echo "will not over write ./search.c"
- fi
- if `test ! -s ./spawn.c`
- then
- echo "writing ./spawn.c"
- cat > ./spawn.c << '\Rogue\Monster\'
- /*
- * Name: MicroEMACS
- * Spawn CLI for System V.
- * Version: 0
- * Last edit: 17-Apr-86
- * By: gonzo!daveb
- * {sun, amdahl, mtxinu}!rtech!daveb
- *
- * Spawn for System V.
- */
- #include "def.h"
-
- #include <signal.h>
- #include <stdio.h>
-
- extern char *getenv();
-
- /*
- * Execute a single command using the shell. If no argument,
- * then print the file in the top (only) buffer, after making
- * sure that it has been flushed to disk.
- */
- /*ARGSUSED*/
- spawncmd( f, n, k)
- int f, n;
- char **k;
- {
- char cmdbuf[80];
- extern char *getenv();
- register int pid;
- register int wpid;
- int (*oqsig)();
- int (*oisig)();
- int status;
- int errp = FALSE;
-
- if (f == FALSE) /* no command provided */
- {
- char *printcmd;
- char *argv[32];
- char argbuf[128];
- char *ptr;
- int argc;
-
- (void)memset(argbuf, 0, 128);
- if ((printcmd = getenv("SPOOLER")) == NULL)
- printcmd = "lp -s";
- (void)strcpy( argbuf, printcmd);
- #ifdef DEBUG
- fprintf(stderr, "spooler='%s'\n", argbuf);
- #endif
- for (argc=0, ptr=argbuf; *ptr; )
- {
- while (*ptr && (*ptr == ' ' || *ptr == '\t'))
- {
- *ptr++ = '\0';
- }
- argv[argc++] = ptr;
- while (*ptr && *ptr != ' ' && *ptr != '\t')
- ++ptr;
- }
- if (argv[argc-1][0] == '\0')
- argv[argc-1] = NULL;
- argv[argc] = NULL;
- #ifdef DEBUG
- {
- int i;
- fprintf(stderr, "argc=%d,", argc);
- fprintf(stderr, " argv='%s'", argv[0]);
- for (i=1; i<=argc; ++i)
- fprintf(stderr, ",'%s'", argv[i]);
- fprintf(stderr, "\n");
- }
- #endif
- (void)strcpy( cmdbuf, wheadp->w_bufp->b_fname);
-
- ewprintf("Please Wait...");
- oqsig = signal(SIGQUIT, SIG_IGN);
- oisig = signal(SIGINT, SIG_IGN);
- if ((pid=fork()) == 0)
- {
- freopen( cmdbuf, "r", stdin);
- execvp( argv[0], argv);
- _exit(1); /* Should do better! */
- }
- else if (pid > 0)
- {
- while ((wpid=wait(&status))>=0 && wpid!=pid)
- ;
- }
- else
- errp = TRUE;
-
- signal(SIGQUIT, oqsig);
- signal(SIGINT, oisig);
- if(errp)
- ewprintf("Print failed (can't create process).");
- else if (status)
- ewprintf("spooler returned error status=%d", status);
- else
- ewprintf("Text Queued for print");
- }
- else
- {
- /*
- * Don't do nuthin currently
- */
- }
- return TRUE;
- }
-
- #ifdef MENU_INSERT
- /*
- * Menu Insert -- spawn a shell with the menu shell script
- */
- spawninsert( f, n, k)
- {
- extern char *strrchr(), *strcpy(), *strcat(), *tmpnam();
- register int pid;
- register int wpid;
- register int (*oqsig)();
- register int (*oisig)();
- int status;
- int errp = FALSE;
- char menup[80], *menuname = NULL;
- char tempfile[L_tmpnam];
-
- (void)strcpy( menup, getenv("DBBIN"));
- if (menup[strlen(menup)-1] != '/')
- (void)strcat( menup, "/");
- if ((menuname = getenv("EMENU")) == NULL)
- {
- menuname = "mgx-menu.sh";
- }
- (void)strcat(menup, menuname);
- menuname = strrchr( menup, '/' );
- menuname = menuname ? menuname++ : menup;
-
- strcpy (tempfile, tmpnam((char *)0));
- ttcolor(CTEXT);
- ttnowindow();
- ttmove(nrow-1, 0);
- if (epresf != FALSE)
- {
- tteeol();
- epresf = FALSE;
- }
- ttclose();
- sgarbf = TRUE; /* Force repaint. */
- oqsig = signal(SIGQUIT, SIG_IGN);
- oisig = signal(SIGINT, SIG_IGN);
- if ((pid=fork()) == 0)
- {
- execlp(menup, menuname, tempfile, NULL);
- _exit(1); /* Should do better! */
- }
- else if (pid > 0)
- {
- while ((wpid=wait(&status))>=0 && wpid!=pid)
- ;
- }
- else
- errp = TRUE;
-
- signal(SIGINT, oisig);
- ttopen();
- if(errp)
- ewprintf("Failed to create process");
- else
- {
- gotobol( FALSE, 0, 0);
- insertfile( tempfile, (char *)0);
- }
- unlink( tempfile);
- return ( errp | status );
- }
- #endif
- \Rogue\Monster\
- else
- echo "will not over write ./spawn.c"
- fi
- if `test ! -s ./symbol.c`
- then
- echo "writing ./symbol.c"
- cat > ./symbol.c << '\Rogue\Monster\'
- /*
- * Symbol tables, and keymap setup.
- * The terminal specific parts of building the
- * keymap has been moved to a better place.
- */
- #include "def.h"
-
- /*
- * Heavily modified routine for the TINY version of MicroGnuEmacs.
- */
-
- /*
- * Defined here so to collect the #ifdef MEYN config stuff in one file
- * If you set either MINDENT or MFILL, then you need to change the bindings
- * in this file to match: KCTRL|'M' -> newline-and-indent and KCTRL|'J' ->
- * insert-newline for MINDENT, and ' ' -> insert-with-wrap for MFILL.
- * MEYN is used for compile-time customization of the system for micros.
- */
-
- int mode = MFILL | MOVRSTK | MFLOW;
-
- /*
- * Defined by "main.c".
- */
- extern int ctrlg(); /* Abort out of things */
- extern int quit(); /* Quit */
-
- /*
- * Defined by "search.c".
- */
- extern int forwsearch(); /* Search forward */
- extern int backsearch(); /* Search backwards */
- extern int searchagain(); /* Repeat last search command */
-
- /*
- * Defined by "basic.c".
- */
- extern int gotobol(); /* Move to start of line */
- extern int backchar(); /* Move backward by characters */
- extern int gotoeol(); /* Move to end of line */
- extern int forwchar(); /* Move forward by characters */
- extern int gotobob(); /* Move to start of buffer */
- extern int gotoeob(); /* Move to end of buffer */
- extern int forwline(); /* Move forward by lines */
- extern int backline(); /* Move backward by lines */
- extern int setmark(); /* Set mark */
- /*
- * Defined by "buffer.c".
- */
- extern int savebuffers(); /* Save unmodified buffers */
- extern int notmodified(); /* Reset modification flag */
-
- #ifdef DIRLIST
- /*
- * Defined by "dirlist.c".
- */
- extern int dirlist(); /* Directory list. */
- #endif
-
- /*
- * Defined by "display.c"
- */
- extern int rotatmode(); /* rotate mode-line help */
-
- /*
- * Defined by "file.c".
- */
- extern int filevisit(); /* Get a file, read write */
- extern int filewrite(); /* Write a file */
- extern int filesave(); /* Save current file */
- extern int fileinsert(); /* Insert file into buffer */
- #ifdef BACKUP
- extern int makebkfile(); /* Control backups on saves */
- #endif
-
- /*
- * Defined by "random.c".
- */
- extern int selfinsert(); /* Insert character */
- extern int showcpos(); /* Show the cursor position */
- extern int openline(); /* Open up a blank line */
- extern int newline(); /* Insert CR-LF */
- extern int forwdel(); /* Forward delete */
- extern int backdel(); /* Backward delete in */
- extern int killline(); /* Kill forward */
- extern int bsmapmode(); /* set bsmap mode */
- extern int flowmode(); /* set flow mode */
- extern int fillmode(); /* set word-wrap mode */
- extern int insovrmode(); /* toggle insert overstrike mode */
- extern int yank(); /* Yank back from killbuffer. */
-
- /*
- * Defined by "region.c".
- */
- extern int killregion(); /* Kill region. */
- #ifdef PREFIXREGION
- extern int prefixregion(); /* Prefix all lines in region */
- extern int setprefix(); /* Set line prefix string */
- #endif
-
- /*
- * Defined by "window.c".
- */
- extern int reposition(); /* Reposition window */
- extern int refresh(); /* Refresh the screen */
-
- /*
- * Defined by "word.c".
- */
- extern int delfword(); /* Delete forward word. */
- extern int delbword(); /* Delete backward word. */
-
- /*
- * Defined by "extend.c".
- */
- extern int extend(); /* Extended commands. */
- extern int startover(); /* reread file, restart edit */
- extern int reallyquit(); /* kill emacs, don't save files */
- extern int deleteline(); /* delete line from anywhere */
- #ifdef STARTUP
- extern int evalexpr(); /* Extended commands (again) */
- extern int evalbuffer(); /* Evaluate current buffer */
- extern int evalfile(); /* Evaluate a file */
- #endif
-
- /*
- * defined by "paragraph.c" - the paragraph justification code.
- */
- extern int gotobop(); /* Move to start of paragraph. */
- extern int gotoeop(); /* Move to end of paragraph. */
- extern int fillpara(); /* Justify a paragraph. */
- extern int killpara(); /* Delete a paragraph. */
- extern int setfillcol(); /* Set fill column for justify. */
- extern int fillword(); /* Insert char with word wrap. */
-
- #ifdef MISLOG
- /*
- * defined by "newlog.c" - the mislog code.
- */
- extern int newlog(); /* newlog function for MISLOG */
- #endif
-
- typedef struct {
- KEY k_key; /* Key to bind. */
- int (*k_funcp)(); /* Function. */
- char *k_name; /* Function name string. */
- } KEYTAB;
-
- /*
- * Default key binding table. This contains
- * the function names, the symbol table name, and (possibly)
- * a key binding for the builtin functions. There are no
- * bindings for C-U or C-X. These are done with special
- * code, but should be done normally.
- */
- KEYTAB key[] = {
- KCTRL|'C', ctrlg, "keyboard-quit",
- KCTRL|'D', forwdel, "delete-char",
- KCTRL|'E', gotoeol, "end-of-line",
- KCTRL|'I', selfinsert, "self-insert-command",
- KCTRL|'G', ctrlg, "keyboard-quit",
- KCTRL|'M', newline, "insert-newline",
- KCTRL|'R', refresh, "redraw-display",
- KCTRL|'S', forwsearch, "search-forward",
- KCTLX|KCTRL|'Q',quit, "save-buffers-kill-emacs",
- KCTLX|KCTRL|'F',filevisit, "find-file",
- KMETA|'X', extend, "execute-extended-command",
- KCTRL|'B', backchar, "backward-char",
- KCTRL|'F', forwchar, "forward-char",
- KCTRL|'N', forwline, "next-line",
- KCTRL|'P', backline, "previous-line",
- KCTLX|'=', showcpos, "what-cursor-position",
- KCTLX|'I', fileinsert, "insert-file",
- KMETA|'M', setmark, "set-mark-command",
- KMETA|'C', killregion, "kill-region",
- KMETA|'P', yank, "yank",
- ' ', fillword, "insert-with-wrap",
- -1, backsearch, "search-backward",
- -1, gotobol, "beginning-of-line",
- -1, reposition, "recenter",
- -1, killline, "kill-line",
- -1, openline, "open-line",
- #ifdef DIRLIST
- -1, dirlist, "display-directory",
- #endif
- -1, filesave, "save-buffer",
- -1, filewrite, "write-file",
- -1, savebuffers, "save-some-buffers",
- -1, setfillcol, "set-fill-column",
- -1, gotoeob, "end-of-buffer",
- -1, gotobob, "beginning-of-buffer",
- -1, gotobop, "backward-paragraph",
- -1, gotoeop, "forward-paragraph",
- -1, fillpara, "fill-paragraph",
- -1, notmodified, "not-modified",
- #ifdef STARTUP
- -1, evalexpr, "eval-expression",
- -1, evalbuffer, "eval-current-buffer",
- -1, evalfile, "load",
- #endif
- -1, bsmapmode, "bsmap-mode",
- -1, flowmode, "flow-mode",
- -1, fillmode, "auto-fill-mode",
- -1, searchagain, "search-again",
- -1, killpara, "kill-paragraph",
- #ifdef PREFIXREGION
- -1, prefixregion, "prefix-region",
- -1, setprefix, "set-prefix-string",
- #endif
- #ifdef BACKUP
- -1, makebkfile, "make-backup-files",
- #endif
- /* new functions for TinyGnuEmacs */
- -1, insovrmode, "toggle-insert-overstrike",
- -1, startover, "restart-edit",
- -1, reallyquit, "kill-emacs",
- -1, deleteline, "delete-line",
- -1, rotatmode, "rotate-help",
- #ifdef MISLOG
- -1, newlog, "newlog",
- #endif
- };
-
- #define NKEY (sizeof(key) / sizeof(key[0]))
-
- /*
- * Just some definitions, to keep ANSI compilers happy.
- */
- VOID keymapinit();
- VOID keyadd();
- VOID keydup();
-
- /*
- * Symbol table lookup.
- * Return a pointer to the SYMBOL node, or NULL if
- * the symbol is not found.
- */
- SYMBOL *
- symlookup(cp) register char *cp;
- {
- register SYMBOL *sp;
-
- #ifdef HASH
- sp = symbol[symhash(cp)];
- #else
- sp = symbol[0];
- #endif
- while (sp != NULL)
- {
- if (strcmp(cp, sp->s_name) == 0)
- return (sp);
- #ifdef HASH
- if ((sp->s_flags&SFEND) != 0) break;
- #endif
- sp = sp->s_symp;
- }
- return (NULL);
- }
-
- #ifdef HASH
- /*
- * Take a string, and compute the symbol table
- * bucket number. This is done by adding all of the characters
- * together, and taking the sum mod NSHASH. The string probably
- * should not contain any GR characters; if it does the "*cp"
- * may get a nagative number on some machines, and the "%"
- * will return a negative number!
- */
- symhash(cp) register char *cp;
- {
- register int c;
- register int n;
-
- n = 0;
- while ((c = *cp++) != 0)
- n += c;
- return (n % NSHASH);
- }
- #endif
-
- /*
- * Build initial keymap. The funny keys
- * (commands, odd control characters) are mapped using
- * a big table and calls to "keyadd". The printing characters
- * are done with some do-it-yourself handwaving. The terminal
- * specific keymap initialization code is called at the
- * very end to finish up. All errors are fatal.
- */
- VOID
- keymapinit()
- {
- register SYMBOL *sp;
- register KEYTAB *kp;
- register int i;
-
- for (i=0; i<NKEYS; ++i)
- binding[i] = NULL;
- for (kp = &key[0]; kp < &key[NKEY]; ++kp)
- keyadd(kp->k_key, kp->k_funcp, kp->k_name);
- keydup((KEY) (KCTLX|KCTRL|'C'), "keyboard-quit");
- keydup((KEY) (KMETA|KCTRL|'C'), "keyboard-quit");
- keyadd((KEY) (KMETA|0x7F), delbword,
- "backward-kill-word");
- keyadd((KEY) 0x7F, backdel, "backward-delete-char");
- /*
- * Should be bound by "tab" already.
- */
- if ((sp=symlookup("self-insert-command")) == NULL)
- panic("no self-insert-command in keymapinit");
- if (binding[0x20] == NULL) /* 0x20 == ' ' may already be */
- binding[0x20] = sp; /* bound to insert-with-wrap */
- for (i=0x21; i<0x7F; ++i)
- {
- if (binding[i] != NULL)
- panic("nonull binding in keymapinit");
- binding[i] = sp;
- }
- ttykeymapinit();
- #ifdef HASH
- /* Link up the symbol table entries */
- for (sp = symbol[i = 0]; i < NSHASH-1; sp = sp->s_symp)
- if (sp->s_symp == NULL) sp->s_symp = symbol[++i];
- #endif
- }
-
- /*
- * Create a new builtin function "name"
- * with function "funcp". If the "new" is a real
- * key, bind it as a side effect. All errors
- * are fatal.
- */
- VOID
- keyadd(new, funcp, name) register KEY new; int (*funcp)(); char *name;
- {
- register SYMBOL *sp;
- #ifdef HASH
- register int hash;
- #endif
-
- if ((sp=(SYMBOL *)malloc(sizeof(SYMBOL))) == NULL)
- panic("No memory");
- #ifdef HASH
- hash = symhash(name);
- if (symbol[hash] == NULL) sp->s_flags |= SFEND;
- sp->s_symp = symbol[hash];
- symbol[hash] = sp;
- #else
- sp->s_symp = symbol[0];
- symbol[0] = sp;
- #endif
- sp->s_name = name;
- sp->s_funcp = funcp;
- if (new >= 0)
- { /* Bind this key. */
- if (binding[new] != NULL)
- {
- char buf[80];
- sprintf(buf,"rebinding old symbol: %s", name);
- panic(buf);
- }
- binding[new] = sp;
- }
- }
-
- /*
- * Bind key "new" to the existing
- * routine "name". If the name cannot be found,
- * or the key is already bound, abort.
- */
- VOID
- keydup(new, name) register KEY new; char *name;
- {
- register SYMBOL *sp;
-
- if (binding[new]!=NULL || (sp=symlookup(name))==NULL)
- {
- #ifdef KEYDUP_ERROR
- fprintf (stderr, "keydup: binding[%d] = %x",
- new, binding[new]);
- fprintf (stderr, " and symlookup(%s) == %x\n", name, sp);
- #endif
- panic("keydup");
- }
- binding[new] = sp;
- }
- \Rogue\Monster\
- else
- echo "will not over write ./symbol.c"
- fi
- if `test ! -s ./tty.c`
- then
- echo "writing ./tty.c"
- cat > ./tty.c << '\Rogue\Monster\'
- /*
- * Termcap/terminfo display driver
- *
- * Termcap is a terminal information database and routines to describe
- * terminals on most UNIX systems. Many other systems have adopted
- * this as a reasonable way to allow for widly varying and ever changing
- * varieties of terminal types. This should be used where practical.
- */
- /* Known problems:
- * tputs is always called with the number of lines affected set to
- * one. Therefore, padding may be insufficient on some sequences
- * dispite termcap being set up correctly.
- *
- * If you have a terminal with no clear to end of screen and
- * memory of lines below the ones visible on the screen, display
- * will be wrong in some cases. I doubt that any such terminal
- * was ever made, but I thought everyone with delete line would
- * have clear to end of screen too...
- *
- * Code for terminals without clear to end of screen and/or clear
- * to end of line has not been extensivly tested.
- *
- * Cost calculations are very rough. Costs of insert/delete line
- * may be far from the truth. This is accentuated by display.c
- * not knowing about multi-line insert/delete.
- *
- * Using scrolling region vs insert/delete line should probably
- * be based on cost rather than the assuption that scrolling
- * region operations look better.
- */
- #include "def.h"
-
- #define BEL 0x07 /* BEL character. */
- #define LF 0x0A /* Line feed. */
-
- extern int ttrow;
- extern int ttcol;
- extern int tttop;
- extern int ttbot;
- extern int tthue;
-
- int tceeol; /* Costs are set later */
- int tcinsl;
- int tcdell;
-
- static int insdel; /* Do we have both insert & delete line? */
-
- #ifdef NO_RESIZE
- static setttysize();
- #endif
-
- char *tgetstr();
- char *tgoto();
- int ttputc();
-
- #define TCAPSLEN 1024
-
- char tcapbuf[TCAPSLEN];
-
- /* PC, UP, and BC are used by termlib, so must be extern and have these
- * names unless you have a non-standard termlib.
- */
-
- int LI; /* standard # lines */
- char PC,
- *CM,
- *CE,
- *UP,
- *BC,
- *IM, /* insert mode */
- *IC, /* insert a single space */
- *EI, /* end insert mode */
- *DC,
- *AL, /* add line */
- *DL, /* del line */
- *pAL, /* parameterized add line */
- *pDL, /* parameterized delete line */
- *TI, /* term init -- start using cursor motion */
- *TE, /* term end --- end using cursor motion */
- *SO,
- *SE,
- *CD,
- *CS, /* set scroll region */
- *SR; /* back index (used with scroll region */
- #ifdef XKEYS
- char *K[NFKEYS], /* other function key codes */
- *L[NFKEYS], /* labels for other functions keys */
- *KS, *KE, /* enter keypad mode, exit keypad mode */
- *KH, *KU, *KD, *KL, *KR; /* home, arrow keys */
- #endif
- int SG; /* number of glitches, 0 for invisable, -1 for none */
- /* (yes virginia, there are terminals with invisible glitches) */
-
- /*
- * Initialize the terminal when the editor
- * gets started up.
- */
- static char tcbuf[1024];
-
- ttinit() {
- #ifndef __50SERIES
- char *getenv();
- char *tv_stype;
- #else
- fortran void gv$get();
- short code;
- static struct {short len; char data[15];} TERM
- = {15, '.'|0200, 'T'|0200, 'E'|0200, 'R'|0200, 'M'|0200,
- 'I'|0200, 'N'|0200, 'A'|0200, 'L'|0200, '_'|0200,
- 'T'|0200, 'Y'|0200, 'P'|0200, 'E'|0200, '$'|0200};
- struct {short len; char data[32];} termtype;
- # define tv_stype termtype.data
- #endif
- char *t, *p, *tgetstr();
- #ifdef XKEYS
- char kname[3], lname[3];
- int i;
- #endif
-
- #ifdef VAXC
- if ((tv_stype = trnlnm("TERM")) == NULL)
- {
- ttclose();
- panic("Environment variable TERM not defined!");
- }
- #else
- #ifndef __50SERIES
- if ((tv_stype = getenv("TERM")) == NULL)/* Don't want VAX C getenv() */
- {
- ttclose();
- panic("Environment variable TERM not defined!");
- }
- #else
- gv$get(TERM, termtype, 31, code);
- if (code)
- {
- ttclose();
- panic("Global variable .Terminal_Type$ not defined");
- }
- termtype.data[termtype.len] = '\0';
- t = tv_stype;
- while(*t) *t++ &= 0177;
- #endif
- #endif
- if((tgetent(tcbuf, tv_stype)) != 1)
- {
- (VOID) strcpy(tcbuf, "Unknown terminal type ");
- (VOID) strcat(tcbuf, tv_stype);
- ttclose();
- panic(tcbuf);
- }
-
- p = tcapbuf;
- t = tgetstr("pc", &p);
- if(t) PC = *t;
-
- LI = tgetnum("li");
- CD = tgetstr("cd", &p);
- CM = tgetstr("cm", &p);
- CE = tgetstr("ce", &p);
- UP = tgetstr("up", &p);
- BC = tgetstr("bc", &p);
- IM = tgetstr("im", &p);
- IC = tgetstr("ic", &p);
- EI = tgetstr("ei", &p);
- DC = tgetstr("dc", &p);
- AL = tgetstr("al", &p);
- DL = tgetstr("dl", &p);
- pAL= tgetstr("AL", &p); /* parameterized insert and del. line */
- pDL= tgetstr("DL", &p);
- TI = tgetstr("ti", &p);
- TE = tgetstr("te", &p);
- SO = tgetstr("so", &p);
- SE = tgetstr("se", &p);
- CS = tgetstr("cs", &p); /* set scrolling region */
- SR = tgetstr("sr", &p);
- SG = tgetnum("sg"); /* standout glitch */
- #ifdef XKEYS
- /* get the 10 standard termcap keys */
- strcpy(kname,"kx");
- strcpy(lname,"lx");
- for (i = 1; i < 10; i++) {
- kname[1] = i + '0';
- K[i] = tgetstr(kname, &p);
- lname[1] = i + '0';
- L[i] = tgetstr(lname, &p);
- }
- kname[1] = 'A';
- K[0] = tgetstr(kname, &p);
- lname[1] = 'A';
- L[0] = tgetstr(lname, &p);
-
- /* Hack to get another bunch */
- strcpy(kname,"Kx");
- strcpy(lname,"Lx");
- for (i = 1; i < 10; i++) {
- kname[1] = i + '0';
- K[10 + i] = tgetstr(kname, &p);
- lname[1] = i + '0';
- L[10 + i] = tgetstr(lname, &p);
- }
- kname[1] = 'A';
- K[10] = tgetstr(kname, &p);
- lname[1] = 'A';
- L[10] = tgetstr(lname, &p);
-
- /* Get the rest of the sequences */
- KS = tgetstr("ks", &p);
- KE = tgetstr("ke", &p);
- KH = tgetstr("kh", &p);
- KU = tgetstr("ku", &p);
- KD = tgetstr("kd", &p);
- KL = tgetstr("kl", &p);
- KR = tgetstr("kr", &p);
- #endif
-
- if(CM == NULL || UP == NULL)
- {
- ttclose();
- panic("This terminal is too stupid to run MicroGnuEmacs\n");
- }
- ttresize(); /* set nrow & ncol */
-
- /* watch out for empty capabilities (sure to be wrong) */
- if (CE && !*CE) CE = NULL;
- if (CS && !*CS) CS = NULL;
- if (SR && !*SR) SR = NULL;
- if (AL && !*AL) AL = NULL;
- if (DL && !*DL) DL = NULL;
- if (pAL && !*pAL) pAL = NULL;
- if (pDL && !*pDL) pDL = NULL;
- if (CD && !*CD) CD = NULL;
-
- if(!CE) tceeol = ncol;
- else tceeol = charcost(CE);
-
- /* Estimate cost of inserting a line */
- if (CS && SR) tcinsl = charcost(CS)*2 + charcost(SR);
- else if (pAL) tcinsl = charcost(pAL);
- else if (AL) tcinsl = charcost(AL);
- else tcinsl = NROW * NCOL; /* make this cost high enough */
-
- /* Estimate cost of deleting a line */
- if (CS) tcdell = charcost(CS)*2 + 1;
- else if (pDL) tcdell = charcost(pDL);
- else if (DL) tcdell = charcost(DL);
- else tcdell = NROW * NCOL; /* make this cost high enough */
-
- /* Flag to indicate that we can both insert and delete lines */
- insdel = (AL || pAL) && (DL || pDL);
-
- if (p >= &tcapbuf[TCAPSLEN])
- {
- ttclose();
- panic("Terminal description too big!\n");
- }
- if (TI && *TI)
- putpad (TI); /* init the term */
- }
-
- /*
- * Clean up the terminal, in anticipation of
- * a return to the command interpreter. This is a no-op
- * on the ANSI display. On the SCALD display, it sets the
- * window back to half screen scrolling. Perhaps it should
- * query the display for the increment, and put it
- * back to what it was.
- */
- tttidy() {
- if (TE && *TE) putpad (TE); /* set the term back to normal mode */
- #ifdef XKEYS
- ttykeymaptidy();
- #endif
- }
-
- /*
- * Move the cursor to the specified
- * origin 0 row and column position. Try to
- * optimize out extra moves; redisplay may
- * have left the cursor in the right
- * location last time!
- */
- ttmove(row, col) {
- char *tgoto();
-
- if (ttrow!=row || ttcol!=col) {
- putpad(tgoto(CM, col, row));
- ttrow = row;
- ttcol = col;
- }
- }
-
- /*
- * Erase to end of line.
- */
- tteeol() {
- if(CE) putpad(CE);
- else {
- register int i=ncol-ttcol;
- while(i--) ttputc(" ");
- ttrow = ttcol = HUGE;
- }
- }
-
- /*
- * Erase to end of page.
- */
- tteeop() {
- if(CD) putpad(CD);
- else {
- putpad(CE);
- if (insdel) ttdell(ttrow + 1, LI, LI - ttrow - 1);
- else { /* do it by hand */
- register int line;
- for (line = ttrow + 1; line <= LI; ++line) {
- ttmove(line, 0);
- tteeol();
- }
- }
- ttrow = ttcol = HUGE;
- }
- }
-
- /*
- * Make a noise.
- */
- ttbeep() {
- ttputc(BEL);
- ttflush();
- }
-
- /*
- * Insert nchunk blank line(s) onto the
- * screen, scrolling the last line on the
- * screen off the bottom. Use the scrolling
- * region if possible for a smoother display.
- * If no scrolling region, use a set
- * of insert and delete line sequences
- */
- ttinsl(row, bot, nchunk) {
- register int i;
-
- if (row == bot) { /* Case of one line insert is */
- ttmove(row, 0); /* special */
- tteeol();
- return;
- }
- if (CS && SR) { /* Use scroll region and back index */
- ttwindow(row,bot);
- ttmove(row, 0);
- while (nchunk--) putpad(SR);
- ttnowindow();
- return;
- } else if (insdel) {
- ttmove(1+bot-nchunk, 0);
- if (pDL) putpad (tgoto(pDL, 0, nchunk));
- else for (i=0; i<nchunk; i++) /* For all lines in the chunk */
- putpad(DL);
- ttmove(row, 0);
- if (pAL) putpad (tgoto(pAL, 0, nchunk));
- else for (i=0; i<nchunk; i++) /* For all lines in the chunk */
- putpad(AL);
- ttrow = HUGE;
- ttcol = HUGE;
- } else panic("ttinsl: Can't insert/delete line");
- }
-
- /*
- * Delete nchunk line(s) from "row", replacing the
- * bottom line on the screen with a blank line.
- * Unless we're using the scrolling region, this is
- * done with a crafty sequences of insert and delete
- * lines. The presence of the echo area makes a
- * boundry condition go away.
- */
- ttdell(row, bot, nchunk)
- {
- register int i;
-
- if (row == bot) { /* One line special case */
- ttmove(row, 0);
- tteeol();
- return;
- }
- if (CS) { /* scrolling region */
- ttwindow(row, bot);
- ttmove(bot, 0);
- while (nchunk--) ttputc(LF);
- ttnowindow();
- }
- else if(insdel) {
- ttmove(row, 0); /* Else use insert/delete line */
- if (pDL) putpad (tgoto(pDL, 0, nchunk));
- else for (i=0; i<nchunk; i++) /* For all lines in the chunk */
- putpad(DL);
- ttmove(1+bot-nchunk,0);
- if (pAL) putpad (tgoto(pAL, 0, nchunk));
- else for (i=0; i<nchunk; i++) /* For all lines in the chunk */
- putpad(AL);
- ttrow = HUGE;
- ttcol = HUGE;
- } else panic("ttdell: Can't insert/delete line");
- }
-
- /*
- * This routine sets the scrolling window
- * on the display to go from line "top" to line
- * "bot" (origin 0, inclusive). The caller checks
- * for the pathalogical 1 line scroll window that
- * doesn't work right, and avoids it. The "ttrow"
- * and "ttcol" variables are set to a crazy value
- * to ensure that the next call to "ttmove" does
- * not turn into a no-op (the window adjustment
- * moves the cursor).
- *
- */
- ttwindow(top, bot)
- {
- if (CS && (tttop!=top || ttbot!=bot)) {
- putpad(tgoto(CS, bot, top));
- ttrow = HUGE; /* Unknown. */
- ttcol = HUGE;
- tttop = top; /* Remember region. */
- ttbot = bot;
- }
- }
-
- /*
- * Switch to full screen scroll. This is
- * used by "spawn.c" just before is suspends the
- * editor, and by "display.c" when it is getting ready
- * to exit. This function gets to full screen scroll
- * by telling the terminal to set a scrolling regin
- * that is LI or nrow rows high, whichever is larger.
- * This behavior seems to work right on systems
- * where you can set your terminal size.
- */
- ttnowindow()
- {
- if (CS) {
- putpad(tgoto(CS, (nrow > LI ? nrow : LI) - 1, 0));
- ttrow = HUGE; /* Unknown. */
- ttcol = HUGE;
- tttop = HUGE; /* No scroll region. */
- ttbot = HUGE;
- }
- }
-
- /*
- * Set the current writing color to the
- * specified color. Watch for color changes that are
- * not going to do anything (the color is already right)
- * and don't send anything to the display.
- * The rainbow version does this in putline.s on a
- * line by line basis, so don't bother sending
- * out the color shift. The "color already right" optimization
- * doesn't work on some terminals (such as Falco): it's gone!
- */
- ttcolor(color) register int color; {
- if (color == CTEXT) { /* Normal video. */
- putpad(SE);
- } else if (color == CMODE) { /* Reverse video. */
- putpad(SO);
- }
- tthue = color; /* Save the color. */
- }
-
- /*
- * This routine is called by the
- * "refresh the screen" command to try and resize
- * the display. The new size, which must be deadstopped
- * to not exceed the NROW and NCOL limits, it stored
- * back into "nrow" and "ncol". Display can always deal
- * with a screen NROW by NCOL. Look in "window.c" to
- * see how the caller deals with a change.
- */
- ttresize() {
- setttysize(); /* found in "ttyio.c", */
- /* ask OS for tty size */
- if (nrow < 1) /* Check limits. */
- nrow = 1;
- else if (nrow > NROW)
- nrow = NROW;
- if (ncol < 1)
- ncol = 1;
- else if (ncol > NCOL)
- ncol = NCOL;
- }
-
- #ifdef NO_RESIZE
- static setttysize() {
- nrow = tgetnum("li");
- ncol = tgetnum("co");
- }
- #endif
-
- static int cci;
-
- static /* fake char output for charcost() */
- fakec(c) char c; {
- #ifdef lint
- c++;
- #endif
- cci++;
- }
-
- /* calculate the cost of doing string s */
- charcost (s) char *s; {
- cci = 0;
-
- tputs(s, nrow, fakec);
- return cci;
- }
-
- putpad(str) char *str; {
- tputs(str, 1, ttputc);
- }
- \Rogue\Monster\
- else
- echo "will not over write ./tty.c"
- fi
- if `test ! -s ./ttyio.c`
- then
- echo "writing ./ttyio.c"
- cat > ./ttyio.c << '\Rogue\Monster\'
- /*
- * Name: MicroEMACS
- * System V terminal I/O.
- * Version: 0
- * Last edit: Tue Aug 26 23:57:57 PDT 1986
- * By: gonzo!daveb
- * {sun, amdahl, mtxinu}!rtech!gonzo!daveb
- *
- * The functions in this file
- * negotiate with the operating system for
- * keyboard characters, and write characters to
- * the display in a barely buffered fashion.
- *
- * This version goes along with tty/termcap/tty.c.
- * Terminal size is determined there, rather than here, and
- * this does not open the termcap file
- */
- #include "def.h"
-
- #include <sys/types.h>
- #include <fcntl.h>
- #include <termio.h>
-
- #define NOBUF 512 /* Output buffer size. */
-
- char obuf[NOBUF]; /* Output buffer. */
- int nobuf; /* buffer count */
-
- static struct termio ot; /* entry state of the terminal */
- static struct termio nt; /* editor's terminal state */
-
- static int ttyactivep = FALSE; /* terminal in editor mode? */
- static int ttysavedp = FALSE; /* terminal state saved? */
-
- int nrow; /* Terminal size, rows. */
- int ncol; /* Terminal size, columns. */
-
- /* These are used to implement typeahead on System V */
-
- int kbdflgs; /* saved keyboard fd flags */
- int kbdpoll; /* in O_NDELAY mode */
- int kbdqp; /* there is a char in kbdq */
- char kbdq; /* char we've already read */
-
- /*
- * This function gets called once, to set up
- * the terminal channel. This version turns off flow
- * control. This may be wrong for your system, but no
- * good solution has really been found (daveb).
- */
- ttopen()
- {
- register char *cp;
- extern char *getenv();
-
- if (ttyactivep)
- return;
-
- if( !ttysavedp )
- {
- if (ioctl(0, TCGETA, &ot) < 0)
- abort();
- nt = ot; /* save entry state */
- nt.c_cc[VMIN] = 1; /* one character read is OK */
- nt.c_cc[VTIME] = 0; /* Never time out. */
- nt.c_iflag |= IGNBRK;
- nt.c_iflag &= ~( ICRNL | INLCR | ISTRIP | IXON | IXOFF );
- nt.c_oflag &= ~OPOST;
- #ifdef BIT7EVEN
- nt.c_cflag &= ~CS8;
- nt.c_cflag |= CS7; /* disallow 8th bit on input */
- nt.c_cflag |= PARENB; /* check parity */
- nt.c_cflag &= ~PARODD; /* even parity */
- #else
- nt.c_cflag |= CS8; /* allow 8th bit on input */
- nt.c_cflag &= ~PARENB; /* Don't check parity */
- #endif
- nt.c_lflag &= ~( ECHO | ICANON | ISIG );
-
- kbdflgs = fcntl( 0, F_GETFL, 0 );
- kbdpoll = FALSE;
-
- ttysavedp = TRUE;
- }
-
- if (ioctl(0, TCSETAF, &nt) < 0)
- abort();
-
- /* This really belongs in tty/termcap... */
-
- if ((cp=getenv("TERMCAP")) == NULL
- || (nrow=getvalue(cp, "li")) <= 0
- || (ncol=getvalue(cp, "co")) <= 0) {
- nrow = 24;
- ncol = 80;
- }
- if (nrow > NROW) /* Don't crash if the */
- nrow = NROW; /* termcap entry is */
- if (ncol > NCOL) /* too big. */
- ncol = NCOL;
-
- ttyactivep = TRUE;
- }
-
- /*
- * This routine scans a string, which is
- * actually the return value of a getenv call for the TERMCAP
- * variable, looking for numeric parameter "name". Return the value
- * if found. Return -1 if not there. Assume that "name" is 2
- * characters long. This limited use of the TERMCAP lets us find
- * out the size of a window on the X display.
- */
- getvalue(cp, name)
- register char *cp;
- register char *name;
- {
- for (;;) {
- while (*cp!=0 && *cp!=':')
- ++cp;
- if (*cp++ == 0) /* Not found. */
- return (-1);
- if (cp[0]==name[0] && cp[1]==name[1] && cp[2]=='#')
- return (atoi(cp+3)); /* Stops on ":". */
- }
- }
-
- /*
- * This function gets called just
- * before we go back home to the shell. Put all of
- * the terminal parameters back.
- */
- ttclose()
- {
- if(!ttysavedp || !ttyactivep)
- return;
- ttflush();
- if (ioctl(0, TCSETAF, &ot) < 0 || fcntl( 0, F_SETFL, kbdflgs ) < 0)
- abort();
- ttyactivep = FALSE;
- }
-
- /*
- * Write character to the display.
- * Characters are buffered up, to make things
- * a little bit more efficient.
- */
- ttputc(c)
- {
- if (nobuf >= NOBUF)
- ttflush();
- obuf[nobuf++] = c;
- }
-
- /*
- * Flush output.
- */
- ttflush()
- {
- if (nobuf != 0) {
- write(1, obuf, nobuf);
- nobuf = 0;
- }
- }
-
- /*
- * Read character from terminal.
- * All 8 bits are returned, so that you can use
- * a multi-national terminal.
- *
- * If keyboard 'queue' already has typeahead from a typeahead() call,
- * just return it. Otherwise, make sure we are in blocking i/o mode
- * and read a character.
- */
- ttgetc()
- {
- if( kbdqp )
- kbdqp = FALSE;
- else
- {
- if( kbdpoll && fcntl( 0, F_SETFL, kbdflgs ) < 0 )
- abort();
- kbdpoll = FALSE;
- while (read(0, &kbdq, 1) != 1)
- ;
- }
- #ifdef BIT7EVEN
- return ( kbdq & 0x7f );
- #else
- return ( kbdq & 0xff );
- #endif
- }
-
- /*
- * Return non-FALSE if typeahead is pending.
- *
- * If already got unread typeahead, do nothing.
- * Otherwise, set keyboard to O_NDELAY if not already, and try
- * a one character read.
- */
- typeahead()
- {
- if( !kbdqp )
- {
- if( !kbdpoll && fcntl( 0, F_SETFL, kbdflgs | O_NDELAY ) < 0 )
- abort();
- kbdqp = (1 == read( 0, &kbdq, 1 ));
- }
- return ( kbdqp );
- }
-
-
- /*
- * panic: print error and die, leaving core file.
- * Don't know why this is needed (daveb).
- */
- panic(s)
- char *s;
- {
- fprintf(stderr, "%s\r\n", s);
- abort();
- }
-
-
- /*
- ** This should check the size of the window, and reset if needed.
- */
-
- setttysize()
- {
- #ifdef TIOCGWINSZ
- if (ioctl(0, TIOCGWINSZ, (char *) &winsize) == 0) {
- nrow = winsize . ws_row;
- ncol = winsize . ws_col;
- } else
- #endif
- if ((nrow=tgetnum ("li")) <= 0
- || (ncol=tgetnum ("co")) <= 0) {
- nrow = 24;
- ncol = 80;
- }
- if (nrow > NROW) /* Don't crash if the */
- nrow = NROW; /* termcap entry is */
- if (ncol > NCOL) /* too big. */
- ncol = NCOL;
- }
-
- \Rogue\Monster\
- else
- echo "will not over write ./ttyio.c"
- fi
- if `test ! -s ./ttykbd.c`
- then
- echo "writing ./ttykbd.c"
- cat > ./ttykbd.c << '\Rogue\Monster\'
- /*
- * Name: MicroEmacs
- * Version: 30
- * Termcap keyboard driver
- * Created: 21-Aug-1986
- * Mic Kaczmarczik ...!ihnp4!seismo!ut-sally!ut-ngp!mic
- * Last edit: 20-Feb-1987
- *
- * [ Several of the nasty comments about the XKEYS code are
- * by me. [Bob Larson (usc-oberon!blarson)] It is my opinion
- * that function keys cannot be made to work with standard
- * emacs keybindings except on a very limited set of terminals.
- * I just work with to many that do not fit the assumptions Mic's
- * XKEYS code makes to consider it useful to me, and think that
- * others considering using this code should look and see what
- * it realy does first.
- * ]
- *
- * If XKEYS is defined this routine looks for the following
- * termcap sequences, which are obtained by "tty.c":
- *
- * ks -- start keypad transmit mode
- * ke -- end keypad transmit mode
- * kh -- home key
- * ku -- up arrow
- * kd -- down arrow
- * kl -- left arrow
- * kr -- right arrow
- * k0-k9 -- standard termcap function keys
- * l0-l9 -- labels for termcap function keys
- * (nonstandard)
- * K0-K9 -- extra keys that we look for -- the get mapped
- * internally to F10-F19
- * L0-L9 -- labels for same.
- *
- * Bugs/features/problems:
- *
- * XKEYS and DPROMPT do not work together well.
- *
- * If the META introducer is used as the initial character of
- * a function key sequence, what should the key parser do when the
- * user wants to type a META-ed key, or just the META introducer
- * alone? This is of practical importance on DEC terminals, where
- * the META introducer is the Escape key. Even worse things happen
- * on terminals that have something (or more than one thing) other
- * than the META introducer as the inital character of a function
- * sequence.
- *
- * The approach I took was that if the META introducer is the first
- * character in a function sequence, and the second character c
- * isn't part of a function key sequence, the parser returns
- * (KMETA | c). If it sees two META introducers in a row, it
- * returns one instance of METACH. This approach is subject to
- * discussion and debate, but it works. [In at lease some cases.]
- *
- * If the META introducer is NOT the first character in a function
- * sequence (including arrow keys) this code has a very nasty
- * side effect of eating that key. For example, on an Adds viewpoint
- * 60, six normal control characters are eaten if you have defined
- * XKEYS and put the keys in the termcap. More than a little
- * creativity is needed because ^U is one of the arrow keys, and
- * prefixes aren't bindable.
- *
- * [ From a quick look at the code, it seems that a single character
- * funciton key won't work, but it is still put in the table.
- * ]
- */
- #include "def.h"
-
- /*
- * Default key name table. Can be overridden by
- * definitions of l0-l9 in the termcap entry. You
- * can't redefine the names for the arrow keys
- * and the home key.
- */
-
- #ifdef XKEYS
- /* key sequences (from tty.c) */
- extern char *K[], *L[], *KS, *KE, *KH, *KU, *KD, *KL, *KR;
- extern int putpad(); /* also from tty.c */
- char *keystrings[] = {
- NULL, "Home", "Down-Arrow", "Up-Arrow",
- "Left-Arrow", "Right-Arrow", "F0", "F1",
- "F2", "F3", "F4", "F5",
- "F6", "F7", "F8", "F9",
- "F10", "F11", "F12", "F13",
- "F14", "F15", "F16", "F17",
- "F18", "F19", NULL, NULL,
- NULL, NULL, NULL, NULL
- };
- #else
- char *keystrings[] = {
- NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL
- };
- #endif
-
- #ifdef XKEYS
- /*
- * Type declarations for data structure we
- * use to parse for function key sequences
- */
- #define NODE 0 /* internal node */
- #define VALUE 1 /* internal key code value */
- #define SENTINEL 2 /* sentinel value */
-
- typedef struct trienode {
- int type; /* one of NODE, LEAF */
- struct trienode *sibling, *child;
- KEY value;
- } TRIENODE, *TRIE;
-
- TRIE keywords, sentinel, talloc(), tinsert();
- #endif
-
- /*
- * Get keyboard character, and interpret
- * any special keys on the keyboard. If XKEYS is
- * #defined, use a dictionary organized as a
- * trie to keep the parsing overhead down.
- *
- * To keep the function call overhead down, do the
- * first level of parse() inside getkbd().
- *
- * Also, since ESC (the usual value of METACH) is
- * the first character in many function key sequences,
- * we return (KMETA | ch) if METACH-<ch> is not
- * the start of an escape sequence. Blecch. Furthermore,
- * if we see METACH-METACH, we return the value METACH.
- * Phhhht.
- */
- getkbd()
- {
- #ifndef XKEYS
- return (ttgetc());
- #else
- register TRIE t;
- register int c;
- KEY code;
-
- c = ttgetc();
- for (t = keywords; t->type == NODE; t = t->sibling)
- if (t->value == c)
- { /* possible function key sequence */
- if (c != METACH)
- return (parse(t->child));
- else
- { /* maybe sequence, maybe META char */
- c = ttgetc();
- for (t = t->child; t->type == NODE; t = t->sibling)
- if (t->value == c)
- return (parse(t->child));
- /* METACH-METACH -> METACH */
- if (c == METACH)
- return (METACH);
- /* Else make c into a META character */
- if (ISLOWER(c) != FALSE)
- c = TOUPPER(c);
- if (c>=0x00 && c<=0x1F)
- c = KCTRL | (c+'@');
- return (KMETA | c);
- }
- }
- return (c);
- #endif
- }
-
- #ifdef XKEYS
- static parse(first)
- TRIE first;
- {
- register TRIE t;
- register int c;
-
- if (first->type == VALUE) /* found a match! */
- return (first->value);
-
- c = ttgetc();
- for (t = first; t->type == NODE; t = t->sibling)/* look thru list */
- if (t->value == c)
- return (parse(t->child)); /* try next level */
- return (c); /* nothing matched */
- }
- #endif
-
- /*
- * If XKEYS is defined, get key definitions from the termcap
- * entry and put them in the parse table.
- *
- * If DO_METAKEY is defined, kbd.c expects function keys to have
- * KCTRL set to differentiate them from real meta-ized control
- * characters. To do this, we put the code (KCTRL | fkey) into
- * the dictionary, instead of the code itself. Trust me...
- */
-
- #ifdef DO_METAKEY
- #define FNKEY(c) ((KEY) (KCTRL | c))
- #else
- #define FNKEY(c) ((KEY) c)
- #endif
-
- ttykeymapinit()
- {
- #ifdef XKEYS
- register int i;
- register int s;
- register char *cp;
- register SYMBOL *sp;
- extern int spawncmd();
- extern int spawninsert();
-
- if (KS && *KS) /* turn on keypad */
- putpad(KS);
-
- tinit(); /* set up initial trie */
-
- for (i = 0; i < NFKEYS; i++)
- {
- if (K[i] && *K[i])
- adddict(K[i], FNKEY(KF0 + i));
- if (L[i] && *L[i]) /* record new name */
- keystrings[(KF0-KFIRST)+i] = L[i];
- }
-
- /*
- * Add the home and arrow keys
- */
- if (KH && *KH)
- adddict(KH, FNKEY(KHOME));
- if (KU && *KU)
- adddict(KU, FNKEY(KUP));
- if (KD && *KD)
- adddict(KD, FNKEY(KDOWN));
- if (KL && *KL)
- adddict(KL, FNKEY(KLEFT));
- if (KR && *KR)
- adddict(KR, FNKEY(KRIGHT));
-
- /*
- * Bind things to the movement keys
- */
- keydup(KHOME, "beginning-of-buffer"); /* for now */
- keydup(KUP, "previous-line");
- keydup(KDOWN, "next-line");
- keydup(KLEFT, "backward-char");
- keydup(KRIGHT, "forward-char");
-
- keydup( KF1, "save-buffers-kill-emacs");
- #ifdef MISLOG
- keydup( KF2, "newlog");
- #endif
- keydup( KF3, "previous-line");
- keydup( KF4, "next-line");
- keydup( KF5, "open-line"); /* modified function */
- keydup( KF6, "fill-paragraph");
- #ifdef MENU_INSERT
- keyadd( KF7, spawninsert, "spawn-insert-file");/* new function */
- #endif
- keydup( KF8, "toggle-insert-overstrike"); /* new function */
- keydup( KF9, "save-buffer");
- keydup( KF0, "rotate-help"); /* new function */
- keydup( KF11, "restart-edit"); /* new function */
- keyadd( KF12, spawncmd, "print-buffer");/* new function */
- keydup( KF13, "search-forward");
- keydup( KF14, "backward-paragraph");
- keydup( KF15, "forward-paragraph");
- keydup( KF16, "beginning-of-line");
- keydup( KF17, "end-of-line");
- keydup( KF18, "delete-line"); /* new function */
- keydup( KF19, "kill-emacs"); /* new function */
-
- #endif XKEYS
- }
-
- #ifdef XKEYS
- /*
- * Clean up the keyboard -- called by tttidy()
- */
- ttykeymaptidy()
- {
- tdelete(keywords); /* get rid of parse tree */
- free(sentinel); /* remove sentinel value */
- if (KE && *KE)
- putpad(KE); /* turn off keypad */
- }
-
- /*
- * * * * * * * * Dictionary management * * * * * * * * *
- */
-
- /*
- * Add a key string to the dictionary.
- */
-
- static adddict(kstr, kcode)
- char *kstr;
- KEY kcode;
- {
- keywords = tinsert(kstr, kcode, keywords);
- }
-
- /*
- * Initialize the parse tree by creating the sentinel value
- */
-
- static tinit()
- {
- keywords = sentinel = talloc();
- sentinel->type = SENTINEL;
- sentinel->value = (KEY) -1;
- sentinel->sibling = sentinel->child = sentinel; /* set up a loop */
- }
-
- /*
- * Deallocate all the space used by the trie --
- * Tell all the siblings to deallocate space, then
- * all the children.
- */
-
- static tdelete(t)
- register TRIE t;
- {
- if (t->type != SENTINEL)
- {
- tdelete(t->sibling);
- tdelete(t->child);
- free(t);
- }
- }
-
- /*
- * Insert a dictionary key string and a value into the dictionary,
- * returning as the value the first sibling in the current sublevel,
- * which may have been changed by an insertion into the list of siblings.
- */
-
- static TRIE tinsert(kstring, kcode, first)
- register char *kstring;
- register KEY kcode;
- TRIE first;
- {
- register TRIE match;
- register TRIE p;
-
- if (!*kstring)
- { /* base case -- return a value node */
- p = talloc();
- p->type = VALUE;
- p->value = kcode;
- p->sibling = p->child = sentinel;
- return (p);
- }
- /* recursive case -- insert rest of string in trie */
-
- /* search for sibling that matches the current character */
- match = NULL;
- for (p = first; p->type == NODE; p = p->sibling)
- if (p->value == *kstring)
- {
- match = p;
- break;
- }
-
- if (match == NULL)
- { /* if not, add it to beginning of the list */
- match = talloc();
- match->type = NODE;
- match->value = *kstring;
- match->sibling = first;
- match->child = sentinel;
- first = match;
- }
- /* add rest of string to this child's subtrie */
- match->child = tinsert(kstring+1, kcode, match->child);
- return (first);
- }
-
- /*
- * Allocate a trie node
- */
- static TRIE talloc()
- {
- char *malloc();
- TRIE t;
-
- if ((t = (TRIE) malloc(sizeof(TRIENODE))) == NULL)
- panic("talloc: can't allocate trie node!");
- return (t);
- }
- #endif
- \Rogue\Monster\
- else
- echo "will not over write ./ttykbd.c"
- fi
- if `test ! -s ./version.c`
- then
- echo "writing ./version.c"
- cat > ./version.c << '\Rogue\Monster\'
- /*
- * This file contains the string that get written
- * out by the emacs-version command.
- * Rich had it generated by a command file. I do
- * it manually, until I can figure out a way to get
- * the MicroGnuEmacs version number generated in an
- * reasonable and automatic manner.
- */
-
- char *version = "TinyGnuEmacs 1b" ;
-
- #ifdef __50SERIES
- #ifndef __CI
- static void dummmy(){} /* work around bug in primos 64v mode */
- #endif
- #endif
- \Rogue\Monster\
- else
- echo "will not over write ./version.c"
- fi
- if `test ! -s ./window.c`
- then
- echo "writing ./window.c"
- cat > ./window.c << '\Rogue\Monster\'
- /*
- * Window handling.
- */
- #include "def.h"
-
- /*
- * Reposition dot in the current
- * window to line "n". If the argument is
- * positive, it is that line. If it is negative it
- * is that line from the bottom. If it is 0 the window
- * is centered (this is what the standard redisplay code
- * does). If GOSREC is undefined, default is 0, so it acts like GNU.
- * If GOSREC is defined, with no argument it defaults to 1
- * and works like in Gosling.
- */
- /*ARGSUSED*/
- reposition(f, n, k)
- {
- #ifndef GOSREC
- curwp->w_force = ((f == FALSE) ? 0 : n) ;
- #else
- curwp->w_force = n;
- #endif
- curwp->w_flag |= WFFORCE;
- sgarbf = TRUE;
- return (TRUE);
- }
-
- /*
- * Refresh the display. A call is made to the
- * "ttresize" entry in the terminal handler, which tries
- * to reset "nrow" and "ncol". They will, however, never
- * be set outside of the NROW or NCOL range. If the display
- * changed size, arrange that everything is redone, then
- * call "update" to fix the display. We do this so the
- * new size can be displayed. In the normal case the
- * call to "update" in "main.c" refreshes the screen,
- * and all of the windows need not be recomputed.
- * Note that when you get to the "display unusable"
- * message, the screen will be messed up. If you make
- * the window bigger again, and send another command,
- * everything will get fixed!
- */
- /*ARGSUSED*/
- refresh(f, n, k)
- {
- register WINDOW *wp;
- register int oldnrow;
- register int oldncol;
-
- oldnrow = nrow;
- oldncol = ncol;
- ttresize();
- if (nrow!=oldnrow || ncol!=oldncol)
- {
- wp = wheadp; /* Find last. */
- while (wp->w_wndp != NULL)
- wp = wp->w_wndp;
- if (nrow < wp->w_toprow+3)
- { /* Check if too small. */
- ewprintf("Display unusable");
- return (FALSE);
- }
- wp->w_ntrows = nrow-wp->w_toprow-2;
- sgarbf = TRUE;
- update();
- if (kbdmop == NULL) ewprintf("New size %d by %d", nrow, ncol);
- }
- else
- sgarbf = TRUE;
- return (TRUE);
- }
- \Rogue\Monster\
- else
- echo "will not over write ./window.c"
- fi
- if `test ! -s ./word.c`
- then
- echo "writing ./word.c"
- cat > ./word.c << '\Rogue\Monster\'
- /*
- * Word mode commands.
- * The routines in this file
- * implement commands that work word at
- * a time. There are all sorts of word mode
- * commands. If I do any sentence and/or paragraph
- * mode commands, they are likely to be put in
- * this file.
- */
- #include "def.h"
-
-
- /*
- * Kill forward by "n" words.
- */
- /*ARGSUSED*/
- delfword(f, n, k)
- {
- register RSIZE size;
- register LINE *dotp;
- register int doto;
-
- if (n < 0)
- return (FALSE);
- if ((lastflag&CFKILL) == 0) /* Purge kill buffer. */
- kdelete();
- thisflag |= CFKILL;
- dotp = curwp->w_dotp;
- doto = curwp->w_doto;
- size = 0;
- while (n--)
- {
- while (inword() == FALSE)
- {
- if (forwchar(FALSE, 1, KRANDOM) == FALSE)
- goto out; /* Hit end of buffer. */
- ++size;
- }
- while (inword() != FALSE)
- {
- if (forwchar(FALSE, 1, KRANDOM) == FALSE)
- goto out; /* Hit end of buffer. */
- ++size;
- }
- }
- out:
- curwp->w_dotp = dotp;
- curwp->w_doto = doto;
- return (ldelete(size, KFORW));
- }
-
- /*
- * Kill backwards by "n" words. The rules
- * for success and failure are now different, to prevent
- * strange behavior at the start of the buffer. The command
- * only fails if something goes wrong with the actual delete
- * of the characters. It is successful even if no characters
- * are deleted, or if you say delete 5 words, and there are
- * only 4 words left. I considered making the first call
- * to "backchar" special, but decided that that would just
- * be wierd. Normally this is bound to "M-Rubout" and
- * to "M-Backspace".
- */
- /*ARGSUSED*/
- delbword(f, n, k)
- {
- register RSIZE size;
-
- if (n < 0)
- return (FALSE);
- if ((lastflag&CFKILL) == 0) /* Purge kill buffer. */
- kdelete();
- thisflag |= CFKILL;
- if (backchar(FALSE, 1, KRANDOM) == FALSE)
- return (TRUE); /* Hit buffer start. */
- size = 1; /* One deleted. */
- while (n--)
- {
- while (inword() == FALSE)
- {
- if (backchar(FALSE, 1, KRANDOM) == FALSE)
- goto out; /* Hit buffer start. */
- ++size;
- }
- while (inword() != FALSE)
- {
- if (backchar(FALSE, 1, KRANDOM) == FALSE)
- goto out; /* Hit buffer start. */
- ++size;
- }
- }
- if (forwchar(FALSE, 1, KRANDOM) == FALSE)
- return (FALSE);
- --size; /* Undo assumed delete. */
- out:
- return (ldelete(size, KBACK));
- }
-
- /*
- * Return TRUE if the character at dot
- * is a character that is considered to be
- * part of a word. The word character list is hard
- * coded. Should be setable.
- */
- inword()
- {
- if (curwp->w_doto == llength(curwp->w_dotp))
- return (FALSE);
- if (ISWORD(lgetc(curwp->w_dotp, curwp->w_doto)) != FALSE)
- return (TRUE);
- return (FALSE);
- }
- \Rogue\Monster\
- else
- echo "will not over write ./word.c"
- fi
- echo "Finished archive 1 of 5"
- exit
-
- --
- =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
- Mark A. Hargrove U.S. TeleCenters
- Voice: 408-496-1800 Santa Clara, CA
- uucp : {dual, hoptoad, hplabs, portal, ptsfa}!well!ustel
-