v02i050: Unify TEXT fields from ACCELL Part 1/5
Mark Hargrove
ustel at well.UUCP
Thu Feb 11 10:43:57 AEST 1988
Comp.sources.misc: Volume 2, Issue 50
Submitted-By: "Mark Hargrove" <ustel at well.UUCP>
Archive-Name: accell-text/Part1
Comp.sources.misc: Volume 2, Issue 50
Submitted-By: "Mark Hargrove" <ustel at 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
More information about the Comp.sources.misc
mailing list