aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@g5.osdl.org>2005-05-31 08:50:56 -0700
committerLinus Torvalds <torvalds@g5.osdl.org>2005-05-31 08:50:56 -0700
commitd7148b21fe4fff228acf5b7006cf9323bd750df7 (patch)
treee49f3fc3013767b4209489e0ced5c3e48618d91d
downloaduemacs-d7148b21fe4fff228acf5b7006cf9323bd750df7.tar.gz
Initial import of em-4.0.15-lt
This is a slightly updated version of uemacs-PK (PK is Pekka Kutvonen) which was used at Helsinki University a long time ago. My fingers cannot be retrained.
-rw-r--r--ansi.c264
-rw-r--r--basic.c462
-rw-r--r--bind.c708
-rw-r--r--buffer.c544
-rw-r--r--crypt.c221
-rw-r--r--display.c1570
-rw-r--r--dosmake.bat2
-rw-r--r--ebind.h249
-rw-r--r--edef.h323
-rw-r--r--efunc.h431
-rw-r--r--emacs.hlp172
-rw-r--r--emacs.lnk29
-rw-r--r--emacs.prj27
-rw-r--r--emacs.ps3667
-rw-r--r--emacs.rc285
-rw-r--r--emacs.wribin0 -> 88320 bytes
-rw-r--r--epath.h53
-rw-r--r--estruct.h731
-rw-r--r--eval.c879
-rw-r--r--evar.h212
-rw-r--r--exec.c1148
-rw-r--r--file.c635
-rw-r--r--fileio.c228
-rw-r--r--ibmpc.c517
-rw-r--r--input.c713
-rw-r--r--isearch.c521
-rw-r--r--line.c655
-rw-r--r--lock.c166
-rw-r--r--main.c895
-rw-r--r--makefile124
-rw-r--r--makefile.dos22
-rw-r--r--makefile.unx121
-rw-r--r--makefilepatch61
-rw-r--r--pklock.c125
-rw-r--r--posix.c159
-rw-r--r--random.c1221
-rw-r--r--readme182
-rw-r--r--readme.39e331
-rw-r--r--region.c212
-rw-r--r--search.c1585
-rw-r--r--shell.cmd57
-rw-r--r--spawn.c628
-rw-r--r--tcap.c386
-rw-r--r--termio.c451
-rw-r--r--vmslink.com29
-rw-r--r--vmsmake.com28
-rw-r--r--vmsvt.c519
-rw-r--r--vt52.c190
-rw-r--r--window.c733
-rw-r--r--word.c717
50 files changed, 24188 insertions, 0 deletions
diff --git a/ansi.c b/ansi.c
new file mode 100644
index 0000000..1f582b3
--- /dev/null
+++ b/ansi.c
@@ -0,0 +1,264 @@
+/* ANSI.C
+ *
+ * The routines in this file provide support for ANSI style terminals
+ * over a serial line. The serial I/O services are provided by routines in
+ * "termio.c". It compiles into nothing if not an ANSI device.
+ *
+ * modified by Petri Kutvonen
+ */
+
+#define termdef 1 /* don't define "term" external */
+
+#include <stdio.h>
+#include "estruct.h"
+#include "edef.h"
+
+#if ANSI
+
+#define NROW 25 /* Screen size. */
+#define NCOL 80 /* Edit if you want to. */
+
+#if PKCODE
+#define MROW 64
+#endif
+#define NPAUSE 100 /* # times thru update to pause */
+#define MARGIN 8 /* size of minimim margin and */
+#define SCRSIZ 64 /* scroll size for extended lines */
+#define BEL 0x07 /* BEL character. */
+#define ESC 0x1B /* ESC character. */
+
+extern int ttopen(); /* Forward references. */
+extern int ttgetc();
+extern int ttputc();
+extern int ttflush();
+extern int ttclose();
+extern int ansimove();
+extern int ansieeol();
+extern int ansieeop();
+extern int ansibeep();
+extern int ansiopen();
+extern int ansirev();
+extern int ansiclose();
+extern int ansikopen();
+extern int ansikclose();
+extern int ansicres();
+
+#if COLOR
+extern int ansifcol();
+extern int ansibcol();
+
+int cfcolor = -1; /* current forground color */
+int cbcolor = -1; /* current background color */
+
+#endif
+
+/*
+ * Standard terminal interface dispatch table. Most of the fields point into
+ * "termio" code.
+ */
+TERM term = {
+#if PKCODE
+ MROW-1,
+#else
+ NROW-1,
+#endif
+ NROW-1,
+ NCOL,
+ NCOL,
+ MARGIN,
+ SCRSIZ,
+ NPAUSE,
+ ansiopen,
+ ansiclose,
+ ansikopen,
+ ansikclose,
+ ttgetc,
+ ttputc,
+ ttflush,
+ ansimove,
+ ansieeol,
+ ansieeop,
+ ansibeep,
+ ansirev,
+ ansicres
+#if COLOR
+ , ansifcol,
+ ansibcol
+#endif
+#if SCROLLCODE
+ , NULL
+#endif
+};
+
+#if COLOR
+ansifcol(color) /* set the current output color */
+
+int color; /* color to set */
+
+{
+ if (color == cfcolor)
+ return;
+ ttputc(ESC);
+ ttputc('[');
+ ansiparm(color+30);
+ ttputc('m');
+ cfcolor = color;
+}
+
+ansibcol(color) /* set the current background color */
+
+int color; /* color to set */
+
+{
+ if (color == cbcolor)
+ return;
+ ttputc(ESC);
+ ttputc('[');
+ ansiparm(color+40);
+ ttputc('m');
+ cbcolor = color;
+}
+#endif
+
+ansimove(row, col)
+{
+ ttputc(ESC);
+ ttputc('[');
+ ansiparm(row+1);
+ ttputc(';');
+ ansiparm(col+1);
+ ttputc('H');
+}
+
+ansieeol()
+{
+ ttputc(ESC);
+ ttputc('[');
+ ttputc('K');
+}
+
+ansieeop()
+{
+#if COLOR
+ ansifcol(gfcolor);
+ ansibcol(gbcolor);
+#endif
+ ttputc(ESC);
+ ttputc('[');
+ ttputc('J');
+}
+
+ansirev(state) /* change reverse video state */
+
+int state; /* TRUE = reverse, FALSE = normal */
+
+{
+#if COLOR
+ int ftmp, btmp; /* temporaries for colors */
+#endif
+
+ ttputc(ESC);
+ ttputc('[');
+ ttputc(state ? '7': '0');
+ ttputc('m');
+#if COLOR
+ if (state == FALSE) {
+ ftmp = cfcolor;
+ btmp = cbcolor;
+ cfcolor = -1;
+ cbcolor = -1;
+ ansifcol(ftmp);
+ ansibcol(btmp);
+ }
+#endif
+}
+
+ansicres() /* change screen resolution */
+
+{
+ return(TRUE);
+}
+
+spal(dummy) /* change pallette settings */
+
+{
+ /* none for now */
+}
+
+ansibeep()
+{
+ ttputc(BEL);
+ ttflush();
+}
+
+ansiparm(n)
+register int n;
+{
+ register int q,r;
+
+ q = n/10;
+ if (q != 0) {
+ r = q/10;
+ if (r != 0) {
+ ttputc((r%10)+'0');
+ }
+ ttputc((q%10) + '0');
+ }
+ ttputc((n%10) + '0');
+}
+
+ansiopen()
+{
+#if V7 | USG | BSD
+ register char *cp;
+ char *getenv();
+
+ if ((cp = getenv("TERM")) == NULL) {
+ puts("Shell variable TERM not defined!");
+ exit(1);
+ }
+ if (strcmp(cp, "vt100") != 0) {
+ puts("Terminal type not 'vt100'!");
+ exit(1);
+ }
+#endif
+ strcpy(sres, "NORMAL");
+ revexist = TRUE;
+ ttopen();
+}
+
+ansiclose()
+
+{
+#if COLOR
+ ansifcol(7);
+ ansibcol(0);
+#endif
+ ttclose();
+}
+
+ansikopen() /* open the keyboard (a noop here) */
+
+{
+}
+
+ansikclose() /* close the keyboard (a noop here) */
+
+{
+}
+
+#if FNLABEL
+fnclabel(f, n) /* label a function key */
+
+int f,n; /* default flag, numeric argument [unused] */
+
+{
+ /* on machines with no function keys...don't bother */
+ return(TRUE);
+}
+#endif
+#else
+ansihello()
+{
+}
+#endif
diff --git a/basic.c b/basic.c
new file mode 100644
index 0000000..7414744
--- /dev/null
+++ b/basic.c
@@ -0,0 +1,462 @@
+/* BASIC.C
+ *
+ * The routines in this file move the cursor around on the screen. They
+ * compute a new value for the cursor, then adjust ".". The display code
+ * always updates the cursor location, so only moves between lines, or
+ * functions that adjust the top line in the window and invalidate the
+ * framing, are hard.
+ *
+ * modified by Petri Kutvonen
+ */
+
+#include <stdio.h>
+#include "estruct.h"
+#include "edef.h"
+
+/*
+ * Move the cursor to the
+ * beginning of the current line.
+ * Trivial.
+ */
+gotobol(f, n)
+{
+ curwp->w_doto = 0;
+ return (TRUE);
+}
+
+/*
+ * Move the cursor backwards by "n" characters. If "n" is less than zero call
+ * "forwchar" to actually do the move. Otherwise compute the new cursor
+ * location. Error if you try and move out of the buffer. Set the flag if the
+ * line pointer for dot changes.
+ */
+backchar(f, n)
+register int n;
+{
+ register LINE *lp;
+
+ if (n < 0)
+ return (forwchar(f, -n));
+ while (n--) {
+ if (curwp->w_doto == 0) {
+ if ((lp=lback(curwp->w_dotp)) == curbp->b_linep)
+ return (FALSE);
+ curwp->w_dotp = lp;
+ curwp->w_doto = llength(lp);
+ curwp->w_flag |= WFMOVE;
+ } else
+ curwp->w_doto--;
+ }
+ return (TRUE);
+}
+
+/*
+ * Move the cursor to the end of the current line. Trivial. No errors.
+ */
+gotoeol(f, n)
+{
+ curwp->w_doto = llength(curwp->w_dotp);
+ return (TRUE);
+}
+
+/*
+ * Move the cursor forwards by "n" characters. If "n" is less than zero call
+ * "backchar" to actually do the move. Otherwise compute the new cursor
+ * location, and move ".". Error if you try and move off the end of the
+ * buffer. Set the flag if the line pointer for dot changes.
+ */
+forwchar(f, n)
+register int n;
+{
+ if (n < 0)
+ return (backchar(f, -n));
+ while (n--) {
+ if (curwp->w_doto == llength(curwp->w_dotp)) {
+ if (curwp->w_dotp == curbp->b_linep)
+ return (FALSE);
+ curwp->w_dotp = lforw(curwp->w_dotp);
+ curwp->w_doto = 0;
+ curwp->w_flag |= WFMOVE;
+ } else
+ curwp->w_doto++;
+ }
+ return (TRUE);
+}
+
+gotoline(f, n) /* move to a particular line.
+ argument (n) must be a positive integer for
+ this to actually do anything */
+
+{
+ register int status; /* status return */
+ char arg[NSTRING]; /* buffer to hold argument */
+
+ /* get an argument if one doesnt exist */
+ if (f == FALSE) {
+ if ((status = mlreply("Line to GOTO: ", arg, NSTRING)) != TRUE) {
+ mlwrite("(Aborted)");
+ return(status);
+ }
+ n = atoi(arg);
+ }
+
+ if (n < 1) /* if a bogus argument...then leave */
+ return(FALSE);
+
+ /* first, we go to the start of the buffer */
+ curwp->w_dotp = lforw(curbp->b_linep);
+ curwp->w_doto = 0;
+ return(forwline(f, n-1));
+}
+
+/*
+ * Goto the beginning of the buffer. Massive adjustment of dot. This is
+ * considered to be hard motion; it really isn't if the original value of dot
+ * is the same as the new value of dot. Normally bound to "M-<".
+ */
+gotobob(f, n)
+{
+ curwp->w_dotp = lforw(curbp->b_linep);
+ curwp->w_doto = 0;
+ curwp->w_flag |= WFHARD;
+ return (TRUE);
+}
+
+/*
+ * Move to the end of the buffer. Dot is always put at the end of the file
+ * (ZJ). The standard screen code does most of the hard parts of update.
+ * Bound to "M->".
+ */
+gotoeob(f, n)
+{
+ curwp->w_dotp = curbp->b_linep;
+ curwp->w_doto = 0;
+ curwp->w_flag |= WFHARD;
+ return (TRUE);
+}
+
+/*
+ * Move forward by full lines. If the number of lines to move is less than
+ * zero, call the backward line function to actually do it. The last command
+ * controls how the goal column is set. Bound to "C-N". No errors are
+ * possible.
+ */
+forwline(f, n)
+{
+ register LINE *dlp;
+
+ if (n < 0)
+ return (backline(f, -n));
+
+ /* if we are on the last line as we start....fail the command */
+ if (curwp->w_dotp == curbp->b_linep)
+ return(FALSE);
+
+ /* if the last command was not note a line move,
+ reset the goal column */
+ if ((lastflag&CFCPCN) == 0)
+ curgoal = getccol(FALSE);
+
+ /* flag this command as a line move */
+ thisflag |= CFCPCN;
+
+ /* and move the point down */
+ dlp = curwp->w_dotp;
+ while (n-- && dlp!=curbp->b_linep)
+ dlp = lforw(dlp);
+
+ /* reseting the current position */
+ curwp->w_dotp = dlp;
+ curwp->w_doto = getgoal(dlp);
+ curwp->w_flag |= WFMOVE;
+ return (TRUE);
+}
+
+/*
+ * This function is like "forwline", but goes backwards. The scheme is exactly
+ * the same. Check for arguments that are less than zero and call your
+ * alternate. Figure out the new line and call "movedot" to perform the
+ * motion. No errors are possible. Bound to "C-P".
+ */
+backline(f, n)
+{
+ register LINE *dlp;
+
+ if (n < 0)
+ return (forwline(f, -n));
+
+
+ /* if we are on the last line as we start....fail the command */
+ if (lback(curwp->w_dotp) == curbp->b_linep)
+ return(FALSE);
+
+ /* if the last command was not note a line move,
+ reset the goal column */
+ if ((lastflag&CFCPCN) == 0)
+ curgoal = getccol(FALSE);
+
+ /* flag this command as a line move */
+ thisflag |= CFCPCN;
+
+ /* and move the point up */
+ dlp = curwp->w_dotp;
+ while (n-- && lback(dlp)!=curbp->b_linep)
+ dlp = lback(dlp);
+
+ /* reseting the current position */
+ curwp->w_dotp = dlp;
+ curwp->w_doto = getgoal(dlp);
+ curwp->w_flag |= WFMOVE;
+ return (TRUE);
+}
+
+#if WORDPRO
+gotobop(f, n) /* go back to the beginning of the current paragraph
+ here we look for a <NL><NL> or <NL><TAB> or <NL><SPACE>
+ combination to delimit the beginning of a paragraph */
+
+int f, n; /* default Flag & Numeric argument */
+
+{
+ register int suc; /* success of last backchar */
+
+ if (n < 0) /* the other way...*/
+ return(gotoeop(f, -n));
+
+ while (n-- > 0) { /* for each one asked for */
+
+ /* first scan back until we are in a word */
+ suc = backchar(FALSE, 1);
+ while (!inword() && suc)
+ suc = backchar(FALSE, 1);
+ curwp->w_doto = 0; /* and go to the B-O-Line */
+
+ /* and scan back until we hit a <NL><NL> or <NL><TAB>
+ or a <NL><SPACE> */
+ while (lback(curwp->w_dotp) != curbp->b_linep)
+ if (llength(curwp->w_dotp) != 0 &&
+#if PKCODE
+ ((justflag == TRUE) ||
+#endif
+ lgetc(curwp->w_dotp, curwp->w_doto) != TAB &&
+ lgetc(curwp->w_dotp, curwp->w_doto) != ' ')
+#if PKCODE
+ )
+#endif
+ curwp->w_dotp = lback(curwp->w_dotp);
+ else
+ break;
+
+ /* and then forward until we are in a word */
+ suc = forwchar(FALSE, 1);
+ while (suc && !inword())
+ suc = forwchar(FALSE, 1);
+ }
+ curwp->w_flag |= WFMOVE; /* force screen update */
+ return(TRUE);
+}
+
+gotoeop(f, n) /* go forword to the end of the current paragraph
+ here we look for a <NL><NL> or <NL><TAB> or <NL><SPACE>
+ combination to delimit the beginning of a paragraph */
+
+int f, n; /* default Flag & Numeric argument */
+
+{
+ register int suc; /* success of last backchar */
+
+ if (n < 0) /* the other way...*/
+ return(gotobop(f, -n));
+
+ while (n-- > 0) { /* for each one asked for */
+
+ /* first scan forward until we are in a word */
+ suc = forwchar(FALSE, 1);
+ while (!inword() && suc)
+ suc = forwchar(FALSE, 1);
+ curwp->w_doto = 0; /* and go to the B-O-Line */
+ if (suc) /* of next line if not at EOF */
+ curwp->w_dotp = lforw(curwp->w_dotp);
+
+ /* and scan forword until we hit a <NL><NL> or <NL><TAB>
+ or a <NL><SPACE> */
+ while (curwp->w_dotp != curbp->b_linep) {
+ if (llength(curwp->w_dotp) != 0 &&
+#if PKCODE
+ ((justflag == TRUE) ||
+#endif
+ lgetc(curwp->w_dotp, curwp->w_doto) != TAB &&
+ lgetc(curwp->w_dotp, curwp->w_doto) != ' ')
+#if PKCODE
+ )
+#endif
+ curwp->w_dotp = lforw(curwp->w_dotp);
+ else
+ break;
+ }
+
+ /* and then backward until we are in a word */
+ suc = backchar(FALSE, 1);
+ while (suc && !inword()) {
+ suc = backchar(FALSE, 1);
+ }
+ curwp->w_doto = llength(curwp->w_dotp); /* and to the EOL */
+ }
+ curwp->w_flag |= WFMOVE; /* force screen update */
+ return(TRUE);
+}
+#endif
+
+/*
+ * This routine, given a pointer to a LINE, and the current cursor goal
+ * column, return the best choice for the offset. The offset is returned.
+ * Used by "C-N" and "C-P".
+ */
+getgoal(dlp)
+register LINE *dlp;
+{
+ register int c;
+ register int col;
+ register int newcol;
+ register int dbo;
+
+ col = 0;
+ dbo = 0;
+ while (dbo != llength(dlp)) {
+ c = lgetc(dlp, dbo);
+ newcol = col;
+ if (c == '\t')
+ newcol |= tabmask;
+ else if (c<0x20 || c==0x7F)
+ ++newcol;
+ ++newcol;
+ if (newcol > curgoal)
+ break;
+ col = newcol;
+ ++dbo;
+ }
+ return (dbo);
+}
+
+/*
+ * Scroll forward by a specified number of lines, or by a full page if no
+ * argument. Bound to "C-V". The "2" in the arithmetic on the window size is
+ * the overlap; this value is the default overlap value in ITS EMACS. Because
+ * this zaps the top line in the display window, we have to do a hard update.
+ */
+forwpage(f, n)
+register int n;
+{
+ register LINE *lp;
+
+ if (f == FALSE) {
+#if SCROLLCODE
+ if (term.t_scroll != NULL)
+ if (overlap == 0)
+ n = curwp->w_ntrows / 3 * 2;
+ else
+ n = curwp->w_ntrows - overlap;
+ else
+#endif
+ n = curwp->w_ntrows - 2; /* Default scroll. */
+ if (n <= 0) /* Forget the overlap */
+ n = 1; /* if tiny window. */
+ } else if (n < 0)
+ return (backpage(f, -n));
+#if CVMVAS
+ else /* Convert from pages */
+ n *= curwp->w_ntrows; /* to lines. */
+#endif
+ lp = curwp->w_linep;
+ while (n-- && lp!=curbp->b_linep)
+ lp = lforw(lp);
+ curwp->w_linep = lp;
+ curwp->w_dotp = lp;
+ curwp->w_doto = 0;
+#if SCROLLCODE
+ curwp->w_flag |= WFHARD|WFKILLS;
+#else
+ curwp->w_flag |= WFHARD;
+#endif
+ return (TRUE);
+}
+
+/*
+ * This command is like "forwpage", but it goes backwards. The "2", like
+ * above, is the overlap between the two windows. The value is from the ITS
+ * EMACS manual. Bound to "M-V". We do a hard update for exactly the same
+ * reason.
+ */
+backpage(f, n)
+register int n;
+{
+ register LINE *lp;
+
+ if (f == FALSE) {
+#if SCROLLCODE
+ if (term.t_scroll != NULL)
+ if (overlap == 0)
+ n = curwp->w_ntrows / 3 * 2;
+ else
+ n = curwp->w_ntrows - overlap;
+ else
+#endif
+ n = curwp->w_ntrows - 2; /* Default scroll. */
+ if (n <= 0) /* Don't blow up if the */
+ n = 1; /* window is tiny. */
+ } else if (n < 0)
+ return (forwpage(f, -n));
+#if CVMVAS
+ else /* Convert from pages */
+ n *= curwp->w_ntrows; /* to lines. */
+#endif
+ lp = curwp->w_linep;
+ while (n-- && lback(lp)!=curbp->b_linep)
+ lp = lback(lp);
+ curwp->w_linep = lp;
+ curwp->w_dotp = lp;
+ curwp->w_doto = 0;
+#if SCROLLCODE
+ curwp->w_flag |= WFHARD|WFINS;
+#else
+ curwp->w_flag |= WFHARD;
+#endif
+ return (TRUE);
+}
+
+/*
+ * Set the mark in the current window to the value of "." in the window. No
+ * errors are possible. Bound to "M-.".
+ */
+setmark(f, n)
+{
+ curwp->w_markp = curwp->w_dotp;
+ curwp->w_marko = curwp->w_doto;
+ mlwrite("(Mark set)");
+ return (TRUE);
+}
+
+/*
+ * Swap the values of "." and "mark" in the current window. This is pretty
+ * easy, bacause all of the hard work gets done by the standard routine
+ * that moves the mark about. The only possible error is "no mark". Bound to
+ * "C-X C-X".
+ */
+swapmark(f, n)
+{
+ register LINE *odotp;
+ register int odoto;
+
+ if (curwp->w_markp == NULL) {
+ mlwrite("No mark in this window");
+ return (FALSE);
+ }
+ odotp = curwp->w_dotp;
+ odoto = curwp->w_doto;
+ curwp->w_dotp = curwp->w_markp;
+ curwp->w_doto = curwp->w_marko;
+ curwp->w_markp = odotp;
+ curwp->w_marko = odoto;
+ curwp->w_flag |= WFMOVE;
+ return (TRUE);
+}
diff --git a/bind.c b/bind.c
new file mode 100644
index 0000000..c12fc67
--- /dev/null
+++ b/bind.c
@@ -0,0 +1,708 @@
+/* BIND.C
+ *
+ * This file is for functions having to do with key bindings,
+ * descriptions, help commands and startup file.
+ *
+ * written 11-feb-86 by Daniel Lawrence
+ * modified by Petri Kutvonen
+ */
+
+#include <stdio.h>
+#include "estruct.h"
+#include "edef.h"
+#include "epath.h"
+
+extern int meta(), cex(), unarg(), ctrlg(); /* dummy prefix binding functions */
+
+help(f, n) /* give me some help!!!!
+ bring up a fake buffer and read the help file
+ into it with view mode */
+{
+ register WINDOW *wp; /* scaning pointer to windows */
+ register BUFFER *bp; /* buffer pointer to help */
+ char *fname; /* ptr to file returned by flook() */
+
+ /* first check if we are already here */
+ bp = bfind("emacs.hlp", FALSE, BFINVS);
+
+ if (bp == NULL) {
+ fname = flook(pathname[1], FALSE);
+ if (fname == NULL) {
+ mlwrite("(Help file is not online)");
+ return(FALSE);
+ }
+ }
+
+ /* split the current window to make room for the help stuff */
+ if (splitwind(FALSE, 1) == FALSE)
+ return(FALSE);
+
+ if (bp == NULL) {
+ /* and read the stuff in */
+ if (getfile(fname, FALSE) == FALSE)
+ return(FALSE);
+ } else
+ swbuffer(bp);
+
+ /* make this window in VIEW mode, update all mode lines */
+ curwp->w_bufp->b_mode |= MDVIEW;
+ curwp->w_bufp->b_flag |= BFINVS;
+ wp = wheadp;
+ while (wp != NULL) {
+ wp->w_flag |= WFMODE;
+ wp = wp->w_wndp;
+ }
+ return(TRUE);
+}
+
+deskey(f, n) /* describe the command for a certain key */
+
+{
+ register int c; /* key to describe */
+ register char *ptr; /* string pointer to scan output strings */
+ char outseq[NSTRING]; /* output buffer for command sequence */
+ int (*getbind())();
+
+ /* prompt the user to type us a key to describe */
+ mlwrite(": describe-key ");
+
+ /* get the command sequence to describe
+ change it to something we can print as well */
+ cmdstr(c = getckey(FALSE), &outseq[0]);
+
+ /* and dump it out */
+ ostring(outseq);
+ ostring(" ");
+
+ /* find the right ->function */
+ if ((ptr = getfname(getbind(c))) == NULL)
+ ptr = "Not Bound";
+
+ /* output the command sequence */
+ ostring(ptr);
+}
+
+/* bindtokey: add a new key to the key binding table */
+
+bindtokey(f, n)
+
+int f, n; /* command arguments [IGNORED] */
+
+{
+ register unsigned int c;/* command key to bind */
+ register int (*kfunc)();/* ptr to the requested function to bind to */
+ register KEYTAB *ktp; /* pointer into the command table */
+ register int found; /* matched command flag */
+ char outseq[80]; /* output buffer for keystroke sequence */
+ int (*getname())();
+
+ /* prompt the user to type in a key to bind */
+ mlwrite(": bind-to-key ");
+
+ /* get the function name to bind it to */
+ kfunc = getname();
+ if (kfunc == NULL) {
+ mlwrite("(No such function)");
+ return(FALSE);
+ }
+ ostring(" ");
+
+ /* get the command sequence to bind */
+ c = getckey((kfunc == meta) || (kfunc == cex) ||
+ (kfunc == unarg) || (kfunc == ctrlg));
+
+ /* change it to something we can print as well */
+ cmdstr(c, &outseq[0]);
+
+ /* and dump it out */
+ ostring(outseq);
+
+ /* if the function is a prefix key */
+ if (kfunc == meta || kfunc == cex ||
+ kfunc == unarg || kfunc == ctrlg) {
+
+ /* search for an existing binding for the prefix key */
+ ktp = &keytab[0];
+ found = FALSE;
+ while (ktp->k_fp != NULL) {
+ if (ktp->k_fp == kfunc)
+ unbindchar(ktp->k_code);
+ ++ktp;
+ }
+
+ /* reset the appropriate global prefix variable */
+ if (kfunc == meta)
+ metac = c;
+ if (kfunc == cex)
+ ctlxc = c;
+ if (kfunc == unarg)
+ reptc = c;
+ if (kfunc == ctrlg)
+ abortc = c;
+ }
+
+ /* search the table to see if it exists */
+ ktp = &keytab[0];
+ found = FALSE;
+ while (ktp->k_fp != NULL) {
+ if (ktp->k_code == c) {
+ found = TRUE;
+ break;
+ }
+ ++ktp;
+ }
+
+ if (found) { /* it exists, just change it then */
+ ktp->k_fp = kfunc;
+ } else { /* otherwise we need to add it to the end */
+ /* if we run out of binding room, bitch */
+ if (ktp >= &keytab[NBINDS]) {
+ mlwrite("Binding table FULL!");
+ return(FALSE);
+ }
+
+ ktp->k_code = c; /* add keycode */
+ ktp->k_fp = kfunc; /* and the function pointer */
+ ++ktp; /* and make sure the next is null */
+ ktp->k_code = 0;
+ ktp->k_fp = NULL;
+ }
+ return(TRUE);
+}
+
+/* unbindkey: delete a key from the key binding table */
+
+unbindkey(f, n)
+
+int f, n; /* command arguments [IGNORED] */
+
+{
+ register int c; /* command key to unbind */
+ char outseq[80]; /* output buffer for keystroke sequence */
+
+ /* prompt the user to type in a key to unbind */
+ mlwrite(": unbind-key ");
+
+ /* get the command sequence to unbind */
+ c = getckey(FALSE); /* get a command sequence */
+
+ /* change it to something we can print as well */
+ cmdstr(c, &outseq[0]);
+
+ /* and dump it out */
+ ostring(outseq);
+
+ /* if it isn't bound, bitch */
+ if (unbindchar(c) == FALSE) {
+ mlwrite("(Key not bound)");
+ return(FALSE);
+ }
+ return(TRUE);
+}
+
+unbindchar(c)
+
+int c; /* command key to unbind */
+
+{
+ register KEYTAB *ktp; /* pointer into the command table */
+ register KEYTAB *sktp; /* saved pointer into the command table */
+ register int found; /* matched command flag */
+
+ /* search the table to see if the key exists */
+ ktp = &keytab[0];
+ found = FALSE;
+ while (ktp->k_fp != NULL) {
+ if (ktp->k_code == c) {
+ found = TRUE;
+ break;
+ }
+ ++ktp;
+ }
+
+ /* if it isn't bound, bitch */
+ if (!found)
+ return(FALSE);
+
+ /* save the pointer and scan to the end of the table */
+ sktp = ktp;
+ while (ktp->k_fp != NULL)
+ ++ktp;
+ --ktp; /* backup to the last legit entry */
+
+ /* copy the last entry to the current one */
+ sktp->k_code = ktp->k_code;
+ sktp->k_fp = ktp->k_fp;
+
+ /* null out the last one */
+ ktp->k_code = 0;
+ ktp->k_fp = NULL;
+ return(TRUE);
+}
+
+desbind(f, n) /* describe bindings
+ bring up a fake buffer and list the key bindings
+ into it with view mode */
+
+#if APROP
+{
+ buildlist(TRUE, "");
+}
+
+apro(f, n) /* Apropos (List functions that match a substring) */
+
+{
+ char mstring[NSTRING]; /* string to match cmd names to */
+ int status; /* status return */
+
+ status = mlreply("Apropos string: ", mstring, NSTRING - 1);
+ if (status != TRUE)
+ return(status);
+
+ return(buildlist(FALSE, mstring));
+}
+
+buildlist(type, mstring) /* build a binding list (limited or full) */
+
+int type; /* true = full list, false = partial list */
+char *mstring; /* match string if a partial list */
+
+#endif
+{
+ register WINDOW *wp; /* scanning pointer to windows */
+ register KEYTAB *ktp; /* pointer into the command table */
+ register NBIND *nptr; /* pointer into the name binding table */
+ register BUFFER *bp; /* buffer to put binding list into */
+ char *strp; /* pointer int string to send */
+ int cpos; /* current position to use in outseq */
+ char outseq[80]; /* output buffer for keystroke sequence */
+
+ /* split the current window to make room for the binding list */
+ if (splitwind(FALSE, 1) == FALSE)
+ return(FALSE);
+
+ /* and get a buffer for it */
+ bp = bfind("*Binding list*", TRUE, 0);
+ if (bp == NULL || bclear(bp) == FALSE) {
+ mlwrite("Can not display binding list");
+ return(FALSE);
+ }
+
+ /* let us know this is in progress */
+ mlwrite("(Building binding list)");
+
+ /* disconect the current buffer */
+ if (--curbp->b_nwnd == 0) { /* Last use. */
+ curbp->b_dotp = curwp->w_dotp;
+ curbp->b_doto = curwp->w_doto;
+ curbp->b_markp = curwp->w_markp;
+ curbp->b_marko = curwp->w_marko;
+ }
+
+ /* connect the current window to this buffer */
+ curbp = bp; /* make this buffer current in current window */
+ bp->b_mode = 0; /* no modes active in binding list */
+ bp->b_nwnd++; /* mark us as more in use */
+ wp = curwp;
+ wp->w_bufp = bp;
+ wp->w_linep = bp->b_linep;
+ wp->w_flag = WFHARD|WFFORCE;
+ wp->w_dotp = bp->b_dotp;
+ wp->w_doto = bp->b_doto;
+ wp->w_markp = NULL;
+ wp->w_marko = 0;
+
+ /* build the contents of this window, inserting it line by line */
+ nptr = &names[0];
+ while (nptr->n_func != NULL) {
+
+ /* add in the command name */
+ strcpy(outseq, nptr->n_name);
+ cpos = strlen(outseq);
+
+#if APROP
+ /* if we are executing an apropos command..... */
+ if (type == FALSE &&
+ /* and current string doesn't include the search string */
+ strinc(outseq, mstring) == FALSE)
+ goto fail;
+#endif
+ /* search down any keys bound to this */
+ ktp = &keytab[0];
+ while (ktp->k_fp != NULL) {
+ if (ktp->k_fp == nptr->n_func) {
+ /* padd out some spaces */
+ while (cpos < 28)
+ outseq[cpos++] = ' ';
+
+ /* add in the command sequence */
+ cmdstr(ktp->k_code, &outseq[cpos]);
+ strcat(outseq, "\n");
+
+ /* and add it as a line into the buffer */
+ if (linstr(outseq) != TRUE)
+ return(FALSE);
+
+ cpos = 0; /* and clear the line */
+ }
+ ++ktp;
+ }
+
+ /* if no key was bound, we need to dump it anyway */
+ if (cpos > 0) {
+ outseq[cpos++] = '\n';
+ outseq[cpos] = 0;
+ if (linstr(outseq) != TRUE)
+ return(FALSE);
+ }
+
+fail: /* and on to the next name */
+ ++nptr;
+ }
+
+ curwp->w_bufp->b_mode |= MDVIEW;/* put this buffer view mode */
+ curbp->b_flag &= ~BFCHG; /* don't flag this as a change */
+ wp->w_dotp = lforw(bp->b_linep);/* back to the beginning */
+ wp->w_doto = 0;
+ wp = wheadp; /* and update ALL mode lines */
+ while (wp != NULL) {
+ wp->w_flag |= WFMODE;
+ wp = wp->w_wndp;
+ }
+ mlwrite(""); /* clear the mode line */
+ return(TRUE);
+}
+
+#if APROP
+strinc(source, sub) /* does source include sub? */
+
+char *source; /* string to search in */
+char *sub; /* substring to look for */
+
+{
+ char *sp; /* ptr into source */
+ char *nxtsp; /* next ptr into source */
+ char *tp; /* ptr into substring */
+
+ /* for each character in the source string */
+ sp = source;
+ while (*sp) {
+ tp = sub;
+ nxtsp = sp;
+
+ /* is the substring here? */
+ while (*tp) {
+ if (*nxtsp++ != *tp)
+ break;
+ else
+ tp++;
+ }
+
+ /* yes, return a success */
+ if (*tp == 0)
+ return(TRUE);
+
+ /* no, onward */
+ sp++;
+ }
+ return(FALSE);
+}
+#endif
+
+/* get a command key sequence from the keyboard */
+
+unsigned int getckey(mflag)
+
+int mflag; /* going for a meta sequence? */
+
+{
+ register unsigned int c; /* character fetched */
+ char tok[NSTRING]; /* command incoming */
+
+ /* check to see if we are executing a command line */
+ if (clexec) {
+ macarg(tok); /* get the next token */
+ return(stock(tok));
+ }
+
+ /* or the normal way */
+ if (mflag)
+ c = get1key();
+ else
+ c = getcmd();
+ return(c);
+}
+
+/* execute the startup file */
+
+startup(sfname)
+
+char *sfname; /* name of startup file (null if default) */
+
+{
+ char *fname; /* resulting file name to execute */
+
+ /* look up the startup file */
+ if (*sfname != 0)
+ fname = flook(sfname, TRUE);
+ else
+ fname = flook(pathname[0], TRUE);
+
+ /* if it isn't around, don't sweat it */
+ if (fname == NULL)
+ return(TRUE);
+
+ /* otherwise, execute the sucker */
+ return(dofile(fname));
+}
+
+/* Look up the existance of a file along the normal or PATH
+ environment variable. Look first in the HOME directory if
+ asked and possible
+*/
+
+char *flook(fname, hflag)
+
+char *fname; /* base file name to search for */
+int hflag; /* Look in the HOME environment variable first? */
+
+{
+ register char *home; /* path to home directory */
+ register char *path; /* environmental PATH variable */
+ register char *sp; /* pointer into path spec */
+ register int i; /* index */
+ static char fspec[NSTRING]; /* full path spec to search */
+ char *getenv();
+
+#if ENVFUNC
+
+ if (hflag) {
+ home = getenv("HOME");
+ if (home != NULL) {
+ /* build home dir file spec */
+ strcpy(fspec, home);
+ strcat(fspec, "/");
+ strcat(fspec, fname);
+
+ /* and try it out */
+ if (ffropen(fspec) == FIOSUC) {
+ ffclose();
+ return(fspec);
+ }
+ }
+ }
+#endif
+
+ /* always try the current directory first */
+ if (ffropen(fname) == FIOSUC) {
+ ffclose();
+ return(fname);
+ }
+
+#if ENVFUNC
+ /* get the PATH variable */
+ path = getenv("PATH");
+ if (path != NULL)
+ while (*path) {
+
+ /* build next possible file spec */
+ sp = fspec;
+ while (*path && (*path != PATHCHR))
+ *sp++ = *path++;
+
+ /* add a terminating dir separator if we need it */
+ if (sp != fspec)
+ *sp++ = '/';
+ *sp = 0;
+ strcat(fspec, fname);
+
+ /* and try it out */
+ if (ffropen(fspec) == FIOSUC) {
+ ffclose();
+ return(fspec);
+ }
+
+ if (*path == PATHCHR)
+ ++path;
+ }
+#endif
+
+ /* look it up via the old table method */
+ for (i=2; i < NPNAMES; i++) {
+ strcpy(fspec, pathname[i]);
+ strcat(fspec, fname);
+
+ /* and try it out */
+ if (ffropen(fspec) == FIOSUC) {
+ ffclose();
+ return(fspec);
+ }
+ }
+
+ return(NULL); /* no such luck */
+}
+
+cmdstr(c, seq) /* change a key command to a string we can print out */
+
+int c; /* sequence to translate */
+char *seq; /* destination string for sequence */
+
+{
+ char *ptr; /* pointer into current position in sequence */
+
+ ptr = seq;
+
+ /* apply meta sequence if needed */
+ if (c & META) {
+ *ptr++ = 'M';
+ *ptr++ = '-';
+ }
+
+ /* apply ^X sequence if needed */
+ if (c & CTLX) {
+ *ptr++ = '^';
+ *ptr++ = 'X';
+ }
+
+ /* apply SPEC sequence if needed */
+ if (c & SPEC) {
+ *ptr++ = 'F';
+ *ptr++ = 'N';
+ }
+
+ /* apply control sequence if needed */
+ if (c & CONTROL) {
+ *ptr++ = '^';
+ }
+
+ /* and output the final sequence */
+
+ *ptr++ = c & 255; /* strip the prefixes */
+
+ *ptr = 0; /* terminate the string */
+}
+
+/* This function looks a key binding up in the binding table */
+
+int (*getbind(c))()
+
+int c; /* key to find what is bound to it */
+
+{
+ register KEYTAB *ktp;
+
+ ktp = &keytab[0]; /* Look in key table. */
+ while (ktp->k_fp != NULL) {
+ if (ktp->k_code == c)
+ return(ktp->k_fp);
+ ++ktp;
+ }
+
+ /* no such binding */
+ return(NULL);
+}
+
+/* getfname: This function takes a ptr to function and gets the name
+ associated with it
+*/
+
+char *getfname(func)
+
+int (*func)(); /* ptr to the requested function to bind to */
+
+{
+ register NBIND *nptr; /* pointer into the name binding table */
+
+ /* skim through the table, looking for a match */
+ nptr = &names[0];
+ while (nptr->n_func != NULL) {
+ if (nptr->n_func == func)
+ return(nptr->n_name);
+ ++nptr;
+ }
+ return(NULL);
+}
+
+int (*fncmatch(fname))() /* match fname to a function in the names table
+ and return any match or NULL if none */
+
+char *fname; /* name to attempt to match */
+
+{
+ register NBIND *ffp; /* pointer to entry in name binding table */
+
+ /* scan through the table, returning any match */
+ ffp = &names[0];
+ while (ffp->n_func != NULL) {
+ if (strcmp(fname, ffp->n_name) == 0)
+ return(ffp->n_func);
+ ++ffp;
+ }
+ return(NULL);
+}
+
+/* stock: String key name TO Command Key */
+
+unsigned int stock(keyname)
+
+char *keyname; /* name of key to translate to Command key form */
+
+{
+ register unsigned int c; /* key sequence to return */
+
+ /* parse it up */
+ c = 0;
+
+ /* first, the META prefix */
+ if (*keyname == 'M' && *(keyname+1) == '-') {
+ c = META;
+ keyname += 2;
+ }
+
+ /* next the function prefix */
+ if (*keyname == 'F' && *(keyname+1) == 'N') {
+ c |= SPEC;
+ keyname += 2;
+ }
+
+ /* control-x as well... (but not with FN) */
+ if (*keyname == '^' && *(keyname+1) == 'X'&& !(c & SPEC)) {
+ c |= CTLX;
+ keyname += 2;
+ }
+
+ /* a control char? */
+ if (*keyname == '^' && *(keyname+1) != 0) {
+ c |= CONTROL;
+ ++keyname;
+ }
+ if (*keyname < 32) {
+ c |= CONTROL;
+ *keyname += 'A';
+ }
+
+
+ /* make sure we are not lower case (not with function keys)*/
+ if (*keyname >= 'a' && *keyname <= 'z' && !(c & SPEC))
+ *keyname -= 32;
+
+ /* the final sequence... */
+ c |= *keyname;
+ return(c);
+}
+
+char *transbind(skey) /* string key name to binding name.... */
+
+char *skey; /* name of keey to get binding for */
+
+{
+ char *bindname;
+ unsigned int stock();
+ int (*getbind())();
+
+ bindname = getfname(getbind(stock(skey)));
+ if (bindname == NULL)
+ bindname = "ERROR";
+
+ return(bindname);
+}
diff --git a/buffer.c b/buffer.c
new file mode 100644
index 0000000..93daa25
--- /dev/null
+++ b/buffer.c
@@ -0,0 +1,544 @@
+/* BUFFER.C
+ *
+ * Buffer management.
+ * Some of the functions are internal,
+ * and some are actually attached to user
+ * keys. Like everyone else, they set hints
+ * for the display system
+ *
+ * modified by Petri Kutvonen
+ */
+
+#include <stdio.h>
+#include "estruct.h"
+#include "edef.h"
+
+/*
+ * Attach a buffer to a window. The
+ * values of dot and mark come from the buffer
+ * if the use count is 0. Otherwise, they come
+ * from some other window.
+ */
+usebuffer(f, n)
+{
+ register BUFFER *bp;
+ register int s;
+ char bufn[NBUFN];
+
+ if ((s=mlreply("Use buffer: ", bufn, NBUFN)) != TRUE)
+ return (s);
+ if ((bp=bfind(bufn, TRUE, 0)) == NULL)
+ return (FALSE);
+ return(swbuffer(bp));
+}
+
+nextbuffer(f, n) /* switch to the next buffer in the buffer list */
+
+int f, n; /* default flag, numeric argument */
+{
+ register BUFFER *bp; /* eligable buffer to switch to*/
+ register BUFFER *bbp; /* eligable buffer to switch to*/
+
+ /* make sure the arg is legit */
+ if (f == FALSE)
+ n = 1;
+ if (n < 1)
+ return(FALSE);
+
+ bbp = curbp;
+ while (n-- > 0) {
+ /* advance to the next buffer */
+ bp = bbp->b_bufp;
+
+ /* cycle through the buffers to find an eligable one */
+ while (bp == NULL || bp->b_flag & BFINVS) {
+ if (bp == NULL)
+ bp = bheadp;
+ else
+ bp = bp->b_bufp;
+
+ /* don't get caught in an infinite loop! */
+ if (bp == bbp)
+ return(FALSE);
+
+ }
+
+ bbp = bp;
+ }
+
+ return(swbuffer(bp));
+}
+
+swbuffer(bp) /* make buffer BP current */
+
+BUFFER *bp;
+
+{
+ register WINDOW *wp;
+
+ if (--curbp->b_nwnd == 0) { /* Last use. */
+ curbp->b_dotp = curwp->w_dotp;
+ curbp->b_doto = curwp->w_doto;
+ curbp->b_markp = curwp->w_markp;
+ curbp->b_marko = curwp->w_marko;
+ }
+ curbp = bp; /* Switch. */
+ if (curbp->b_active != TRUE) { /* buffer not active yet*/
+ /* read it in and activate it */
+ readin(curbp->b_fname, TRUE);
+ curbp->b_dotp = lforw(curbp->b_linep);
+ curbp->b_doto = 0;
+ curbp->b_active = TRUE;
+ curbp->b_mode |= gmode; /* P.K. */
+ }
+ curwp->w_bufp = bp;
+ curwp->w_linep = bp->b_linep; /* For macros, ignored. */
+ curwp->w_flag |= WFMODE|WFFORCE|WFHARD; /* Quite nasty. */
+ if (bp->b_nwnd++ == 0) { /* First use. */
+ curwp->w_dotp = bp->b_dotp;
+ curwp->w_doto = bp->b_doto;
+ curwp->w_markp = bp->b_markp;
+ curwp->w_marko = bp->b_marko;
+ cknewwindow();
+ return (TRUE);
+ }
+ wp = wheadp; /* Look for old. */
+ while (wp != NULL) {
+ if (wp!=curwp && wp->w_bufp==bp) {
+ curwp->w_dotp = wp->w_dotp;
+ curwp->w_doto = wp->w_doto;
+ curwp->w_markp = wp->w_markp;
+ curwp->w_marko = wp->w_marko;
+ break;
+ }
+ wp = wp->w_wndp;
+ }
+ cknewwindow();
+ return (TRUE);
+}
+
+/*
+ * Dispose of a buffer, by name.
+ * Ask for the name. Look it up (don't get too
+ * upset if it isn't there at all!). Get quite upset
+ * if the buffer is being displayed. Clear the buffer (ask
+ * if the buffer has been changed). Then free the header
+ * line and the buffer header. Bound to "C-X K".
+ */
+killbuffer(f, n)
+
+{
+ register BUFFER *bp;
+ register int s;
+ char bufn[NBUFN];
+
+ if ((s=mlreply("Kill buffer: ", bufn, NBUFN)) != TRUE)
+ return(s);
+ if ((bp=bfind(bufn, FALSE, 0)) == NULL) /* Easy if unknown. */
+ return (TRUE);
+ if(bp->b_flag & BFINVS) /* Deal with special buffers */
+ return (TRUE); /* by doing nothing. */
+ return(zotbuf(bp));
+}
+
+zotbuf(bp) /* kill the buffer pointed to by bp */
+
+register BUFFER *bp;
+
+{
+ register BUFFER *bp1;
+ register BUFFER *bp2;
+ register int s;
+
+ if (bp->b_nwnd != 0) { /* Error if on screen. */
+ mlwrite("Buffer is being displayed");
+ return (FALSE);
+ }
+ if ((s=bclear(bp)) != TRUE) /* Blow text away. */
+ return (s);
+ free((char *) bp->b_linep); /* Release header line. */
+ bp1 = NULL; /* Find the header. */
+ bp2 = bheadp;
+ while (bp2 != bp) {
+ bp1 = bp2;
+ bp2 = bp2->b_bufp;
+ }
+ bp2 = bp2->b_bufp; /* Next one in chain. */
+ if (bp1 == NULL) /* Unlink it. */
+ bheadp = bp2;
+ else
+ bp1->b_bufp = bp2;
+ free((char *) bp); /* Release buffer block */
+ return (TRUE);
+}
+
+namebuffer(f,n) /* Rename the current buffer */
+
+int f, n; /* default Flag & Numeric arg */
+
+{
+ register BUFFER *bp; /* pointer to scan through all buffers */
+ char bufn[NBUFN]; /* buffer to hold buffer name */
+
+ /* prompt for and get the new buffer name */
+ask: if (mlreply("Change buffer name to: ", bufn, NBUFN) != TRUE)
+ return(FALSE);
+
+ /* and check for duplicates */
+ bp = bheadp;
+ while (bp != NULL) {
+ if (bp != curbp) {
+ /* if the names the same */
+ if (strcmp(bufn, bp->b_bname) == 0)
+ goto ask; /* try again */
+ }
+ bp = bp->b_bufp; /* onward */
+ }
+
+ strcpy(curbp->b_bname, bufn); /* copy buffer name to structure */
+ curwp->w_flag |= WFMODE; /* make mode line replot */
+ mlerase();
+ return(TRUE);
+}
+
+/*
+ List all of the active buffers. First update the special
+ buffer that holds the list. Next make sure at least 1
+ window is displaying the buffer list, splitting the screen
+ if this is what it takes. Lastly, repaint all of the
+ windows that are displaying the list. Bound to "C-X C-B".
+ A numeric argument forces it to list invisable buffers as
+ well.
+*/
+
+listbuffers(f, n)
+{
+ register WINDOW *wp;
+ register BUFFER *bp;
+ register int s;
+
+ if ((s=makelist(f)) != TRUE)
+ return (s);
+ if (blistp->b_nwnd == 0) { /* Not on screen yet. */
+ if ((wp=wpopup()) == NULL)
+ return (FALSE);
+ bp = wp->w_bufp;
+ if (--bp->b_nwnd == 0) {
+ bp->b_dotp = wp->w_dotp;
+ bp->b_doto = wp->w_doto;
+ bp->b_markp = wp->w_markp;
+ bp->b_marko = wp->w_marko;
+ }
+ wp->w_bufp = blistp;
+ ++blistp->b_nwnd;
+ }
+ wp = wheadp;
+ while (wp != NULL) {
+ if (wp->w_bufp == blistp) {
+ wp->w_linep = lforw(blistp->b_linep);
+ wp->w_dotp = lforw(blistp->b_linep);
+ wp->w_doto = 0;
+ wp->w_markp = NULL;
+ wp->w_marko = 0;
+ wp->w_flag |= WFMODE|WFHARD;
+ }
+ wp = wp->w_wndp;
+ }
+ return (TRUE);
+}
+
+/*
+ * This routine rebuilds the
+ * text in the special secret buffer
+ * that holds the buffer list. It is called
+ * by the list buffers command. Return TRUE
+ * if everything works. Return FALSE if there
+ * is an error (if there is no memory). Iflag
+ * indecates weather to list hidden buffers.
+ */
+#define MAXLINE MAXCOL
+makelist(iflag)
+
+int iflag; /* list hidden buffer flag */
+
+{
+ register char *cp1;
+ register char *cp2;
+ register int c;
+ register BUFFER *bp;
+ register LINE *lp;
+ register int s;
+ register int i;
+ long nbytes; /* # of bytes in current buffer */
+ char b[7+1];
+ char line[MAXLINE];
+
+ blistp->b_flag &= ~BFCHG; /* Don't complain! */
+ if ((s=bclear(blistp)) != TRUE) /* Blow old text away */
+ return (s);
+ strcpy(blistp->b_fname, "");
+ if (addline("ACT MODES Size Buffer File") == FALSE
+ || addline("--- ----- ---- ------ ----") == FALSE)
+ return (FALSE);
+ bp = bheadp; /* For all buffers */
+
+ /* build line to report global mode settings */
+ cp1 = &line[0];
+ *cp1++ = ' ';
+ *cp1++ = ' ';
+ *cp1++ = ' ';
+ *cp1++ = ' ';
+
+ /* output the mode codes */
+ for (i = 0; i < NUMMODES; i++)
+ if (gmode & (1 << i))
+ *cp1++ = modecode[i];
+ else
+ *cp1++ = '.';
+ strcpy(cp1, " Global Modes");
+ if (addline(line) == FALSE)
+ return(FALSE);
+
+ /* output the list of buffers */
+ while (bp != NULL) {
+ /* skip invisable buffers if iflag is false */
+ if (((bp->b_flag&BFINVS) != 0) && (iflag != TRUE)) {
+ bp = bp->b_bufp;
+ continue;
+ }
+ cp1 = &line[0]; /* Start at left edge */
+
+ /* output status of ACTIVE flag (has the file been read in? */
+ if (bp->b_active == TRUE) /* "@" if activated */
+ *cp1++ = '@';
+ else
+ *cp1++ = ' ';
+
+ /* output status of changed flag */
+ if ((bp->b_flag&BFCHG) != 0) /* "*" if changed */
+ *cp1++ = '*';
+ else
+ *cp1++ = ' ';
+
+ /* report if the file is truncated */
+ if ((bp->b_flag&BFTRUNC) != 0)
+ *cp1++ = '#';
+ else
+ *cp1++ = ' ';
+
+ *cp1++ = ' '; /* space */
+
+ /* output the mode codes */
+ for (i = 0; i < NUMMODES; i++) {
+ if (bp->b_mode & (1 << i))
+ *cp1++ = modecode[i];
+ else
+ *cp1++ = '.';
+ }
+ *cp1++ = ' '; /* Gap. */
+ nbytes = 0L; /* Count bytes in buf. */
+ lp = lforw(bp->b_linep);
+ while (lp != bp->b_linep) {
+ nbytes += (long)llength(lp)+1L;
+ lp = lforw(lp);
+ }
+ ltoa(b, 7, nbytes); /* 6 digit buffer size. */
+ cp2 = &b[0];
+ while ((c = *cp2++) != 0)
+ *cp1++ = c;
+ *cp1++ = ' '; /* Gap. */
+ cp2 = &bp->b_bname[0]; /* Buffer name */
+ while ((c = *cp2++) != 0)
+ *cp1++ = c;
+ cp2 = &bp->b_fname[0]; /* File name */
+ if (*cp2 != 0) {
+ while (cp1 < &line[3+1+5+1+6+4+NBUFN])
+ *cp1++ = ' ';
+ while ((c = *cp2++) != 0) {
+ if (cp1 < &line[MAXLINE-1])
+ *cp1++ = c;
+ }
+ }
+ *cp1 = 0; /* Add to the buffer. */
+ if (addline(line) == FALSE)
+ return (FALSE);
+ bp = bp->b_bufp;
+ }
+ return (TRUE); /* All done */
+}
+
+ltoa(buf, width, num)
+
+char buf[];
+int width;
+long num;
+
+{
+ buf[width] = 0; /* End of string. */
+ while (num >= 10) { /* Conditional digits. */
+ buf[--width] = (int)(num%10L) + '0';
+ num /= 10L;
+ }
+ buf[--width] = (int)num + '0'; /* Always 1 digit. */
+ while (width != 0) /* Pad with blanks. */
+ buf[--width] = ' ';
+}
+
+/*
+ * The argument "text" points to
+ * a string. Append this line to the
+ * buffer list buffer. Handcraft the EOL
+ * on the end. Return TRUE if it worked and
+ * FALSE if you ran out of room.
+ */
+addline(text)
+char *text;
+{
+ register LINE *lp;
+ register int i;
+ register int ntext;
+
+ ntext = strlen(text);
+ if ((lp=lalloc(ntext)) == NULL)
+ return (FALSE);
+ for (i=0; i<ntext; ++i)
+ lputc(lp, i, text[i]);
+ blistp->b_linep->l_bp->l_fp = lp; /* Hook onto the end */
+ lp->l_bp = blistp->b_linep->l_bp;
+ blistp->b_linep->l_bp = lp;
+ lp->l_fp = blistp->b_linep;
+ if (blistp->b_dotp == blistp->b_linep) /* If "." is at the end */
+ blistp->b_dotp = lp; /* move it to new line */
+ return (TRUE);
+}
+
+/*
+ * Look through the list of
+ * buffers. Return TRUE if there
+ * are any changed buffers. Buffers
+ * that hold magic internal stuff are
+ * not considered; who cares if the
+ * list of buffer names is hacked.
+ * Return FALSE if no buffers
+ * have been changed.
+ */
+anycb()
+{
+ register BUFFER *bp;
+
+ bp = bheadp;
+ while (bp != NULL) {
+ if ((bp->b_flag&BFINVS)==0 && (bp->b_flag&BFCHG)!=0)
+ return (TRUE);
+ bp = bp->b_bufp;
+ }
+ return (FALSE);
+}
+
+/*
+ * Find a buffer, by name. Return a pointer
+ * to the BUFFER structure associated with it.
+ * If the buffer is not found
+ * and the "cflag" is TRUE, create it. The "bflag" is
+ * the settings for the flags in in buffer.
+ */
+BUFFER *
+bfind(bname, cflag, bflag)
+register char *bname;
+{
+ register BUFFER *bp;
+ register BUFFER *sb; /* buffer to insert after */
+ register LINE *lp;
+ char *malloc();
+
+ bp = bheadp;
+ while (bp != NULL) {
+ if (strcmp(bname, bp->b_bname) == 0)
+ return (bp);
+ bp = bp->b_bufp;
+ }
+ if (cflag != FALSE) {
+ if ((bp=(BUFFER *)malloc(sizeof(BUFFER))) == NULL)
+ return (NULL);
+ if ((lp=lalloc(0)) == NULL) {
+ free((char *) bp);
+ return (NULL);
+ }
+ /* find the place in the list to insert this buffer */
+ if (bheadp == NULL || strcmp(bheadp->b_bname, bname) > 0) {
+ /* insert at the beginning */
+ bp->b_bufp = bheadp;
+ bheadp = bp;
+ } else {
+ sb = bheadp;
+ while (sb->b_bufp != NULL) {
+ if (strcmp(sb->b_bufp->b_bname, bname) > 0)
+ break;
+ sb = sb->b_bufp;
+ }
+
+ /* and insert it */
+ bp->b_bufp = sb->b_bufp;
+ sb->b_bufp = bp;
+ }
+
+ /* and set up the other buffer fields */
+ bp->b_active = TRUE;
+ bp->b_dotp = lp;
+ bp->b_doto = 0;
+ bp->b_markp = NULL;
+ bp->b_marko = 0;
+ bp->b_flag = bflag;
+ bp->b_mode = gmode;
+ bp->b_nwnd = 0;
+ bp->b_linep = lp;
+ strcpy(bp->b_fname, "");
+ strcpy(bp->b_bname, bname);
+#if CRYPT
+ bp->b_key[0] = 0;
+#endif
+ lp->l_fp = lp;
+ lp->l_bp = lp;
+ }
+ return (bp);
+}
+
+/*
+ * This routine blows away all of the text
+ * in a buffer. If the buffer is marked as changed
+ * then we ask if it is ok to blow it away; this is
+ * to save the user the grief of losing text. The
+ * window chain is nearly always wrong if this gets
+ * called; the caller must arrange for the updates
+ * that are required. Return TRUE if everything
+ * looks good.
+ */
+bclear(bp)
+register BUFFER *bp;
+{
+ register LINE *lp;
+ register int s;
+
+ if ((bp->b_flag&BFINVS) == 0 /* Not scratch buffer. */
+ && (bp->b_flag&BFCHG) != 0 /* Something changed */
+ && (s=mlyesno("Discard changes")) != TRUE)
+ return (s);
+ bp->b_flag &= ~BFCHG; /* Not changed */
+ while ((lp=lforw(bp->b_linep)) != bp->b_linep)
+ lfree(lp);
+ bp->b_dotp = bp->b_linep; /* Fix "." */
+ bp->b_doto = 0;
+ bp->b_markp = NULL; /* Invalidate "mark" */
+ bp->b_marko = 0;
+ return (TRUE);
+}
+
+unmark(f, n) /* unmark the current buffers change flag */
+
+int f, n; /* unused command arguments */
+
+{
+ curbp->b_flag &= ~BFCHG;
+ curwp->w_flag |= WFMODE;
+ return(TRUE);
+}
diff --git a/crypt.c b/crypt.c
new file mode 100644
index 0000000..ffd27dc
--- /dev/null
+++ b/crypt.c
@@ -0,0 +1,221 @@
+/* CRYPT.C
+ *
+ * Encryption routines
+ *
+ * written by Dana Hoggatt and Daniel Lawrence
+ */
+
+#include <stdio.h>
+#include "estruct.h"
+#include "edef.h"
+
+#if CRYPT
+
+static int mod95();
+
+setkey(f, n) /* reset encryption key of current buffer */
+
+int f; /* default flag */
+int n; /* numeric argument */
+
+{
+ register int status; /* return status */
+ int odisinp; /* original vlaue of disinp */
+ char key[NPAT]; /* new encryption string */
+
+ /* turn command input echo off */
+ odisinp = disinp;
+ disinp = FALSE;
+
+ /* get the string to use as an encrytion string */
+ status = mlreply("Encryption String: ", key, NPAT - 1);
+ disinp = odisinp;
+ if (status != TRUE)
+ return(status);
+
+ /* and encrypt it */
+ crypt((char *)NULL, 0);
+ crypt(key, strlen(key));
+
+ /* and save it off */
+ strcpy(curbp->b_key, key);
+ mlwrite(" "); /* clear it off the bottom line */
+ return(TRUE);
+}
+
+/**********
+ *
+ * crypt - in place encryption/decryption of a buffer
+ *
+ * (C) Copyright 1986, Dana L. Hoggatt
+ * 1216, Beck Lane, Lafayette, IN
+ *
+ * When consulting directly with the author of this routine,
+ * please refer to this routine as the "DLH-POLY-86-B CIPHER".
+ *
+ * This routine was written for Dan Lawrence, for use in V3.8 of
+ * MicroEMACS, a public domain text/program editor.
+ *
+ * I kept the following goals in mind when preparing this function:
+ *
+ * 1. All printable characters were to be encrypted back
+ * into the printable range, control characters and
+ * high-bit characters were to remain unaffected. this
+ * way, encrypted would still be just as cheap to
+ * transmit down a 7-bit data path as they were before.
+ *
+ * 2. The encryption had to be portable. The encrypted
+ * file from one computer should be able to be decrypted
+ * on another computer.
+ *
+ * 3. The encryption had to be inexpensive, both in terms
+ * of speed and space.
+ *
+ * 4. The system needed to be secure against all but the
+ * most determined of attackers.
+ *
+ * For encryption of a block of data, one calls crypt passing
+ * a pointer to the data block and its length. The data block is
+ * encrypted in place, that is, the encrypted output overwrites
+ * the input. Decryption is totally isomorphic, and is performed
+ * in the same manner by the same routine.
+ *
+ * Before using this routine for encrypting data, you are expected
+ * to specify an encryption key. This key is an arbitrary string,
+ * to be supplied by the user. To set the key takes two calls to
+ * crypt(). First, you call
+ *
+ * crypt(NULL, vector)
+ *
+ * This resets all internal control information. Typically (and
+ * specifically in the case on MICRO-emacs) you would use a "vector"
+ * of 0. Other values can be used to customize your editor to be
+ * "incompatable" with the normally distributed version. For
+ * this purpose, the best results will be obtained by avoiding
+ * multiples of 95.
+ *
+ * Then, you "encrypt" your password by calling
+ *
+ * crypt(pass, strlen(pass))
+ *
+ * where "pass" is your password string. Crypt() will destroy
+ * the original copy of the password (it becomes encrypted),
+ * which is good. You do not want someone on a multiuser system
+ * to peruse your memory space and bump into your password.
+ * Still, it is a better idea to erase the password buffer to
+ * defeat memory perusal by a more technical snooper.
+ *
+ * For the interest of cryptologists, at the heart of this
+ * function is a Beaufort Cipher. The cipher alphabet is the
+ * range of printable characters (' ' to '~'), all "control"
+ * and "high-bit" characters are left unaltered.
+ *
+ * The key is a variant autokey, derived from a wieghted sum
+ * of all the previous clear text and cipher text. A counter
+ * is used as salt to obiterate any simple cyclic behavior
+ * from the clear text, and key feedback is used to assure
+ * that the entire message is based on the original key,
+ * preventing attacks on the last part of the message as if
+ * it were a pure autokey system.
+ *
+ * Overall security of encrypted data depends upon three
+ * factors: the fundamental cryptographic system must be
+ * difficult to compromise; exhaustive searching of the key
+ * space must be computationally expensive; keys and plaintext
+ * must remain out of sight. This system satisfies this set
+ * of conditions to within the degree desired for MicroEMACS.
+ *
+ * Though direct methods of attack (against systems such as
+ * this) do exist, they are not well known and will consume
+ * considerable amounts of computing time. An exhaustive
+ * search requires over a billion investigations, on average.
+ *
+ * The choice, entry, storage, manipulation, alteration,
+ * protection and security of the keys themselves are the
+ * responsiblity of the user.
+ *
+ **********/
+
+crypt(bptr, len)
+register char *bptr; /* buffer of characters to be encrypted */
+register unsigned len; /* number of characters in the buffer */
+{
+ register int cc; /* current character being considered */
+
+ static long key = 0; /* 29 bit encipherment key */
+ static int salt = 0; /* salt to spice up key with */
+
+ if (!bptr) { /* is there anything here to encrypt? */
+ key = len; /* set the new key */
+ salt = len; /* set the new salt */
+ return;
+ }
+ while (len--) { /* for every character in the buffer */
+
+ cc = *bptr; /* get a character out of the buffer */
+
+ /* only encipher printable characters */
+ if ((cc >= ' ') && (cc <= '~')) {
+
+/** If the upper bit (bit 29) is set, feed it back into the key. This
+ assures us that the starting key affects the entire message. **/
+
+ key &= 0x1FFFFFFFL; /* strip off overflow */
+ if (key & 0x10000000L) {
+ key ^= 0x0040A001L; /* feedback */
+ }
+
+/** Down-bias the character, perform a Beaufort encipherment, and
+ up-bias the character again. We want key to be positive
+ so that the left shift here will be more portable and the
+ mod95() faster **/
+
+ cc = mod95((int)(key % 95) - (cc - ' ')) + ' ';
+
+/** the salt will spice up the key a little bit, helping to obscure
+ any patterns in the clear text, particularly when all the
+ characters (or long sequences of them) are the same. We do
+ not want the salt to go negative, or it will affect the key
+ too radically. It is always a good idea to chop off cyclics
+ to prime values. **/
+
+ if (++salt >= 20857) { /* prime modulus */
+ salt = 0;
+ }
+
+/** our autokey (a special case of the running key) is being
+ generated by a wieghted checksum of clear text, cipher
+ text, and salt. **/
+
+ key = key + key + cc + *bptr + salt;
+ }
+ *bptr++ = cc; /* put character back into buffer */
+ }
+ return;
+}
+
+static int mod95(val)
+
+register int val;
+
+{
+ /* The mathematical MOD does not match the computer MOD */
+
+ /* Yes, what I do here may look strange, but it gets the
+ job done, and portably at that. */
+
+ while (val >= 9500)
+ val -= 9500;
+ while (val >= 950)
+ val -= 950;
+ while (val >= 95)
+ val -= 95;
+ while (val < 0)
+ val += 95;
+ return (val);
+}
+#else
+nocrypt()
+{
+}
+#endif
diff --git a/display.c b/display.c
new file mode 100644
index 0000000..45aca3b
--- /dev/null
+++ b/display.c
@@ -0,0 +1,1570 @@
+/* DISPLAY.C
+ *
+ * The functions in this file handle redisplay. There are two halves, the
+ * ones that update the virtual display screen, and the ones that make the
+ * physical display screen the same as the virtual display screen. These
+ * functions use hints that are left in the windows by the commands.
+ *
+ * modified by Petri Kutvonen
+ */
+
+#include <stdio.h>
+#include "estruct.h"
+#include "edef.h"
+
+typedef struct VIDEO {
+ int v_flag; /* Flags */
+#if COLOR
+ int v_fcolor; /* current forground color */
+ int v_bcolor; /* current background color */
+ int v_rfcolor; /* requested forground color */
+ int v_rbcolor; /* requested background color */
+#endif
+ char v_text[1]; /* Screen data. */
+} VIDEO;
+
+#define VFCHG 0x0001 /* Changed flag */
+#define VFEXT 0x0002 /* extended (beyond column 80) */
+#define VFREV 0x0004 /* reverse video status */
+#define VFREQ 0x0008 /* reverse video request */
+#define VFCOL 0x0010 /* color change requested */
+
+VIDEO **vscreen; /* Virtual screen. */
+#if MEMMAP == 0 || SCROLLCODE
+VIDEO **pscreen; /* Physical screen. */
+#endif
+
+int displaying = TRUE;
+#if UNIX
+#include <signal.h>
+#endif
+#ifdef SIGWINCH
+#include <sys/ioctl.h>
+/* for window size changes */
+int chg_width, chg_height;
+#endif
+
+/*
+ * Initialize the data structures used by the display code. The edge vectors
+ * used to access the screens are set up. The operating system's terminal I/O
+ * channel is set up. All the other things get initialized at compile time.
+ * The original window has "WFCHG" set, so that it will get completely
+ * redrawn on the first call to "update".
+ */
+vtinit()
+{
+ register int i;
+ register VIDEO *vp;
+ char *malloc();
+
+ TTopen(); /* open the screen */
+ TTkopen(); /* open the keyboard */
+ TTrev(FALSE);
+ vscreen = (VIDEO **) malloc(term.t_mrow*sizeof(VIDEO *));
+
+ if (vscreen == NULL)
+ exit(1);
+
+#if MEMMAP == 0 || SCROLLCODE
+ pscreen = (VIDEO **) malloc(term.t_mrow*sizeof(VIDEO *));
+
+ if (pscreen == NULL)
+ exit(1);
+#endif
+
+ for (i = 0; i < term.t_mrow; ++i)
+ {
+ vp = (VIDEO *) malloc(sizeof(VIDEO)+term.t_mcol);
+
+ if (vp == NULL)
+ exit(1);
+
+ vp->v_flag = 0;
+#if COLOR
+ vp->v_rfcolor = 7;
+ vp->v_rbcolor = 0;
+#endif
+ vscreen[i] = vp;
+#if MEMMAP == 0 || SCROLLCODE
+ vp = (VIDEO *) malloc(sizeof(VIDEO)+term.t_mcol);
+
+ if (vp == NULL)
+ exit(1);
+
+ vp->v_flag = 0;
+ pscreen[i] = vp;
+#endif
+ }
+}
+
+#if CLEAN
+/* free up all the dynamically allocated video structures */
+
+vtfree()
+{
+ int i;
+ for (i = 0; i < term.t_mrow; ++i) {
+ free(vscreen[i]);
+#if MEMMAP == 0 || SCROLLCODE
+ free(pscreen[i]);
+#endif
+ }
+ free(vscreen);
+#if MEMMAP == 0 || SCROLLCODE
+ free(pscreen);
+#endif
+}
+#endif
+
+/*
+ * Clean up the virtual terminal system, in anticipation for a return to the
+ * operating system. Move down to the last line and clear it out (the next
+ * system prompt will be written in the line). Shut down the channel to the
+ * terminal.
+ */
+vttidy()
+{
+ mlerase();
+ movecursor(term.t_nrow, 0);
+ TTflush();
+ TTclose();
+ TTkclose();
+#ifdef PKCODE
+ write(1, "\r", 1);
+#endif
+}
+
+/*
+ * Set the virtual cursor to the specified row and column on the virtual
+ * screen. There is no checking for nonsense values; this might be a good
+ * idea during the early stages.
+ */
+vtmove(row, col)
+{
+ vtrow = row;
+ vtcol = col;
+}
+
+/* Write a character to the virtual screen. The virtual row and
+ column are updated. If we are not yet on left edge, don't print
+ it yet. If the line is too long put a "$" in the last column.
+ This routine only puts printing characters into the virtual
+ terminal buffers. Only column overflow is checked.
+*/
+
+vtputc(c)
+
+int c;
+
+{
+ register VIDEO *vp; /* ptr to line being updated */
+
+ vp = vscreen[vtrow];
+
+ if (vtcol >= term.t_ncol) {
+ ++vtcol;
+ vp->v_text[term.t_ncol - 1] = '$';
+ } else if (c < 0x20 || c == 0x7F) {
+ if (c == '\t') {
+ do {
+ vtputc(' ');
+ } while (((vtcol + taboff)&tabmask) != 0);
+ } else {
+ vtputc('^');
+ vtputc(c ^ 0x40);
+ }
+ } else {
+ if (vtcol >= 0)
+ vp->v_text[vtcol] = c;
+ ++vtcol;
+ }
+}
+
+/*
+ * Erase from the end of the software cursor to the end of the line on which
+ * the software cursor is located.
+ */
+vteeol()
+{
+/* register VIDEO *vp; */
+ register char *vcp = vscreen[vtrow]->v_text;
+
+/* vp = vscreen[vtrow]; */
+ while (vtcol < term.t_ncol)
+/* vp->v_text[vtcol++] = ' '; */
+ vcp[vtcol++] = ' ';
+}
+
+/* upscreen: user routine to force a screen update
+ always finishes complete update */
+
+upscreen(f, n)
+
+{
+ update(TRUE);
+ return(TRUE);
+}
+
+#if SCROLLCODE
+int scrflags;
+#endif
+
+/*
+ * Make sure that the display is right. This is a three part process. First,
+ * scan through all of the windows looking for dirty ones. Check the framing,
+ * and refresh the screen. Second, make sure that "currow" and "curcol" are
+ * correct for the current window. Third, make the virtual and physical
+ * screens the same.
+ */
+update(force)
+
+int force; /* force update past type ahead? */
+
+{
+ register WINDOW *wp;
+
+#if TYPEAH && ! PKCODE
+ if (force == FALSE && typahead())
+ return(TRUE);
+#endif
+#if VISMAC == 0
+ if (force == FALSE && kbdmode == PLAY)
+ return(TRUE);
+#endif
+
+ displaying = TRUE;
+
+#if SCROLLCODE
+
+ /* first, propagate mode line changes to all instances of
+ a buffer displayed in more than one window */
+ wp = wheadp;
+ while (wp != NULL) {
+ if (wp->w_flag & WFMODE) {
+ if (wp->w_bufp->b_nwnd > 1) {
+ /* make sure all previous windows have this */
+ register WINDOW *owp;
+ owp = wheadp;
+ while (owp != NULL) {
+ if (owp->w_bufp == wp->w_bufp)
+ owp->w_flag |= WFMODE;
+ owp = owp->w_wndp;
+ }
+ }
+ }
+ wp = wp->w_wndp;
+ }
+
+#endif
+
+ /* update any windows that need refreshing */
+ wp = wheadp;
+ while (wp != NULL) {
+ if (wp->w_flag) {
+ /* if the window has changed, service it */
+ reframe(wp); /* check the framing */
+#if SCROLLCODE
+ if (wp->w_flag & (WFKILLS|WFINS)) {
+ scrflags |= (wp->w_flag & (WFINS|WFKILLS));
+ wp->w_flag &= ~(WFKILLS|WFINS);
+ }
+#endif
+ if ((wp->w_flag & ~WFMODE) == WFEDIT)
+ updone(wp); /* update EDITed line */
+ else if (wp->w_flag & ~WFMOVE)
+ updall(wp); /* update all lines */
+#if SCROLLCODE
+ if (scrflags || (wp->w_flag & WFMODE))
+#else
+ if (wp->w_flag & WFMODE)
+#endif
+ modeline(wp); /* update modeline */
+ wp->w_flag = 0;
+ wp->w_force = 0;
+ }
+ /* on to the next window */
+ wp = wp->w_wndp;
+ }
+
+ /* recalc the current hardware cursor location */
+ updpos();
+
+#if MEMMAP && ! SCROLLCODE
+ /* update the cursor and flush the buffers */
+ movecursor(currow, curcol - lbound);
+#endif
+
+ /* check for lines to de-extend */
+ upddex();
+
+ /* if screen is garbage, re-plot it */
+ if (sgarbf != FALSE)
+ updgar();
+
+ /* update the virtual screen to the physical screen */
+ updupd(force);
+
+ /* update the cursor and flush the buffers */
+ movecursor(currow, curcol - lbound);
+ TTflush();
+ displaying = FALSE;
+#if SIGWINCH
+ while (chg_width || chg_height)
+ newscreensize(chg_height,chg_width);
+#endif
+ return(TRUE);
+}
+
+/* reframe: check to see if the cursor is on in the window
+ and re-frame it if needed or wanted */
+
+reframe(wp)
+
+WINDOW *wp;
+
+{
+ register LINE *lp, *lp0;
+ register int i;
+
+ /* if not a requested reframe, check for a needed one */
+ if ((wp->w_flag & WFFORCE) == 0) {
+#if SCROLLCODE
+ /* loop from one line above the window to one line after */
+ lp = wp->w_linep;
+ lp0 = lback(lp);
+ if (lp0 == wp->w_bufp->b_linep)
+ i = 0;
+ else {
+ i = -1;
+ lp = lp0;
+ }
+ for (; i <= (int)(wp->w_ntrows); i++)
+#else
+ lp = wp->w_linep;
+ for (i = 0; i < wp->w_ntrows; i++)
+#endif
+ {
+ /* if the line is in the window, no reframe */
+ if (lp == wp->w_dotp) {
+#if SCROLLCODE
+ /* if not _quite_ in, we'll reframe gently */
+ if ( i < 0 || i == wp->w_ntrows) {
+ /* if the terminal can't help, then
+ we're simply outside */
+ if (term.t_scroll == NULL)
+ i = wp->w_force;
+ break;
+ }
+#endif
+ return(TRUE);
+ }
+
+ /* if we are at the end of the file, reframe */
+ if (lp == wp->w_bufp->b_linep)
+ break;
+
+ /* on to the next line */
+ lp = lforw(lp);
+ }
+ }
+
+#if SCROLLCODE
+ if (i == -1) { /* we're just above the window */
+ i = scrollcount; /* put dot at first line */
+ scrflags |= WFINS;
+ } else if (i == wp->w_ntrows) { /* we're just below the window */
+ i = -scrollcount; /* put dot at last line */
+ scrflags |= WFKILLS;
+ } else /* put dot where requested */
+#endif
+ i = wp->w_force; /* (is 0, unless reposition() was called) */
+
+ wp->w_flag |= WFMODE;
+
+ /* how far back to reframe? */
+ if (i > 0) { /* only one screen worth of lines max */
+ if (--i >= wp->w_ntrows)
+ i = wp->w_ntrows - 1;
+ } else if (i < 0) { /* negative update???? */
+ i += wp->w_ntrows;
+ if (i < 0)
+ i = 0;
+ } else
+ i = wp->w_ntrows / 2;
+
+ /* backup to new line at top of window */
+ lp = wp->w_dotp;
+ while (i != 0 && lback(lp) != wp->w_bufp->b_linep) {
+ --i;
+ lp = lback(lp);
+ }
+
+ /* and reset the current line at top of window */
+ wp->w_linep = lp;
+ wp->w_flag |= WFHARD;
+ wp->w_flag &= ~WFFORCE;
+ return(TRUE);
+}
+
+/* updone: update the current line to the virtual screen */
+
+updone(wp)
+
+WINDOW *wp; /* window to update current line in */
+
+{
+ register LINE *lp; /* line to update */
+ register int sline; /* physical screen line to update */
+ register int i;
+
+ /* search down the line we want */
+ lp = wp->w_linep;
+ sline = wp->w_toprow;
+ while (lp != wp->w_dotp) {
+ ++sline;
+ lp = lforw(lp);
+ }
+
+ /* and update the virtual line */
+ vscreen[sline]->v_flag |= VFCHG;
+ vscreen[sline]->v_flag &= ~VFREQ;
+ vtmove(sline, 0);
+ for (i=0; i < llength(lp); ++i)
+ vtputc(lgetc(lp, i));
+#if COLOR
+ vscreen[sline]->v_rfcolor = wp->w_fcolor;
+ vscreen[sline]->v_rbcolor = wp->w_bcolor;
+#endif
+ vteeol();
+}
+
+/* updall: update all the lines in a window on the virtual screen */
+
+updall(wp)
+
+WINDOW *wp; /* window to update lines in */
+
+{
+ register LINE *lp; /* line to update */
+ register int sline; /* physical screen line to update */
+ register int i;
+
+ /* search down the lines, updating them */
+ lp = wp->w_linep;
+ sline = wp->w_toprow;
+ while (sline < wp->w_toprow + wp->w_ntrows) {
+
+ /* and update the virtual line */
+ vscreen[sline]->v_flag |= VFCHG;
+ vscreen[sline]->v_flag &= ~VFREQ;
+ vtmove(sline, 0);
+ if (lp != wp->w_bufp->b_linep) {
+ /* if we are not at the end */
+ for (i=0; i < llength(lp); ++i)
+ vtputc(lgetc(lp, i));
+ lp = lforw(lp);
+ }
+
+ /* on to the next one */
+#if COLOR
+ vscreen[sline]->v_rfcolor = wp->w_fcolor;
+ vscreen[sline]->v_rbcolor = wp->w_bcolor;
+#endif
+ vteeol();
+ ++sline;
+ }
+
+}
+
+/* updpos: update the position of the hardware cursor and handle extended
+ lines. This is the only update for simple moves. */
+
+updpos()
+
+{
+ register LINE *lp;
+ register int c;
+ register int i;
+
+ /* find the current row */
+ lp = curwp->w_linep;
+ currow = curwp->w_toprow;
+ while (lp != curwp->w_dotp) {
+ ++currow;
+ lp = lforw(lp);
+ }
+
+ /* find the current column */
+ curcol = 0;
+ i = 0;
+ while (i < curwp->w_doto) {
+ c = lgetc(lp, i++);
+ if (c == '\t')
+ curcol |= tabmask;
+ else
+ if (c < 0x20 || c == 0x7f)
+ ++curcol;
+
+ ++curcol;
+ }
+
+ /* if extended, flag so and update the virtual line image */
+ if (curcol >= term.t_ncol - 1) {
+ vscreen[currow]->v_flag |= (VFEXT | VFCHG);
+ updext();
+ } else
+ lbound = 0;
+}
+
+/* upddex: de-extend any line that derserves it */
+
+upddex()
+
+{
+ register WINDOW *wp;
+ register LINE *lp;
+ register int i,j;
+
+ wp = wheadp;
+
+ while (wp != NULL) {
+ lp = wp->w_linep;
+ i = wp->w_toprow;
+
+ while (i < wp->w_toprow + wp->w_ntrows) {
+ if (vscreen[i]->v_flag & VFEXT) {
+ if ((wp != curwp) || (lp != wp->w_dotp) ||
+ (curcol < term.t_ncol - 1)) {
+ vtmove(i, 0);
+ for (j = 0; j < llength(lp); ++j)
+ vtputc(lgetc(lp, j));
+ vteeol();
+
+ /* this line no longer is extended */
+ vscreen[i]->v_flag &= ~VFEXT;
+ vscreen[i]->v_flag |= VFCHG;
+ }
+ }
+ lp = lforw(lp);
+ ++i;
+ }
+ /* and onward to the next window */
+ wp = wp->w_wndp;
+ }
+}
+
+/* updgar: if the screen is garbage, clear the physical screen and
+ the virtual screen and force a full update */
+
+updgar()
+
+{
+ register char *txt;
+ register int i,j;
+
+ for (i = 0; i < term.t_nrow; ++i) {
+ vscreen[i]->v_flag |= VFCHG;
+#if REVSTA
+ vscreen[i]->v_flag &= ~VFREV;
+#endif
+#if COLOR
+ vscreen[i]->v_fcolor = gfcolor;
+ vscreen[i]->v_bcolor = gbcolor;
+#endif
+#if MEMMAP == 0 || SCROLLCODE
+ txt = pscreen[i]->v_text;
+ for (j = 0; j < term.t_ncol; ++j)
+ txt[j] = ' ';
+#endif
+ }
+
+ movecursor(0, 0); /* Erase the screen. */
+ (*term.t_eeop)();
+ sgarbf = FALSE; /* Erase-page clears */
+ mpresf = FALSE; /* the message area. */
+#if COLOR
+ mlerase(); /* needs to be cleared if colored */
+#endif
+}
+
+/* updupd: update the physical screen from the virtual screen */
+
+updupd(force)
+
+int force; /* forced update flag */
+
+{
+ register VIDEO *vp1;
+ register int i;
+
+#if SCROLLCODE
+ if (scrflags & WFKILLS)
+ scrolls(FALSE);
+ if (scrflags & WFINS)
+ scrolls(TRUE);
+ scrflags = 0;
+#endif
+
+ for (i = 0; i < term.t_nrow; ++i) {
+ vp1 = vscreen[i];
+
+ /* for each line that needs to be updated*/
+ if ((vp1->v_flag & VFCHG) != 0) {
+#if TYPEAH && ! PKCODE
+ if (force == FALSE && typahead())
+ return(TRUE);
+#endif
+#if MEMMAP && ! SCROLLCODE
+ updateline(i, vp1);
+#else
+ updateline(i, vp1, pscreen[i]);
+#endif
+ }
+ }
+ return(TRUE);
+}
+
+#if SCROLLCODE
+
+/* optimize out scrolls (line breaks, and newlines) */
+/* arg. chooses between looking for inserts or deletes */
+int
+scrolls(inserts) /* returns true if it does something */
+{
+ struct VIDEO *vpv ; /* virtual screen image */
+ struct VIDEO *vpp ; /* physical screen image */
+ int i, j, k ;
+ int rows, cols ;
+ int first, match, count, ptarget, vtarget, end ;
+ int longmatch, longcount;
+ int from, to;
+
+ if (!term.t_scroll) /* no way to scroll */
+ return FALSE;
+
+ rows = term.t_nrow ;
+ cols = term.t_ncol ;
+
+ first = -1 ;
+ for (i = 0; i < rows; i++) { /* find first wrong line */
+ if (!texttest(i,i)) {
+ first = i;
+ break;
+ }
+ }
+
+ if (first < 0)
+ return FALSE; /* no text changes */
+
+ vpv = vscreen[first] ;
+ vpp = pscreen[first] ;
+
+ if (inserts) {
+ /* determine types of potential scrolls */
+ end = endofline(vpv->v_text,cols) ;
+ if ( end == 0 )
+ ptarget = first ; /* newlines */
+ else if ( strncmp(vpp->v_text, vpv->v_text, end) == 0 )
+ ptarget = first + 1 ; /* broken line newlines */
+ else
+ ptarget = first ;
+ } else {
+ vtarget = first + 1 ;
+ }
+
+ /* find the matching shifted area */
+ match = -1 ;
+ longmatch = -1;
+ longcount = 0;
+ from = inserts ? ptarget : vtarget;
+ for (i = from+1; i < rows-longcount /* P.K. */; i++) {
+ if (inserts ? texttest(i,from) : texttest(from,i) ) {
+ match = i ;
+ count = 1 ;
+ for (j=match+1, k=from+1; j<rows && k<rows; j++, k++) {
+ if (inserts ? texttest(j,k) : texttest(k,j))
+ count++ ;
+ else
+ break ;
+ }
+ if (longcount < count) {
+ longcount = count;
+ longmatch = match;
+ }
+ }
+ }
+ match = longmatch;
+ count = longcount;
+
+ if (!inserts) {
+ /* full kill case? */
+ if (match > 0 && texttest(first, match-1)) {
+ vtarget-- ;
+ match-- ;
+ count++ ;
+ }
+ }
+
+ /* do the scroll */
+ if (match>0 && count>2) { /* got a scroll */
+ /* move the count lines starting at ptarget to match */
+ if (inserts) {
+ from = ptarget;
+ to = match;
+ } else {
+ from = match;
+ to = vtarget;
+ }
+#if 0
+ {
+ char line[NLINE];
+ sprintf(line,
+ "scrolls: move the %d lines starting at %d to %d, first %d, scrolls %d",
+ count,from,to,first, 2*count >= abs(from-to));
+ mlwrite(line);
+ }
+#endif
+ if (2*count < abs(from-to))
+ return(FALSE);
+ scrscroll(from, to, count) ;
+ for (i = 0; i < count; i++) {
+ vpp = pscreen[to+i] ;
+ vpv = vscreen[to+i];
+ strncpy(vpp->v_text, vpv->v_text, cols) ;
+ vpp->v_flag = vpv->v_flag; /* XXX */
+ if (vpp->v_flag & VFREV) {
+ vpp->v_flag &= ~VFREV;
+ vpp->v_flag |= ~VFREQ;
+ }
+#if MEMMAP
+ vscreen[to+i]->v_flag &= ~VFCHG;
+#endif
+ }
+ if (inserts) {
+ from = ptarget;
+ to = match;
+ } else {
+ from = vtarget+count;
+ to = match+count;
+ }
+#if MEMMAP == 0
+ for (i = from; i < to; i++) {
+ char *txt;
+ txt = pscreen[i]->v_text;
+ for (j = 0; j < term.t_ncol; ++j)
+ txt[j] = ' ';
+ vscreen[i]->v_flag |= VFCHG;
+ }
+#endif
+ return(TRUE) ;
+ }
+ return(FALSE) ;
+}
+
+/* move the "count" lines starting at "from" to "to" */
+scrscroll(from, to, count)
+{
+ ttrow = ttcol = -1;
+ (*term.t_scroll)(from,to,count);
+}
+
+texttest(vrow,prow) /* return TRUE on text match */
+int vrow, prow ; /* virtual, physical rows */
+{
+struct VIDEO *vpv = vscreen[vrow] ; /* virtual screen image */
+struct VIDEO *vpp = pscreen[prow] ; /* physical screen image */
+
+ return (!memcmp(vpv->v_text, vpp->v_text, term.t_ncol)) ;
+}
+
+/* return the index of the first blank of trailing whitespace */
+int
+endofline(s,n)
+char *s ;
+{
+int i ;
+ for (i = n - 1; i >= 0; i--)
+ if (s[i] != ' ') return(i+1) ;
+ return(0) ;
+}
+
+#endif /* SCROLLCODE */
+
+/* updext: update the extended line which the cursor is currently
+ on at a column greater than the terminal width. The line
+ will be scrolled right or left to let the user see where
+ the cursor is
+ */
+
+updext()
+
+{
+ register int rcursor; /* real cursor location */
+ register LINE *lp; /* pointer to current line */
+ register int j; /* index into line */
+
+ /* calculate what column the real cursor will end up in */
+ rcursor = ((curcol - term.t_ncol) % term.t_scrsiz) + term.t_margin;
+ taboff = lbound = curcol - rcursor + 1;
+
+ /* scan through the line outputing characters to the virtual screen */
+ /* once we reach the left edge */
+ vtmove(currow, -lbound); /* start scanning offscreen */
+ lp = curwp->w_dotp; /* line to output */
+ for (j=0; j<llength(lp); ++j) /* until the end-of-line */
+ vtputc(lgetc(lp, j));
+
+ /* truncate the virtual line, restore tab offset */
+ vteeol();
+ taboff = 0;
+
+ /* and put a '$' in column 1 */
+ vscreen[currow]->v_text[0] = '$';
+}
+
+/*
+ * Update a single line. This does not know how to use insert or delete
+ * character sequences; we are using VT52 functionality. Update the physical
+ * row and column variables. It does try an exploit erase to end of line. The
+ * RAINBOW version of this routine uses fast video.
+ */
+#if MEMMAP
+/* UPDATELINE specific code for the IBM-PC and other compatables */
+
+updateline(row, vp1
+#if SCROLLCODE
+ , vp2
+#endif
+)
+
+int row; /* row of screen to update */
+struct VIDEO *vp1; /* virtual screen image */
+
+#if SCROLLCODE
+struct VIDEO *vp2;
+#endif
+{
+#if SCROLLCODE
+ register char *cp1;
+ register char *cp2;
+ register int nch;
+
+ cp1 = &vp1->v_text[0];
+ cp2 = &vp2->v_text[0];
+ nch = term.t_ncol;
+ do
+ {
+ *cp2 = *cp1;
+ ++cp2;
+ ++cp1;
+ }
+ while (--nch);
+#endif
+#if COLOR
+ scwrite(row, vp1->v_text, vp1->v_rfcolor, vp1->v_rbcolor);
+ vp1->v_fcolor = vp1->v_rfcolor;
+ vp1->v_bcolor = vp1->v_rbcolor;
+#else
+ if (vp1->v_flag & VFREQ)
+ scwrite(row, vp1->v_text, 0, 7);
+ else
+ scwrite(row, vp1->v_text, 7, 0);
+#endif
+ vp1->v_flag &= ~(VFCHG | VFCOL); /* flag this line as changed */
+
+}
+
+#else
+
+updateline(row, vp1, vp2)
+
+int row; /* row of screen to update */
+struct VIDEO *vp1; /* virtual screen image */
+struct VIDEO *vp2; /* physical screen image */
+
+{
+#if RAINBOW
+/* UPDATELINE specific code for the DEC rainbow 100 micro */
+
+ register char *cp1;
+ register char *cp2;
+ register int nch;
+
+ /* since we don't know how to make the rainbow do this, turn it off */
+ flags &= (~VFREV & ~VFREQ);
+
+ cp1 = &vp1->v_text[0]; /* Use fast video. */
+ cp2 = &vp2->v_text[0];
+ putline(row+1, 1, cp1);
+ nch = term.t_ncol;
+
+ do
+ {
+ *cp2 = *cp1;
+ ++cp2;
+ ++cp1;
+ }
+ while (--nch);
+ *flags &= ~VFCHG;
+#else
+/* UPDATELINE code for all other versions */
+
+ register char *cp1;
+ register char *cp2;
+ register char *cp3;
+ register char *cp4;
+ register char *cp5;
+ register int nbflag; /* non-blanks to the right flag? */
+ int rev; /* reverse video flag */
+ int req; /* reverse video request flag */
+
+
+ /* set up pointers to virtual and physical lines */
+ cp1 = &vp1->v_text[0];
+ cp2 = &vp2->v_text[0];
+
+#if COLOR
+ TTforg(vp1->v_rfcolor);
+ TTbacg(vp1->v_rbcolor);
+#endif
+
+#if REVSTA | COLOR
+ /* if we need to change the reverse video status of the
+ current line, we need to re-write the entire line */
+ rev = (vp1->v_flag & VFREV) == VFREV;
+ req = (vp1->v_flag & VFREQ) == VFREQ;
+ if ((rev != req)
+#if COLOR
+ || (vp1->v_fcolor != vp1->v_rfcolor) || (vp1->v_bcolor != vp1->v_rbcolor)
+#endif
+ ) {
+ movecursor(row, 0); /* Go to start of line. */
+ /* set rev video if needed */
+ if (rev != req)
+ (*term.t_rev)(req);
+
+ /* scan through the line and dump it to the screen and
+ the virtual screen array */
+ cp3 = &vp1->v_text[term.t_ncol];
+ while (cp1 < cp3) {
+ TTputc(*cp1);
+ ++ttcol;
+ *cp2++ = *cp1++;
+ }
+ /* turn rev video off */
+ if (rev != req)
+ (*term.t_rev)(FALSE);
+
+ /* update the needed flags */
+ vp1->v_flag &= ~VFCHG;
+ if (req)
+ vp1->v_flag |= VFREV;
+ else
+ vp1->v_flag &= ~VFREV;
+#if COLOR
+ vp1->v_fcolor = vp1->v_rfcolor;
+ vp1->v_bcolor = vp1->v_rbcolor;
+#endif
+ return(TRUE);
+ }
+#endif
+
+ /* advance past any common chars at the left */
+ while (cp1 != &vp1->v_text[term.t_ncol] && cp1[0] == cp2[0]) {
+ ++cp1;
+ ++cp2;
+ }
+
+/* This can still happen, even though we only call this routine on changed
+ * lines. A hard update is always done when a line splits, a massive
+ * change is done, or a buffer is displayed twice. This optimizes out most
+ * of the excess updating. A lot of computes are used, but these tend to
+ * be hard operations that do a lot of update, so I don't really care.
+ */
+ /* if both lines are the same, no update needs to be done */
+ if (cp1 == &vp1->v_text[term.t_ncol]) {
+ vp1->v_flag &= ~VFCHG; /* flag this line is changed */
+ return(TRUE);
+ }
+
+ /* find out if there is a match on the right */
+ nbflag = FALSE;
+ cp3 = &vp1->v_text[term.t_ncol];
+ cp4 = &vp2->v_text[term.t_ncol];
+
+ while (cp3[-1] == cp4[-1]) {
+ --cp3;
+ --cp4;
+ if (cp3[0] != ' ') /* Note if any nonblank */
+ nbflag = TRUE; /* in right match. */
+ }
+
+ cp5 = cp3;
+
+ /* Erase to EOL ? */
+ if (nbflag == FALSE && eolexist == TRUE && (req != TRUE)) {
+ while (cp5!=cp1 && cp5[-1]==' ')
+ --cp5;
+
+ if (cp3-cp5 <= 3) /* Use only if erase is */
+ cp5 = cp3; /* fewer characters. */
+ }
+
+ movecursor(row, cp1 - &vp1->v_text[0]); /* Go to start of line. */
+#if REVSTA
+ TTrev(rev);
+#endif
+
+ while (cp1 != cp5) { /* Ordinary. */
+ TTputc(*cp1);
+ ++ttcol;
+ *cp2++ = *cp1++;
+ }
+
+ if (cp5 != cp3) { /* Erase. */
+ TTeeol();
+ while (cp1 != cp3)
+ *cp2++ = *cp1++;
+ }
+#if REVSTA
+ TTrev(FALSE);
+#endif
+ vp1->v_flag &= ~VFCHG; /* flag this line as updated */
+ return(TRUE);
+#endif
+}
+#endif
+
+/*
+ * Redisplay the mode line for the window pointed to by the "wp". This is the
+ * only routine that has any idea of how the modeline is formatted. You can
+ * change the modeline format by hacking at this routine. Called by "update"
+ * any time there is a dirty window.
+ */
+modeline(wp)
+ WINDOW *wp;
+{
+ register char *cp;
+ register int c;
+ register int n; /* cursor position count */
+ register BUFFER *bp;
+ register int i; /* loop index */
+ register int lchar; /* character to draw line in buffer with */
+ register int firstm; /* is this the first mode? */
+ char tline[NLINE]; /* buffer for part of mode line */
+
+ n = wp->w_toprow+wp->w_ntrows; /* Location. */
+ vscreen[n]->v_flag |= VFCHG | VFREQ | VFCOL;/* Redraw next time. */
+#if COLOR
+ vscreen[n]->v_rfcolor = 0; /* black on */
+ vscreen[n]->v_rbcolor = 7; /* white.....*/
+#endif
+ vtmove(n, 0); /* Seek to right line. */
+ if (wp == curwp) /* mark the current buffer */
+#if PKCODE
+ lchar = '-';
+#else
+ lchar = '=';
+#endif
+ else
+#if REVSTA
+ if (revexist)
+ lchar = ' ';
+ else
+#endif
+ lchar = '-';
+
+ bp = wp->w_bufp;
+#if PKCODE == 0
+ if ((bp->b_flag&BFTRUNC) != 0)
+ vtputc('#');
+ else
+#endif
+ vtputc(lchar);
+
+ if ((bp->b_flag&BFCHG) != 0) /* "*" if changed. */
+ vtputc('*');
+ else
+ vtputc(lchar);
+
+ n = 2;
+
+ strcpy(tline, " ");
+ strcat(tline, PROGNAME);
+ strcat(tline, " ");
+ strcat(tline, VERSION);
+ strcat(tline, ": ");
+ cp = &tline[0];
+ while ((c = *cp++) != 0)
+ {
+ vtputc(c);
+ ++n;
+ }
+
+ cp = &bp->b_bname[0];
+ while ((c = *cp++) != 0)
+ {
+ vtputc(c);
+ ++n;
+ }
+
+ strcpy(tline, " (");
+
+ /* display the modes */
+
+ firstm = TRUE;
+ if ((bp->b_flag&BFTRUNC) != 0)
+ {
+ firstm = FALSE;
+ strcat(tline, "Truncated");
+ }
+ for (i = 0; i < NUMMODES; i++) /* add in the mode flags */
+ if (wp->w_bufp->b_mode & (1 << i)) {
+ if (firstm != TRUE)
+ strcat(tline, " ");
+ firstm = FALSE;
+ strcat(tline, mode2name[i]);
+ }
+ strcat(tline,") ");
+
+ cp = &tline[0];
+ while ((c = *cp++) != 0)
+ {
+ vtputc(c);
+ ++n;
+ }
+
+#if 0
+ vtputc(lchar);
+ vtputc((wp->w_flag&WFCOLR) != 0 ? 'C' : lchar);
+ vtputc((wp->w_flag&WFMODE) != 0 ? 'M' : lchar);
+ vtputc((wp->w_flag&WFHARD) != 0 ? 'H' : lchar);
+ vtputc((wp->w_flag&WFEDIT) != 0 ? 'E' : lchar);
+ vtputc((wp->w_flag&WFMOVE) != 0 ? 'V' : lchar);
+ vtputc((wp->w_flag&WFFORCE) != 0 ? 'F' : lchar);
+ vtputc(lchar);
+ n += 8;
+#endif
+
+#if PKCODE
+ if (bp->b_fname[0] != 0 &&
+ strcmp(bp->b_bname, bp->b_fname) != 0)
+#else
+ if (bp->b_fname[0] != 0) /* File name. */
+#endif
+ {
+#if PKCODE == 0
+ cp = "File: ";
+
+ while ((c = *cp++) != 0)
+ {
+ vtputc(c);
+ ++n;
+ }
+#endif
+
+ cp = &bp->b_fname[0];
+
+ while ((c = *cp++) != 0)
+ {
+ vtputc(c);
+ ++n;
+ }
+
+ vtputc(' ');
+ ++n;
+ }
+
+ while (n < term.t_ncol) /* Pad to full width. */
+ {
+ vtputc(lchar);
+ ++n;
+ }
+
+ { /* determine if top line, bottom line, or both are visible */
+ LINE *lp = wp->w_linep;
+ int rows = wp->w_ntrows;
+ char *msg = NULL;
+
+ vtcol = n - 7; /* strlen(" top ") plus a couple */
+ while (rows--) {
+ lp = lforw(lp);
+ if (lp == wp->w_bufp->b_linep) {
+ msg = " Bot ";
+ break;
+ }
+ }
+ if (lback(wp->w_linep) == wp->w_bufp->b_linep) {
+ if (msg) {
+ if (wp->w_linep == wp->w_bufp->b_linep)
+ msg = " Emp ";
+ else
+ msg = " All ";
+ } else {
+ msg = " Top ";
+ }
+ }
+ if (!msg)
+ {
+ LINE *lp;
+ int numlines, predlines, ratio;
+
+ lp = lforw(bp->b_linep);
+ numlines = 0;
+ while (lp != bp->b_linep) {
+ if (lp == wp->w_linep) {
+ predlines = numlines;
+ }
+ ++numlines;
+ lp = lforw(lp);
+ }
+ if (wp->w_dotp == bp->b_linep) {
+ msg = " Bot ";
+ } else {
+ ratio = 0;
+ if (numlines != 0)
+ ratio = (100L*predlines) / numlines;
+ if (ratio > 99)
+ ratio = 99;
+ sprintf(tline, " %2d%% ", ratio);
+ msg = tline;
+ }
+ }
+
+ cp = msg;
+ while ((c = *cp++) != 0)
+ {
+ vtputc(c);
+ ++n;
+ }
+ }
+}
+
+upmode() /* update all the mode lines */
+
+{
+ register WINDOW *wp;
+
+ wp = wheadp;
+ while (wp != NULL) {
+ wp->w_flag |= WFMODE;
+ wp = wp->w_wndp;
+ }
+}
+
+/*
+ * Send a command to the terminal to move the hardware cursor to row "row"
+ * and column "col". The row and column arguments are origin 0. Optimize out
+ * random calls. Update "ttrow" and "ttcol".
+ */
+movecursor(row, col)
+ {
+ if (row!=ttrow || col!=ttcol)
+ {
+ ttrow = row;
+ ttcol = col;
+ TTmove(row, col);
+ }
+ }
+
+/*
+ * Erase the message line. This is a special routine because the message line
+ * is not considered to be part of the virtual screen. It always works
+ * immediately; the terminal buffer is flushed via a call to the flusher.
+ */
+mlerase()
+ {
+ int i;
+
+ movecursor(term.t_nrow, 0);
+ if (discmd == FALSE)
+ return;
+
+#if COLOR
+ TTforg(7);
+ TTbacg(0);
+#endif
+ if (eolexist == TRUE)
+ TTeeol();
+ else {
+ for (i = 0; i < term.t_ncol - 1; i++)
+ TTputc(' ');
+ movecursor(term.t_nrow, 1); /* force the move! */
+ movecursor(term.t_nrow, 0);
+ }
+ TTflush();
+ mpresf = FALSE;
+ }
+
+/*
+ * Write a message into the message line. Keep track of the physical cursor
+ * position. A small class of printf like format items is handled. Assumes the
+ * stack grows down; this assumption is made by the "++" in the argument scan
+ * loop. Set the "message line" flag TRUE.
+ */
+
+mlwrite(fmt, arg)
+
+char *fmt; /* format string for output */
+char *arg; /* pointer to first argument to print */
+
+{
+ register int c; /* current char in format string */
+ register char *ap; /* ptr to current data field */
+
+ /* if we are not currently echoing on the command line, abort this */
+ if (discmd == FALSE) {
+ movecursor(term.t_nrow, 0);
+ return;
+ }
+
+#if COLOR
+ /* set up the proper colors for the command line */
+ TTforg(7);
+ TTbacg(0);
+#endif
+
+ /* if we can not erase to end-of-line, do it manually */
+ if (eolexist == FALSE) {
+ mlerase();
+ TTflush();
+ }
+
+ movecursor(term.t_nrow, 0);
+ ap = (char *) &arg;
+ while ((c = *fmt++) != 0) {
+ if (c != '%') {
+ TTputc(c);
+ ++ttcol;
+ } else {
+ c = *fmt++;
+ switch (c) {
+#if PKCODE
+ case '*':
+ ap = *(char **)ap;
+ break;
+#endif
+ case 'd':
+ mlputi(*(int *)ap, 10);
+ ap += sizeof(int);
+ break;
+
+ case 'o':
+ mlputi(*(int *)ap, 8);
+ ap += sizeof(int);
+ break;
+
+ case 'x':
+ mlputi(*(int *)ap, 16);
+ ap += sizeof(int);
+ break;
+
+ case 'D':
+ mlputli(*(long *)ap, 10);
+ ap += sizeof(long);
+ break;
+
+ case 's':
+ mlputs(*(char **)ap);
+ ap += sizeof(char *);
+ break;
+
+ case 'f':
+ mlputf(*(int *)ap);
+ ap += sizeof(int);
+ break;
+
+ default:
+ TTputc(c);
+ ++ttcol;
+ }
+ }
+ }
+
+ /* if we can, erase to the end of screen */
+ if (eolexist == TRUE)
+ TTeeol();
+ TTflush();
+ mpresf = TRUE;
+}
+
+/* Force a string out to the message line regardless of the
+ current $discmd setting. This is needed when $debug is TRUE
+ and for the write-message and clear-message-line commands
+*/
+
+mlforce(s)
+
+char *s; /* string to force out */
+
+{
+ register int oldcmd; /* original command display flag */
+
+ oldcmd = discmd; /* save the discmd value */
+ discmd = TRUE; /* and turn display on */
+ mlwrite(s); /* write the string out */
+ discmd = oldcmd; /* and restore the original setting */
+}
+
+/*
+ * Write out a string. Update the physical cursor position. This assumes that
+ * the characters in the string all have width "1"; if this is not the case
+ * things will get screwed up a little.
+ */
+mlputs(s)
+ char *s;
+ {
+ register int c;
+
+ while ((c = *s++) != 0)
+ {
+ TTputc(c);
+ ++ttcol;
+ }
+ }
+
+/*
+ * Write out an integer, in the specified radix. Update the physical cursor
+ * position.
+ */
+mlputi(i, r)
+ {
+ register int q;
+ static char hexdigits[] = "0123456789ABCDEF";
+
+ if (i < 0)
+ {
+ i = -i;
+ TTputc('-');
+ }
+
+ q = i/r;
+
+ if (q != 0)
+ mlputi(q, r);
+
+ TTputc(hexdigits[i%r]);
+ ++ttcol;
+ }
+
+/*
+ * do the same except as a long integer.
+ */
+mlputli(l, r)
+ long l;
+ {
+ register long q;
+
+ if (l < 0)
+ {
+ l = -l;
+ TTputc('-');
+ }
+
+ q = l/r;
+
+ if (q != 0)
+ mlputli(q, r);
+
+ TTputc((int)(l%r)+'0');
+ ++ttcol;
+ }
+
+/*
+ * write out a scaled integer with two decimal places
+ */
+
+mlputf(s)
+
+int s; /* scaled integer to output */
+
+{
+ int i; /* integer portion of number */
+ int f; /* fractional portion of number */
+
+ /* break it up */
+ i = s / 100;
+ f = s % 100;
+
+ /* send out the integer portion */
+ mlputi(i, 10);
+ TTputc('.');
+ TTputc((f / 10) + '0');
+ TTputc((f % 10) + '0');
+ ttcol += 3;
+}
+
+#if RAINBOW
+
+putline(row, col, buf)
+ int row, col;
+ char buf[];
+ {
+ int n;
+
+ n = strlen(buf);
+ if (col + n - 1 > term.t_ncol)
+ n = term.t_ncol - col + 1;
+ Put_Data(row, col, n, buf);
+ }
+#endif
+
+/* Get terminal size from system.
+ Store number of lines into *heightp and width into *widthp.
+ If zero or a negative number is stored, the value is not valid. */
+
+getscreensize (widthp, heightp)
+int *widthp, *heightp;
+{
+#ifdef TIOCGWINSZ
+ struct winsize size;
+ *widthp = 0;
+ *heightp = 0;
+ if (ioctl (0, TIOCGWINSZ, &size) < 0)
+ return;
+ *widthp = size.ws_col;
+ *heightp = size.ws_row;
+#else
+ *widthp = 0;
+ *heightp = 0;
+#endif
+}
+
+#ifdef SIGWINCH
+void sizesignal(signr)
+int signr;
+{
+ int w, h;
+ extern int errno;
+ int old_errno = errno;
+
+ getscreensize (&w, &h);
+
+ if (h && w && (h-1 != term.t_nrow || w != term.t_ncol))
+ newscreensize(h, w);
+
+ signal (SIGWINCH, sizesignal);
+ errno = old_errno;
+}
+
+newscreensize (h, w)
+int h, w;
+{
+ /* do the change later */
+ if (displaying) {
+ chg_width = w;
+ chg_height = h;
+ return;
+ }
+ chg_width = chg_height = 0;
+ if (h - 1 < term.t_mrow)
+ newsize(TRUE,h);
+ if (w < term.t_mcol)
+ newwidth(TRUE,w);
+
+ update(TRUE);
+ return TRUE;
+}
+
+#endif
+
diff --git a/dosmake.bat b/dosmake.bat
new file mode 100644
index 0000000..3956635
--- /dev/null
+++ b/dosmake.bat
@@ -0,0 +1,2 @@
+cl -AL -Ot -Gs -c *.c
+link @emacs.lnk
diff --git a/ebind.h b/ebind.h
new file mode 100644
index 0000000..432462a
--- /dev/null
+++ b/ebind.h
@@ -0,0 +1,249 @@
+/* EBIND.H
+ *
+ * Initial default key to function bindings
+ *
+ * Modified by Petri Kutvonen
+ */
+
+/*
+ * Command table.
+ * This table is *roughly* in ASCII order, left to right across the
+ * characters of the command. This explains the funny location of the
+ * control-X commands.
+ */
+KEYTAB keytab[NBINDS] = {
+ {CONTROL|'A', gotobol},
+ {CONTROL|'B', backchar},
+ {CONTROL|'C', insspace},
+ {CONTROL|'D', forwdel},
+ {CONTROL|'E', gotoeol},
+ {CONTROL|'F', forwchar},
+ {CONTROL|'G', ctrlg},
+ {CONTROL|'H', backdel},
+ {CONTROL|'I', tab},
+ {CONTROL|'J', indent},
+ {CONTROL|'K', killtext},
+ {CONTROL|'L', refresh},
+ {CONTROL|'M', newline},
+ {CONTROL|'N', forwline},
+ {CONTROL|'O', openline},
+ {CONTROL|'P', backline},
+ {CONTROL|'Q', quote},
+ {CONTROL|'R', backsearch},
+ {CONTROL|'S', forwsearch},
+ {CONTROL|'T', twiddle},
+ {CONTROL|'U', unarg},
+ {CONTROL|'V', forwpage},
+ {CONTROL|'W', killregion},
+ {CONTROL|'X', cex},
+ {CONTROL|'Y', yank},
+ {CONTROL|'Z', backpage},
+ {CONTROL|']', meta},
+ {CTLX|CONTROL|'B', listbuffers},
+ {CTLX|CONTROL|'C', quit}, /* Hard quit. */
+#if PKCODE & AEDIT
+ {CTLX|CONTROL|'A', detab},
+#endif
+#if PKCODE
+ {CTLX|CONTROL|'D', filesave}, /* alternative */
+#else
+#if AEDIT
+ {CTLX|CONTROL|'D', detab},
+#endif
+#endif
+#if AEDIT
+ {CTLX|CONTROL|'E', entab},
+#endif
+ {CTLX|CONTROL|'F', filefind},
+ {CTLX|CONTROL|'I', insfile},
+ {CTLX|CONTROL|'L', lowerregion},
+ {CTLX|CONTROL|'M', delmode},
+ {CTLX|CONTROL|'N', mvdnwind},
+ {CTLX|CONTROL|'O', deblank},
+ {CTLX|CONTROL|'P', mvupwind},
+ {CTLX|CONTROL|'R', fileread},
+ {CTLX|CONTROL|'S', filesave},
+#if AEDIT
+ {CTLX|CONTROL|'T', trim},
+#endif
+ {CTLX|CONTROL|'U', upperregion},
+ {CTLX|CONTROL|'V', viewfile},
+ {CTLX|CONTROL|'W', filewrite},
+ {CTLX|CONTROL|'X', swapmark},
+ {CTLX|CONTROL|'Z', shrinkwind},
+ {CTLX|'?', deskey},
+ {CTLX|'!', spawn},
+ {CTLX|'@', pipecmd},
+ {CTLX|'#', filter},
+ {CTLX|'$', execprg},
+ {CTLX|'=', showcpos},
+ {CTLX|'(', ctlxlp},
+ {CTLX|')', ctlxrp},
+ {CTLX|'^', enlargewind},
+ {CTLX|'0', delwind},
+ {CTLX|'1', onlywind},
+ {CTLX|'2', splitwind},
+ {CTLX|'A', setvar},
+ {CTLX|'B', usebuffer},
+ {CTLX|'C', spawncli},
+#if BSD | __hpux | SVR4
+ {CTLX|'D', bktoshell},
+#endif
+ {CTLX|'E', ctlxe},
+ {CTLX|'F', setfillcol},
+ {CTLX|'K', killbuffer},
+ {CTLX|'M', setmode},
+ {CTLX|'N', filename},
+ {CTLX|'O', nextwind},
+ {CTLX|'P', prevwind},
+#if PKCODE
+ {CTLX|'Q', quote}, /* alternative */
+#endif
+#if ISRCH
+ {CTLX|'R', risearch},
+ {CTLX|'S', fisearch},
+#endif
+ {CTLX|'W', resize},
+ {CTLX|'X', nextbuffer},
+ {CTLX|'Z', enlargewind},
+#if WORDPRO
+ {META|CONTROL|'C', wordcount},
+#endif
+#if PKCODE
+ {META|CONTROL|'D', newsize},
+#endif
+#if PROC
+ {META|CONTROL|'E', execproc},
+#endif
+#if CFENCE
+ {META|CONTROL|'F', getfence},
+#endif
+ {META|CONTROL|'H', delbword},
+ {META|CONTROL|'K', unbindkey},
+ {META|CONTROL|'L', reposition},
+ {META|CONTROL|'M', delgmode},
+ {META|CONTROL|'N', namebuffer},
+ {META|CONTROL|'R', qreplace},
+ {META|CONTROL|'S', newsize},
+ {META|CONTROL|'T', newwidth},
+ {META|CONTROL|'V', scrnextdw},
+#if WORDPRO
+ {META|CONTROL|'W', killpara},
+#endif
+ {META|CONTROL|'Z', scrnextup},
+ {META|' ', setmark},
+ {META|'?', help},
+ {META|'!', reposition},
+ {META|'.', setmark},
+ {META|'>', gotoeob},
+ {META|'<', gotobob},
+ {META|'~', unmark},
+#if APROP
+ {META|'A', apro},
+#endif
+ {META|'B', backword},
+ {META|'C', capword},
+ {META|'D', delfword},
+#if CRYPT
+ {META|'E', setkey},
+#endif
+ {META|'F', forwword},
+ {META|'G', gotoline},
+#if PKCODE
+#if WORDPRO
+ {META|'J', justpara},
+#endif
+#endif
+ {META|'K', bindtokey},
+ {META|'L', lowerword},
+ {META|'M', setgmode},
+#if WORDPRO
+ {META|'N', gotoeop},
+ {META|'P', gotobop},
+ {META|'Q', fillpara},
+#endif
+ {META|'R', sreplace},
+#if PKCODE
+ {META|'S', forwsearch}, /* alternative P.K. */
+#else
+#if BSD
+ {META|'S', bktoshell},
+#endif
+#endif
+ {META|'U', upperword},
+ {META|'V', backpage},
+ {META|'W', copyregion},
+ {META|'X', namedcmd},
+ {META|'Z', quickexit},
+ {META|0x7F, delbword},
+
+#if MSDOS
+ {SPEC|CONTROL|'_', forwhunt},
+ {SPEC|CONTROL|'S', backhunt},
+ {SPEC|71, gotobol},
+ {SPEC|72, backline},
+ {SPEC|73, backpage},
+ {SPEC|75, backchar},
+ {SPEC|77, forwchar},
+ {SPEC|79, gotoeol},
+ {SPEC|80, forwline},
+ {SPEC|81, forwpage},
+ {SPEC|82, insspace},
+ {SPEC|83, forwdel},
+ {SPEC|115, backword},
+ {SPEC|116, forwword},
+#if WORDPRO
+ {SPEC|132, gotobop},
+ {SPEC|118, gotoeop},
+#endif
+ {SPEC|84, cbuf1},
+ {SPEC|85, cbuf2},
+ {SPEC|86, cbuf3},
+ {SPEC|87, cbuf4},
+ {SPEC|88, cbuf5},
+ {SPEC|89, cbuf6},
+ {SPEC|90, cbuf7},
+ {SPEC|91, cbuf8},
+ {SPEC|92, cbuf9},
+ {SPEC|93, cbuf10},
+#if PKCODE
+ {SPEC|117, gotoeob},
+ {SPEC|119, gotobob},
+ {SPEC|141, gotobop},
+ {SPEC|145, gotoeop},
+ {SPEC|146, yank},
+ {SPEC|147, killregion},
+#endif
+#endif
+
+#if VT220
+ {SPEC|'1', fisearch}, /* VT220 keys */
+ {SPEC|'2', yank},
+ {SPEC|'3', killregion},
+ {SPEC|'4', setmark},
+ {SPEC|'5', backpage},
+ {SPEC|'6', forwpage},
+ {SPEC|'A', backline},
+ {SPEC|'B', forwline},
+ {SPEC|'C', forwchar},
+ {SPEC|'D', backchar},
+ {SPEC|'c', meta},
+ {SPEC|'d', backchar},
+ {SPEC|'e', forwline},
+ {SPEC|'f', gotobob},
+ {SPEC|'h', help},
+ {SPEC|'i', cex},
+#endif
+
+ {0x7F, backdel},
+
+ /* special internal bindings */
+ SPEC|META|'W', wrapword, /* called on word wrap */
+ SPEC|META|'C', nullproc, /* every command input */
+ SPEC|META|'R', nullproc, /* on file read */
+ SPEC|META|'X', nullproc, /* on window change P.K. */
+
+ {0, NULL}
+};
+
+
diff --git a/edef.h b/edef.h
new file mode 100644
index 0000000..67aa375
--- /dev/null
+++ b/edef.h
@@ -0,0 +1,323 @@
+/* EDEF.H
+ *
+ * Global variable definitions
+ *
+ * written by Dave G. Conroy
+ * modified by Steve Wilhite, George Jones
+ * greatly modified by Daniel Lawrence
+ * modified by Petri Kutvonen
+ */
+
+/* some global fuction declarations */
+
+char *flook();
+char *getctext();
+char *getfname();
+char *getval();
+char *gtenv();
+char *gtfun();
+char *gtusr();
+char *itoa();
+char *ltos();
+char *malloc();
+char *mklower();
+char *mkupper();
+char *strcat();
+char *strcpy();
+char *strncpy();
+char *token();
+char *transbind();
+unsigned int getckey();
+unsigned int stock();
+
+#ifdef maindef
+
+/* for MAIN.C */
+
+/* initialized global definitions */
+
+int fillcol = 72; /* Current fill column */
+short kbdm[NKBDM]; /* Macro */
+char *execstr = NULL; /* pointer to string to execute */
+char golabel[NPAT] = ""; /* current line to go to */
+int execlevel = 0; /* execution IF level */
+int eolexist = TRUE; /* does clear to EOL exist */
+int revexist = FALSE; /* does reverse video exist? */
+int flickcode = FALSE; /* do flicker supression? */
+char *modename[] = { /* name of modes */
+ "WRAP", "CMODE", "SPELL", "EXACT", "VIEW", "OVER",
+ "MAGIC", "CRYPT", "ASAVE"};
+char *mode2name[] = { /* name of modes */
+ "Wrap", "Cmode", "Spell", "Exact", "View", "Over",
+ "Magic", "Crypt", "Asave"};
+char modecode[] = "WCSEVOMYA"; /* letters to represent modes */
+int gmode = 0; /* global editor mode */
+int gflags = GFREAD; /* global control flag */
+#if PKCODE & IBMPC
+int gfcolor = 8; /* global forgrnd color (white) */
+#else
+int gfcolor = 7; /* global forgrnd color (white) */
+#endif
+int gbcolor = 0; /* global backgrnd color (black)*/
+int gasave = 256; /* global ASAVE size */
+int gacount = 256; /* count until next ASAVE */
+int sgarbf = TRUE; /* TRUE if screen is garbage */
+int mpresf = FALSE; /* TRUE if message in last line */
+int clexec = FALSE; /* command line execution flag */
+int mstore = FALSE; /* storing text to macro flag */
+int discmd = TRUE; /* display command flag */
+int disinp = TRUE; /* display input characters */
+struct BUFFER *bstore = NULL; /* buffer to store macro text to*/
+int vtrow = 0; /* Row location of SW cursor */
+int vtcol = 0; /* Column location of SW cursor */
+int ttrow = HUGE; /* Row location of HW cursor */
+int ttcol = HUGE; /* Column location of HW cursor */
+int lbound = 0; /* leftmost column of current line
+ being displayed */
+int taboff = 0; /* tab offset for display */
+int metac = CONTROL | '['; /* current meta character */
+int ctlxc = CONTROL | 'X'; /* current control X prefix char */
+int reptc = CONTROL | 'U'; /* current universal repeat char */
+int abortc = CONTROL | 'G'; /* current abort command char */
+
+int quotec = 0x11; /* quote char during mlreply() */
+int tabmask = 0x07; /* tabulator mask */
+char *cname[] = { /* names of colors */
+ "BLACK", "RED", "GREEN", "YELLOW", "BLUE",
+ "MAGENTA", "CYAN", "WHITE"
+#if PKCODE & IBMPC
+ ,"HIGH"
+#endif
+ };
+KILL *kbufp = NULL; /* current kill buffer chunk pointer */
+KILL *kbufh = NULL; /* kill buffer header pointer */
+int kused = KBLOCK; /* # of bytes used in kill buffer */
+WINDOW *swindow = NULL; /* saved window pointer */
+int cryptflag = FALSE; /* currently encrypting? */
+short *kbdptr; /* current position in keyboard buf */
+short *kbdend = &kbdm[0]; /* ptr to end of the keyboard */
+int kbdmode = STOP; /* current keyboard macro mode */
+int kbdrep = 0; /* number of repetitions */
+int restflag = FALSE; /* restricted use? */
+int lastkey = 0; /* last keystoke */
+int seed = 0; /* random number seed */
+long envram = 0l; /* # of bytes current in use by malloc */
+int macbug = FALSE; /* macro debuging flag */
+char errorm[] = "ERROR"; /* error literal */
+char truem[] = "TRUE"; /* true literal */
+char falsem[] = "FALSE"; /* false litereal */
+int cmdstatus = TRUE; /* last command status */
+char palstr[49] = ""; /* palette string */
+int saveflag = 0; /* Flags, saved with the $target var */
+char *fline = NULL; /* dynamic return line */
+int flen = 0; /* current length of fline */
+int rval = 0; /* return value of a subprocess */
+#if CALLED
+int eexitflag = FALSE; /* EMACS exit flag */
+int eexitval = 0; /* and the exit return value */
+#endif
+#if PKCODE
+int nullflag = FALSE; /* accept null characters */
+int justflag = FALSE; /* justify, don't fill */
+#endif
+int overlap = 0; /* line overlap in forw/back page */
+int scrollcount = 1; /* number of lines to scroll */
+
+/* uninitialized global definitions */
+
+int currow; /* Cursor row */
+int curcol; /* Cursor column */
+int thisflag; /* Flags, this command */
+int lastflag; /* Flags, last command */
+int curgoal; /* Goal for C-P, C-N */
+WINDOW *curwp; /* Current window */
+BUFFER *curbp; /* Current buffer */
+WINDOW *wheadp; /* Head of list of windows */
+BUFFER *bheadp; /* Head of list of buffers */
+BUFFER *blistp; /* Buffer for C-X C-B */
+
+BUFFER *bfind(); /* Lookup a buffer by name */
+WINDOW *wpopup(); /* Pop up window creation */
+LINE *lalloc(); /* Allocate a line */
+char sres[NBUFN]; /* current screen resolution */
+
+char pat[NPAT]; /* Search pattern */
+char tap[NPAT]; /* Reversed pattern array. */
+char rpat[NPAT]; /* replacement pattern */
+
+/* The variable matchlen holds the length of the matched
+ * string - used by the replace functions.
+ * The variable patmatch holds the string that satisfies
+ * the search command.
+ * The variables matchline and matchoff hold the line and
+ * offset position of the *start* of match.
+ */
+unsigned int matchlen = 0;
+unsigned int mlenold = 0;
+char *patmatch = NULL;
+LINE *matchline = NULL;
+int matchoff = 0;
+
+#if MAGIC
+/*
+ * The variables magical and rmagical determine if there
+ * were actual metacharacters in the search and replace strings -
+ * if not, then we don't have to use the slower MAGIC mode
+ * search functions.
+ */
+short int magical = FALSE;
+short int rmagical = FALSE;
+MC mcpat[NPAT]; /* the magic pattern */
+MC tapcm[NPAT]; /* the reversed magic pattern */
+RMC rmcpat[NPAT]; /* the replacement magic array */
+
+#endif
+
+/* directive name table:
+ This holds the names of all the directives.... */
+
+char *dname[] = {
+ "if", "else", "endif",
+ "goto", "return", "endm",
+ "while", "endwhile", "break",
+ "force"
+};
+
+#if DEBUGM
+/* vars needed for macro debugging output */
+char outline[NSTRING]; /* global string to hold debug line text */
+#endif
+
+#else
+
+/* for all the other .C files */
+
+/* initialized global external declarations */
+
+extern int fillcol; /* Fill column */
+extern short kbdm[]; /* Holds kayboard macro data */
+extern char pat[]; /* Search pattern */
+extern char rpat[]; /* Replacement pattern */
+extern char *execstr; /* pointer to string to execute */
+extern char golabel[]; /* current line to go to */
+extern int execlevel; /* execution IF level */
+extern int eolexist; /* does clear to EOL exist? */
+extern int revexist; /* does reverse video exist? */
+extern int flickcode; /* do flicker supression? */
+extern char *modename[]; /* text names of modes */
+extern char *mode2name[]; /* text names of modes */
+extern char modecode[]; /* letters to represent modes */
+extern KEYTAB keytab[]; /* key bind to functions table */
+extern NBIND names[]; /* name to function table */
+extern int gmode; /* global editor mode */
+extern int gflags; /* global control flag */
+extern int gfcolor; /* global forgrnd color (white) */
+extern int gbcolor; /* global backgrnd color (black)*/
+extern int gasave; /* global ASAVE size */
+extern int gacount; /* count until next ASAVE */
+extern int sgarbf; /* State of screen unknown */
+extern int mpresf; /* Stuff in message line */
+extern int clexec; /* command line execution flag */
+extern int mstore; /* storing text to macro flag */
+extern int discmd; /* display command flag */
+extern int disinp; /* display input characters */
+extern struct BUFFER *bstore; /* buffer to store macro text to*/
+extern int vtrow; /* Row location of SW cursor */
+extern int vtcol; /* Column location of SW cursor */
+extern int ttrow; /* Row location of HW cursor */
+extern int ttcol; /* Column location of HW cursor */
+extern int lbound; /* leftmost column of current line
+ being displayed */
+extern int taboff; /* tab offset for display */
+extern int metac; /* current meta character */
+extern int ctlxc; /* current control X prefix char */
+extern int reptc; /* current universal repeat char */
+extern int abortc; /* current abort command char */
+
+extern int quotec; /* quote char during mlreply() */
+extern int tabmask;
+extern char *cname[]; /* names of colors */
+extern KILL *kbufp; /* current kill buffer chunk pointer */
+extern KILL *kbufh; /* kill buffer header pointer */
+extern int kused; /* # of bytes used in KB */
+extern WINDOW *swindow; /* saved window pointer */
+extern int cryptflag; /* currently encrypting? */
+extern short *kbdptr; /* current position in keyboard buf */
+extern short *kbdend; /* ptr to end of the keyboard */
+extern int kbdmode; /* current keyboard macro mode */
+extern int kbdrep; /* number of repetitions */
+extern int restflag; /* restricted use? */
+extern int lastkey; /* last keystoke */
+extern int seed; /* random number seed */
+extern long envram; /* # of bytes current in use by malloc */
+extern int macbug; /* macro debuging flag */
+extern char errorm[]; /* error literal */
+extern char truem[]; /* true literal */
+extern char falsem[]; /* false litereal */
+extern int cmdstatus; /* last command status */
+extern char palstr[]; /* palette string */
+extern int saveflag; /* Flags, saved with the $target var */
+extern char *fline; /* dynamic return line */
+extern int flen; /* current length of fline */
+extern int rval; /* return value of a subprocess */
+#if CALLED
+extern int eexitflag; /* EMACS exit flag */
+extern int eexitval; /* and the exit return value */
+#endif
+#if PKCODE
+extern int justflag; /* justify, don't fill */
+#endif
+extern int overlap; /* line overlap in forw/back page */
+extern int scrollcount; /* number of lines to scroll */
+
+/* uninitialized global external declarations */
+
+extern int currow; /* Cursor row */
+extern int curcol; /* Cursor column */
+extern int thisflag; /* Flags, this command */
+extern int lastflag; /* Flags, last command */
+extern int curgoal; /* Goal for C-P, C-N */
+extern WINDOW *curwp; /* Current window */
+extern BUFFER *curbp; /* Current buffer */
+extern WINDOW *wheadp; /* Head of list of windows */
+extern BUFFER *bheadp; /* Head of list of buffers */
+extern BUFFER *blistp; /* Buffer for C-X C-B */
+
+extern BUFFER *bfind(); /* Lookup a buffer by name */
+extern WINDOW *wpopup(); /* Pop up window creation */
+extern LINE *lalloc(); /* Allocate a line */
+extern char sres[NBUFN]; /* current screen resolution */
+extern char pat[]; /* Search pattern */
+extern char tap[]; /* Reversed pattern array. */
+extern char rpat[]; /* replacement pattern */
+
+extern unsigned int matchlen;
+extern unsigned int mlenold;
+extern char *patmatch;
+extern LINE *matchline;
+extern int matchoff;
+
+#if MAGIC
+extern short int magical;
+extern short int rmagical;
+extern MC mcpat[NPAT]; /* the magic pattern */
+extern MC tapcm[NPAT]; /* the reversed magic pattern */
+extern RMC rmcpat[NPAT]; /* the replacement magic array */
+#endif
+
+extern char *dname[]; /* directive name table */
+
+#if DEBUGM
+/* vars needed for macro debugging output */
+extern char outline[]; /* global string to hold debug line text */
+#endif
+
+#endif
+
+/* terminal table defined only in TERM.C */
+
+#ifndef termdef
+extern TERM term; /* Terminal information. */
+#endif
+
+
diff --git a/efunc.h b/efunc.h
new file mode 100644
index 0000000..cb8de1e
--- /dev/null
+++ b/efunc.h
@@ -0,0 +1,431 @@
+/* EFUNC.H
+ *
+ * Function declarations and names
+ *
+ * This file list all the C code functions used
+ * and the names to use to bind keys to them. To add functions,
+ * declare it here in both the extern function list and the name
+ * binding table.
+ *
+ * modified by Petri Kutvonen
+ */
+
+/* External function declarations */
+
+extern int ctrlg(); /* Abort out of things */
+extern int quit(); /* Quit */
+extern int ctlxlp(); /* Begin macro */
+extern int ctlxrp(); /* End macro */
+extern int ctlxe(); /* Execute macro */
+extern int fileread(); /* Get a file, read only */
+extern int filefind(); /* Get a file, read write */
+extern int filewrite(); /* Write a file */
+extern int filesave(); /* Save current file */
+extern int filename(); /* Adjust file name */
+extern int getccol(); /* Get current column */
+extern int gotobol(); /* Move to start of line */
+extern int forwchar(); /* Move forward by characters */
+extern int gotoeol(); /* Move to end of line */
+extern int backchar(); /* Move backward by characters */
+extern int forwline(); /* Move forward by lines */
+extern int backline(); /* Move backward by lines */
+extern int forwpage(); /* Move forward by pages */
+extern int backpage(); /* Move backward by pages */
+extern int gotobob(); /* Move to start of buffer */
+extern int gotoeob(); /* Move to end of buffer */
+extern int setfillcol(); /* Set fill column. */
+extern int setmark(); /* Set mark */
+extern int swapmark(); /* Swap "." and mark */
+extern int forwsearch(); /* Search forward */
+extern int backsearch(); /* Search backwards */
+extern int sreplace(); /* search and replace */
+extern int qreplace(); /* search and replace w/query */
+extern int showcpos(); /* Show the cursor position */
+extern int nextwind(); /* Move to the next window */
+extern int prevwind(); /* Move to the previous window */
+extern int onlywind(); /* Make current window only one */
+extern int splitwind(); /* Split current window */
+extern int mvdnwind(); /* Move window down */
+extern int mvupwind(); /* Move window up */
+extern int enlargewind(); /* Enlarge display window. */
+extern int shrinkwind(); /* Shrink window. */
+extern int listbuffers(); /* Display list of buffers */
+extern int usebuffer(); /* Switch a window to a buffer */
+extern int killbuffer(); /* Make a buffer go away. */
+extern int reposition(); /* Reposition window */
+extern int refresh(); /* Refresh the screen */
+extern int twiddle(); /* Twiddle characters */
+extern int tab(); /* Insert tab */
+extern int newline(); /* Insert CR-LF */
+extern int indent(); /* Insert CR-LF, then indent */
+extern int openline(); /* Open up a blank line */
+extern int deblank(); /* Delete blank lines */
+extern int quote(); /* Insert literal */
+extern int backword(); /* Backup by words */
+extern int forwword(); /* Advance by words */
+extern int forwdel(); /* Forward delete */
+extern int backdel(); /* Backward delete */
+extern int killtext(); /* Kill forward */
+extern int yank(); /* Yank back from killbuffer. */
+extern int upperword(); /* Upper case word. */
+extern int lowerword(); /* Lower case word. */
+extern int upperregion(); /* Upper case region. */
+extern int lowerregion(); /* Lower case region. */
+extern int capword(); /* Initial capitalize word. */
+extern int delfword(); /* Delete forward word. */
+extern int delbword(); /* Delete backward word. */
+extern int killregion(); /* Kill region. */
+extern int copyregion(); /* Copy region to kill buffer. */
+extern int spawncli(); /* Run CLI in a subjob. */
+extern int spawn(); /* Run a command in a subjob. */
+#if BSD | __hpux | SVR4
+extern int bktoshell(); /* suspend emacs to parent shell*/
+extern int rtfrmshell(); /* return from a suspended state*/
+#endif
+extern int quickexit(); /* low keystroke style exit. */
+extern int setmode(); /* set an editor mode */
+extern int delmode(); /* delete a mode */
+extern int gotoline(); /* go to a numbered line */
+extern int namebuffer(); /* rename the current buffer */
+#if WORDPRO
+extern int gotobop(); /* go to beginning/paragraph */
+extern int gotoeop(); /* go to end/paragraph */
+extern int fillpara(); /* fill current paragraph */
+#if PKCODE
+extern int justpara(); /* justify current paragraph */
+#endif
+#endif
+extern int help(); /* get the help file here */
+extern int deskey(); /* describe a key's binding */
+extern int viewfile(); /* find a file in view mode */
+extern int insfile(); /* insert a file */
+extern int scrnextup(); /* scroll next window back */
+extern int scrnextdw(); /* scroll next window down */
+extern int bindtokey(); /* bind a function to a key */
+extern int unbindkey(); /* unbind a key's function */
+extern int namedcmd(); /* execute named command */
+extern int desbind(); /* describe bindings */
+extern int execcmd(); /* execute a command line */
+extern int execbuf(); /* exec commands from a buffer */
+extern int execfile(); /* exec commands from a file */
+extern int nextbuffer(); /* switch to the next buffer */
+#if WORDPRO
+extern int killpara(); /* kill the current paragraph */
+#endif
+extern int setgmode(); /* set a global mode */
+extern int delgmode(); /* delete a global mode */
+extern int insspace(); /* insert a space forword */
+extern int forwhunt(); /* hunt forward for next match */
+extern int backhunt(); /* hunt backwards for next match*/
+extern int pipecmd(); /* pipe command into buffer */
+extern int filter(); /* filter buffer through dos */
+extern int delwind(); /* delete the current window */
+extern int cbuf1(); /* execute numbered comd buffer */
+extern int cbuf2();
+extern int cbuf3();
+extern int cbuf4();
+extern int cbuf5();
+extern int cbuf6();
+extern int cbuf7();
+extern int cbuf8();
+extern int cbuf9();
+extern int cbuf10();
+extern int cbuf11();
+extern int cbuf12();
+extern int cbuf13();
+extern int cbuf14();
+extern int cbuf15();
+extern int cbuf16();
+extern int cbuf17();
+extern int cbuf18();
+extern int cbuf19();
+extern int cbuf20();
+extern int cbuf21();
+extern int cbuf22();
+extern int cbuf23();
+extern int cbuf24();
+extern int cbuf25();
+extern int cbuf26();
+extern int cbuf27();
+extern int cbuf28();
+extern int cbuf29();
+extern int cbuf30();
+extern int cbuf31();
+extern int cbuf32();
+extern int cbuf33();
+extern int cbuf34();
+extern int cbuf35();
+extern int cbuf36();
+extern int cbuf37();
+extern int cbuf38();
+extern int cbuf39();
+extern int cbuf40();
+extern int storemac(); /* store text for macro */
+extern int resize(); /* resize current window */
+extern int clrmes(); /* clear the message line */
+extern int meta(); /* meta prefix dummy function */
+extern int cex(); /* ^X prefix dummy function */
+extern int unarg(); /* ^U repeat arg dummy function */
+extern int istring(); /* insert string in text */
+extern int unmark(); /* unmark current buffer */
+#if ISRCH
+extern int fisearch(); /* forward incremental search */
+extern int risearch(); /* reverse incremental search */
+#endif
+#if WORDPRO
+extern int wordcount(); /* count words in region */
+#endif
+extern int savewnd(); /* save current window */
+extern int restwnd(); /* restore current window */
+extern int upscreen(); /* force screen update */
+extern int writemsg(); /* write text on message line */
+#if FNLABEL
+extern int fnclabel(); /* set function key label */
+#endif
+#if APROP
+extern int apro(); /* apropos fuction */
+#endif
+#if CRYPT
+extern int setkey(); /* set encryption key */
+#endif
+extern int wrapword(); /* wordwrap function */
+#if CFENCE
+extern int getfence(); /* move cursor to a matching fence */
+#endif
+extern int newsize(); /* change the current screen size */
+extern int setvar(); /* set a variables value */
+extern int newwidth(); /* change the current screen width */
+#if AEDIT
+extern int trim(); /* trim whitespace from end of line */
+extern int detab(); /* detab rest of line */
+extern int entab(); /* entab rest of line */
+#endif
+#if PROC
+extern int storeproc(); /* store names procedure */
+extern int execproc(); /* execute procedure */
+#endif
+extern int nullproc(); /* does nothing... */
+extern int ovstring(); /* overwrite a string */
+extern int execprg(); /* execute a program */
+
+extern int cknewwindow();
+
+/* Name to function binding table
+
+ This table gives the names of all the bindable functions
+ end their C function address. These are used for the bind-to-key
+ function.
+*/
+
+NBIND names[] = {
+ {"abort-command", ctrlg},
+ {"add-mode", setmode},
+ {"add-global-mode", setgmode},
+#if APROP
+ {"apropos", apro},
+#endif
+ {"backward-character", backchar},
+ {"begin-macro", ctlxlp},
+ {"beginning-of-file", gotobob},
+ {"beginning-of-line", gotobol},
+ {"bind-to-key", bindtokey},
+ {"buffer-position", showcpos},
+ {"case-region-lower", lowerregion},
+ {"case-region-upper", upperregion},
+ {"case-word-capitalize", capword},
+ {"case-word-lower", lowerword},
+ {"case-word-upper", upperword},
+ {"change-file-name", filename},
+ {"change-screen-size", newsize},
+ {"change-screen-width", newwidth},
+ {"clear-and-redraw", refresh},
+ {"clear-message-line", clrmes},
+ {"copy-region", copyregion},
+#if WORDPRO
+ {"count-words", wordcount},
+#endif
+ {"ctlx-prefix", cex},
+ {"delete-blank-lines", deblank},
+ {"delete-buffer", killbuffer},
+ {"delete-mode", delmode},
+ {"delete-global-mode", delgmode},
+ {"delete-next-character", forwdel},
+ {"delete-next-word", delfword},
+ {"delete-other-windows", onlywind},
+ {"delete-previous-character", backdel},
+ {"delete-previous-word", delbword},
+ {"delete-window", delwind},
+ {"describe-bindings", desbind},
+ {"describe-key", deskey},
+#if AEDIT
+ {"detab-line", detab},
+#endif
+ {"end-macro", ctlxrp},
+ {"end-of-file", gotoeob},
+ {"end-of-line", gotoeol},
+#if AEDIT
+ {"entab-line", entab},
+#endif
+ {"exchange-point-and-mark", swapmark},
+ {"execute-buffer", execbuf},
+ {"execute-command-line", execcmd},
+ {"execute-file", execfile},
+ {"execute-macro", ctlxe},
+ {"execute-macro-1", cbuf1},
+ {"execute-macro-2", cbuf2},
+ {"execute-macro-3", cbuf3},
+ {"execute-macro-4", cbuf4},
+ {"execute-macro-5", cbuf5},
+ {"execute-macro-6", cbuf6},
+ {"execute-macro-7", cbuf7},
+ {"execute-macro-8", cbuf8},
+ {"execute-macro-9", cbuf9},
+ {"execute-macro-10", cbuf10},
+ {"execute-macro-11", cbuf11},
+ {"execute-macro-12", cbuf12},
+ {"execute-macro-13", cbuf13},
+ {"execute-macro-14", cbuf14},
+ {"execute-macro-15", cbuf15},
+ {"execute-macro-16", cbuf16},
+ {"execute-macro-17", cbuf17},
+ {"execute-macro-18", cbuf18},
+ {"execute-macro-19", cbuf19},
+ {"execute-macro-20", cbuf20},
+ {"execute-macro-21", cbuf21},
+ {"execute-macro-22", cbuf22},
+ {"execute-macro-23", cbuf23},
+ {"execute-macro-24", cbuf24},
+ {"execute-macro-25", cbuf25},
+ {"execute-macro-26", cbuf26},
+ {"execute-macro-27", cbuf27},
+ {"execute-macro-28", cbuf28},
+ {"execute-macro-29", cbuf29},
+ {"execute-macro-30", cbuf30},
+ {"execute-macro-31", cbuf31},
+ {"execute-macro-32", cbuf32},
+ {"execute-macro-33", cbuf33},
+ {"execute-macro-34", cbuf34},
+ {"execute-macro-35", cbuf35},
+ {"execute-macro-36", cbuf36},
+ {"execute-macro-37", cbuf37},
+ {"execute-macro-38", cbuf38},
+ {"execute-macro-39", cbuf39},
+ {"execute-macro-40", cbuf40},
+ {"execute-named-command", namedcmd},
+#if PROC
+ {"execute-procedure", execproc},
+#endif
+ {"execute-program", execprg},
+ {"exit-emacs", quit},
+#if WORDPRO
+ {"fill-paragraph", fillpara},
+#endif
+ {"filter-buffer", filter},
+ {"find-file", filefind},
+ {"forward-character", forwchar},
+ {"goto-line", gotoline},
+#if CFENCE
+ {"goto-matching-fence", getfence},
+#endif
+ {"grow-window", enlargewind},
+ {"handle-tab", tab},
+ {"hunt-forward", forwhunt},
+ {"hunt-backward", backhunt},
+ {"help", help},
+ {"i-shell", spawncli},
+#if ISRCH
+ {"incremental-search", fisearch},
+#endif
+ {"insert-file", insfile},
+ {"insert-space", insspace},
+ {"insert-string", istring},
+#if WORDPRO
+#if PKCODE
+ {"justify-paragraph", justpara},
+#endif
+ {"kill-paragraph", killpara},
+#endif
+ {"kill-region", killregion},
+ {"kill-to-end-of-line", killtext},
+#if FNLABEL
+ {"label-function-key", fnclabel},
+#endif
+ {"list-buffers", listbuffers},
+ {"meta-prefix", meta},
+ {"move-window-down", mvdnwind},
+ {"move-window-up", mvupwind},
+ {"name-buffer", namebuffer},
+ {"newline", newline},
+ {"newline-and-indent", indent},
+ {"next-buffer", nextbuffer},
+ {"next-line", forwline},
+ {"next-page", forwpage},
+#if WORDPRO
+ {"next-paragraph", gotoeop},
+#endif
+ {"next-window", nextwind},
+ {"next-word", forwword},
+ {"nop", nullproc},
+ {"open-line", openline},
+ {"overwrite-string", ovstring},
+ {"pipe-command", pipecmd},
+ {"previous-line", backline},
+ {"previous-page", backpage},
+#if WORDPRO
+ {"previous-paragraph", gotobop},
+#endif
+ {"previous-window", prevwind},
+ {"previous-word", backword},
+ {"query-replace-string", qreplace},
+ {"quick-exit", quickexit},
+ {"quote-character", quote},
+ {"read-file", fileread},
+ {"redraw-display", reposition},
+ {"resize-window", resize},
+ {"restore-window", restwnd},
+ {"replace-string", sreplace},
+#if ISRCH
+ {"reverse-incremental-search", risearch},
+#endif
+#if PROC
+ {"run", execproc},
+#endif
+ {"save-file", filesave},
+ {"save-window", savewnd},
+ {"scroll-next-up", scrnextup},
+ {"scroll-next-down", scrnextdw},
+ {"search-forward", forwsearch},
+ {"search-reverse", backsearch},
+ {"select-buffer", usebuffer},
+ {"set", setvar},
+#if CRYPT
+ {"set-encryption-key", setkey},
+#endif
+ {"set-fill-column", setfillcol},
+ {"set-mark", setmark},
+ {"shell-command", spawn},
+ {"shrink-window", shrinkwind},
+ {"split-current-window", splitwind},
+ {"store-macro", storemac},
+#if PROC
+ {"store-procedure", storeproc},
+#endif
+#if BSD | __hpux | SVR4
+ {"suspend-emacs", bktoshell},
+#endif
+ {"transpose-characters", twiddle},
+#if AEDIT
+ {"trim-line", trim},
+#endif
+ {"unbind-key", unbindkey},
+ {"universal-argument", unarg},
+ {"unmark-buffer", unmark},
+ {"update-screen", upscreen},
+ {"view-file", viewfile},
+ {"wrap-word", wrapword},
+ {"write-file", filewrite},
+ {"write-message", writemsg},
+ {"yank", yank},
+
+ {"", NULL}
+};
diff --git a/emacs.hlp b/emacs.hlp
new file mode 100644
index 0000000..375de33
--- /dev/null
+++ b/emacs.hlp
@@ -0,0 +1,172 @@
+=> uEmacs/PK 4.0 HELP INDEX
+.. The very basics
+.. Cursor movement
+.. File commands
+.. Miscellaneous character commands
+.. Mode commands
+.. Keys and commands
+.. Deleting and inserting
+.. Formatting
+.. Window commands
+.. Buffer commands
+.. Searching and replacing
+.. Accessing the operating system
+.. Macro commands
+.. Miscellaneous
+.. Functions
+.. System variables
+.. File name completion
+-------------------------------------------------------------------------------
+=> THE VERY BASICS
+Notations: ^X means <Ctrl> and X. The <Meta> key is <Esc> on most systems.
+Exiting: ^G aborts almost any operation. ^X ^C will get you out of uEmacs.
+
+A BUFFER is a named area containing a FILE being edited. Many buffers may
+be active at once. Many WINDOWS may be active at once on the screen. All
+windows may show different parts of the same buffer, or each may display a
+different one.
+-------------------------------------------------------------------------------
+=> CURSOR MOVEMENT
+Backward character .... ^B Forward character ..... ^F
+Previous word ......... Meta B Next word ............. Meta F
+Beginning of line ..... ^A End of line ........... ^E
+Previous line ......... ^P Next line ............. ^N
+Previous paragraph .... Meta P Next paragraph ........ Meta N
+Previous page ......... ^Z Next page ............. ^V
+Beginning of file ..... Meta < End of file ........... Meta >
+-------------------------------------------------------------------------------
+=> FILE COMMANDS
+Find file ............. ^X ^F Quick exit ............ Meta Z
+View file ............. ^X ^V Exit emacs ............ ^X ^C
+Insert file ........... ^X ^I
+Change file name ...... ^X N Filter buffer ......... ^X #
+Save file ............. ^X ^D
+Read file ............. ^X ^R
+Write file ............ ^X ^W Execute file .......... not bound
+-------------------------------------------------------------------------------
+=> MISCELLANEOUS CHARACTER COMMANDS
+Newline ............... ^M Transpose characters .. ^T
+Newline and indent .... ^J Trim line ............. ^X ^T
+Open line ............. ^O
+Handle tab ............ ^I Quote character ....... ^X Q
+Insert space .......... ^C
+Goto line ............. Meta G Abort command ......... ^G
+Goto matching fence ... Meta ^F
+-------------------------------------------------------------------------------
+=> MODE COMMANDS
+Add mode .............. ^X M Add global mode ....... Meta M
+Delete mode ........... ^X ^M Delete global mode .... Meta ^M
+OVER :: Overwrite, don't insert MAGIC :: Match patterns in search
+WRAP :: Automatic carriage return ^ $ Beginning and end of line
+VIEW :: View only, don't change . Any character \c Character c
+CMODE :: C program indenting c* Any number of character c
+EXACT :: Match case in search [ ] Character class
+-------------------------------------------------------------------------------
+=> KEYS AND COMMANDS
+Bind to key ........... Meta K Help .................. Meta ?
+Unbind key ............ Meta ^K Apropos ............... Meta A
+Describe key .......... ^X ? Abort command ......... ^G
+Describe bindings ..... not bound
+Meta prefix ........... Esc :: Although meta-prefix can be bound to
+Cntlx prefix .......... ^X :: some other key, no other command can
+Execute named command . Meta X :: be bound to Esc.
+-------------------------------------------------------------------------------
+=> DELETING AND INSERTING
+Delete previous character ^H Delete next character . ^D
+Delete previous word .. Meta ^H Delete next word ...... Meta D
+Kill to end of line ... ^K Set mark .............. Meta Space
+Kill region ........... ^W Yank .................. ^Y
+Kill paragraph ........ Meta ^W Exchange point and mark ^X ^X
+Delete blank lines .... ^X ^O :: A region is defined as the area between
+Copy region ........... Meta W :: the mark and the current position.
+-------------------------------------------------------------------------------
+=> FORMATTING
+Case word upper ....... Meta U Case word lower ....... Meta L
+Case region upper ..... ^X ^U Case region lower ..... ^X ^L
+Case word capitalize .. Meta C Trim line ............. ^X ^T
+ Detab line ............ ^X ^A
+Set fill column ....... ^X F Entab line ............ ^X ^E
+Fill paragraph ........ Meta Q Change screen size .... Meta ^D
+Justify paragraph ..... Meta J Change screen width ... Meta ^T
+-------------------------------------------------------------------------------
+=> WINDOW COMMANDS
+Split current window .. ^X 2 Next window ........... ^X O
+Delete other windows .. ^X 1 Previous window ....... ^X P
+Delete window ......... ^X 0 Scroll next up ........ Meta ^Z
+Grow window ........... ^X Z Scroll next down ...... Meta ^V
+Shrink window ......... ^X ^Z Resize window ......... ^X W
+Move window up ........ ^X ^P Save window ........... not bound
+Move window down ...... ^X ^N Restore window ........ not bound
+-------------------------------------------------------------------------------
+=> BUFFER COMMANDS
+Next buffer ........... ^X X Buffer position ....... ^X =
+Select buffer ......... ^X B Unmark buffer ......... Meta ~
+List buffers .......... ^X ^B
+Delete buffer ......... ^X K Write message ......... not bound
+Name buffer ........... Meta ^N Clear message line .... not bound
+Filter buffer ......... ^X #
+Pipe command .......... ^X @ Execute buffer ........ not bound
+-------------------------------------------------------------------------------
+=> SEARCHING AND REPLACING
+Search forward ........ Meta S :: End string with Meta.
+Incremental search .... ^X S :: Search next ^X, stop Meta, cancel ^G.
+Search reverse ........ ^R
+Reverse incremental search Hunt forward .......... Alt-S
+....................... ^X R Hunt backward ......... Alt-R
+Replace string ........ Meta R
+Query replace string .. Meta ^R :: Yes/no Y/N, replace rest !, cancel ^G.
+-------------------------------------------------------------------------------
+=> ACCESSING THE OPERATING SYSTEM
+Quick exit ............ Meta Z :: Write out all changed buffers and exit.
+Exit emacs ............ ^X ^C :: Exit without automatic save.
+I shell ............... ^X C :: Start a new command processor.
+Shell command ......... ^X ! :: Execute one operating system command.
+Pipe command .......... ^X @ :: Pipe command results to a new buffer. *
+Filter buffer ......... ^X # :: Filter buffer through a program. *
+Execute program ....... ^X $ :: * Not under VMS.
+-------------------------------------------------------------------------------
+=> MACRO COMMANDS
+Begin macro ........... ^X (
+End macro ............. ^X )
+Execute macro ......... ^X E
+Store macro ........... not bound
+Execute macro nn ...... not bound
+Store procedure ....... not bound
+Execute procedure ..... Meta ^E
+-------------------------------------------------------------------------------
+=> MISCELLANEOUS
+Universal argument .... ^U Set mark .............. Meta Space
+Clear and redraw ...... ^L Exchange point and mark ^X ^X
+Redraw display ........ Meta ^L
+Execute named command . Meta X Insert string ......... not bound
+Execute command line .. not bound Overwrite string ...... not bound
+Set encryption key .... Meta E Wrap word ............. not bound
+Count words ........... Meta ^C Update screen ......... not bound
+-------------------------------------------------------------------------------
+=> SYSTEM VARIABLES
+Set ................... Meta ^A Current buffer name ... $cbufname
+Tabulator (4, 8)....... $tab Current file name ..... $cfname
+Screen resolution ..... $sres :: NORMAL, CGA, EGA, VGA
+Display commands ...... $discmd :: TRUE, FALSE
+Scrolling enabled ..... $scroll :: TRUE, FALSE, can only be reset
+Scrolling movement .... $jump :: # lines, default 1, 0 = 1/2 page
+Page overlap .......... $overlap :: # lines, default 0, 0 = 1/3 page
+-------------------------------------------------------------------------------
+=> FUNCTIONS
+&neg, &abs, &add, &sub, &tim, &div, &mod ... Arithmetic
+&equ, &les, &gre ........................... Arithmetic comparisons
+&not, &and, &or ............................ Logical
+&lef s len, &rig s pos, &mid s pos len ..... Substring
+&cat, &len, &upp, &low, &asc, &chr ......... Other string operations
+&seq, &sle, &sgr ........................... String comparisons
+&sin ....................................... String index
+-------------------------------------------------------------------------------
+=> FILE NAME COMPLETION
+
+File name completion can be used with all file commands (find-file,
+view-file, ...) but it works only under UNIX and MS-DOS. It is invoked
+by a <Space> or <Tab>. If there exist more than one possible completions
+they are displayed one by one. If the file name contains wild card
+characters, the name is expanded instead of simple completion. Special
+characters can be entered verbatim by prefixing them with ^V (or ^Q).
+-------------------------------------------------------------------------------
diff --git a/emacs.lnk b/emacs.lnk
new file mode 100644
index 0000000..e242c23
--- /dev/null
+++ b/emacs.lnk
@@ -0,0 +1,29 @@
+ANSI.OBJ+
+BASIC.OBJ+
+BIND.OBJ+
+BUFFER.OBJ+
+CRYPT.OBJ+
+DISPLAY.OBJ+
+EVAL.OBJ+
+EXEC.OBJ+
+FILE.OBJ+
+FILEIO.OBJ+
+IBMPC.OBJ+
+INPUT.OBJ+
+ISEARCH.OBJ+
+LINE.OBJ+
+LOCK.OBJ+
+MAIN.OBJ+
+RANDOM.OBJ+
+REGION.OBJ+
+SEARCH.OBJ+
+SPAWN.OBJ+
+TCAP.OBJ+
+TERMIO.OBJ+
+VMSVT.OBJ+
+VT52.OBJ+
+WINDOW.OBJ+
+WORD.OBJ/E/STACK:20000
+EMACS.EXE/NOI/NOE
+NUL
+;
diff --git a/emacs.prj b/emacs.prj
new file mode 100644
index 0000000..2399d5b
--- /dev/null
+++ b/emacs.prj
@@ -0,0 +1,27 @@
+ANSI (EBIND.H EDEF.H EFUNC.H EPATH.H ESTRUCT.H EVAR.H)
+BASIC (EBIND.H EDEF.H EFUNC.H EPATH.H ESTRUCT.H EVAR.H)
+BIND (EBIND.H EDEF.H EFUNC.H EPATH.H ESTRUCT.H EVAR.H)
+BUFFER (EBIND.H EDEF.H EFUNC.H EPATH.H ESTRUCT.H EVAR.H)
+CRYPT (EBIND.H EDEF.H EFUNC.H EPATH.H ESTRUCT.H EVAR.H)
+DISPLAY (EBIND.H EDEF.H EFUNC.H EPATH.H ESTRUCT.H EVAR.H)
+EVAL (EBIND.H EDEF.H EFUNC.H EPATH.H ESTRUCT.H EVAR.H)
+EXEC (EBIND.H EDEF.H EFUNC.H EPATH.H ESTRUCT.H EVAR.H)
+FILE (EBIND.H EDEF.H EFUNC.H EPATH.H ESTRUCT.H EVAR.H)
+FILEIO (EBIND.H EDEF.H EFUNC.H EPATH.H ESTRUCT.H EVAR.H)
+IBMPC (EBIND.H EDEF.H EFUNC.H EPATH.H ESTRUCT.H EVAR.H)
+INPUT (EBIND.H EDEF.H EFUNC.H EPATH.H ESTRUCT.H EVAR.H)
+ISEARCH (EBIND.H EDEF.H EFUNC.H EPATH.H ESTRUCT.H EVAR.H)
+LINE (EBIND.H EDEF.H EFUNC.H EPATH.H ESTRUCT.H EVAR.H)
+LOCK (EBIND.H EDEF.H EFUNC.H EPATH.H ESTRUCT.H EVAR.H)
+MAIN (EBIND.H EDEF.H EFUNC.H EPATH.H ESTRUCT.H EVAR.H)
+PKLOCK (EBIND.H EDEF.H EFUNC.H EPATH.H ESTRUCT.H EVAR.H)
+RANDOM (EBIND.H EDEF.H EFUNC.H EPATH.H ESTRUCT.H EVAR.H)
+REGION (EBIND.H EDEF.H EFUNC.H EPATH.H ESTRUCT.H EVAR.H)
+SEARCH (EBIND.H EDEF.H EFUNC.H EPATH.H ESTRUCT.H EVAR.H)
+SPAWN (EBIND.H EDEF.H EFUNC.H EPATH.H ESTRUCT.H EVAR.H)
+TCAP (EBIND.H EDEF.H EFUNC.H EPATH.H ESTRUCT.H EVAR.H)
+TERMIO (EBIND.H EDEF.H EFUNC.H EPATH.H ESTRUCT.H EVAR.H)
+VMSVT (EBIND.H EDEF.H EFUNC.H EPATH.H ESTRUCT.H EVAR.H)
+VT52 (EBIND.H EDEF.H EFUNC.H EPATH.H ESTRUCT.H EVAR.H)
+WINDOW (EBIND.H EDEF.H EFUNC.H EPATH.H ESTRUCT.H EVAR.H)
+WORD (EBIND.H EDEF.H EFUNC.H EPATH.H ESTRUCT.H EVAR.H)
diff --git a/emacs.ps b/emacs.ps
new file mode 100644
index 0000000..7a63fc5
--- /dev/null
+++ b/emacs.ps
@@ -0,0 +1,3667 @@
+%!PS-Adobe-1.0
+%%DocumentFonts: Courier
+%%Title: <stdin> (mpage)
+%%Creator: mpage
+%%CreationDate: Tue Dec 3 13:26:16 1991
+%%Pages: (atend)
+%%BoundingBox: 20 20 596 776
+%%EndComments
+
+/mp_stm usertime def
+/mp_pgc statusdict begin pagecount end def
+statusdict begin /jobname (<stdin>) def end
+%%%BoundingBox: 13 10 577 832
+%%%Creator: Windows PSCRIPT
+%%%Title: Write - EMACS
+%%%Pages: (atend)
+%%%EndComments
+/showsheet { showpage } bind def
+/showpage { } def
+statusdict begin 0 setjobtimeout end
+statusdict begin statusdict /jobname (Write - EMACS) put end
+/Win33Dict 290 dict def Win33Dict begin/bd{bind def}bind def/in{72
+mul}bd/ed{exch def}bd/ld{load def}bd/tr/translate ld/gs/gsave ld/gr/grestore
+ld/M/moveto ld/L/lineto ld/rmt/rmoveto ld/rlt/rlineto ld/rct/rcurveto
+ld/st/stroke ld/n/newpath ld/sm/setmatrix ld/cm/currentmatrix ld/cp/closepath
+ld/ARC/arcn ld/TR{65536 div}bd/lj/setlinejoin ld/lc/setlinecap ld/ml/setmiterlimit
+ld/sl/setlinewidth ld/sc{0 index 2 index eq 2 index 4 index eq and{pop
+pop 255 div setgray}{3{255 div 3 1 roll}repeat setrgbcolor}ifelse}bd/FC{bR
+bG bB sc}bd/fC{/bB ed/bG ed/bR ed}bd/HC{hR hG hB sc}bd/hC{/hB ed/hG
+ed/hR ed}bd/PC{pR pG pB sc}bd/pC{/pB ed/pG ed/pR ed}bd/sM matrix def/PenW
+1 def/iPen 5 def/mxF matrix def/mxE matrix def/fBE false def/iDevRes
+72 0 matrix defaultmatrix dtransform dup mul exch dup mul add sqrt
+def/SS{/SV save def}bd/RS{SV restore}bd/EJ{gsave showpage grestore}bd/#C{userdict
+begin/#copies ed end}bd/SM{/iRes ed/cyP exch def/cxP exch def/cyM exch
+def/cxM exch def 72 iRes div dup neg scale 0 ne{cyP cxP neg tr 90 rotate
+cxM cyM}{cxM cyM cyP sub}ifelse tr 0 0 transform .25 add round .25
+sub exch .25 add round .25 sub exch itransform translate}bd/SJ{1 index
+0 eq{pop pop/fBE false def}{1 index/Break ed div/dxBreak ed/fBE true
+def}ifelse}bd/ANSIVec[ 16#0/grave 16#1/acute 16#2/circumflex 16#3/tilde
+16#4/macron 16#5/breve 16#6/dotaccent 16#7/dieresis 16#8/ring 16#9/cedilla
+16#A/hungarumlaut 16#B/ogonek 16#C/caron 16#D/dotlessi 16#27/quotesingle
+16#60/grave 16#7C/bar 16#91/quoteleft 16#92/quoteright 16#93/quotedblleft
+16#94/quotedblright 16#95/bullet 16#96/endash 16#97/emdash 16#A0/space
+16#A4/currency 16#A6/brokenbar 16#A7/section 16#A8/dieresis 16#A9/copyright
+16#AA/ordfeminine 16#AB/guillemotleft 16#AC/logicalnot 16#AD/hyphen
+16#AE/registered 16#AF/macron 16#B0/degree 16#B1/plusminus 16#B2/twosuperior
+16#B3/threesuperior 16#B4/acute 16#B5/mu 16#B6/paragraph 16#B7/periodcentered
+16#B8/cedilla 16#B9/onesuperior 16#BA/ordmasculine 16#BB/guillemotright
+16#BC/onequarter 16#BD/onehalf 16#BE/threequarters 16#BF/questiondown
+16#C0/Agrave 16#C1/Aacute 16#C2/Acircumflex 16#C3/Atilde 16#C4/Adieresis
+16#C5/Aring 16#C6/AE 16#C7/Ccedilla 16#C8/Egrave 16#C9/Eacute 16#CA/Ecircumflex
+16#CB/Edieresis 16#CC/Igrave 16#CD/Iacute 16#CE/Icircumflex 16#CF/Idieresis
+16#D0/Eth 16#D1/Ntilde 16#D2/Ograve 16#D3/Oacute 16#D4/Ocircumflex
+16#D5/Otilde 16#D6/Odieresis 16#D7/multiply 16#D8/Oslash 16#D9/Ugrave
+16#DA/Uacute 16#DB/Ucircumflex 16#DC/Udieresis 16#DD/Yacute 16#DE/Thorn
+16#DF/germandbls 16#E0/agrave 16#E1/aacute 16#E2/acircumflex 16#E3/atilde
+16#E4/adieresis 16#E5/aring 16#E6/ae 16#E7/ccedilla 16#E8/egrave 16#E9/eacute
+16#EA/ecircumflex 16#EB/edieresis 16#EC/igrave 16#ED/iacute 16#EE/icircumflex
+16#EF/idieresis 16#F0/eth 16#F1/ntilde 16#F2/ograve 16#F3/oacute 16#F4/ocircumflex
+16#F5/otilde 16#F6/odieresis 16#F7/divide 16#F8/oslash 16#F9/ugrave
+16#FA/uacute 16#FB/ucircumflex 16#FC/udieresis 16#FD/yacute 16#FE/thorn
+16#FF/ydieresis ] def/reencdict 12 dict def/IsChar{basefontdict/CharStrings
+get exch known}bd/MapCh{dup IsChar not{pop/bullet}if newfont/Encoding
+get 3 1 roll put}bd/MapDegree{16#b0/degree IsChar{/degree}{/ring}ifelse
+MapCh}bd/MapBB{16#a6/brokenbar IsChar{/brokenbar}{/bar}ifelse MapCh}bd/ANSIFont{reencdict
+begin/newfontname ed/basefontname ed FontDirectory newfontname known
+not{/basefontdict basefontname findfont def/newfont basefontdict maxlength
+dict def basefontdict{exch dup/FID ne{dup/Encoding eq{exch dup length
+array copy newfont 3 1 roll put}{exch newfont 3 1 roll put}ifelse}{pop
+pop}ifelse}forall newfont/FontName newfontname put 127 1 159{newfont/Encoding
+get exch/bullet put}for ANSIVec aload pop ANSIVec length 2 idiv{MapCh}repeat
+MapDegree MapBB newfontname newfont definefont pop}if newfontname end}bd/SB{FC/str
+ed str length fBE not{dup 1 gt{1 sub}if}if/cbStr ed/dxGdi ed/y0 ed/x0
+ed str stringwidth esc 0 ne{mxE itransform exch neg dxGdi add cbStr
+div exch mxE transform}{exch neg dxGdi add cbStr div exch}ifelse/dyExtra
+ed/dxExtra ed x0 y0 M fBE{dxBreak 0 BCh dxExtra dyExtra str awidthshow}{dxExtra
+dyExtra str ashow}ifelse fUL{x0 y0 M dxUL dyUL rmt dxGdi fBE{Break
+add}if 0 mxE transform rlt cyUL sl st}if fSO{x0 y0 M dxSO dySO rmt
+dxGdi fBE{Break add}if 0 mxE transform rlt cyUL sl st}if n/fBE false
+def}bd/font{/name ed/Ascent ed 0 ne/fSO ed 0 ne/fUL ed/Sy ed/Sx ed
+10.0 div/ori ed -10.0 div/esc ed/BCh ed name findfont [Sx 0 0 Sy neg
+0 Ascent] esc mxE rotate mxF concatmatrix makefont setfont fUL{currentfont
+dup/FontInfo get/UnderlinePosition known not{pop/Courier findfont}if/FontInfo
+get/UnderlinePosition get 1000 div 0 exch mxF transform/dyUL ed/dxUL
+ed}if fSO{0 .3 mxF transform/dySO ed/dxSO ed}if fUL fSO or{currentfont
+dup/FontInfo get/UnderlineThickness known not{pop/Courier findfont}if/FontInfo
+get/UnderlineThickness get 1000 div Sy mul/cyUL ed}if}bd/min{2 copy
+gt{exch}if pop}bd/max{2 copy lt{exch}if pop}bd/CP{/ft ed{{ft 0 eq{clip}{eoclip}ifelse}stopped{currentflat
+1 add setflat}{exit}ifelse}loop}bd/patfont 10 dict def patfont begin/FontType
+3 def/FontMatrix [1 0 0 1 0 0] def/FontBBox [0 0 32 32] def/Encoding
+StandardEncoding def/BuildChar{pop pop 32 0 0 0 32 32 setcachedevice
+2 2 scale 16 16 false [1 0 0 1 .25 .25]{pat}imagemask}bd end/p{/pat
+32 string def{}forall 0 1 7{dup 2 mul pat exch 3 index put dup 2 mul
+1 add pat exch 3 index put dup 2 mul 16 add pat exch 3 index put 2
+mul 17 add pat exch 2 index put pop}for}bd/pfill{/PatFont patfont definefont
+setfont/ch(AAAA)def X0 128 X1{Y0 32 Y1{1 index exch M ch show}for pop}for}bd/vert{X0
+w X1{dup Y0 M Y1 L st}for}bd/horz{Y0 w Y1{dup X0 exch M X1 exch L st}for}bd/fdiag{X0
+w X1{Y0 M X1 X0 sub dup rlt st}for Y0 w Y1{X0 exch M Y1 Y0 sub dup
+rlt st}for}bd/bdiag{X0 w X1{Y1 M X1 X0 sub dup neg rlt st}for Y0 w
+Y1{X0 exch M Y1 Y0 sub dup neg rlt st}for}bd/AU{1 add cvi 15 or}bd/AD{1
+sub cvi -16 and}bd/SHR{pathbbox AU/Y1 ed AU/X1 ed AD/Y0 ed AD/X0 ed}bd/hfill{2
+sl [] 0 setdash n/w iRes 20 div 8 div round 8 mul def dup 0 eq{horz}if
+dup 1 eq{vert}if dup 2 eq{fdiag}if dup 3 eq{bdiag}if dup 4 eq{horz
+vert}if 5 eq{fdiag bdiag}if}bd/F{/ft ed fm 256 and 0 ne{gs FC ft 0
+eq{fill}{eofill}ifelse gr}if fm 1536 and 0 ne{SHR gs HC ft CP fm 1024
+and 0 ne{/Tmp save def pfill Tmp restore}{fm 15 and hfill}ifelse gr}if}bd/S{PenW
+sl PC st}bd/m matrix def/GW{iRes 12 div PenW add cvi}bd/DoW{iRes 50
+div PenW add cvi}bd/DW{iRes 8 div PenW add cvi}bd/SP{/PenW ed/iPen
+ed iPen 0 eq{[] 0 setdash}if iPen 1 eq{[DW GW] 0 setdash}if iPen 2
+eq{[DoW GW] 0 setdash}if iPen 3 eq{[DW GW DoW GW] 0 setdash}if iPen
+4 eq{[DW GW DoW GW DoW GW] 0 setdash}if}bd/E{m cm pop tr scale 0 0
+1 0 360 arc cp m sm}bd/AG{/sy ed/sx ed sx div 4 1 roll sy div 4 1 roll
+sx div 4 1 roll sy div 4 1 roll atan/a2 ed atan/a1 ed sx sy scale a1
+a2 ARC}def/A{m cm pop tr AG m sm}def/P{m cm pop tr 0 0 M AG cp m sm}def/RR{m
+cm pop/y2 ed/x2 ed/ys y2 x2 div 1 max def/xs x2 y2 div 1 max def/y1
+exch ys div def/x1 exch xs div def/y0 exch ys div def/x0 exch xs div
+def/r2 x2 y2 min def xs ys scale x0 r2 add y0 M x1 y0 x1 y1 r2 arcto
+4{pop}repeat x1 y1 x0 y1 r2 arcto 4{pop}repeat x0 y1 x0 y0 r2 arcto
+4{pop}repeat x0 y0 x1 y0 r2 arcto 4{pop}repeat m sm cp}bd/PP{{rlt}repeat}bd/OB{gs
+sc B fill gr}bd/B{M/dy ed/dx ed dx 0 rlt 0 dy rlt dx neg 0 rlt cp}bd/CB{B
+clip n}bd
+%%EndProlog
+% %%Page: 1 1
+%%Page: 1 1
+/sheetsave save def
+gsave
+24 817 translate -90 rotate
+393 596 div 548 842 div scale
+0 0 moveto 0 842 lineto 596 842 lineto 596 0 lineto
+closepath clip newpath
+0 54 39 2478 3507 300 SM
+SS
+0 0 0 fC
+32 0 0 150 150 0 0 152 /Symbol font
+714 255 86 (m) SB
+32 0 0 150 150 0 0 145 /Times-Bold /font29 ANSIFont font
+800 262 467 (Emacs/) SB
+32 0 0 117 117 0 0 113 /Times-Bold /font29 ANSIFont font
+1267 294 162 (PK) SB
+32 0 0 150 150 0 0 145 /Times-Bold /font29 ANSIFont font
+1429 262 226 ( 4.0) SB
+32 0 0 58 58 0 0 52 /Times-Roman /font32 ANSIFont font
+635 517 1099 (Full screen editor based on MicroEMACS 3.9e) SB
+32 0 0 58 58 0 0 54 /Times-Italic /font31 ANSIFont font
+867 648 635 (written by Dave G. Conroy) SB
+710 717 949 (greatly modified by Daniel M. Lawrence) SB
+827 786 714 (modified by Petri H. Kutvonen) SB
+32 0 0 46 46 0 0 41 /Times-BoldItalic /font30 ANSIFont font
+32 0 0 46 46 0 0 44 /Times-Bold /font29 ANSIFont font
+1010 959 349 (Copyright notices) SB
+32 0 0 46 46 0 0 43 /Times-Italic /font31 ANSIFont font
+48 6 SJ
+418 1069 767 (MicroEMACS 3.9e \251 Copyright 1987 by ) SB
+36 4 SJ
+1233 1069 741 (Daniel M. Lawrence. Reference Manual) SB
+12 6 SJ
+418 1123 717 (Copyright 1987 by Brian Straight and ) SB
+18 6 SJ
+1147 1123 845 (Daniel M. Lawrence. All Rights Reserved. No) SB
+418 1177 1189 (copyright claimed for modifications made by Petri H. Kutvonen.) SB
+32 0 0 46 46 0 0 44 /Times-Bold /font29 ANSIFont font
+856 1339 715 (Original statement of copying policy) SB
+32 0 0 46 46 0 0 43 /Times-Italic /font31 ANSIFont font
+110 10 SJ
+418 1449 1182 (MicroEMACS 3.9e can be copied and distributed freely for any ) SB
+1710 1449 300 (non-commercial) SB
+9 3 SJ
+418 1503 552 (purposes. MicroEMACS 3.9e ) SB
+28 7 SJ
+979 1503 1003 (can only be corporated into commercial software with) SB
+418 1557 1108 (the permission of the current author [Daniel M. Lawrence].) SB
+32 0 0 58 58 0 0 56 /Times-Bold /font29 ANSIFont font
+182 1719 466 (INTRODUCTION) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+35 5 SJ
+182 1850 546 (uEmacs/PK 4.0 is a screen ) SB
+80 10 SJ
+763 1850 1344 (editor for programming and word processing. It is available for the) SB
+4 4 SJ
+182 1914 608 (IBM-PC and its clones, UNIX) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+794 1909 15 (\256) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+8 8 SJ
+809 1914 939 ( System V and 4.[23]BSD \(including SunOS, ) SB
+6 3 SJ
+1756 1914 425 (DEC Ultrix and IBM) SB
+182 1972 1116 (AIX\), and VAX/VMS. Some of its capabilities include:) SB
+32 0 0 50 50 0 0 41 /ZapfDingbats font
+182 2094 38 (o) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+359 2090 804 (Multiple windows on screen at one time) SB
+32 0 0 50 50 0 0 41 /ZapfDingbats font
+182 2212 38 (o) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+359 2208 683 (Multiple files in the editor at once) SB
+32 0 0 50 50 0 0 41 /ZapfDingbats font
+182 2330 38 (o) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+359 2326 734 (Limited on-screen formatting of text) SB
+32 0 0 50 50 0 0 41 /ZapfDingbats font
+182 2448 38 (o) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+359 2444 609 (User changeable command set) SB
+32 0 0 50 50 0 0 41 /ZapfDingbats font
+182 2566 38 (o) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+359 2562 558 (User written editing macros) SB
+32 0 0 50 50 0 0 41 /ZapfDingbats font
+182 2684 38 (o) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+359 2680 973 (Compatibility across all supported environments) SB
+11 11 SJ
+359 2796 1339 (This manual is designed as a reference manual. All the commands ) SB
+8 4 SJ
+1709 2796 470 (in uEmacs are listed, in) SB
+182 2854 1612 (functional groups, along with detailed descriptions of what each command does.) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+182 3183 198 (uEmacs 4.0) SB
+891 3183 209 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1100 3176 43 ( -) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1143 3183 11 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1154 3176 25 (1) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1179 3183 11 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1190 3176 17 (-) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1918 3183 269 (December 1991) SB
+showpage
+% %%Page: 2 2
+grestore sheetsave restore
+/sheetsave save def
+gsave
+24 416 translate -90 rotate
+393 596 div 548 842 div scale
+0 0 moveto 0 842 lineto 596 842 lineto 596 0 lineto
+closepath clip newpath
+0 54 39 2478 3507 300 SM
+0 0 0 fC
+32 0 0 58 58 0 0 56 /Times-Bold /font29 ANSIFont font
+182 197 456 (HOW TO START) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+182 328 1837 (uEmacs is invoked from the operating system command level with a command of the form:) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+359 442 130 (emacs) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+489 445 37 ( {) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+526 443 147 (options) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+673 445 37 (} ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+710 443 125 (filelist) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+182 563 455 (where options may be:) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+182 677 42 (-v) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+536 680 584 (All the following files are in ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+1120 678 100 (View) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1220 680 372 ( mode \(read only\).) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+182 738 39 (-e) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+536 741 735 (All the following files can be edited.) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+182 857 42 (-g) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+224 858 25 (n) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+536 860 380 (Go directly to line ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+916 858 25 (n) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+941 860 316 ( of the first file.) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+182 918 29 (+) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+211 919 25 (n) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+536 921 380 (Go directly to line ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+916 919 25 (n) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+941 921 316 ( of the first file.) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+182 1037 36 (-s) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+218 1038 116 (string) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+536 1040 795 (Go to the end of the first occurrence of ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+1331 1038 116 (string) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1447 1040 313 ( in the first file.) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+182 1156 39 (-r) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+15 5 SJ
+536 1159 819 (Restricted mode. Prevents uEmacs from ) SB
+20 5 SJ
+1370 1159 797 (executing many of its commands which) SB
+34 17 SJ
+536 1219 1556 (would allow you to break out of it, or edit files other then the ones named on ) SB
+2126 1219 61 (the) SB
+536 1277 298 (command line.) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+182 1391 45 (-n) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+536 1394 1112 (Allow reading of files which contain NULL characters.) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+182 1510 47 (@) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+229 1511 83 (sfile) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+536 1513 392 (Execute macro file ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+928 1511 83 (sfile) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1011 1513 707 ( instead of the standard startup file.) SB
+182 1623 85 (and ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+267 1621 125 (filelist) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+392 1623 848 ( is a list of files to be edited. For example:) SB
+32 0 0 42 42 0 0 33 /Courier /font0 ANSIFont font
+359 1752 1125 (emacs @start1.cmd -g56 test.c -v head.h def.h) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+48 12 SJ
+359 1856 1506 (means to first execute macro file start1.cmd instead of the standard startup ) SB
+5 1 SJ
+1913 1856 269 (file, emacs.rc) SB
+6 3 SJ
+182 1914 324 (\(or .emacsrc on ) SB
+42 14 SJ
+512 1914 1633 (UNIX, see appendix for details\) and then read in test.c, position the cursor to line) SB
+45 9 SJ
+182 1972 792 (56, and be ready to read in files head.h ) SB
+18 3 SJ
+1019 1972 252 (and def.h in ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+1289 1970 100 (View) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+36 6 SJ
+1389 1972 762 ( \(read-only\) mode. In the simple case,) SB
+182 2031 659 (uEmacs is usually run by typing:) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+359 2145 130 (emacs) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+489 2148 13 ( ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+502 2146 64 (file) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+182 2266 135 (where ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+317 2264 64 (file) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+381 2266 710 ( is the name of the file to be edited.) SB
+32 0 0 58 58 0 0 56 /Times-Bold /font29 ANSIFont font
+182 2439 1119 (HOW TO GET HELP AND HOW TO EXIT) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+6 1 SJ
+182 2571 112 (Esc ?) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+66 11 SJ
+300 2574 967 ( \(or actually Meta ? as you soon will learn\) will ) SB
+49 7 SJ
+1333 2574 805 (bring up a short summary of all uEmacs) SB
+182 2635 1105 (commands. On a VT200 or equivalent you can use the ) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+1287 2632 103 (Help) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1390 2635 499 ( key. On an IBM-PC try ) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+1889 2632 56 (F1) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1945 2635 13 (.) SB
+16 4 SJ
+359 2757 375 (Don't panic if you ) SB
+20 4 SJ
+750 2757 517 (get stuck within uEmacs. ) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+1287 2754 145 (Ctrl-G) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+30 6 SJ
+1432 2757 725 ( will abort almost any operation and) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+182 2815 297 (Ctrl-X Ctrl-C) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+479 2818 569 ( will get you out of uEmacs.) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+182 3183 198 (uEmacs 4.0) SB
+891 3183 209 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1100 3176 43 ( -) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1143 3183 11 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1154 3176 25 (2) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1179 3183 11 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1190 3176 17 (-) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1918 3183 269 (December 1991) SB
+showpage
+% %%Page: 3 3
+grestore sheetsave restore
+showsheet
+%%Page: 2 2
+/sheetsave save def
+gsave
+24 817 translate -90 rotate
+393 596 div 548 842 div scale
+0 0 moveto 0 842 lineto 596 842 lineto 596 0 lineto
+closepath clip newpath
+0 54 39 2478 3507 300 SM
+0 0 0 fC
+32 0 0 58 58 0 0 56 /Times-Bold /font29 ANSIFont font
+182 197 867 (HOW TO TYPE IN COMMANDS) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+42 14 SJ
+182 328 1616 (Most commands in uEmacs are a single keystroke, or a keystroke preceded by a ) SB
+4 1 SJ
+1840 328 343 (command prefix.) SB
+20 4 SJ
+182 387 593 (Control commands appear in ) SB
+18 3 SJ
+795 387 472 (the documentation like ) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+1285 384 65 (^A) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+42 7 SJ
+1350 387 795 ( which means to depress the <Ctrl> key) SB
+12 6 SJ
+182 448 652 (and while holding it down, type ) SB
+21 7 SJ
+846 448 876 (the A character. Meta commands appear as ) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+3 1 SJ
+1743 445 160 (Meta A) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+6 2 SJ
+1906 448 275 ( which means) SB
+77 7 SJ
+182 508 727 (to strike the <Meta> key \(<Esc> on ) SB
+108 9 SJ
+986 508 1093 (most computers\) and then after releasing it, type the A) SB
+182 567 1014 (character. Control-X commands usually appear as ) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+1 1 SJ
+1197 564 114 (^X A) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+8 8 SJ
+1312 567 867 ( which means to hold down the control key) SB
+182 627 184 (and type ) SB
+13 13 SJ
+367 627 1807 (the X character then type the A character. Both meta commands and control-X commands) SB
+24 8 SJ
+182 685 945 (can be control characters as well, for example, ) SB
+12 3 SJ
+1151 685 235 (^X ^O \(the ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+1398 683 358 (delete-blank-lines) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+12 3 SJ
+1756 685 419 ( command\) means to) SB
+182 744 1594 (hold down <Ctrl>, type X, keep holding down <Ctrl> and type the O character.) SB
+98 14 SJ
+359 860 1529 (Many commands in uEmacs can be executed a number of times. In order to ) SB
+8 1 SJ
+1986 860 193 (make one) SB
+7 7 SJ
+182 918 1048 (command repeat many times, type <Meta> \(<Esc>\) ) SB
+14 7 SJ
+1237 918 936 (followed by a number, and then the command.) SB
+182 976 255 (for example:) SB
+359 1092 237 (Meta 12 ^K) SB
+36 12 SJ
+359 1208 1414 (will delete 12 lines starting at the cursor and going down. Sometimes, ) SB
+12 3 SJ
+1809 1208 366 (the repeat count is) SB
+48 16 SJ
+182 1266 1760 (used as an argument to the command as in the set-tab command where the repeat count ) SB
+8 2 SJ
+1990 1266 189 (is used to) SB
+182 1324 625 (set the spacing of the tab stops.) SB
+32 0 0 58 58 0 0 56 /Times-Bold /font29 ANSIFont font
+182 1496 609 (THE COMMAND LIST) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+24 6 SJ
+182 1627 509 (The following is a list of ) SB
+55 11 SJ
+715 1627 1417 (all the commands in uEmacs. Listed is the command name, the default) SB
+130 13 SJ
+182 1685 1603 (\(normal\) keystrokes used to invoke it, and alternative keys for the IBM-PC and ) SB
+1915 1685 272 (VT200-series) SB
+182 1743 1120 (terminals, and a description of what the command does.) SB
+32 0 0 58 58 0 0 56 /Times-Bold /font29 ANSIFont font
+182 1915 459 (Moving the cursor) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 2044 285 (previous-page) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 2046 54 (^Z) SB
+1186 2046 127 (Pg Up) SB
+1600 2046 197 (Prev Scrn) SB
+359 2163 1021 (Move one screen towards the beginning of the file.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 2277 197 (next-page) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 2279 59 (^V) SB
+1186 2279 127 (Pg Dn) SB
+1600 2279 202 (Next Scrn) SB
+359 2396 893 (Move one screen towards the end of the file.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 2510 337 (beginning-of-file) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 2512 143 (Meta <) SB
+1186 2512 145 (^Home) SB
+359 2629 878 (Place the cursor at the beginning of the file.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 2743 209 (end-of-file) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 2745 143 (Meta >) SB
+1186 2745 104 (^End) SB
+359 2862 750 (Place the cursor at the end of the file.) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+182 3183 198 (uEmacs 4.0) SB
+891 3183 209 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1100 3176 43 ( -) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1143 3183 11 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1154 3176 25 (3) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1179 3183 11 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1190 3176 17 (-) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1918 3183 269 (December 1991) SB
+showpage
+% %%Page: 4 4
+grestore sheetsave restore
+/sheetsave save def
+gsave
+24 416 translate -90 rotate
+393 596 div 548 842 div scale
+0 0 moveto 0 842 lineto 596 842 lineto 596 0 lineto
+closepath clip newpath
+0 54 39 2478 3507 300 SM
+0 0 0 fC
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 201 370 (forward-character) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 203 51 (^F) SB
+32 0 0 50 50 0 0 51 /Symbol font
+1186 197 49 (\336) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+32 0 0 50 50 0 0 51 /Symbol font
+1600 197 49 (\336) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+359 322 1766 (Move the cursor one character to the right. Go down to the beginning of the next line if ) SB
+2126 322 61 (the) SB
+182 380 968 (cursor was already at the end of the current line.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 498 406 (backward-character) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 500 56 (^B) SB
+32 0 0 50 50 0 0 51 /Symbol font
+1186 494 49 (\334) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+32 0 0 50 50 0 0 51 /Symbol font
+1600 494 49 (\334) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+45 15 SJ
+359 619 1440 (Move the cursor one character to the left. Go to the end of the previous ) SB
+12 3 SJ
+1844 619 331 (line if the cursor) SB
+182 677 798 (was at the beginning of the current line.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 795 202 (next-word) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 797 143 (Meta F) SB
+1186 797 23 (^) SB
+32 0 0 50 50 0 0 51 /Symbol font
+1209 791 49 (\336) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+359 916 1013 (Place the cursor at the beginning of the next word.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 1034 290 (previous-word) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 1036 148 (Meta B) SB
+1186 1036 23 (^) SB
+32 0 0 50 50 0 0 51 /Symbol font
+1209 1030 49 (\334) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+359 1155 1099 (Place the cursor at the beginning of the previous word.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 1269 348 (beginning-of-line) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 1271 59 (^A) SB
+1186 1271 122 (Home) SB
+359 1388 978 (Move cursor to the beginning of the current line.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 1502 220 (end-of-line) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 1504 54 (^E) SB
+1186 1504 81 (End) SB
+359 1621 924 (Move the cursor to the end of the current line.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 1739 175 (next-line) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 1741 59 (^N) SB
+32 0 0 50 50 0 0 51 /Symbol font
+1186 1735 30 (\337) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+32 0 0 50 50 0 0 51 /Symbol font
+1600 1735 30 (\337) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+359 1860 638 (Move the cursor down one line.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 1978 263 (previous-line) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 1980 51 (^P) SB
+32 0 0 50 50 0 0 51 /Symbol font
+1186 1974 30 (\335) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+32 0 0 50 50 0 0 51 /Symbol font
+1600 1974 30 (\335) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+359 2099 577 (Move the cursor up one line.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 2213 181 (goto-line) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 2215 151 (Meta G) SB
+26 13 SJ
+359 2332 1181 (Goto a specific line in the file. I.e. Meta 65 Meta G would ) SB
+18 6 SJ
+1566 2332 603 (put the cursor on the 65th line) SB
+182 2390 420 (of the current buffer.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 2508 313 (next-paragraph) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 2510 151 (Meta N) SB
+1186 2510 23 (^) SB
+32 0 0 50 50 0 0 51 /Symbol font
+1209 2504 30 (\337) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+359 2629 1179 (Put the cursor at the first end of paragraph after the cursor.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 2747 401 (previous-paragraph) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 2749 143 (Meta P) SB
+1186 2749 23 (^) SB
+32 0 0 50 50 0 0 51 /Symbol font
+1209 2743 30 (\335) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+359 2868 1343 (Put the cursor at the first beginning of paragraph before the cursor.) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+182 3183 198 (uEmacs 4.0) SB
+891 3183 209 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1100 3176 43 ( -) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1143 3183 11 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1154 3176 25 (4) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1179 3183 11 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1190 3176 17 (-) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1918 3183 269 (December 1991) SB
+showpage
+% %%Page: 5 5
+grestore sheetsave restore
+showsheet
+%%Page: 3 3
+/sheetsave save def
+gsave
+24 817 translate -90 rotate
+393 596 div 548 842 div scale
+0 0 moveto 0 842 lineto 596 842 lineto 596 0 lineto
+closepath clip newpath
+0 54 39 2478 3507 300 SM
+0 0 0 fC
+32 0 0 58 58 0 0 56 /Times-Bold /font29 ANSIFont font
+182 197 548 (Deleting and inserting) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 330 517 (delete-previous-character) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 332 59 (^H) SB
+32 0 0 50 50 0 0 51 /Symbol font
+1186 326 49 (\254) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+20 10 SJ
+359 451 1162 (Delete the character immediately to the left of the cursor. ) SB
+18 6 SJ
+1541 451 628 (If the cursor is at the beginning) SB
+182 509 1396 (of a line, this will join the current line on the end of the previous one.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 623 429 (delete-next-character) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 625 59 (^D) SB
+1186 625 72 (Del) SB
+359 742 1350 (Delete the character the cursor is on. If the cursor is at the end of a ) SB
+5 5 SJ
+1710 742 472 (line, the next line is put) SB
+182 800 577 (at the end of the current one.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 919 422 (delete-previous word) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 921 174 (Meta ^H) SB
+1186 921 115 (Meta ) SB
+32 0 0 50 50 0 0 51 /Symbol font
+1301 915 49 (\254) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+359 1040 686 (Delete the word before the cursor.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 1154 338 (delete-next-word) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 1156 151 (Meta D) SB
+359 1273 757 (Delete the word starting at the cursor.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 1388 357 (kill-to-end-of-line) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 1390 59 (^K) SB
+359 1507 1588 (When used with no argument, this command deletes all text from the cursor to ) SB
+3 3 SJ
+1948 1507 236 (the end of a) SB
+30 10 SJ
+182 1565 926 (line. When used on a blank line, it deletes the ) SB
+32 8 SJ
+1138 1565 1017 (blank line. When used with an argument, it deletes) SB
+182 1623 595 (the specified number of lines.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 1737 243 (insert-space) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 1739 56 (^C) SB
+1186 1739 61 (Ins) SB
+359 1856 1017 (Insert a space before the character the cursor is on.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 1970 155 (newline) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 1972 136 (Return) SB
+1186 1972 109 (Enter) SB
+24 12 SJ
+359 2089 1185 (Insert a newline into the text, move the cursor down to the ) SB
+12 4 SJ
+1568 2089 607 (beginning of the next physical) SB
+182 2147 921 (line, carrying any text that was after it with it.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 2261 389 (newline-and-indent) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 2263 42 (^J) SB
+359 2380 1670 (Insert a newline into the text, and indent the new line the same as the previous line.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 2498 217 (handle-tab) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 2500 40 (^I) SB
+32 0 0 50 50 0 0 51 /Symbol font
+1186 2494 59 (\256|) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1600 2500 78 (Tab) SB
+48 4 SJ
+359 2619 515 (With no argument, move ) SB
+143 11 SJ
+922 2619 1122 (the cursor to the beginning of the next tab stop. With an) SB
+24 6 SJ
+182 2677 610 (argument of zero, use real tab ) SB
+45 9 SJ
+816 2677 1326 (characters when tabbing. With a non-zero argument, use spaces to) SB
+182 2735 593 (tab every argument positions.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 2849 358 (delete-blank-lines) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 2851 131 (^X ^O) SB
+359 2968 1383 (Delete all the blank lines before and after the current cursor position.) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+182 3183 198 (uEmacs 4.0) SB
+891 3183 209 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1100 3176 43 ( -) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1143 3183 11 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1154 3176 25 (5) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1179 3183 11 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1190 3176 17 (-) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1918 3183 269 (December 1991) SB
+showpage
+% %%Page: 6 6
+grestore sheetsave restore
+/sheetsave save def
+gsave
+24 416 translate -90 rotate
+393 596 div 548 842 div scale
+0 0 moveto 0 842 lineto 596 842 lineto 596 0 lineto
+closepath clip newpath
+0 54 39 2478 3507 300 SM
+0 0 0 fC
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 197 175 (trim-line) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 199 126 (^X ^T) SB
+359 316 902 (Delete trailing white space from current line.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 430 203 (detab-line) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 432 131 (^X ^A) SB
+359 549 1533 (Change tabulator characters to appropriate number of spaces on current line.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 663 203 (entab-line) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 665 126 (^X ^E) SB
+359 782 1382 (Change spaces to tabulator characters where possible on current line.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 896 294 (kill-paragraph) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 898 185 (Meta ^W) SB
+359 1015 1022 (Delete the paragraph that the cursor is currently in.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 1129 211 (kill-region) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 1131 70 (^W) SB
+1186 1131 95 (^Del) SB
+1600 1131 166 (Remove) SB
+359 1248 1702 (Delete all the characters from the cursor to the mark set with the set-mark command.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 1362 241 (copy-region) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 1364 162 (Meta W) SB
+40 10 SJ
+359 1481 1139 (Copy all the characters between the cursor and the mark ) SB
+20 4 SJ
+1538 1481 629 (set with the set-mark command) SB
+182 1539 1184 (into the kill buffer \(so they can later be yanked elsewhere\).) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 1653 189 (open-line) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 1655 59 (^O) SB
+359 1772 1160 (Insert a newline at the cursor, but do not move the cursor.) SB
+32 0 0 58 58 0 0 56 /Times-Bold /font29 ANSIFont font
+182 1944 248 (Searching) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 2073 309 (search-forward) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 2075 51 (^S) SB
+1600 2075 143 (Meta S) SB
+60 10 SJ
+359 2192 1087 (Search for a string from the current cursor position to ) SB
+49 7 SJ
+1506 2192 632 (the end of the file. The string is) SB
+22 11 SJ
+182 2250 1161 (typed on on the bottom line of the screen, and terminated ) SB
+15 5 SJ
+1365 2250 807 (with the <Meta> key. Special characters) SB
+16 8 SJ
+182 2308 806 (can be typed in by preceding them with ) SB
+39 13 SJ
+1004 2308 1144 (a ^Q or ^V. A single ^Q or ^V indicates a null string. On) SB
+40 5 SJ
+182 2366 852 (successive searches, hitting <Meta> alone ) SB
+72 8 SJ
+1074 2366 833 (causes the last search string to be reused. ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+9 1 SJ
+1979 2364 199 (Note: The) SB
+182 2423 1700 (command ^S cannot be used if your terminal uses XON-XOFF-flow control. Use the ) SB
+2 2 SJ
+1883 2423 302 (second form or) SB
+182 2482 387 (incremental-search) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+569 2484 13 ( ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+582 2482 157 (instead.) SB
+182 2599 294 (search-reverse) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 2601 56 (^R) SB
+359 2718 1778 (This command searches backwards in the file. In all other ways it is like search-forward.) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+182 3183 198 (uEmacs 4.0) SB
+891 3183 209 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1100 3176 43 ( -) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1143 3183 11 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1154 3176 25 (6) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1179 3183 11 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1190 3176 17 (-) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1918 3183 269 (December 1991) SB
+showpage
+% %%Page: 7 7
+grestore sheetsave restore
+showsheet
+%%Page: 4 4
+/sheetsave save def
+gsave
+24 817 translate -90 rotate
+393 596 div 548 842 div scale
+0 0 moveto 0 842 lineto 596 842 lineto 596 0 lineto
+closepath clip newpath
+0 54 39 2478 3507 300 SM
+0 0 0 fC
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 197 387 (incremental-search) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 199 100 (^X S) SB
+1600 199 92 (Find) SB
+359 316 1212 (This command is similar to forward-search, but it processes ) SB
+5 5 SJ
+1572 316 610 (the search as each character of) SB
+60 15 SJ
+182 374 1378 (the input string is typed in. This allows the user to only use as many ) SB
+20 4 SJ
+1620 374 547 (keystrokes as are needed to) SB
+182 432 1969 (uniquely specify the string being searched. Several control characters are active while i-searching:) SB
+359 548 178 (^S or ^X) SB
+714 548 960 (Skip to the next occurrence of the current string) SB
+359 606 56 (^R) SB
+714 606 943 (Skip to the last occurrence of the current string) SB
+359 668 127 (^H or ) SB
+32 0 0 50 50 0 0 51 /Symbol font
+486 662 49 (\254) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+16 2 SJ
+714 668 178 (Back up ) SB
+90 10 SJ
+908 668 1189 (to the last match \(possibly deleting the last character on the) SB
+714 729 271 (search string\)) SB
+359 787 59 (^G) SB
+714 787 628 (Abort the search, return to start) SB
+359 845 102 (Meta) SB
+714 845 500 (End the search, stay here) SB
+359 961 1388 (Always remember to terminate the search by hitting <Meta> \(or ^G\).) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 1075 549 (reverse-incremental-search) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 1077 105 (^X R) SB
+359 1194 1717 (This command is the same as incremental-search, but it starts in the reverse direction.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 1308 266 (hunt-forward) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 1310 175 (unbound) SB
+1186 1310 513 (\(<Alt> S on the IBM PC\)) SB
+359 1427 1274 (This command repeats the last search with the last search string) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 1541 302 (hunt-backward) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 1543 175 (unbound) SB
+1186 1543 518 (\(<Alt> R on the IBM PC\)) SB
+359 1660 1569 (The last search string is looked for starting at the cursor and going backwards.) SB
+32 0 0 58 58 0 0 56 /Times-Bold /font29 ANSIFont font
+182 1832 248 (Replacing) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 1961 282 (replace-string) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 1963 148 (Meta R) SB
+359 2080 455 (This command allows ) SB
+11 11 SJ
+815 2080 1361 (you to replace all occurrences of one string with another string. The) SB
+24 12 SJ
+182 2138 1335 (replacement starts at the current location of the cursor and goes to ) SB
+18 6 SJ
+1541 2138 628 (the end of the current buffer. A) SB
+182 2196 1201 (numeric argument will limit the number of strings replaced.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 2310 412 (query-replace-string) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 2312 171 (Meta ^R) SB
+30 3 SJ
+359 2429 467 (Like the replace-string ) SB
+88 8 SJ
+856 2429 1243 (command, this command will replace one string with another.) SB
+14 1 SJ
+182 2487 209 (However, ) SB
+240 16 SJ
+405 2487 1542 (it allows you to step through each string and ask you if you wish to make the) SB
+22 11 SJ
+182 2545 1262 (replacement. When the computer asks if you wish to make the ) SB
+9 3 SJ
+1466 2545 712 (replacement, the following answers) SB
+182 2603 246 (are allowed:) SB
+359 2719 36 (Y) SB
+714 2719 1129 (Make the replacement and continue on to the next string) SB
+359 2777 36 (N) SB
+714 2777 858 (Don't make the replacement, then continue) SB
+359 2835 17 (!) SB
+714 2835 903 (Replace the rest of the strings without asking) SB
+359 2893 59 (^G) SB
+714 2893 376 (Stop the command) SB
+359 2951 13 (.) SB
+714 2951 768 (Go back to place the command started) SB
+359 3009 22 (?) SB
+714 3009 396 (Get a list of options) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+182 3183 198 (uEmacs 4.0) SB
+891 3183 209 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1100 3176 43 ( -) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1143 3183 11 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1154 3176 25 (7) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1179 3183 11 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1190 3176 17 (-) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1918 3183 269 (December 1991) SB
+showpage
+% %%Page: 8 8
+grestore sheetsave restore
+/sheetsave save def
+gsave
+24 416 translate -90 rotate
+393 596 div 548 842 div scale
+0 0 moveto 0 842 lineto 596 842 lineto 596 0 lineto
+closepath clip newpath
+0 54 39 2478 3507 300 SM
+0 0 0 fC
+32 0 0 58 58 0 0 56 /Times-Bold /font29 ANSIFont font
+182 313 715 (Capitalizing and transposing) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 442 340 (case-word-upper) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 444 151 (Meta U) SB
+359 561 879 (Change the following word into upper case.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 675 418 (case-word-capitalize) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 677 148 (Meta C) SB
+359 794 613 (Capitalize the following word.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 908 337 (case-word-lower) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 910 146 (Meta L) SB
+359 1027 840 (Change the following word to lower case.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 1141 368 (case-region-upper) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 1143 131 (^X ^U) SB
+359 1260 1403 (Change all the alphabetic characters in a marked region to upper case.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 1374 365 (case-region-lower) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 1376 126 (^X ^L) SB
+359 1493 1403 (Change all the alphabetic characters in a marked region to lower case.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 1607 422 (transpose-characters) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 1609 54 (^T) SB
+359 1726 1174 (Swap the last and second last characters behind the cursor.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 1840 321 (quote-character) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 1842 59 (^Q) SB
+1600 1842 108 (^X Q) SB
+40 5 SJ
+359 1959 633 (Insert the next typed character, ) SB
+81 9 SJ
+1032 1959 1074 (ignoring the fact that it may be a command character.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 2015 1573 (Note: This command may cause problems if XON-XOFF-flow control is used.) SB
+32 0 0 58 58 0 0 56 /Times-Bold /font29 ANSIFont font
+182 2190 661 (Regions and the kill buffer) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 2319 174 (set-mark) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 2321 234 (Meta Space) SB
+1600 2321 122 (Select) SB
+30 10 SJ
+359 2438 1046 (This command is used to delimit the beginning of a ) SB
+16 4 SJ
+1435 2438 736 (marked region. Many commands are) SB
+112 16 SJ
+182 2496 1576 (effective for a region of text. A region is defined as the text between the mark ) SB
+16 2 SJ
+1870 2496 301 (and the current) SB
+10 5 SJ
+182 2554 561 (cursor position. To delete a ) SB
+36 12 SJ
+753 2554 1398 (section of text, for example, one moves the cursor to the beginning of) SB
+10 5 SJ
+182 2612 444 (the text to be deleted, ) SB
+30 10 SJ
+636 2612 1521 (issues the set-mark command by typing <Meta> <Space>, moves the cursor) SB
+102 17 SJ
+182 2670 1569 (to the end of the text to be deleted, and then deletes it by using the kill-region ) SB
+7 1 SJ
+1853 2670 327 (\(^W\) command.) SB
+16 16 SJ
+182 2728 1395 (Only one mark can be set in one window or one buffer at a time, and ) SB
+8 4 SJ
+1593 2728 586 (uEmacs will try to remember) SB
+182 2786 1316 (a mark set in an offscreen buffer when it is called back on screen.) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+182 3183 198 (uEmacs 4.0) SB
+891 3183 209 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1100 3176 43 ( -) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1143 3183 11 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1154 3176 25 (8) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1179 3183 11 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1190 3176 17 (-) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1918 3183 269 (December 1991) SB
+showpage
+% %%Page: 9 9
+grestore sheetsave restore
+showsheet
+%%Page: 5 5
+/sheetsave save def
+gsave
+24 817 translate -90 rotate
+393 596 div 548 842 div scale
+0 0 moveto 0 842 lineto 596 842 lineto 596 0 lineto
+closepath clip newpath
+0 54 39 2478 3507 300 SM
+0 0 0 fC
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 197 519 (exchange-point-and-mark) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 199 131 (^X ^X) SB
+12 12 SJ
+359 316 1411 (This command moves the cursor to the current marked position in the ) SB
+4 2 SJ
+1782 316 401 (current window and) SB
+12 3 SJ
+182 374 333 (moves the mark ) SB
+80 16 SJ
+527 374 1580 (to where the cursor was. This is very useful in finding where a mark was, or in) SB
+182 432 845 (returning to a position previously marked.) SB
+32 0 0 58 58 0 0 56 /Times-Bold /font29 ANSIFont font
+182 604 515 (Copying and moving) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 733 211 (kill-region) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 735 70 (^W) SB
+1600 735 166 (Remove) SB
+4 2 SJ
+359 852 312 (This command ) SB
+42 14 SJ
+675 852 1470 (is used to copy the current region \(as defined by the current mark and the) SB
+182 910 536 (cursor\) into the kill buffer.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 1024 94 (yank) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 1026 59 (^Y) SB
+1186 1026 84 (^Ins) SB
+1600 1026 224 (Insert Here) SB
+10 5 SJ
+359 1143 550 (This copies the contents of ) SB
+33 11 SJ
+919 1143 1235 (the kill buffer into the text at the current cursor position. This) SB
+182 1201 1918 (does not clear the kill buffer, and thus may be used to make multiple copies of a section of text.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 1315 241 (copy-region) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 1317 162 (Meta W) SB
+60 5 SJ
+359 1434 705 (This command copies the contents ) SB
+104 8 SJ
+1124 1434 959 (of the current region into the kill buffer without) SB
+182 1492 691 (deleting it from the current buffer.) SB
+32 0 0 58 58 0 0 56 /Times-Bold /font29 ANSIFont font
+182 1664 481 (Modes of operation) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 1793 200 (add-mode) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 1795 116 (^X M) SB
+359 1912 662 (Add a mode to the current buffer) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 2026 244 (delete-mode) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 2028 139 (^X ^M) SB
+359 2145 765 (Delete a mode from the current buffer) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 2259 345 (add-global-mode) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 2261 159 (Meta M) SB
+18 6 SJ
+359 2378 522 (Add a mode to the global ) SB
+40 10 SJ
+899 2378 1248 (modes which get inherited by any new buffers that are created) SB
+182 2436 276 (while editing.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 2550 389 (delete-global-mode) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 2552 182 (Meta ^M) SB
+17 17 SJ
+359 2669 1696 (Delete a mode from the global mode list. This mode list is displayed as the first line ) SB
+2 1 SJ
+2072 2669 113 (in the) SB
+182 2727 920 (output produced by the list-buffers command.) SB
+39 13 SJ
+359 2843 1528 (Modes are assigned to all buffers that exist during an editing session. These ) SB
+4 1 SJ
+1926 2843 257 (modes effect) SB
+182 2901 1609 (the way text is inserted, and the operation of some commands. Legal modes are:) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+182 3183 198 (uEmacs 4.0) SB
+891 3183 209 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1100 3176 43 ( -) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1143 3183 11 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1154 3176 25 (9) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1179 3183 11 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1190 3176 17 (-) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1918 3183 269 (December 1991) SB
+showpage
+% %%Page: 10 10
+grestore sheetsave restore
+/sheetsave save def
+gsave
+24 416 translate -90 rotate
+393 596 div 548 842 div scale
+0 0 moveto 0 842 lineto 596 842 lineto 596 0 lineto
+closepath clip newpath
+0 54 39 2478 3507 300 SM
+0 0 0 fC
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+359 197 121 (Over ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+480 200 17 (-) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+497 197 13 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+510 200 327 (Overwrite mode) SB
+25 5 SJ
+359 318 616 (In this mode, typed characters ) SB
+42 7 SJ
+1000 318 1145 (replace existing characters rather than being inserted into) SB
+90 10 SJ
+359 376 1422 (existing lines. Newlines still insert themselves, but all other characters ) SB
+20 2 SJ
+1871 376 296 (will write over) SB
+70 14 SJ
+359 434 1619 (existing characters on the current line being edited. This mode is very useful for ) SB
+2048 434 139 (editing) SB
+359 492 524 (charts, figures, and tables.) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+359 606 138 (Wrap ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+497 609 17 (-) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+514 606 13 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+527 609 351 (Word wrap mode) SB
+359 727 610 (In this mode, when the cursor ) SB
+10 10 SJ
+970 727 1207 (crosses the current fill column \(which defaults to 72\) it will,) SB
+21 7 SJ
+359 785 884 (at the next word break, automatically insert ) SB
+28 7 SJ
+1264 785 895 (a newline, dragging the last word down with) SB
+60 12 SJ
+359 843 1512 (it. This makes typing prose much easier since the newline \(<Return>\) only ) SB
+18 3 SJ
+1931 843 238 (needs to be) SB
+359 901 515 (used between paragraphs.) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+359 1015 121 (View ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+480 1018 645 (- File viewing \(read-only\) mode) SB
+359 1136 1347 (In this mode, no commands which can change the text are allowed.) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+359 1250 196 (Cmode - ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+555 1253 492 (C program editing mode) SB
+28 4 SJ
+359 1371 344 (This mode is for ) SB
+72 9 SJ
+731 1371 1384 (editing programs written in the 'C' programming language. When the) SB
+24 8 SJ
+359 1429 844 (newline is used, the editor will attempt to ) SB
+28 7 SJ
+1227 1429 932 (place the cursor at the proper indentation level) SB
+8 1 SJ
+359 1487 63 (on ) SB
+117 13 SJ
+430 1487 1640 (the next line. Close braces are automatically un-idented for the user, and also pre-) SB
+78 6 SJ
+359 1545 973 (processor commands are automatically set flush ) SB
+84 6 SJ
+1410 1545 693 (with the left margin. When a close) SB
+359 1603 1644 (parenthesis or brace is typed, if the matching open is on screen, the cursor briefly ) SB
+1 1 SJ
+2004 1603 182 (moves to) SB
+63 7 SJ
+359 1661 703 (it, and then back. \(Typing any key ) SB
+70 7 SJ
+1125 1661 992 (will abort this fence matching, executing the next) SB
+359 1719 477 (command immediately\)) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+359 1833 122 (Exact) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+481 1836 721 ( - Exact case matching on searching) SB
+105 7 SJ
+359 1954 990 (Normally case is insignificant during the various ) SB
+64 4 SJ
+1454 1954 669 (search commands. This forces all) SB
+359 2012 900 (matching to take character case into account.) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+359 2126 133 (Magic) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+492 2129 778 ( - Regular expression pattern matching) SB
+20 10 SJ
+359 2247 1484 (This feature causes search commands to accept various pattern characters ) SB
+6 2 SJ
+1863 2247 318 (to allow regular) SB
+359 2305 1123 (expression search and replaces. See chapter "The Magic) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+1482 2303 13 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1495 2305 364 (Mode" for details.) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+359 2420 127 (Asave) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+486 2423 355 ( - Automatic save) SB
+359 2541 1814 (This causes uEmacs to write your current file on disk when a certain number \(default 256\)) SB
+359 2599 740 (of new characters have been entered.) SB
+32 0 0 58 58 0 0 56 /Times-Bold /font29 ANSIFont font
+182 2771 536 (On-screen formatting) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 2900 292 (set-fill-column) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 2902 100 (^X F) SB
+359 3019 500 (Sets the column used by ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+859 3017 111 (Wrap) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+970 3019 222 ( mode and ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+1192 3017 286 (fill-paragraph) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1478 3019 98 ( and ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+1576 3017 352 (justify-paragraph) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1928 3019 242 ( commands.) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+182 3183 198 (uEmacs 4.0) SB
+891 3183 209 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1100 3176 43 ( -) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1143 3183 11 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1154 3176 50 (10) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1204 3183 11 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1215 3176 17 (-) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1918 3183 269 (December 1991) SB
+showpage
+% %%Page: 11 11
+grestore sheetsave restore
+showsheet
+%%Page: 6 6
+/sheetsave save def
+gsave
+24 817 translate -90 rotate
+393 596 div 548 842 div scale
+0 0 moveto 0 842 lineto 596 842 lineto 596 0 lineto
+closepath clip newpath
+0 54 39 2478 3507 300 SM
+0 0 0 fC
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 259 217 (handle-tab) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 261 40 (^I) SB
+32 0 0 50 50 0 0 51 /Symbol font
+1186 255 59 (\256|) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1600 261 78 (Tab) SB
+56 7 SJ
+359 380 795 (Given a numeric argument, the tab key ) SB
+72 8 SJ
+1210 380 905 (resets the normal behavior of the tab key. An) SB
+90 18 SJ
+182 438 1829 (argument of zero causes the tab key to generate hardware tabs \(at each 8 or 4 columns, see ) SB
+2101 438 86 ($tab) SB
+14 14 SJ
+182 496 1681 (variable\). A non-zero argument will cause the tab key to generate enough spaces to ) SB
+4 2 SJ
+1877 496 306 (reach a column) SB
+182 554 1578 (of a multiple of the argument given. This also resets the spacing used while in ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+1760 552 141 (Cmode) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1901 554 13 (.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 669 286 (fill-paragraph) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 671 151 (Meta Q) SB
+13 13 SJ
+359 788 1488 (This takes all the text in the current paragraph \(as defined by surrounding ) SB
+6 3 SJ
+1860 788 321 (blank lines, or a) SB
+182 846 1664 (leading indent\) and attempt to fill it from the left margin to the current fill column.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 960 352 (justify-paragraph) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 962 134 (Meta J) SB
+12 2 SJ
+359 1079 148 (This is ) SB
+28 4 SJ
+519 1079 444 (a modified version of ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+991 1077 299 (fill-paragraph.) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+63 9 SJ
+1290 1079 834 ( The left margin is taken to be the current) SB
+182 1138 1423 (column. No extra white space is inserted after punctuation. The cursor ) SB
+5 5 SJ
+1606 1138 576 (is moved to the beginning of) SB
+182 1196 312 (next paragraph.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 1310 297 (buffer-position) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 1312 100 (^X =) SB
+359 1429 312 (This command ) SB
+13 13 SJ
+672 1429 1502 (reports on the current and total lines and characters of the current buffer. It) SB
+182 1487 1515 (also gives the hexadecimal code of the character currently under the cursor.) SB
+32 0 0 58 58 0 0 56 /Times-Bold /font29 ANSIFont font
+182 1659 443 (Multiple windows) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 1788 421 (split-current-window) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 1790 97 (^X 2) SB
+66 11 SJ
+359 1907 1330 (If possible, this command splits the current window into two near ) SB
+14 2 SJ
+1755 1907 418 (equal windows, each) SB
+24 12 SJ
+182 1965 1611 (displaying the buffer displayed by the original window. A numeric argument of ) SB
+9 3 SJ
+1817 1965 361 (1 forces the upper) SB
+24 6 SJ
+182 2023 611 (window to be the new current ) SB
+60 12 SJ
+817 2023 1310 (window, and an argument of 2 forces the lower window to be the) SB
+182 2081 425 (new current window.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 2195 291 (delete-window) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 2197 97 (^X 0) SB
+15 3 SJ
+359 2314 494 (This command attempts ) SB
+66 11 SJ
+868 2314 1253 (to delete the current window, retrieving the lines for use in the) SB
+182 2372 537 (window above or below it.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 2486 432 (delete-other-windows) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 2488 97 (^X 1) SB
+40 8 SJ
+359 2605 988 (All other windows are deleted by this command. ) SB
+30 5 SJ
+1387 2605 770 (The current window becomes the only) SB
+182 2663 842 (window, using the entire available screen.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 2777 255 (next-window) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 2779 108 (^X O) SB
+24 6 SJ
+359 2896 671 (Make the next window down the ) SB
+40 8 SJ
+1054 2896 1029 (current window. With an argument, this makes the ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+2123 2894 25 (n) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+2148 2896 39 (th) SB
+182 2955 591 (window from the top current.) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+182 3183 198 (uEmacs 4.0) SB
+891 3183 209 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1100 3176 43 ( -) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1143 3183 11 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1154 3176 50 (11) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1204 3183 11 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1215 3176 17 (-) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1918 3183 269 (December 1991) SB
+showpage
+% %%Page: 12 12
+grestore sheetsave restore
+/sheetsave save def
+gsave
+24 416 translate -90 rotate
+393 596 div 548 842 div scale
+0 0 moveto 0 842 lineto 596 842 lineto 596 0 lineto
+closepath clip newpath
+0 54 39 2478 3507 300 SM
+0 0 0 fC
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 197 343 (previous-window) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 199 100 (^X P) SB
+8 1 SJ
+359 316 126 (Make ) SB
+117 13 SJ
+493 316 1513 (the next window up the current window. With an argument, this makes the ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+2123 314 25 (n) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+2148 316 39 (th) SB
+182 375 917 (window from the bottom the current window.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 489 338 (scroll-next-down) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 491 174 (Meta ^V) SB
+359 608 746 (Scroll the next window down a page.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 722 280 (scroll-next-up) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 724 169 (Meta ^Z) SB
+359 841 685 (Scroll the next window up a page.) SB
+32 0 0 58 58 0 0 56 /Times-Bold /font29 ANSIFont font
+182 1013 517 (Controlling windows) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 1142 274 (grow-window) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 1144 95 (^X ^) SB
+359 1261 1526 (Enlarge the current window by the argument number of lines \(1 by default\).) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 1375 296 (shrink-window) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 1377 126 (^X ^Z) SB
+359 1494 1504 (Shrink the current window by the argument number of lines \(1 by default\).) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 1608 287 (resize-window) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 1610 119 (^X W) SB
+2 2 SJ
+359 1727 239 (Change the ) SB
+28 14 SJ
+600 1727 1559 (size of the current window to the number of line specified by the argument, if) SB
+182 1785 176 (possible.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 1899 402 (move-window-down) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 1901 131 (^X ^N) SB
+359 2018 1193 (Move the window into the current buffer down by one line.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 2132 344 (move-window-up) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 2134 123 (^X ^P) SB
+359 2251 1132 (Move the window into the current buffer up by one line.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 2365 304 (redraw-display) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 2367 169 (Meta ^L) SB
+16 8 SJ
+359 2484 990 (Redraw the current window with the current line ) SB
+24 8 SJ
+1365 2484 798 (in the middle of the window, or with an) SB
+182 2542 771 (argument, with the current line on the ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+953 2540 25 (n) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+978 2542 598 (th line of the current window.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 2657 354 (clear-and-redraw) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 2659 54 (^L) SB
+99 9 SJ
+359 2776 1089 (Clear the screen and redraw the entire display. Useful ) SB
+36 3 SJ
+1547 2776 604 (on timesharing systems where) SB
+182 2834 1020 (messages and other things can garbage the display.) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+182 3183 198 (uEmacs 4.0) SB
+891 3183 209 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1100 3176 43 ( -) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1143 3183 11 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1154 3176 50 (12) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1204 3183 11 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1215 3176 17 (-) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1918 3183 269 (December 1991) SB
+showpage
+% %%Page: 13 13
+grestore sheetsave restore
+showsheet
+%%Page: 7 7
+/sheetsave save def
+gsave
+24 817 translate -90 rotate
+393 596 div 548 842 div scale
+0 0 moveto 0 842 lineto 596 842 lineto 596 0 lineto
+closepath clip newpath
+0 54 39 2478 3507 300 SM
+0 0 0 fC
+32 0 0 58 58 0 0 56 /Times-Bold /font29 ANSIFont font
+182 197 404 (Multiple buffers) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 327 249 (select-buffer) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 329 105 (^X B) SB
+18 3 SJ
+359 446 325 (Switch to using ) SB
+77 11 SJ
+702 446 1408 (another buffer in the current window. uEmacs will prompt you for the) SB
+182 504 517 (name of the buffer to use.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 618 219 (next-buffer) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 620 108 (^X X) SB
+359 737 1425 (Switch to using the next buffer in the buffer list in the current window.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 851 244 (name-buffer) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 853 174 (Meta ^N) SB
+359 970 780 (Change the name of the current buffer.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 1084 255 (delete-buffer) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 1086 108 (^X K) SB
+22 11 SJ
+359 1203 1256 (Dispose of an undisplayed buffer in the editor and reclaim the ) SB
+12 4 SJ
+1637 1203 538 (space. This does not delete) SB
+182 1261 664 (the file the buffer was read from.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 1375 216 (list-buffers) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 1377 128 (^X ^B) SB
+359 1494 511 (Split the current window ) SB
+13 13 SJ
+871 1494 1303 (and in one half bring up a list of all the buffers currently existing) SB
+6 6 SJ
+182 1552 648 (in the editor. The active modes, ) SB
+22 11 SJ
+836 1552 1329 (change flag, and active flag for each buffer is also displayed. \(The) SB
+182 1610 1852 (change flag is an * if the buffer has been changed and not written out. The active flag is not ) SB
+2 2 SJ
+2035 1610 150 (an @ if) SB
+10 2 SJ
+182 1668 154 (the file ) SB
+96 16 SJ
+346 1668 1745 (had been specified on the command line, but has not been read in yet since nothing has) SB
+182 1726 483 (switched to that buffer.\)) SB
+32 0 0 58 58 0 0 56 /Times-Bold /font29 ANSIFont font
+182 1898 461 (Reading from disk) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 2027 159 (find-file) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 2029 123 (^X ^F) SB
+7 1 SJ
+359 2146 105 (Find ) SB
+128 16 SJ
+471 2146 1588 (the named file. If it is already in a buffer, make that buffer active in the current) SB
+182 2204 1478 (window, otherwise attempt to create a new buffer and read the file into it.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 2318 172 (read-file) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 2320 128 (^X ^R) SB
+40 4 SJ
+359 2437 415 (Read the named file ) SB
+99 9 SJ
+814 2437 1274 (into the current buffer \(overwriting the previous contents of the) SB
+182 2495 1398 (current buffer. If the change flag is set, a confirmation will be asked\).) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 2610 194 (insert-file) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 2612 112 (^X ^I) SB
+359 2729 1341 (Insert the named file into the current position of the current buffer.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 2843 172 (view-file) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 2845 131 (^X ^V) SB
+6 2 SJ
+359 2962 296 (Like find-file, ) SB
+56 14 SJ
+661 2962 1470 (this command either finds the file in a buffer, or creates a new buffer and) SB
+182 3020 1080 (reads the file in. In addition, this leaves that buffer in ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+1262 3018 100 (View) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1362 3020 137 ( mode.) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+182 3183 198 (uEmacs 4.0) SB
+891 3183 209 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1100 3176 43 ( -) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1143 3183 11 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1154 3176 50 (13) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1204 3183 11 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1215 3176 17 (-) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1918 3183 269 (December 1991) SB
+showpage
+% %%Page: 14 14
+grestore sheetsave restore
+/sheetsave save def
+gsave
+24 416 translate -90 rotate
+393 596 div 548 842 div scale
+0 0 moveto 0 842 lineto 596 842 lineto 596 0 lineto
+closepath clip newpath
+0 54 39 2478 3507 300 SM
+0 0 0 fC
+32 0 0 58 58 0 0 56 /Times-Bold /font29 ANSIFont font
+182 313 790 (Automatic file name completion) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+30 6 SJ
+182 444 696 (File name completion can be used ) SB
+30 5 SJ
+908 444 668 (with all file oriented commands \() SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+6 1 SJ
+1606 442 370 (find-file, view-file,) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+18 3 SJ
+1982 444 187 ( ...\) but it) SB
+68 17 SJ
+182 503 1834 (works only under UNIX and MS-DOS. It is invoked by a <Space> or <Tab>. If there exist ) SB
+2084 503 103 (more) SB
+16 4 SJ
+182 561 617 (than one possible completions ) SB
+60 12 SJ
+815 561 1312 (they are displayed one by one. If the file name contains wild card) SB
+12 3 SJ
+182 619 423 (characters, the name ) SB
+50 10 SJ
+617 619 1520 (is expanded instead of simple completion. Special characters can be entered) SB
+182 677 899 (verbatim by prefixing them with ^V \(or ^Q\).) SB
+32 0 0 58 58 0 0 56 /Times-Bold /font29 ANSIFont font
+182 849 348 (Saving to disk) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 978 169 (save-file) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 980 123 (^X ^S) SB
+1600 980 131 (^X ^D) SB
+359 1097 355 (If the contents of ) SB
+14 14 SJ
+715 1097 1458 (the current buffer have been changed, write it back to the file it was read) SB
+182 1155 124 (from. ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+306 1153 1169 (Use ^X ^D if your terminal uses XON-XOFF-flow control.) SB
+182 1270 183 (write-file) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 1272 142 (^X ^W) SB
+36 6 SJ
+359 1389 664 (Write the contents of the current ) SB
+70 10 SJ
+1059 1389 1058 (file to the named file, this also changes the file name) SB
+182 1447 1107 (associated with the current buffer to the new file name.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 1561 350 (change-file-name) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 1563 108 (^X N) SB
+359 1680 1495 (Change the name associated with the current buffer to the file name given.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 1795 197 (quick-exit) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 1797 146 (Meta Z) SB
+30 10 SJ
+359 1914 1035 (Write out all changed buffers to the files they were ) SB
+28 7 SJ
+1424 1914 735 (read from and exit the editor. This is) SB
+182 1972 636 (the normal way to exit uEmacs.) SB
+32 0 0 58 58 0 0 56 /Times-Bold /font29 ANSIFont font
+182 2144 771 (Accessing the operating system) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 2273 305 (shell-command) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 2275 89 (^X !) SB
+359 2392 408 (Send one command ) SB
+10 10 SJ
+768 2392 1409 (to execute to the operating system command processor, or shell. Upon) SB
+182 2450 1344 (completion, uEmacs will wait for a keystroke to redraw the screen.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 2564 297 (pipe-command) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 2566 118 (^X @) SB
+18 9 SJ
+359 2683 1268 (Execute one operating system command and pipe the resulting ) SB
+15 5 SJ
+1645 2683 527 (output into a buffer by the) SB
+182 2741 426 (name of "command".) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 2855 233 (filter-buffer) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+415 2857 13 ( ) SB
+891 2857 97 (^X #) SB
+20 10 SJ
+359 2974 1338 (Execute one operating system command, using the contents of the ) SB
+9 3 SJ
+1717 2974 461 (current buffer as input,) SB
+182 3032 1497 (and sending the results back to the same buffer, replacing the original text.) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+182 3183 198 (uEmacs 4.0) SB
+891 3183 209 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1100 3176 43 ( -) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1143 3183 11 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1154 3176 50 (14) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1204 3183 11 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1215 3176 17 (-) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1918 3183 269 (December 1991) SB
+showpage
+% %%Page: 15 15
+grestore sheetsave restore
+showsheet
+%%Page: 8 8
+/sheetsave save def
+gsave
+24 817 translate -90 rotate
+393 596 div 548 842 div scale
+0 0 moveto 0 842 lineto 596 842 lineto 596 0 lineto
+closepath clip newpath
+0 54 39 2478 3507 300 SM
+0 0 0 fC
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 255 125 (i-shell) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 257 105 (^X C) SB
+359 374 260 (Push up to a ) SB
+11 11 SJ
+620 374 1556 (new command processor or shell. Upon exiting the shell, uEmacs will redraw) SB
+182 432 622 (its screen and continue editing.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 546 301 (suspend-emacs) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 548 108 (^X D) SB
+1600 548 482 (\(only under 4.[23]BSD\)) SB
+359 665 1756 (This command suspends the editing processor and puts it into the background. The "fg") SB
+182 723 610 (command will restart uEmacs.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 837 213 (exit-emacs) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 839 128 (^X ^C) SB
+12 12 SJ
+359 956 1404 (Exit uEmacs back to the operating system. If there are any unwritten, ) SB
+4 2 SJ
+1775 956 408 (changed buffers, the) SB
+182 1014 736 (editor will promt to discard changes.) SB
+32 0 0 58 58 0 0 56 /Times-Bold /font29 ANSIFont font
+182 1186 717 (Key bindings and commands) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 1315 228 (bind-to-key) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 1317 151 (Meta K) SB
+96 16 SJ
+359 1434 1669 (This command takes one of the named commands and binds it to a key. From then ) SB
+2124 1434 63 (on,) SB
+182 1492 1232 (whenever that key is struck, the bound command is executed.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 1606 222 (unbind-key) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 1608 174 (Meta ^K) SB
+359 1725 749 (This unbinds a command from a key.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 1839 251 (describe-key) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 1841 94 (^X ?) SB
+50 5 SJ
+359 1958 615 (This command will allow you ) SB
+132 12 SJ
+1024 1958 1031 (to type a key and it will then report the name of the) SB
+182 2016 573 (command bound to that key.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 2130 510 (execute-named-command) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 2132 151 (Meta X) SB
+21 7 SJ
+359 2249 795 (This command will prompt you for the ) SB
+28 7 SJ
+1175 2249 984 (name of a command to execute. Typing <Space>) SB
+15 5 SJ
+182 2307 524 (part way through will tell ) SB
+56 14 SJ
+721 2307 1410 (the editor to attempt to complete the name on its own. If it then beeps,) SB
+182 2365 784 (there is no such command to complete.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 2479 357 (describe-bindings) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 2481 175 (unbound) SB
+359 2598 983 (This command splits the current window, and in ) SB
+9 9 SJ
+1343 2598 835 (one of the windows makes a list of all the) SB
+182 2656 1148 (named commands, and the keys currently bound to them.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 2770 163 (apropos) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 2772 151 (Meta A) SB
+359 2889 791 (This command is a modification of the ) SB
+1150 2889 210 (command ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+1360 2887 370 (describe-bindings.) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1730 2889 346 ( It lists all named) SB
+182 2948 807 (commands that match a given substring.) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+182 3183 198 (uEmacs 4.0) SB
+891 3183 209 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1100 3176 43 ( -) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1143 3183 11 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1154 3176 50 (15) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1204 3183 11 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1215 3176 17 (-) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1918 3183 269 (December 1991) SB
+showpage
+% %%Page: 16 16
+grestore sheetsave restore
+/sheetsave save def
+gsave
+24 416 translate -90 rotate
+393 596 div 548 842 div scale
+0 0 moveto 0 842 lineto 596 842 lineto 596 0 lineto
+closepath clip newpath
+0 54 39 2478 3507 300 SM
+0 0 0 fC
+32 0 0 58 58 0 0 56 /Times-Bold /font29 ANSIFont font
+182 255 510 (Command execution) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+12 4 SJ
+182 386 475 (Commands can also be ) SB
+36 9 SJ
+669 386 1482 (executed as command scripts. This allows commands and their arguments) SB
+182 444 1607 (to be stored in files and executed. The general form of a command script line is:) SB
+359 560 24 ({) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+383 558 431 (optional repeat count) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+814 560 37 (} ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+851 558 319 (command-name) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1170 560 37 ( {) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+1207 558 390 (optional arguments) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1597 560 24 (}) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 675 452 (execute-command-line) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 677 175 (unbound) SB
+359 794 597 (Execute a typed in script line.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 908 285 (execute-buffer) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 910 175 (unbound) SB
+70 14 SJ
+359 1027 1445 (Executes script lines in the named buffer. If the buffer is off screen and ) SB
+12 2 SJ
+1874 1027 301 (an error occurs) SB
+182 1085 1382 (during execution, the cursor will be left on the line causing the error.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 1199 230 (execute-file) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 1201 175 (unbound) SB
+359 1318 1663 (Executes script lines from a file. This is the normal way to execute a special script.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 1432 379 (clear-message-line) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 1434 175 (unbound) SB
+12 1 SJ
+359 1551 140 (Clears ) SB
+182 14 SJ
+511 1551 1494 (the message line during script execution. This is useful so as not to leave a) SB
+182 1609 1098 (confusing message from the last commands in a script.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 1723 287 (write-message) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 1725 175 (unbound) SB
+359 1842 778 (Write a message on the command line.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 1956 288 (unmark-buffer) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 1958 175 (unbound) SB
+27 9 SJ
+359 2075 1089 (Remove the change flag from the current buffer. This ) SB
+24 6 SJ
+1475 2075 688 (is very useful in scripts where you) SB
+182 2133 1905 (are creating help windows, and don't want uEmacs to complain about not saving them to a file.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 2247 246 (insert-string) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 2249 175 (unbound) SB
+63 9 SJ
+359 2366 1003 (Insert a string into the current buffer. This allows ) SB
+56 7 SJ
+1425 2366 706 (you to build up text within a buffer) SB
+182 2424 1630 (without reading it in from a file. Some special characters are allowed, as follows:) SB
+359 2540 52 (~n) SB
+714 2540 158 (newline) SB
+359 2598 41 (~t) SB
+714 2598 61 (tab) SB
+359 2656 52 (~b) SB
+714 2656 204 (backspace) SB
+359 2714 44 (~f) SB
+714 2714 184 (formfeed) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 2828 323 (overwrite-string) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 2830 175 (unbound) SB
+359 2947 1252 (Insert or overwrite a string into the current buffer. Works like ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+1611 2945 246 (insert-string) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1857 2947 65 ( in ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+1922 2945 99 (Over) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+2021 2947 137 ( mode.) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+182 3183 198 (uEmacs 4.0) SB
+891 3183 209 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1100 3176 43 ( -) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1143 3183 11 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1154 3176 50 (16) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1204 3183 11 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1215 3176 17 (-) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1918 3183 269 (December 1991) SB
+showpage
+% %%Page: 17 17
+grestore sheetsave restore
+showsheet
+%%Page: 9 9
+/sheetsave save def
+gsave
+24 817 translate -90 rotate
+393 596 div 548 842 div scale
+0 0 moveto 0 842 lineto 596 842 lineto 596 0 lineto
+closepath clip newpath
+0 54 39 2478 3507 300 SM
+0 0 0 fC
+32 0 0 58 58 0 0 56 /Times-Bold /font29 ANSIFont font
+182 255 274 (Screen size) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+45 9 SJ
+182 386 948 (On an IBM-PC the screen size is controlled by ) SB
+42 7 SJ
+1175 386 970 (the monitor type. Although 25x80 is the default,) SB
+108 9 SJ
+182 444 848 (43x80 can be used on an EGA screen and ) SB
+117 9 SJ
+1138 444 932 (52x80 on a VGA screen. The screen size is set) SB
+133 7 SJ
+182 502 1153 (automatically when setting the screen resolution variable ) SB
+100 5 SJ
+1468 502 619 ($sres to "EGA" or "VGA" \(see) SB
+182 560 521 (Environmental variables\).) SB
+30 6 SJ
+359 676 708 (Under UNIX and VMS the default ) SB
+48 8 SJ
+1097 676 1042 (screen size depends on terminal settings used by the) SB
+24 3 SJ
+182 734 413 (operating system. If ) SB
+99 11 SJ
+619 734 1469 (you use a window system under UNIX, uEmacs can even detect dynamic) SB
+182 792 1178 (changes of virtual screen size and resize itself accordingly.) SB
+359 908 1733 (However, the screen size can be controlled manually by the following two commands:) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 1022 381 (change-screen-size) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 1024 174 (Meta ^D) SB
+359 1141 770 (Change the number of lines on screen.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 1255 418 (change-screen-width) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 1257 169 (Meta ^T) SB
+359 1374 845 (Change the number of columns on screen.) SB
+32 0 0 58 58 0 0 56 /Times-Bold /font29 ANSIFont font
+182 1546 671 (Keyboard macro execution) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+16 8 SJ
+182 1677 1059 (Also available is one keyboard macro, which allows ) SB
+24 8 SJ
+1257 1677 906 (you to record a number of commands as they) SB
+182 1735 668 (are executed and play them back.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 1849 255 (begin-macro) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 1851 89 (^X \() SB
+359 1968 650 (Start recording keyboard macro.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 2082 216 (end-macro) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 2084 89 (^X \)) SB
+359 2201 647 (Stop recording keyboard macro.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 2315 293 (execute-macro) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+475 2317 13 ( ) SB
+891 2317 103 (^X E) SB
+359 2434 511 (Execute keyboard macro.) SB
+32 0 0 58 58 0 0 56 /Times-Bold /font29 ANSIFont font
+182 2606 541 (THE MAGIC MODE) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+48 6 SJ
+182 2740 619 (In the Magic mode of uEmacs ) SB
+81 9 SJ
+849 2740 1257 (certain characters gain special meanings when used in a search) SB
+50 5 SJ
+182 2798 719 (pattern. Collectively they are know ) SB
+99 9 SJ
+951 2798 1137 (as regular expressions, and a limited number of them are) SB
+49 7 SJ
+182 2856 1041 (supported in uEmacs. They grant greater flexibility ) SB
+40 5 SJ
+1272 2856 875 (when using the search command. However,) SB
+182 2914 1039 (they do not affect the incremental search command.) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+182 3183 198 (uEmacs 4.0) SB
+891 3183 209 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1100 3176 43 ( -) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1143 3183 11 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1154 3176 50 (17) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1204 3183 11 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1215 3176 17 (-) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1918 3183 269 (December 1991) SB
+showpage
+% %%Page: 18 18
+grestore sheetsave restore
+/sheetsave save def
+gsave
+24 416 translate -90 rotate
+393 596 div 548 842 div scale
+0 0 moveto 0 842 lineto 596 842 lineto 596 0 lineto
+closepath clip newpath
+0 54 39 2478 3507 300 SM
+0 0 0 fC
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+359 199 853 (The symbols that have special meaning in ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+1212 197 128 (Magic) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1340 199 350 ( mode are ^, $, ., ) SB
+6 6 SJ
+1691 199 490 (*, [ \(and ], used with it\),) SB
+18 9 SJ
+182 258 672 (and \\ . The characters ^ and $ fix ) SB
+30 10 SJ
+872 258 1285 (the search pattern to the beginning and end of line, respectively.) SB
+18 18 SJ
+182 316 1826 (The ^ character must appear at the beginning of the search string, and the $ must appear at ) SB
+2 1 SJ
+2026 316 159 (the end,) SB
+182 374 1592 (otherwise they loose their meaning and are treated just like any other character.) SB
+359 490 330 (For example, in ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+689 488 128 (Magic) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+817 490 1033 ( mode, searching for the pattern "t$" would put the ) SB
+3 3 SJ
+1851 490 333 (cursor at the end) SB
+30 15 SJ
+182 549 1412 (of any line that ended with the letter 't'. Note that this is different than ) SB
+9 3 SJ
+1624 549 554 (searching for "t<NL>", that) SB
+45 15 SJ
+182 607 1567 (is, 't' followed by a newline character. The character $ \(and ^, for that matter\) ) SB
+8 2 SJ
+1794 607 385 (matches a position,) SB
+14 7 SJ
+182 665 761 (not a character, so the cursor remains ) SB
+39 13 SJ
+957 665 1191 (at the end of the line. But a newline is a character that must) SB
+182 723 255 (be matched, ) SB
+17 17 SJ
+438 723 1732 (just like any other character, which means that the cursor is placed just after it - on the) SB
+182 781 529 (beginning of the next line.) SB
+84 14 SJ
+359 897 1533 (The character . has a very simple meaning - it matches any single character, ) SB
+7 1 SJ
+1976 897 204 (except the) SB
+4 4 SJ
+182 955 472 (newline. Thus a search ) SB
+26 13 SJ
+658 955 1503 (for "bad.er" could match "badger", "badder" \(slang\), or up to the 'r' of "bad) SB
+182 1013 131 (error".) SB
+55 5 SJ
+359 1129 520 (The character * is known ) SB
+120 10 SJ
+934 1129 1133 (as closure, and means that zero or more of the preceding) SB
+34 17 SJ
+182 1187 1893 (character will match. If there is no character preceding, * has no special meaning, and since it ) SB
+2109 1187 78 (will) SB
+112 16 SJ
+182 1245 1755 (not match with a newline, * will have no special meaning if preceded by the beginning ) SB
+8 1 SJ
+2049 1245 130 (of line) SB
+182 1303 958 (symbol ^ or the literal newline character <NL>.) SB
+359 1419 1366 (The notion of zero or more characters is important. If, for example, ) SB
+4 4 SJ
+1726 1419 457 (your cursor was on the) SB
+182 1477 75 (line) SB
+32 0 0 42 42 0 0 33 /Courier /font0 ANSIFont font
+359 1591 800 (This line is missing two vowels.) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+80 16 SJ
+359 1693 1709 (and a search was made for "a*", the cursor would not move, because it is guaranteed ) SB
+2148 1693 39 (to) SB
+182 1751 1845 (match no letter 'a' , which satisfies the search conditions. If you wanted to search for one or ) SB
+1 1 SJ
+2028 1751 158 (more of) SB
+42 7 SJ
+182 1809 694 (the letter 'a', you would search for ) SB
+77 11 SJ
+918 1809 1192 ("aa*", which would match the letter a, then zero or more of) SB
+182 1867 113 (them.) SB
+132 12 SJ
+359 1983 1292 (The character [ indicates the beginning of a character class. It is ) SB
+36 3 SJ
+1783 1983 368 (similar to the 'any') SB
+15 15 SJ
+182 2041 1712 (character ., but you get to choose which characters you want to match. The character ) SB
+4 2 SJ
+1909 2041 274 (class is ended) SB
+182 2099 1844 (with the character ]. So, while a search for "ba.e" will match "bane", "bade", "bale", "bate", ) SB
+1 1 SJ
+2027 2099 159 (etc, you) SB
+21 7 SJ
+182 2157 714 (can limit it to matching "babe" and ) SB
+36 9 SJ
+917 2157 1234 ("bake" by searching for "ba[bk]e". Only one of the characters) SB
+9 9 SJ
+182 2215 821 (inside the [ and ] will match a character. ) SB
+22 11 SJ
+1012 2215 1153 (If in fact you want to match any character except those in) SB
+24 12 SJ
+182 2273 1141 (the character class, you can put a ^ as the first character. ) SB
+24 8 SJ
+1347 2273 816 (It must be the first character of the class,) SB
+182 2331 1492 (or else it has no special meaning. So, a search for [^aeiou] will match any ) SB
+3 3 SJ
+1675 2331 509 (character except a vowel,) SB
+182 2389 1074 (but a search for [aeiou^] will match any vowel or a ^.) SB
+359 2505 784 (If you have a lot of characters in order ) SB
+10 10 SJ
+1144 2505 1033 (that you want to put in the character class, you may) SB
+9 9 SJ
+182 2563 783 (use a dash \(-\) as a range character. So, ) SB
+22 11 SJ
+974 2563 1077 ([a-z] will match any letter \(or any lower case letter if ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+2073 2561 114 (Exact) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+27 9 SJ
+182 2622 934 (mode is on\), and [0-9a-f] will match any digit ) SB
+40 10 SJ
+1143 2622 1004 (or any letter 'a' through 'f', which happen to be the) SB
+10 10 SJ
+182 2680 1144 (characters for hexadecimal numbers. If the dash is at the ) SB
+16 8 SJ
+1336 2680 835 (beginning or end of a character class, it is) SB
+182 2738 457 (taken to be just a dash.) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+182 3183 198 (uEmacs 4.0) SB
+891 3183 209 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1100 3176 43 ( -) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1143 3183 11 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1154 3176 50 (18) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1204 3183 11 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1215 3176 17 (-) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1918 3183 269 (December 1991) SB
+showpage
+% %%Page: 19 19
+grestore sheetsave restore
+showsheet
+%%Page: 10 10
+/sheetsave save def
+gsave
+24 817 translate -90 rotate
+393 596 div 548 842 div scale
+0 0 moveto 0 842 lineto 596 842 lineto 596 0 lineto
+closepath clip newpath
+0 54 39 2478 3507 300 SM
+0 0 0 fC
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+40 8 SJ
+359 199 816 (The escape character \\ is for those times ) SB
+36 6 SJ
+1215 199 483 (when you want to be in ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+1734 197 128 (Magic) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+18 3 SJ
+1862 199 307 ( mode, but also) SB
+6 6 SJ
+182 258 657 (want to use a regular expression ) SB
+24 12 SJ
+845 258 1318 (character to be just a character. It turns off the special meaning of) SB
+39 13 SJ
+182 316 1068 (the character. So a search for "it \\ ." will search for a ) SB
+32 8 SJ
+1289 316 866 (line with "it.", and not "it" followed by any) SB
+3 3 SJ
+182 374 416 (other character. The ) SB
+32 16 SJ
+601 374 1554 (escape character will also let you put ^, -, or ] inside a character class with no) SB
+182 432 390 (special side effects.) SB
+32 0 0 58 58 0 0 56 /Times-Bold /font29 ANSIFont font
+182 612 470 (uEmacs MACROS) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+32 4 SJ
+182 735 526 (Macros are programs that ) SB
+90 10 SJ
+740 735 1357 (are used to customize the editor and to perform complicated editing) SB
+10 5 SJ
+182 793 535 (tasks. They may be stored ) SB
+33 11 SJ
+727 793 1427 (in files or buffers and may be executed using an appropriate command,) SB
+24 4 SJ
+182 851 280 (or bound to a ) SB
+14 2 SJ
+486 851 503 (particular keystroke. The) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+7 1 SJ
+1003 849 416 ( execute-macro-<n>) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+35 5 SJ
+1426 851 726 ( editor commands cause the macros,) SB
+12 12 SJ
+182 910 1239 (numbered from 1 to 40, to be executed. Macros are stored by ) SB
+10 5 SJ
+1433 910 628 (executing files that contain the ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+2071 908 116 (store-) SB
+182 967 127 (macro) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+36 6 SJ
+309 969 677 ( command. The macro number is ) SB
+21 3 SJ
+1022 969 250 (given to the ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+7 1 SJ
+1293 967 256 (store-macro ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+28 4 SJ
+1556 969 603 (command as an argument. All) SB
+182 1028 1416 (script lines then encountered will be stored rather than being executed.) SB
+3 3 SJ
+359 1136 328 (There are many ) SB
+18 9 SJ
+690 1136 1479 (different aspects to the macro language within uEmacs. Editor commands) SB
+3 3 SJ
+182 1194 308 (are the various ) SB
+20 10 SJ
+493 1194 1674 (commands that manipulate text, buffers, windows, etc, within the editor. Directives) SB
+45 15 SJ
+182 1252 1855 (are commands which control what lines get executed within a macro. Also there are various ) SB
+2082 1252 105 (types) SB
+21 3 SJ
+182 1310 572 (of variables. Environmental ) SB
+80 10 SJ
+775 1310 1332 (variables both control and report on different aspects of the editor.) SB
+28 14 SJ
+182 1368 1902 (User variables hold string values which may be changed and inspected. Buffer variables allow ) SB
+2112 1368 75 (text) SB
+165 11 SJ
+182 1426 1405 (to be placed into variables. Interactive variables allow the program to ) SB
+48 3 SJ
+1752 1426 387 (prompt the user for) SB
+182 1484 1377 (information. Functions can be used to manipulate all these variables.) SB
+32 0 0 58 58 0 0 56 /Times-Bold /font29 ANSIFont font
+182 1640 239 (Variables) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+25 5 SJ
+182 1763 569 (Variables in uEmacs can be ) SB
+60 10 SJ
+776 1763 1351 (used to return values within expressions, as repeat counts to editing) SB
+15 5 SJ
+182 1821 491 (commands, or as text to ) SB
+48 12 SJ
+688 1821 1451 (be inserted into buffers and messages. The value of these variables is set) SB
+10 2 SJ
+182 1879 195 (using the ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+387 1877 55 (set) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+10 2 SJ
+442 1879 102 ( \(^X ) SB
+78 13 SJ
+554 1879 1555 (A\) command. For example, to set the current fill column to 64 characters, the) SB
+182 1938 737 (following macro line would be used:) SB
+32 0 0 42 42 0 0 33 /Courier /font0 ANSIFont font
+359 2044 375 (set $fillcol 64) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+32 16 SJ
+359 2138 1599 (or to have the contents of %name inserted at the point in the current buffer, the ) SB
+1990 2138 197 (command) SB
+182 2196 330 (to use would be:) SB
+32 0 0 42 42 0 0 33 /Courier /font0 ANSIFont font
+359 2302 475 (insert-string %name) SB
+32 0 0 58 58 0 0 56 /Times-Bold /font29 ANSIFont font
+182 2444 614 (Environmental variables) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+359 2565 928 ("What good is a quote if you can't change it?") SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+15 3 SJ
+182 2676 399 (These variables are ) SB
+78 13 SJ
+596 2676 1513 (used to change different aspects of the way the editor works. Also they will) SB
+3 3 SJ
+182 2734 362 (return the current ) SB
+24 12 SJ
+547 2734 1616 (settings if used as part of an expression. All environmental variable names begin) SB
+182 2792 435 (with a dollar sign \($\).) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+182 3183 198 (uEmacs 4.0) SB
+891 3183 209 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1100 3176 43 ( -) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1143 3183 11 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1154 3176 50 (19) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1204 3183 11 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1215 3176 17 (-) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1918 3183 269 (December 1991) SB
+showpage
+% %%Page: 20 20
+grestore sheetsave restore
+/sheetsave save def
+gsave
+24 416 translate -90 rotate
+393 596 div 548 842 div scale
+0 0 moveto 0 842 lineto 596 842 lineto 596 0 lineto
+closepath clip newpath
+0 54 39 2478 3507 300 SM
+0 0 0 fC
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+359 199 180 ($pagelen) SB
+714 199 764 (Number of screen lines used currently) SB
+359 257 203 ($curwidth) SB
+714 257 699 (Number of columns used currently) SB
+359 315 150 ($curcol) SB
+714 315 830 (Current column of point in current buffer) SB
+359 373 164 ($curline) SB
+714 373 755 (Current line of point in current buffer) SB
+359 431 222 ($cbufname) SB
+714 431 539 (Name of the current buffer) SB
+359 489 172 ($cfname) SB
+714 489 619 (File name of the current buffer) SB
+359 547 136 ($wline) SB
+714 547 707 (Number of lines in current window) SB
+359 605 158 ($cwline) SB
+714 605 467 (Current line in window) SB
+359 663 145 ($fillcol) SB
+714 663 418 (Current fill column \() SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+1132 661 111 (Wrap) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1243 663 150 ( mode, ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+1393 661 664 (fill-paragraph, justify-paragraph) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+2057 663 17 (\)) SB
+359 722 153 ($lwidth) SB
+714 722 423 (Width of current line) SB
+359 780 100 ($line) SB
+714 780 390 (Text of current line) SB
+359 838 175 ($curchar) SB
+714 838 688 (Current character under the cursor) SB
+359 954 156 ($flicker) SB
+714 954 1374 (Flicker flag, set to TRUE if IBM CGA or old AT&T/Olivetti, set to ) SB
+714 1012 471 (FALSE for most others) SB
+359 1070 102 ($sres) SB
+714 1070 520 (Current screen resolution:) SB
+714 1128 936 (CGA, MONO, EGA, or VGA on the IBM-PC,) SB
+714 1186 477 (NORMAL on all others) SB
+359 1302 147 ($debug) SB
+714 1302 650 (Flag to trigger macro debugging) SB
+359 1360 169 ($discmd) SB
+714 1360 938 (If TRUE, display commands on command line) SB
+359 1418 138 ($status) SB
+90 10 SJ
+714 1418 1147 (Return status of the success of the last command \(TRUE ) SB
+10 1 SJ
+1951 1418 226 (or FALSE\)) SB
+714 1476 483 (usually used with !force) SB
+359 1592 135 ($asave) SB
+714 1592 901 (Number of characters between auto-saves in ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+1615 1590 119 (Asave) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1734 1592 124 ( mode) SB
+359 1651 158 ($acount) SB
+714 1651 842 (Number of characters until next auto-save) SB
+359 1767 172 ($version) SB
+714 1767 484 (uEmacs version number) SB
+359 1825 225 ($progname) SB
+714 1825 761 (Returns program name, "uEmacs/PK") SB
+359 1941 152 ($search) SB
+714 1941 288 (Search pattern) SB
+359 1999 169 ($replace) SB
+714 1999 1098 (Replacement pattern, can e.g. be set to an empty string) SB
+359 2057 147 ($match) SB
+714 2057 485 (Last matched pattern in ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+1199 2055 128 (Magic) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1327 2057 124 ( mode) SB
+359 2116 92 ($kill) SB
+714 2116 449 (Kill buffer \(read only\)) SB
+359 2232 86 ($tab) SB
+45 9 SJ
+714 2232 960 ("Hard" tabulator stop, 8 or 4, use the command ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+1719 2230 217 (handle-tab) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+15 3 SJ
+1936 2232 133 ( to set ) SB
+2084 2232 103 (other) SB
+714 2291 415 (\(soft\) tabulator stops) SB
+359 2407 136 ($scroll) SB
+714 2407 953 (Scrolling flag, TRUE if your screen can scroll, ) SB
+3 3 SJ
+1668 2407 516 (FALSE otherwise, can be) SB
+714 2465 1143 (set to FALSE if you don't like uEmacs's way of scrolling) SB
+359 2523 128 ($jump) SB
+35 7 SJ
+714 2523 713 (Number of lines to scroll when top ) SB
+36 6 SJ
+1462 2523 689 (or end of screen has been reached,) SB
+714 2581 900 (default 1, the value 0 has a special meaning: ) SB
+5 5 SJ
+1615 2581 567 (scroll 1/2 page \(which is the) SB
+714 2639 679 (default if scrolling is not enabled\)) SB
+359 2697 175 ($overlap) SB
+12 4 SJ
+714 2697 591 (Number of overlapping lines ) SB
+20 5 SJ
+1317 2697 750 (when browsing files with commands ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+2087 2695 100 (next-) SB
+7 1 SJ
+714 2754 110 (page ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+7 1 SJ
+831 2756 85 (and ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+923 2754 298 (previous-page,) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+63 9 SJ
+1221 2756 651 ( 2 is a typical value, default is 0 ) SB
+16 2 SJ
+1935 2756 236 (which has a) SB
+714 2815 521 (special meaning: 1/3 page) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+182 3183 198 (uEmacs 4.0) SB
+891 3183 209 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1100 3176 43 ( -) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1143 3183 11 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1154 3176 50 (20) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1204 3183 11 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1215 3176 17 (-) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1918 3183 269 (December 1991) SB
+showpage
+% %%Page: 21 21
+grestore sheetsave restore
+showsheet
+%%Page: 11 11
+/sheetsave save def
+gsave
+24 817 translate -90 rotate
+393 596 div 548 842 div scale
+0 0 moveto 0 842 lineto 596 842 lineto 596 0 lineto
+closepath clip newpath
+0 54 39 2478 3507 300 SM
+0 0 0 fC
+32 0 0 58 58 0 0 56 /Times-Bold /font29 ANSIFont font
+182 197 358 (User variables) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+126 14 SJ
+182 320 1740 (User variables allow you, the user, to store strings and manipulate them. These strings ) SB
+10 1 SJ
+2048 320 129 (can be) SB
+182 378 905 (pieces of text, numbers \(in text form\), or the ) SB
+7 7 SJ
+1088 378 1092 (logical values TRUE and FALSE. These variables can) SB
+108 12 SJ
+182 436 1532 (be combined, tested, inserted into buffers, and otherwise used to control the ) SB
+20 2 SJ
+1822 436 345 (way your macros) SB
+8 2 SJ
+182 494 252 (execute. Up ) SB
+75 15 SJ
+442 494 1670 (to 100 user variables may be in use in one editing session. All users variable names) SB
+120 15 SJ
+182 552 1732 (must begin with a percent sign \(%\) and may contain any printing characters. Only the ) SB
+9 1 SJ
+2034 552 144 (first 10) SB
+36 9 SJ
+182 610 1383 (characters are significant \(i.e. differences beyond the tenth character ) SB
+15 3 SJ
+1601 610 571 (are ignored\). Most operators) SB
+182 668 994 (will truncate strings to a length of 128 characters.) SB
+32 0 0 58 58 0 0 56 /Times-Bold /font29 ANSIFont font
+182 824 402 (Buffer variables) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+121 11 SJ
+182 947 1208 (Buffer variables are special in that they can only be queried ) SB
+60 5 SJ
+1511 947 616 (and cannot be set. What buffer) SB
+21 21 SJ
+182 1005 1890 (variables are is a way to take text from a buffer and place it in a variable. For example, if you ) SB
+2093 1005 94 (have) SB
+182 1063 484 (a buffer by the name of ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+666 1061 119 (rigel2) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+785 1063 494 (, and it contains the text:) SB
+32 0 0 42 42 0 0 33 /Courier /font0 ANSIFont font
+359 1170 200 (Richmond) SB
+359 1212 225 (Lafayette) SB
+359 1254 350 (<*>Bloomington) SB
+1186 1254 800 (\(where <*> is the current point\)) SB
+359 1296 300 (Indianapolis) SB
+359 1338 100 (Gary) SB
+359 1380 1800 (-* uEmacs/PK 4.0: rigel2 \(Wrap\) /data/rigel2.txt ---------------- All --) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+359 1474 758 (and within a command you reference ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+1117 1472 144 (#rigel2) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1261 1474 115 (, like:) SB
+32 0 0 42 42 0 0 33 /Courier /font0 ANSIFont font
+359 1581 525 (insert-string #rigel2) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+18 9 SJ
+359 1675 928 (uEmacs would start at the current point in the ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+2 1 SJ
+1305 1673 132 (rigel2 ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+24 8 SJ
+1439 1675 724 (buffer and grab all the text up to the) SB
+48 12 SJ
+182 1734 1178 (end of that line and pass that back. Then it would advance ) SB
+35 7 SJ
+1408 1734 744 (the point to the beginning of the next) SB
+13 13 SJ
+182 1792 1774 (line. Thus, after our last command executes, the string "Bloomington" gets inserted into ) SB
+2 1 SJ
+1969 1792 216 (the current) SB
+182 1850 444 (buffer, and the buffer ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+626 1848 132 (rigel2 ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+758 1850 394 (now looks like this:) SB
+32 0 0 42 42 0 0 33 /Courier /font0 ANSIFont font
+359 1957 200 (Richmond) SB
+359 1999 225 (Lafayette) SB
+359 2041 275 (Bloomington) SB
+359 2083 375 (<*>Indianapolis) SB
+1186 2083 800 (\(where <*> is the current point\)) SB
+359 2125 100 (Gary) SB
+359 2167 1800 (-* uEmacs/PK 4.0: rigel2 \(Wrap\) /data/rigel2.txt ---------------- All --) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+359 2261 798 (As you have probably noticed, a buffer ) SB
+8 8 SJ
+1158 2261 1021 (variable consists of the buffer name, preceded by a) SB
+182 2319 306 (pound sign \(#\).) SB
+32 0 0 58 58 0 0 56 /Times-Bold /font29 ANSIFont font
+182 2475 512 (Interactive variables) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+10 10 SJ
+182 2598 1243 (Interactive variables are actually a method to prompt the user ) SB
+16 8 SJ
+1435 2598 736 (for a string. This is done by using an) SB
+1 1 SJ
+182 2656 49 (at ) SB
+34 17 SJ
+232 2656 1921 (sign \(@\) followed either with a quoted string, or a variable containing a string. The string is the) SB
+182 2714 695 (placed on the bottom line, and the ) SB
+13 13 SJ
+878 2714 1296 (editor waits for the user to type in a string. Then the string typed) SB
+182 2772 1585 (in by the users is returned as the value of the interactive variable. For example:) SB
+32 0 0 42 42 0 0 33 /Courier /font0 ANSIFont font
+359 2878 600 (set %quest "What file? ") SB
+359 2920 425 (find-file @%quest) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+359 3006 1195 (will ask the user for a file name, and then attempt to find it.) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+182 3183 198 (uEmacs 4.0) SB
+891 3183 209 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1100 3176 43 ( -) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1143 3183 11 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1154 3176 50 (21) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1204 3183 11 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1215 3176 17 (-) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1918 3183 269 (December 1991) SB
+showpage
+% %%Page: 22 22
+grestore sheetsave restore
+/sheetsave save def
+gsave
+24 416 translate -90 rotate
+393 596 div 548 842 div scale
+0 0 moveto 0 842 lineto 596 842 lineto 596 0 lineto
+closepath clip newpath
+0 54 39 2478 3507 300 SM
+0 0 0 fC
+32 0 0 58 58 0 0 56 /Times-Bold /font29 ANSIFont font
+182 247 244 (Functions) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+5 1 SJ
+182 370 210 (Functions ) SB
+84 14 SJ
+397 370 1706 (can be used to manipulate variables in various ways. Functions can have one, two, or) SB
+182 428 479 (three arguments. These ) SB
+11 11 SJ
+662 428 1514 (arguments will always be placed after the function on the current command) SB
+34 17 SJ
+182 486 1895 (line. For example, if we wanted to increase the current fill column by two, using uEmacs's set ) SB
+2111 486 76 (\(^X) SB
+182 544 615 (A\) command, we would write:) SB
+32 0 0 42 42 0 0 33 /Courier /font0 ANSIFont font
+359 650 700 (set $fillcol &add $fillcol 2) SB
+359 700 800 ( \\ \\ \\ \\ \\___) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1159 695 264 (second operand) SB
+32 0 0 42 42 0 0 33 /Courier /font0 ANSIFont font
+359 750 800 ( \\ \\ \\ \\________) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1159 745 215 (first operand) SB
+32 0 0 42 42 0 0 33 /Courier /font0 ANSIFont font
+359 800 800 ( \\ \\ \\______________) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1159 795 326 (function to execute) SB
+32 0 0 42 42 0 0 33 /Courier /font0 ANSIFont font
+359 850 800 ( \\ \\____________________) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1159 845 239 (variable to set) SB
+32 0 0 42 42 0 0 33 /Courier /font0 ANSIFont font
+359 900 800 ( \\__________________________) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1159 895 355 (set \(^X A\) command) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+40 10 SJ
+359 994 1391 (Function names always begin with the ampersand \(&\) character, and ) SB
+10 2 SJ
+1790 994 387 (are only significant) SB
+10 5 SJ
+182 1052 548 (to the first three characters ) SB
+30 10 SJ
+740 1052 1417 (after the ampersand. Functions will normally expect one of three types) SB
+182 1110 1306 (of arguments, and will automatically convert types when needed.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 1216 86 (num) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+359 1218 1394 (An ascii string of digits which is interpreted as a numeric value. Any ) SB
+3 3 SJ
+1754 1218 430 (string which does not) SB
+359 1277 1205 (start with a digit or a minus sign \(-\) will be considered zero.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 1391 52 (str) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+359 1393 1599 (An arbitrary string of characters. Strings are limited to 128 characters in length.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 1508 64 (log) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+20 4 SJ
+359 1510 534 (A logical value consisting ) SB
+54 9 SJ
+913 1510 1220 (of the string "TRUE" or "FALSE". Numeric strings will also) SB
+359 1569 581 (evaluate to "FALSE" if they ) SB
+10 10 SJ
+941 1569 1236 (are equal to zero, and "TRUE" if they are non-zero. Arbitrary) SB
+359 1627 889 (text strings will have the value of "FALSE".) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 1741 654 (Numeric functions: \(return num\)) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+182 1850 123 (&add) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+536 1851 185 (num num) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 1853 372 (Add two numbers.) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+182 1911 117 (&sub) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+536 1912 185 (num num) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 1914 850 (Subtract the second number from the first.) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+182 1972 115 (&tim) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+297 1975 41 (es) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+536 1973 185 (num num) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 1975 461 (Multiply two numbers.) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+182 2033 109 (&div) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+291 2036 61 (ide) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+536 2034 185 (num num) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 2036 1248 (Divide the first number by the second giving an integer result.) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+182 2094 137 (&mod) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+536 2095 185 (num num) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 2097 1274 (Return the reminder of dividing the first number by the second.) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+182 2155 117 (&neg) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+299 2158 58 (ate) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+536 2156 86 (num) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 2158 457 (Multiply the arg by -1.) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+182 2216 114 (&abs) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+536 2217 86 (num) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 2219 314 (Absolute value.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 2327 851 (String manipulation functions: \(return str\)) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+182 2436 106 (&cat) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+536 2437 117 (str str) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 2439 815 (Concatenate the two strings to form one.) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+182 2497 95 (&lef) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+277 2500 14 (t) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+536 2498 151 (str num) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 2500 828 (Return the num leftmost characters from ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+1719 2498 52 (str) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1771 2500 13 (.) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+182 2558 103 (&rig) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+285 2561 39 (ht) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+536 2559 151 (str num) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 2561 856 (Return the num rightmost characters from ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+1747 2559 52 (str) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1799 2561 13 (.) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+182 2619 126 (&mid) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+536 2620 300 (str num1 num2) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 2622 283 (Starting from ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+1174 2620 111 (num1) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1285 2622 239 ( position in ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+1524 2620 52 (str) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1576 2622 159 (, return ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+1735 2620 111 (num2) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1846 2622 228 ( characters.) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+182 2680 126 (&upp) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+308 2683 39 (er) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+536 2681 52 (str) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 2683 223 (Uppercase ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+1114 2681 65 (str.) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+182 2741 117 (&low) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+299 2744 39 (er) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+536 2742 52 (str) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 2744 229 (Lowercase ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+1120 2742 65 (str.) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+182 2802 114 (&chr) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+536 2803 86 (num) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 2805 917 (Return a single character with character code ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+1808 2803 99 (num.) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+182 2863 117 (&env) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+536 2864 52 (str) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 2866 808 (Retrieve a system environment variable.) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+182 2924 112 (&bin) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+294 2927 89 (ding) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+536 2925 52 (str) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 2927 914 (Look up what function name is bound to key ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+1805 2925 65 (str.) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+182 2985 112 (&gtk) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+294 2988 47 (ey) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+536 2986 52 (str) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 2988 1068 (Waits and returns next keystroke, argument not used.) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+182 3046 101 (&fin) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+283 3049 25 (d) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+536 3047 52 (str) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 3049 306 (Look for a file ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+1197 3047 52 (str) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1249 3049 813 ( on the search path, return the full name.) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+182 3183 198 (uEmacs 4.0) SB
+891 3183 209 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1100 3176 43 ( -) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1143 3183 11 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1154 3176 50 (22) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1204 3183 11 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1215 3176 17 (-) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1918 3183 269 (December 1991) SB
+showpage
+% %%Page: 23 23
+grestore sheetsave restore
+showsheet
+%%Page: 12 12
+/sheetsave save def
+gsave
+24 817 translate -90 rotate
+393 596 div 548 842 div scale
+0 0 moveto 0 842 lineto 596 842 lineto 596 0 lineto
+closepath clip newpath
+0 54 39 2478 3507 300 SM
+0 0 0 fC
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 247 848 (Logical and testing functions: \(return log\)) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+182 356 112 (&not) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+536 357 64 (log) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 359 675 (Return the opposite logical value.) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+182 417 123 (&and) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+536 418 191 (log1 log2) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 420 149 (If both ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+1040 418 89 (log1) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1129 420 98 ( and ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+1227 418 89 (log2) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1316 420 521 ( are TRUE, return TRUE.) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+182 478 89 (&or) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+536 479 191 (log1 log2) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 481 174 (If either ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+1065 479 89 (log1) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1154 481 68 ( or ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+1222 479 89 (log2) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1311 481 493 ( is TRUE, return TRUE.) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+182 539 120 (&equ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+302 542 36 (al) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+536 540 235 (num1 num2) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 542 47 (If ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+938 540 111 (num1) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1049 542 98 ( and ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+1147 540 111 (num2) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1258 542 750 ( are numerically equal, return TRUE.) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+182 600 97 (&les) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+279 603 19 (s) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+536 601 235 (num1 num2) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 603 47 (If ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+938 601 111 (num1) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1049 603 245 ( is less than ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+1294 601 111 (num2) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1405 603 303 (, return TRUE.) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+182 661 111 (&gre) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+293 664 75 (ater) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+536 662 235 (num1 num2) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+771 664 13 ( ) SB
+891 664 47 (If ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+938 662 111 (num1) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1049 664 310 ( is greater than ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+1359 662 111 (num2) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1470 664 303 (, return TRUE.) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+182 722 111 (&seq) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+293 725 61 (ual) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+536 723 167 (str1 str2) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 725 908 (If the two strings are the same, return TRUE.) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+182 783 97 (&sle) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+279 786 38 (ss) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+536 784 167 (str1 str2) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 786 47 (If ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+938 784 77 (str1) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1015 786 538 ( is less alphabetically than ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+1553 784 77 (str2) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1630 786 303 (, return TRUE.) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+182 844 108 (&sgr) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+290 847 97 (eater) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+536 845 167 (str1 str2) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 847 47 (If ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+938 845 77 (str1) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1015 847 658 ( is alphabetically greater than or ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+1673 845 77 (str2) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1750 847 303 (, return TRUE.) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+182 905 103 (&exi) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+285 908 33 (st) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+536 906 52 (str) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 908 127 (If file ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+1018 906 52 (str) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1070 908 429 ( exists, return TRUE.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 1024 1166 (Other string functions \(return num\) and special functions:) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+182 1141 103 (&sin) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+285 1144 72 (dex) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+536 1142 167 (str1 str2) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 1144 593 (Returns position of substring ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+1484 1142 77 (str2) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1561 1144 154 ( within ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+1715 1142 90 (str1,) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1805 1144 357 ( or 0 if not found.) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+182 1202 108 (&asc) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+290 1205 28 (ii) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+536 1203 52 (str) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 1205 819 (Returns ASCII code of first character of ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+1710 1203 65 (str.) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+182 1263 112 (&ind) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+294 1266 89 (irect) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+536 1264 52 (str) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+891 1266 188 (Evaluate ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+1079 1264 52 (str) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1131 1266 276 ( as a variable.) SB
+33 11 SJ
+359 1376 1593 (This last function deserves more explanation. The &IND function evaluates its ) SB
+1985 1376 202 (argument,) SB
+90 15 SJ
+182 1434 1639 (takes the resulting string, and then uses it as a variable name. For example, given ) SB
+7 1 SJ
+1911 1434 269 (the following) SB
+182 1492 303 (code sequence:) SB
+32 0 0 42 42 0 0 33 /Courier /font0 ANSIFont font
+359 1598 600 (; set up reference table) SB
+359 1640 200 (set %one) SB
+714 1640 250 ("elephant") SB
+359 1682 225 (set %two ) SB
+714 1682 225 ("giraffe") SB
+359 1724 275 (set %three ) SB
+714 1724 200 ("donkey") SB
+359 1808 275 (set %index ) SB
+714 1808 125 ("two") SB
+359 1850 625 (insert-string &ind %index) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+99 9 SJ
+359 1936 1034 (the string "giraffe" would have been inserted at the ) SB
+60 5 SJ
+1492 1936 635 (point in the current buffer. This) SB
+182 1994 1075 (indirection can be safely nested up to about 10 levels.) SB
+32 0 0 58 58 0 0 56 /Times-Bold /font29 ANSIFont font
+182 2150 249 (Directives) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+42 6 SJ
+182 2273 918 (Directives are commands which only operate ) SB
+64 8 SJ
+1142 2273 981 (within an executing macro, i.e. they do not make) SB
+42 14 SJ
+182 2331 1439 (sense as a single command. As such, they cannot be called up singly or ) SB
+12 3 SJ
+1663 2331 512 (bound to keystroke. Used) SB
+182 2389 1412 (within macros, they control what lines are executed and in what order.) SB
+3 3 SJ
+359 2497 468 (Directives always start ) SB
+22 11 SJ
+830 2497 1335 (with the exclamation mark \(!\) character and must be the first thing) SB
+182 2555 560 (placed on a line. Directives ) SB
+6 6 SJ
+743 2555 1438 (executed singly \(via the execute-command-line command\) interactively) SB
+182 2613 317 (will be ignored.) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+182 2777 182 (!ENDM ) SB
+32 0 0 58 58 0 0 56 /Times-Bold /font29 ANSIFont font
+364 2769 216 (directive) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+128 16 SJ
+182 2892 1700 (This directive is used to terminate a macro being stored. For example, if a file being ) SB
+2010 2892 177 (executed) SB
+182 2950 342 (contains the text:) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+182 3183 198 (uEmacs 4.0) SB
+891 3183 209 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1100 3176 43 ( -) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1143 3183 11 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1154 3176 50 (23) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1204 3183 11 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1215 3176 17 (-) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1918 3183 269 (December 1991) SB
+showpage
+% %%Page: 24 24
+grestore sheetsave restore
+/sheetsave save def
+gsave
+24 416 translate -90 rotate
+393 596 div 548 842 div scale
+0 0 moveto 0 842 lineto 596 842 lineto 596 0 lineto
+closepath clip newpath
+0 54 39 2478 3507 300 SM
+0 0 0 fC
+32 0 0 42 42 0 0 33 /Courier /font0 ANSIFont font
+359 247 25 (;) SB
+536 247 1300 (Read in a file in view mode, and make the window red) SB
+359 289 50 (26) SB
+536 289 275 (store-macro) SB
+536 331 675 (find-file @"File to view: ") SB
+536 373 375 (add-mode "view") SB
+536 415 350 (add-mode "red") SB
+359 457 125 (!endm) SB
+359 499 1175 (write-message "[Consult macro has been loaded]") SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+28 7 SJ
+359 584 998 (only the lines between the store-macro command ) SB
+30 6 SJ
+1385 584 772 (and the !ENDM directive are stored in) SB
+182 642 201 (macro 26.) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+182 806 205 (!FORCE ) SB
+32 0 0 58 58 0 0 56 /Times-Bold /font29 ANSIFont font
+387 798 216 (directive) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+21 7 SJ
+182 921 802 (When uEmacs executes a macro, if any ) SB
+40 10 SJ
+1005 921 1142 (command fails, the macro is terminated at that point. If a) SB
+182 979 2004 (line is preceded by a !FORCE directive, execution continues weather the command succeeds or not.) SB
+32 0 0 42 42 0 0 33 /Courier /font0 ANSIFont font
+359 1085 25 (;) SB
+536 1085 625 (Merge the top two windows) SB
+359 1127 275 (save-window) SB
+891 1127 800 ( ;remember what window we are at) SB
+359 1169 325 (1 next-window) SB
+891 1169 550 ( ;go to the top window) SB
+359 1211 325 (delete-window) SB
+891 1211 650 ( ;merge it with the second) SB
+359 1253 525 (!force restore-window) SB
+891 1253 500 ( ;This will continue) SB
+182 1295 25 ( ) SB
+359 1295 350 (add-mode "red") SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+182 1436 263 (!IF, !ELSE, ) SB
+32 0 0 58 58 0 0 56 /Times-Bold /font29 ANSIFont font
+445 1428 93 (and) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+538 1436 198 ( !ENDIF ) SB
+32 0 0 58 58 0 0 56 /Times-Bold /font29 ANSIFont font
+736 1428 239 (directives) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+12 4 SJ
+182 1551 497 (The !IF directive allows ) SB
+48 12 SJ
+691 1551 1448 (statements only to be executed if a condition specified in the directive is) SB
+24 3 SJ
+182 1609 322 (met. Every line ) SB
+108 12 SJ
+528 1609 1551 (following the !IF directive, until the first !ELSE or !ENDIF directive, is only) SB
+6 6 SJ
+182 1667 816 (executed if the expression following the ) SB
+18 9 SJ
+1004 1667 1165 (!IF directive evaluates to a TRUE value. For example, the) SB
+182 1725 1451 (following macro segment creates the portion of a text file automatically.) SB
+32 0 0 42 42 0 0 33 /Courier /font0 ANSIFont font
+359 1831 1000 (!if &sequal %curplace "timespace vortex") SB
+536 1873 950 (insert-string "First, rematerialize~n") SB
+359 1915 150 (!endif) SB
+359 1957 675 (!if &sequal %planet "earth") SB
+536 1999 975 (!if &sequal %time "late 20th century" ) SB
+714 2041 800 (write-message "Contact U.N.I.T.") SB
+536 2083 125 (!else) SB
+714 2125 1175 (insert-string "Investigate the situation....~n") SB
+714 2167 1000 (insert-string "\(SAY 'stay here Sara'\)~n") SB
+536 2209 150 (!endif) SB
+359 2251 125 (!else) SB
+536 2293 1250 (set %conditions @"Atmosphere conditions outside? ") SB
+536 2335 750 (!if &sequal %conditions "safe") SB
+714 2377 1050 (insert-string &cat "Go outside......" "~n") SB
+714 2419 775 (insert-string "lock the door~n") SB
+536 2461 125 (!else) SB
+714 2503 1250 (insert-string "Dematerialize... try somewhen else") SB
+714 2545 175 (newline) SB
+536 2587 150 (!endif) SB
+359 2629 150 (!endif) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+182 3183 198 (uEmacs 4.0) SB
+891 3183 209 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1100 3176 43 ( -) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1143 3183 11 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1154 3176 50 (24) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1204 3183 11 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1215 3176 17 (-) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1918 3183 269 (December 1991) SB
+showpage
+% %%Page: 25 25
+grestore sheetsave restore
+showsheet
+%%Page: 13 13
+/sheetsave save def
+gsave
+24 817 translate -90 rotate
+393 596 div 548 842 div scale
+0 0 moveto 0 842 lineto 596 842 lineto 596 0 lineto
+closepath clip newpath
+0 54 39 2478 3507 300 SM
+0 0 0 fC
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+182 205 180 (!GOTO ) SB
+32 0 0 58 58 0 0 56 /Times-Bold /font29 ANSIFont font
+362 197 216 (directive) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+13 13 SJ
+182 320 1568 (Flow can be controlled within a uEmacs macro using the !GOTO directive. It ) SB
+6 3 SJ
+1763 320 418 (takes as an argument) SB
+10 10 SJ
+182 378 930 (a label. A label consists of a line starting with ) SB
+16 8 SJ
+1122 378 1049 (an asterisk \(*\) and then an alphanumeric label. Only) SB
+182 436 1164 (labels in the currently executing macro can be jumped to, ) SB
+7 7 SJ
+1347 436 833 (and trying to jump to a non-existing label) SB
+182 494 656 (terminates execution of a macro.) SB
+32 0 0 42 42 0 0 33 /Courier /font0 ANSIFont font
+359 600 25 (;) SB
+536 600 1325 (Create a block of DATA statements for a BASIC program) SB
+536 642 650 (insert-string "1000 DATA ") SB
+536 684 425 (set %linenum 1000) SB
+359 726 150 (*nxtin) SB
+536 768 325 (update-screen) SB
+891 768 725 (;make sure we see the changes) SB
+536 810 650 (set %data @"Next number: ") SB
+536 852 450 (!if &equal %data 0) SB
+714 894 300 (!goto finish) SB
+536 936 150 (!endif) SB
+536 978 575 (!if &greater $curcol 60) SB
+714 1020 675 (2 delete-previous-character) SB
+714 1062 175 (newline) SB
+714 1104 725 (set %linenum &add %linenum 10) SB
+714 1146 900 (insert-string &cat %linenum " DATA ") SB
+536 1188 150 (!endif) SB
+536 1230 725 (insert-string &cat %data ", ") SB
+536 1272 275 (!goto nxtin) SB
+359 1314 175 (*finish) SB
+536 1356 675 (2 delete-previous-character) SB
+536 1398 175 (newline) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+182 1548 240 (!RETURN ) SB
+32 0 0 58 58 0 0 56 /Times-Bold /font29 ANSIFont font
+422 1540 216 (directive) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+182 1663 1806 (The !RETURN directive causes the current macro to exit, either returning to the caller \(if ) SB
+2 2 SJ
+1989 1663 196 (any\) or to) SB
+182 1721 627 (interactive mode. For example:) SB
+32 0 0 42 42 0 0 33 /Courier /font0 ANSIFont font
+359 1827 25 (;) SB
+536 1827 900 (Check the monitor type and set %mtyp) SB
+359 1869 600 (!if &sequal $sres "MONO") SB
+536 1911 275 (set %mtyp 1) SB
+536 1953 175 (!return) SB
+359 1995 125 (!else) SB
+536 2037 275 (set %mtyp 2) SB
+359 2079 150 (!endif) SB
+359 2121 1250 (insert-string "You are on a MONOCHROME machine!~n") SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+182 2290 204 (!WHILE ) SB
+32 0 0 58 58 0 0 56 /Times-Bold /font29 ANSIFont font
+386 2282 93 (and) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+479 2290 322 ( !ENDWHILE ) SB
+32 0 0 58 58 0 0 56 /Times-Bold /font29 ANSIFont font
+801 2282 239 (directives) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+182 2416 1105 (The !WHILE directive causes a block of of statements ) SB
+1287 2416 895 (to be executed while a condition specified in) SB
+182 2474 1903 (the directive is TRUE. Every line following the !WHILE directive until the first !ENDWHILE) SB
+182 2532 1031 (directive belongs to body of the loop. For example:) SB
+32 0 0 42 42 0 0 33 /Courier /font0 ANSIFont font
+359 2646 25 (;) SB
+536 2646 1275 (Now we know that emacs.hlp is visible, switch to it) SB
+359 2688 1025 (!while &not &sequal $cbufname "emacs.hlp") SB
+536 2730 275 (next-window) SB
+359 2772 225 (!endwhile) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+182 3183 198 (uEmacs 4.0) SB
+891 3183 209 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1100 3176 43 ( -) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1143 3183 11 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1154 3176 50 (25) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1204 3183 11 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1215 3176 17 (-) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1918 3183 269 (December 1991) SB
+showpage
+% %%Page: 26 26
+grestore sheetsave restore
+/sheetsave save def
+gsave
+24 416 translate -90 rotate
+393 596 div 548 842 div scale
+0 0 moveto 0 842 lineto 596 842 lineto 596 0 lineto
+closepath clip newpath
+0 54 39 2478 3507 300 SM
+0 0 0 fC
+32 0 0 58 58 0 0 56 /Times-Bold /font29 ANSIFont font
+182 263 1273 (APPENDIX: Search order for the initialization file) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+182 407 1560 (Under UNIX uEmacs searches for its initialization file in the following order:) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+182 521 38 (1.) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+359 524 1030 (File given with the @-option on the command line.) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+182 582 38 (2.) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+359 583 178 (.emacsrc) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+537 585 501 ( in the current directory.) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+182 643 38 (3.) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+359 644 178 (.emacsrc) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+537 646 501 ( in your home directory.) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+182 704 38 (4.) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+359 707 160 (System ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+519 705 178 (.emacsrc) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+697 707 994 ( in a standard place \(compiled into the program\).) SB
+8 1 SJ
+182 826 47 (If ) SB
+108 12 SJ
+237 826 1231 (any of the files 1-3 is found the system initialization file will ) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+1576 823 70 (not) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+36 4 SJ
+1646 826 505 ( be executed. The system) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+182 885 178 (.emacsrc) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+90 9 SJ
+360 887 1008 ( tries to execute two additional initialization files ) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+1458 884 103 (after) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+20 2 SJ
+1561 887 87 ( the ) SB
+22 2 SJ
+1668 887 497 (system initialization file,) SB
+182 947 161 (namely:) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+182 1061 38 (5.) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+359 1062 112 (.emrc) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+471 1064 501 ( in your home directory.) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+182 1122 38 (6.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+359 1123 112 (.emrc) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+471 1125 501 ( in the current directory.) SB
+48 12 SJ
+182 1243 1577 (The preferred method for modifying your uEmacs environment is to create an ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+1807 1241 112 (.emrc) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+8 2 SJ
+1919 1243 26 ( ) SB
+10 2 SJ
+1953 1243 224 (file in your) SB
+28 7 SJ
+182 1303 785 (home directory where you can put any ) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+4 1 SJ
+995 1300 462 (additional commands) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+12 3 SJ
+1461 1303 211 ( you want ) SB
+20 4 SJ
+1684 1303 483 (to be executed. You can) SB
+182 1363 591 (further tailor this by creating ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+773 1361 138 (.emrc ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+911 1363 529 (files in any subdirectories.) SB
+182 1480 1318 (Under MS-DOS the search order is similar but a little bit simpler:) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+182 1594 38 (1.) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+359 1597 1030 (File given with the @-option on the command line.) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+182 1655 38 (2.) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+359 1656 178 (emacs.rc) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+537 1658 501 ( in the current directory.) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+182 1716 38 (3.) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+359 1719 160 (System ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+519 1717 191 (emacs.rc,) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+710 1719 1308 ( along the DOS %path, usually in the same directory as uEmacs.) SB
+182 1837 242 (The system ) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+424 1835 178 (emacs.rc) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+602 1837 596 ( tries then to execute the file:) SB
+32 0 0 50 50 0 0 48 /Times-Bold /font29 ANSIFont font
+182 1952 38 (4.) SB
+32 0 0 50 50 0 0 47 /Times-Italic /font31 ANSIFont font
+359 1953 112 (em.rc) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+471 1955 501 ( in the current directory.) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+182 3183 198 (uEmacs 4.0) SB
+891 3183 209 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1100 3176 43 ( -) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1143 3183 11 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1154 3176 50 (26) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1204 3183 11 ( ) SB
+32 0 0 50 50 0 0 45 /Times-Roman /font32 ANSIFont font
+1215 3176 17 (-) SB
+32 0 0 42 42 0 0 38 /Times-Roman /font32 ANSIFont font
+1918 3183 269 (December 1991) SB
+showpage
+% %%Trailer
+grestore sheetsave restore
+showsheet
+%%Trailer
+end
+%%Pages: 13
diff --git a/emacs.rc b/emacs.rc
new file mode 100644
index 0000000..407d908
--- /dev/null
+++ b/emacs.rc
@@ -0,0 +1,285 @@
+; EMACS.RC / .emascrc
+;
+; Startup file for MicroEMACS 3.9 and uEmacs/PK 4.0
+; This file is executed every time the editor is entered.
+;
+; Modified by Petri Kutvonen, last edited September 1991.
+
+set $discmd "FALSE"
+
+; First, try to resolve if we are on a PC ... yes, this is a kludge
+
+!if &seq $sres "NORMAL"
+ set %system "OTHER"
+!else
+ set %system "PC"
+!endif
+
+!if &seq %system "PC"
+
+; PC specific initialization
+
+write-message "(Setting up)"
+
+; Comment out or change this line if you want more than 25 lines,
+; other possible $sres values include EGA and VGA
+
+set $sres "CGA"
+
+; Uncomment next line if your old screen "snows"
+
+;set $flicker "TRUE"
+
+; If your screen "snows" you'll not like scrolling
+
+!if &seq $flicker "TRUE"
+ set $scroll "FALSE"
+!endif
+
+; Function keys (unshifted)
+; f1 f2 f3 f4 f5 f6 f7 f8 f9 f10
+; FN; FN< FN= FN> FN? FN@ FNA FNB FNC FND
+
+bind-to-key help FN;
+bind-to-key exit-emacs FND
+
+; Function keys (shifted)
+; F1 F2 F3 F4 F5 F6 F7 F8 F9 F10
+; FNT FNU FNV FNW FNX FNY FNZ FN[ FN\ FN]
+
+; Other special keys (unshifted)
+; Home End Ins Del PgUp PgDn
+; FNG FNO FNR FNS FNI FNQ
+
+; Some common Alt-keys
+; Alt-X Alt-Z Alt-C Alt-F Alt-O
+; FN- FN, FN. FN! FN^X
+
+bind-to-key exit-emacs FN-
+bind-to-key quick-exit FN,
+bind-to-key i-shell FN.
+bind-to-key find-file FN!
+bind-to-key view-file FN/
+bind-to-key next-window FN^X
+
+; Set screen colors
+
+; You can define a DOS environment variable EMACS_BW (any value)
+; if you don't like colors, e.g. if you have a LCD screen
+
+!if &seq &env "EMACS_BW" ""
+ add-global-mode "blue"
+ add-global-mode "HIGH"
+!endif
+
+!endif
+
+; Help facility
+
+40 store-macro
+ set $discmd "FALSE"
+ !if &not &seq $cbufname "emacs.hlp"
+ write-message "(Loading Help)"
+ !force help
+ !force 8 resize-window
+ !if &seq %system "PC"
+ !if &seq &env "EMACS_BW" ""
+ add-mode "red"
+ !endif
+ bind-to-key execute-macro-38 FNI
+ bind-to-key execute-macro-37 FNQ
+ !else
+ bind-to-key execute-macro-38 FN5
+ bind-to-key execute-macro-37 FN6
+ !endif
+ beginning-of-line
+ 2 forward-character
+ 1 redraw-display
+ save-window
+ !if &seq %system "PC"
+ set %hlpupdn "<PgUp> / <PgDn>"
+ set %hlphelp "<F1>"
+ !else
+ set %hlpupdn "<Prev Scrn> / <Next Scrn>"
+ set %hlphelp "<Help>"
+ !endif
+ execute-macro-39
+ !else
+ set %hlpcode &lef $line 2
+ !if &seq %hlpcode ".."
+ set %hlptopic &mid $line 4 99
+ end-of-line
+ !force search-forward %hlptopic
+ beginning-of-line
+ 2 forward-character
+ 1 redraw-display
+ execute-macro-39
+ !else
+ !if &seq %system "PC"
+ bind-to-key previous-page FNI
+ bind-to-key next-page FNQ
+ !else
+ bind-to-key previous-page FN5
+ bind-to-key next-page FN6
+ !endif
+ !force restore-window
+ !force delete-window
+ clear-message-line
+ !endif
+ !endif
+ set $discmd "TRUE"
+!endm
+
+bind-to-key execute-macro-40 M-?
+!if &seq %system "PC"
+ bind-to-key execute-macro-40 FN;
+!else
+ bind-to-key execute-macro-40 FNh
+!endif
+
+; Help on Help
+
+39 store-macro
+ !if &seq &rig $line 5 "INDEX"
+ write-message &cat "Select topic from list and press " %hlphelp
+ !else
+ write-message &cat "Use " &cat %hlpupdn &cat " to scan help file -- " &cat %hlphelp " to toggle help window"
+ !endif
+!endm
+
+; Previous help page
+
+38 store-macro
+ !if &seq $cbufname "emacs.hlp"
+ beginning-of-line
+ !force search-reverse "=>"
+ 2 forward-character
+ 1 redraw-display
+ execute-macro-39
+ !else
+ previous-page
+ !endif
+!endm
+
+; Next help page
+
+37 store-macro
+ !if &seq $cbufname "emacs.hlp"
+ beginning-of-line
+ 2 forward-character
+ !force search-forward "=>"
+ 1 redraw-display
+ execute-macro-39
+ !else
+ next-page
+ !endif
+!endm
+
+; Set up auto CMODE
+
+36 store-macro
+ !if &seq &mid $cfname 1 7 "/tmp/Re"
+ add-mode "wrap"
+ !return
+ !endif
+ !if &gre &sin $cfname "/.ed" 0
+ add-mode "wrap"
+ !return
+ !endif
+ !if &gre &sin $cfname "/.let" 0
+ add-mode "wrap"
+ !return
+ !endif
+ !if &gre &sin $cfname "/.art" 0
+ add-mode "wrap"
+ !return
+ !endif
+ !if &gre &sin $cfname "/nn." 0
+ add-mode "wrap"
+ !return
+ !endif
+ set %rctmp &sin $cfname "."
+ !if &equ %rctmp 0
+ !return
+ !endif
+ set %rctmp &mid $cfname &add %rctmp 1 5
+ !if &or &seq %rctmp "c" &seq %rctmp "h"
+ add-mode "cmode"
+ !endif
+ !if &or &seq %rctmp "txt" &or &seq %rctmp "doc" &or &seq %rctmp "tmp" &seq %rctmp "tex"
+ add-mode "wrap"
+ !endif
+
+!endm
+
+bind-to-key execute-macro-36 M-FNR
+
+; Setup for ASCII {|}[\] to ISO Latin-1 translation
+
+21 store-macro
+ insert-string "ä"
+!endm
+22 store-macro
+ insert-string "ö"
+!endm
+23 store-macro
+ insert-string "å"
+!endm
+24 store-macro
+ insert-string "Ä"
+!endm
+25 store-macro
+ insert-string "Ö"
+!endm
+26 store-macro
+ insert-string "Å"
+!endm
+
+27 store-macro
+ bind-to-key execute-macro-21 {
+ bind-to-key execute-macro-22 |
+ bind-to-key execute-macro-23 }
+ bind-to-key execute-macro-24 [
+ bind-to-key execute-macro-25 \
+ bind-to-key execute-macro-26 ]
+ write-message "ISO Latin-1 äöåÄÖÅ"
+!endm
+
+28 store-macro
+ unbind-key {
+ unbind-key |
+ unbind-key }
+ unbind-key [
+ unbind-key \
+ unbind-key ]
+ write-message "ASCII {|}[\]"
+!endm
+
+bind-to-key execute-macro-27 ^X[
+bind-to-key execute-macro-28 ^X]
+
+; Make cut-paste easier in window systems
+
+bind-to-key newline ^J
+
+; uEmacs/PK specific initialization
+
+!if &seq $progname "uEmacs/PK"
+
+; Don't scroll on a Sun
+
+ !if &or &seq $TERM "sun" &seq $TERM "sun-cmd"
+ set $scroll "FALSE"
+ !endif
+
+; Execute local initialization files
+
+ !if &seq %system "PC"
+ !force execute-file "EM.RC"
+ !else
+ !force execute-file &cat $HOME "/.emrc"
+ !force execute-file ".emrc"
+ !endif
+!endif
+
+set $discmd "TRUE"
diff --git a/emacs.wri b/emacs.wri
new file mode 100644
index 0000000..16ffbc9
--- /dev/null
+++ b/emacs.wri
Binary files differ
diff --git a/epath.h b/epath.h
new file mode 100644
index 0000000..fe1d57a
--- /dev/null
+++ b/epath.h
@@ -0,0 +1,53 @@
+/* EPATH.H
+ *
+ * This file contains certain info needed to locate the
+ * initialization (etc) files on a system dependent basis
+ *
+ * modified by Petri Kutvonen
+ */
+
+/* possible names and paths of help files under different OSs */
+
+char *pathname[] =
+
+#if MSDOS
+{
+ "emacs.rc",
+ "emacs.hlp",
+ "\\sys\\public\\",
+ "\\usr\\bin\\",
+ "\\bin\\",
+ "\\",
+ ""
+};
+#endif
+
+#if V7 | BSD | USG
+{
+ ".emacsrc",
+ "emacs.hlp",
+#if PKCODE
+ "/usr/global/lib/",
+ "/usr/local/bin/",
+ "/usr/local/lib/",
+#endif
+ "/usr/local/",
+ "/usr/lib/",
+ ""
+};
+#endif
+
+#if VMS
+{
+ "emacs.rc",
+ "emacs.hlp",
+ "",
+#if PKCODE
+ "sys$login:",
+ "emacs_dir:",
+#endif
+ "sys$sysdevice:[vmstools]"
+};
+#endif
+
+#define NPNAMES (sizeof(pathname)/sizeof(char *))
diff --git a/estruct.h b/estruct.h
new file mode 100644
index 0000000..30772d5
--- /dev/null
+++ b/estruct.h
@@ -0,0 +1,731 @@
+/* ESTRUCT.H
+ *
+ * Structure and preprocessor defines
+ *
+ * written by Dave G. Conroy
+ * modified by Steve Wilhite, George Jones
+ * substantially modified by Daniel Lawrence
+ * modified by Petri Kutvonen
+ */
+
+#define MAXCOL 500
+#define MAXROW 500
+
+#ifdef MSDOS
+#undef MSDOS
+#endif
+#ifdef EGA
+#undef EGA
+#endif
+#ifdef CTRLZ
+#undef CTRLZ
+#endif
+
+/* Program Identification.....
+
+ PROGNAME should always be MicroEMACS for a distibrution
+ unmodified version. People using MicroEMACS as a shell
+ for other products should change this to reflect their
+ product. Macros can query this via the $progname variable
+
+ this version in called uEmacs/PK
+*/
+
+#define PROGNAME "uEmacs/PK"
+#define VERSION "4.0.15"
+
+/* Machine/OS definitions */
+
+#if defined(AUTOCONF) || defined(MSDOS) || defined(BSD) || defined(SYSV) || defined(VMS)
+
+/* make an intelligent guess about the target system */
+
+#if defined(__TURBOC__)
+#define MSDOS 1 /* MS/PC DOS 3.1-4.0 with Turbo C 2.0 */
+#else
+#define MSDOS 0
+#endif
+
+#if defined(BSD) || defined(sun) || defined(ultrix) || (defined(vax) && defined(unix)) || defined(ultrix) || defined(__osf__)
+#ifndef BSD
+#define BSD 1 /* Berkeley UNIX */
+#endif
+#else
+#define BSD 0
+#endif
+
+#if defined(SVR4) || defined(__linux__) /* ex. SunOS 5.3 */
+#define SVR4 1
+#define SYSV 1
+#undef BSD
+#endif
+
+#if defined(SYSV) || defined(u3b2) || defined(_AIX) || (defined(i386) && defined(unix)) || defined(__hpux)
+#define USG 1 /* System V UNIX */
+#else
+#define USG 0
+#endif
+
+#if defined(VMS) || (defined(vax) && ! defined(unix))
+#define VMS 1 /* VAX/VMS */
+#else
+#define VMS 0
+#endif
+
+#define V7 0 /* no more */
+
+#else
+
+#define MSDOS 1 /* MS-DOS */
+#define V7 0 /* V7 UNIX or Coherent or BSD4.2*/
+#define BSD 0 /* UNIX BSD 4.2 and ULTRIX */
+#define USG 0 /* UNIX system V */
+#define VMS 0 /* VAX/VMS */
+
+#endif /*autoconf */
+
+#ifndef AUTOCONF
+
+/* Compiler definitions */
+#define UNIX 0 /* a random UNIX compiler */
+#define MSC 0 /* MicroSoft C compiler, versions 3 up */
+#define TURBO 1 /* Turbo C/MSDOS */
+
+#else
+
+#define UNIX (V7 | BSD | USG)
+#define MSC 0
+#define TURBO MSDOS
+
+#endif /*autoconf */
+
+/* Debugging options */
+
+#define RAMSIZE 0 /* dynamic RAM memory usage tracking */
+#define RAMSHOW 0 /* auto dynamic RAM reporting */
+
+#ifndef AUTOCONF
+
+/* Special keyboard definitions */
+
+#define VT220 0 /* Use keypad escapes P.K. */
+#define VT100 0 /* Handle VT100 style keypad. */
+
+/* Terminal Output definitions */
+
+#define ANSI 0 /* ANSI escape sequences */
+#define VMSVT 0 /* various VMS terminal entries */
+#define VT52 0 /* VT52 terminal (Zenith). */
+#define TERMCAP 0 /* Use TERMCAP */
+#define IBMPC 1 /* IBM-PC CGA/MONO/EGA driver */
+
+#else
+
+#define VT220 (UNIX | VMS)
+#define VT100 0
+
+#define ANSI 0
+#define VMSVT VMS
+#define VT52 0
+#define TERMCAP UNIX
+#define IBMPC MSDOS
+
+#endif /*autoconf */
+
+/* Configuration options */
+
+#define CVMVAS 1 /* arguments to page forward/back in pages */
+#define CLRMSG 0 /* space clears the message line with no insert */
+#define CFENCE 1 /* fench matching in CMODE */
+#define TYPEAH 1 /* type ahead causes update to be skipped */
+#define DEBUGM 1 /* $debug triggers macro debugging */
+#define VISMAC 0 /* update display during keyboard macros */
+#define CTRLZ 0 /* add a ^Z at end of files under MSDOS only */
+#define ADDCR 0 /* ajout d'un CR en fin de chaque ligne (ST520) */
+#define NBRACE 1 /* new style brace matching command */
+#define REVSTA 1 /* Status line appears in reverse video */
+
+#ifndef AUTOCONF
+
+#define COLOR 1 /* color commands and windows */
+#define FILOCK 0 /* file locking under unix BSD 4.2 */
+
+#else
+
+#define COLOR MSDOS
+#ifdef SVR4
+#define FILOCK 1
+#else
+#define FILOCK BSD
+#endif
+
+#endif /* autoconf */
+
+#define ISRCH 1 /* Incremental searches like ITS EMACS */
+#define WORDPRO 1 /* Advanced word processing features */
+#define FNLABEL 0 /* function key label code [HP150] */
+#define APROP 1 /* Add code for Apropos command */
+#define CRYPT 1 /* file encryption enabled? */
+#define MAGIC 1 /* include regular expression matching? */
+#define AEDIT 1 /* advanced editing options: en/detabbing */
+#define PROC 1 /* named procedures */
+#define CLEAN 0 /* de-alloc memory on exit */
+#define CALLED 0 /* is emacs a called subroutine? or stand alone */
+
+#define ASCII 1 /* always using ASCII char sequences for now */
+#define EBCDIC 0 /* later IBM mainfraim versions will use EBCDIC */
+
+#ifndef AUTOCONF
+
+#define XONXOFF 0 /* don't disable XON-XOFF flow control P.K. */
+#define NATIONL 0 /* interprete [,],\,{,},| as characters P.K. */
+
+#else
+
+#define XONXOFF (UNIX | VMS)
+#define NATIONL (UNIX | VMS)
+
+#endif /* autoconf */
+
+#define PKCODE 1 /* include my extensions P.K., define always */
+#define IBMCHR MSDOS /* use IBM PC character set P.K. */
+#define SCROLLCODE 1 /* scrolling code P.K. */
+
+/* System dependant library redefinitions, structures and includes */
+
+#if TURBO
+#include <dos.h>
+#include <mem.h>
+#undef peek
+#undef poke
+#define peek(a,b,c,d) movedata(a,b,FP_SEG(c),FP_OFF(c),d)
+#define poke(a,b,c,d) movedata(FP_SEG(c),FP_OFF(c),a,b,d)
+#endif
+
+#if VMS
+#define atoi xatoi
+#define abs xabs
+#define getname xgetname
+#endif
+
+#if MSDOS & MSC
+#include <dos.h>
+#include <memory.h>
+#define peek(a,b,c,d) movedata(a,b,FP_SEG(c),FP_OFF(c),d)
+#define poke(a,b,c,d) movedata(FP_SEG(c),FP_OFF(c),a,b,d)
+#define movmem(a, b, c) memcpy(b, a, c)
+#endif
+
+#if VMS
+#define unlink(a) delete(a)
+#endif
+
+/* define some ability flags */
+
+#if IBMPC
+#define MEMMAP 1
+#else
+#define MEMMAP 0
+#endif
+
+#if MSDOS | V7 | USG | BSD
+#define ENVFUNC 1
+#else
+#define ENVFUNC 0
+#endif
+
+/* Emacs global flag bit definitions (for gflags) */
+
+#define GFREAD 1
+
+/* internal constants */
+
+#define NBINDS 256 /* max # of bound keys */
+#define NFILEN 80 /* # of bytes, file name */
+#define NBUFN 16 /* # of bytes, buffer name */
+#define NLINE 256 /* # of bytes, input line */
+#define NSTRING 128 /* # of bytes, string buffers */
+#define NKBDM 256 /* # of strokes, keyboard macro */
+#define NPAT 128 /* # of bytes, pattern */
+#define HUGE 1000 /* Huge number */
+#define NLOCKS 100 /* max # of file locks active */
+#define NCOLORS 8 /* number of supported colors */
+#define KBLOCK 250 /* sizeof kill buffer chunks */
+#define NBLOCK 16 /* line block chunk size */
+#define NVSIZE 10 /* max #chars in a var name */
+
+#define CONTROL 0x0100 /* Control flag, or'ed in */
+#define META 0x0200 /* Meta flag, or'ed in */
+#define CTLX 0x0400 /* ^X flag, or'ed in */
+#define SPEC 0x0800 /* special key (function keys) */
+
+#if PKCODE
+#define MAXNLINE 100000 /* max lines from one file */
+#endif
+
+#ifdef FALSE
+#undef FALSE
+#endif
+#ifdef TRUE
+#undef TRUE
+#endif
+
+#define FALSE 0 /* False, no, bad, etc. */
+#define TRUE 1 /* True, yes, good, etc. */
+#define ABORT 2 /* Death, ^G, abort, etc. */
+#define FAILED 3 /* not-quite fatal false return */
+
+#define STOP 0 /* keyboard macro not in use */
+#define PLAY 1 /* playing */
+#define RECORD 2 /* recording */
+
+/* Directive definitions */
+
+#define DIF 0
+#define DELSE 1
+#define DENDIF 2
+#define DGOTO 3
+#define DRETURN 4
+#define DENDM 5
+#define DWHILE 6
+#define DENDWHILE 7
+#define DBREAK 8
+#define DFORCE 9
+
+#define NUMDIRS 10
+
+/*
+ * PTBEG, PTEND, FORWARD, and REVERSE are all toggle-able values for
+ * the scan routines.
+ */
+#define PTBEG 0 /* Leave the point at the beginning on search */
+#define PTEND 1 /* Leave the point at the end on search */
+#define FORWARD 0 /* forward direction */
+#define REVERSE 1 /* backwards direction */
+
+#define FIOSUC 0 /* File I/O, success. */
+#define FIOFNF 1 /* File I/O, file not found. */
+#define FIOEOF 2 /* File I/O, end of file. */
+#define FIOERR 3 /* File I/O, error. */
+#define FIOMEM 4 /* File I/O, out of memory */
+#define FIOFUN 5 /* File I/O, eod of file/bad line*/
+
+#define CFCPCN 0x0001 /* Last command was C-P, C-N */
+#define CFKILL 0x0002 /* Last command was a kill */
+
+#define BELL 0x07 /* a bell character */
+#define TAB 0x09 /* a tab character */
+
+#if V7 | USG | BSD
+#define PATHCHR ':'
+#else
+#define PATHCHR ';'
+#endif
+
+#define INTWIDTH sizeof(int) * 3
+
+/* Macro argument token types */
+
+#define TKNUL 0 /* end-of-string */
+#define TKARG 1 /* interactive argument */
+#define TKBUF 2 /* buffer argument */
+#define TKVAR 3 /* user variables */
+#define TKENV 4 /* environment variables */
+#define TKFUN 5 /* function.... */
+#define TKDIR 6 /* directive */
+#define TKLBL 7 /* line label */
+#define TKLIT 8 /* numeric literal */
+#define TKSTR 9 /* quoted string literal */
+#define TKCMD 10 /* command name */
+
+/* Internal defined functions */
+
+#define nextab(a) (a & ~tabmask) + (tabmask+1)
+#ifdef abs
+#undef abs
+#endif
+
+/* DIFCASE represents the integer difference between upper
+ and lower case letters. It is an xor-able value, which is
+ fortunate, since the relative positions of upper to lower
+ case letters is the opposite of ascii in ebcdic.
+*/
+
+#ifdef islower
+#undef islower
+#endif
+
+#if PKCODE
+#ifdef isupper
+#undef isupper
+#endif
+#endif
+
+#if ASCII
+
+#define DIFCASE 0x20
+
+#if NATIONL
+#define LASTUL ']'
+#define LASTLL '}'
+#else
+#define LASTUL 'Z'
+#define LASTLL 'z'
+#endif
+
+#if IBMCHR
+
+#define isletter(c) (('a' <= c && LASTLL >= c) || ('A' <= c && LASTUL >= c) || (128<=c && c<=167))
+#define islower(c) (('a' <= c && LASTLL >= c))
+#define isupper(c) (('A' <= c && LASTUL >= c))
+
+#else
+
+#define isletter(c) isxletter((0xFF & (c)))
+#define islower(c) isxlower((0xFF & (c)))
+#define isupper(c) isxupper((0xFF & (c)))
+
+#define isxletter(c) (('a' <= c && LASTLL >= c) || ('A' <= c && LASTUL >= c) || (192<=c && c<=255))
+#define isxlower(c) (('a' <= c && LASTLL >= c) || (224 <= c && 252 >= c))
+#define isxupper(c) (('A' <= c && LASTUL >= c) || (192 <= c && 220 >= c))
+
+#endif
+
+#endif
+
+#if EBCDIC
+
+#define DIFCASE 0x40
+#define isletter(c) (('a' <= c && 'i' >= c) || ('j' <= c && 'r' >= c) || ('s' <= c && 'z' >= c) || ('A' <= c && 'I' >= c) || ('J' <= c && 'R' >= c) || ('S' <= c && 'Z' >= c))
+#define islower(c) (('a' <= c && 'i' >= c) || ('j' <= c && 'r' >= c) || ('s' <= c && 'z' >= c))
+#if PKCODE
+#define isupper(c) (('A' <= c && 'I' >= c) || ('J' <= c && 'R' >= c) || ('S' <= c && 'Z' >= c))
+#endif
+
+#endif
+
+/* Dynamic RAM tracking and reporting redefinitions */
+
+#if RAMSIZE
+#define malloc allocate
+#define free release
+#endif
+
+/* De-allocate memory always on exit (if the operating system or
+ main program can not
+*/
+
+#if CLEAN
+#define exit(a) cexit(a)
+#endif
+
+/*
+ * There is a window structure allocated for every active display window. The
+ * windows are kept in a big list, in top to bottom screen order, with the
+ * listhead at "wheadp". Each window contains its own values of dot and mark.
+ * The flag field contains some bits that are set by commands to guide
+ * redisplay. Although this is a bit of a compromise in terms of decoupling,
+ * the full blown redisplay is just too expensive to run for every input
+ * character.
+ */
+typedef struct WINDOW {
+ struct WINDOW *w_wndp; /* Next window */
+ struct BUFFER *w_bufp; /* Buffer displayed in window */
+ struct LINE *w_linep; /* Top line in the window */
+ struct LINE *w_dotp; /* Line containing "." */
+ short w_doto; /* Byte offset for "." */
+ struct LINE *w_markp; /* Line containing "mark" */
+ short w_marko; /* Byte offset for "mark" */
+ char w_toprow; /* Origin 0 top row of window */
+ char w_ntrows; /* # of rows of text in window */
+ char w_force; /* If NZ, forcing row. */
+ char w_flag; /* Flags. */
+#if COLOR
+ char w_fcolor; /* current forground color */
+ char w_bcolor; /* current background color */
+#endif
+} WINDOW;
+
+#define WFFORCE 0x01 /* Window needs forced reframe */
+#define WFMOVE 0x02 /* Movement from line to line */
+#define WFEDIT 0x04 /* Editing within a line */
+#define WFHARD 0x08 /* Better to a full display */
+#define WFMODE 0x10 /* Update mode line. */
+#define WFCOLR 0x20 /* Needs a color change */
+
+#if SCROLLCODE
+#define WFKILLS 0x40 /* something was deleted */
+#define WFINS 0x80 /* something was inserted */
+#endif
+
+
+/*
+ * Text is kept in buffers. A buffer header, described below, exists for every
+ * buffer in the system. The buffers are kept in a big list, so that commands
+ * that search for a buffer by name can find the buffer header. There is a
+ * safe store for the dot and mark in the header, but this is only valid if
+ * the buffer is not being displayed (that is, if "b_nwnd" is 0). The text for
+ * the buffer is kept in a circularly linked list of lines, with a pointer to
+ * the header line in "b_linep".
+ * Buffers may be "Inactive" which means the files associated with them
+ * have not been read in yet. These get read in at "use buffer" time.
+ */
+typedef struct BUFFER {
+ struct BUFFER *b_bufp; /* Link to next BUFFER */
+ struct LINE *b_dotp; /* Link to "." LINE structure */
+ short b_doto; /* Offset of "." in above LINE */
+ struct LINE *b_markp; /* The same as the above two, */
+ short b_marko; /* but for the "mark" */
+ struct LINE *b_linep; /* Link to the header LINE */
+ char b_active; /* window activated flag */
+ char b_nwnd; /* Count of windows on buffer */
+ char b_flag; /* Flags */
+ int b_mode; /* editor mode of this buffer */
+ char b_fname[NFILEN]; /* File name */
+ char b_bname[NBUFN]; /* Buffer name */
+#if CRYPT
+ char b_key[NPAT]; /* current encrypted key */
+#endif
+} BUFFER;
+
+#define BFINVS 0x01 /* Internal invisable buffer */
+#define BFCHG 0x02 /* Changed since last write */
+#define BFTRUNC 0x04 /* buffer was truncated when read */
+
+/* mode flags */
+#define NUMMODES 9 /* # of defined modes */
+
+#define MDWRAP 0x0001 /* word wrap */
+#define MDCMOD 0x0002 /* C indentation and fence match*/
+#define MDSPELL 0x0004 /* spell error parcing */
+#define MDEXACT 0x0008 /* Exact matching for searches */
+#define MDVIEW 0x0010 /* read-only buffer */
+#define MDOVER 0x0020 /* overwrite mode */
+#define MDMAGIC 0x0040 /* regular expresions in search */
+#define MDCRYPT 0x0080 /* encrytion mode active */
+#define MDASAVE 0x0100 /* auto-save mode */
+
+/*
+ * The starting position of a region, and the size of the region in
+ * characters, is kept in a region structure. Used by the region commands.
+ */
+typedef struct {
+ struct LINE *r_linep; /* Origin LINE address. */
+ short r_offset; /* Origin LINE offset. */
+ long r_size; /* Length in characters. */
+} REGION;
+
+/*
+ * All text is kept in circularly linked lists of "LINE" structures. These
+ * begin at the header line (which is the blank line beyond the end of the
+ * buffer). This line is pointed to by the "BUFFER". Each line contains a the
+ * number of bytes in the line (the "used" size), the size of the text array,
+ * and the text. The end of line is not stored as a byte; it's implied. Future
+ * additions will include update hints, and a list of marks into the line.
+ */
+typedef struct LINE {
+ struct LINE *l_fp; /* Link to the next line */
+ struct LINE *l_bp; /* Link to the previous line */
+ short l_size; /* Allocated size */
+ short l_used; /* Used size */
+ char l_text[1]; /* A bunch of characters. */
+} LINE;
+
+#define lforw(lp) ((lp)->l_fp)
+#define lback(lp) ((lp)->l_bp)
+#define lgetc(lp, n) ((lp)->l_text[(n)]&0xFF)
+#define lputc(lp, n, c) ((lp)->l_text[(n)]=(c))
+#define llength(lp) ((lp)->l_used)
+
+/*
+ * The editor communicates with the display using a high level interface. A
+ * "TERM" structure holds useful variables, and indirect pointers to routines
+ * that do useful operations. The low level get and put routines are here too.
+ * This lets a terminal, in addition to having non standard commands, have
+ * funny get and put character code too. The calls might get changed to
+ * "termp->t_field" style in the future, to make it possible to run more than
+ * one terminal type.
+ */
+typedef struct {
+ short t_mrow; /* max number of rows allowable */
+ short t_nrow; /* current number of rows used */
+ short t_mcol; /* max Number of columns. */
+ short t_ncol; /* current Number of columns. */
+ short t_margin; /* min margin for extended lines*/
+ short t_scrsiz; /* size of scroll region " */
+ int t_pause; /* # times thru update to pause */
+ int (*t_open)(); /* Open terminal at the start. */
+ int (*t_close)(); /* Close terminal at end. */
+ int (*t_kopen)(); /* Open keyboard */
+ int (*t_kclose)(); /* close keyboard */
+ int (*t_getchar)(); /* Get character from keyboard. */
+ int (*t_putchar)(); /* Put character to display. */
+ int (*t_flush)(); /* Flush output buffers. */
+ int (*t_move)(); /* Move the cursor, origin 0. */
+ int (*t_eeol)(); /* Erase to end of line. */
+ int (*t_eeop)(); /* Erase to end of page. */
+ int (*t_beep)(); /* Beep. */
+ int (*t_rev)(); /* set reverse video state */
+ int (*t_rez)(); /* change screen resolution */
+#if COLOR
+ int (*t_setfor)(); /* set forground color */
+ int (*t_setback)(); /* set background color */
+#endif
+#if SCROLLCODE
+ int (*t_scroll)(); /* scroll a region of the screen */
+#endif
+} TERM;
+
+/* TEMPORARY macros for terminal I/O (to be placed in a machine
+ dependant place later) */
+
+#define TTopen (*term.t_open)
+#define TTclose (*term.t_close)
+#define TTkopen (*term.t_kopen)
+#define TTkclose (*term.t_kclose)
+#define TTgetc (*term.t_getchar)
+#define TTputc (*term.t_putchar)
+#define TTflush (*term.t_flush)
+#define TTmove (*term.t_move)
+#define TTeeol (*term.t_eeol)
+#define TTeeop (*term.t_eeop)
+#define TTbeep (*term.t_beep)
+#define TTrev (*term.t_rev)
+#define TTrez (*term.t_rez)
+#if COLOR
+#define TTforg (*term.t_setfor)
+#define TTbacg (*term.t_setback)
+#endif
+
+/* structure for the table of initial key bindings */
+
+typedef struct {
+ short k_code; /* Key code */
+ int (*k_fp)(); /* Routine to handle it */
+} KEYTAB;
+
+/* structure for the name binding table */
+
+typedef struct {
+ char *n_name; /* name of function key */
+ int (*n_func)(); /* function name is bound to */
+} NBIND;
+
+/* The editor holds deleted text chunks in the KILL buffer. The
+ kill buffer is logically a stream of ascii characters, however
+ due to its unpredicatable size, it gets implemented as a linked
+ list of chunks. (The d_ prefix is for "deleted" text, as k_
+ was taken up by the keycode structure)
+*/
+
+typedef struct KILL {
+ struct KILL *d_next; /* link to next chunk, NULL if last */
+ char d_chunk[KBLOCK]; /* deleted text */
+} KILL;
+
+/* When emacs' command interpetor needs to get a variable's name,
+ rather than it's value, it is passed back as a VDESC variable
+ description structure. The v_num field is a index into the
+ appropriate variable table.
+*/
+
+typedef struct VDESC {
+ int v_type; /* type of variable */
+ int v_num; /* ordinal pointer to variable in list */
+} VDESC;
+
+/* The !WHILE directive in the execution language needs to
+ stack references to pending whiles. These are stored linked
+ to each currently open procedure via a linked list of
+ the following structure
+*/
+
+typedef struct WHBLOCK {
+ LINE *w_begin; /* ptr to !while statement */
+ LINE *w_end; /* ptr to the !endwhile statement*/
+ int w_type; /* block type */
+ struct WHBLOCK *w_next; /* next while */
+} WHBLOCK;
+
+#define BTWHILE 1
+#define BTBREAK 2
+
+/*
+ * Incremental search defines.
+ */
+#if ISRCH
+
+#define CMDBUFLEN 256 /* Length of our command buffer */
+
+#define IS_ABORT 0x07 /* Abort the isearch */
+#define IS_BACKSP 0x08 /* Delete previous char */
+#define IS_TAB 0x09 /* Tab character (allowed search char) */
+#define IS_NEWLINE 0x0D /* New line from keyboard (Carriage return) */
+#define IS_QUOTE 0x11 /* Quote next character */
+#define IS_REVERSE 0x12 /* Search backward */
+#define IS_FORWARD 0x13 /* Search forward */
+#define IS_VMSQUOTE 0x16 /* VMS quote character */
+#define IS_VMSFORW 0x18 /* Search forward for VMS */
+#define IS_QUIT 0x1B /* Exit the search */
+#define IS_RUBOUT 0x7F /* Delete previous character */
+
+/* IS_QUIT is no longer used, the variable metac is used instead */
+
+#endif
+
+#if MAGIC
+/*
+ * Defines for the metacharacters in the regular expression
+ * search routines.
+ */
+#define MCNIL 0 /* Like the '\0' for strings.*/
+#define LITCHAR 1 /* Literal character, or string.*/
+#define ANY 2
+#define CCL 3
+#define NCCL 4
+#define BOL 5
+#define EOL 6
+#define DITTO 7
+#define CLOSURE 256 /* An or-able value.*/
+#define MASKCL CLOSURE - 1
+
+#define MC_ANY '.' /* 'Any' character (except newline).*/
+#define MC_CCL '[' /* Character class.*/
+#define MC_NCCL '^' /* Negate character class.*/
+#define MC_RCCL '-' /* Range in character class.*/
+#define MC_ECCL ']' /* End of character class.*/
+#define MC_BOL '^' /* Beginning of line.*/
+#define MC_EOL '$' /* End of line.*/
+#define MC_CLOSURE '*' /* Closure - does not extend past newline.*/
+#define MC_DITTO '&' /* Use matched string in replacement.*/
+#define MC_ESC '\\' /* Escape - suppress meta-meaning.*/
+
+#define BIT(n) (1 << (n)) /* An integer with one bit set.*/
+#define CHCASE(c) ((c) ^ DIFCASE) /* Toggle the case of a letter.*/
+
+/* HICHAR - 1 is the largest character we will deal with.
+ * HIBYTE represents the number of bytes in the bitmap.
+ */
+#define HICHAR 256
+#define HIBYTE HICHAR >> 3
+
+/* Typedefs that define the bitmap type for searching (BITMAP),
+ * the meta-character structure for MAGIC mode searching (MC),
+ * and the meta-character structure for MAGIC mode replacment (RMC).
+ */
+typedef char *BITMAP;
+
+typedef struct {
+ short int mc_type;
+ union {
+ int lchar;
+ BITMAP cclmap;
+ } u;
+} MC;
+
+typedef struct {
+ short int mc_type;
+ char *rstr;
+} RMC;
+#endif
+
diff --git a/eval.c b/eval.c
new file mode 100644
index 0000000..496b5aa
--- /dev/null
+++ b/eval.c
@@ -0,0 +1,879 @@
+/* EVAL.C
+ *
+ * Expression evaluation functions
+ *
+ * written 1986 by Daniel Lawrence
+ * modified by Petri Kutvonen
+ */
+
+#include <stdio.h>
+#include "estruct.h"
+#include "edef.h"
+#include "evar.h"
+
+varinit() /* initialize the user variable list */
+
+{
+ register int i;
+
+ for (i=0; i < MAXVARS; i++)
+ uv[i].u_name[0] = 0;
+}
+
+char *gtfun(fname) /* evaluate a function */
+
+char *fname; /* name of function to evaluate */
+
+{
+ register int fnum; /* index to function to eval */
+ register int status; /* return status */
+ register char *tsp; /* temporary string pointer */
+ char arg1[NSTRING]; /* value of first argument */
+ char arg2[NSTRING]; /* value of second argument */
+ char arg3[NSTRING]; /* value of third argument */
+ static char result[2 * NSTRING]; /* string result */
+ char *flook(); /* look file up on path */
+ char *xlat(); /* translate a char string */
+#if ENVFUNC
+ char *getenv(); /* get environment string */
+#endif
+
+ /* look the function up in the function table */
+ fname[3] = 0; /* only first 3 chars significant */
+ mklower(fname); /* and let it be upper or lower case */
+ for (fnum = 0; fnum < NFUNCS; fnum++)
+ if (strcmp(fname, funcs[fnum].f_name) == 0)
+ break;
+
+ /* return errorm on a bad reference */
+ if (fnum == NFUNCS)
+ return(errorm);
+
+ /* if needed, retrieve the first argument */
+ if (funcs[fnum].f_type >= MONAMIC) {
+ if ((status = macarg(arg1)) != TRUE)
+ return(errorm);
+
+ /* if needed, retrieve the second argument */
+ if (funcs[fnum].f_type >= DYNAMIC) {
+ if ((status = macarg(arg2)) != TRUE)
+ return(errorm);
+
+ /* if needed, retrieve the third argument */
+ if (funcs[fnum].f_type >= TRINAMIC)
+ if ((status = macarg(arg3)) != TRUE)
+ return(errorm);
+ }
+ }
+
+
+ /* and now evaluate it! */
+ switch (fnum) {
+ case UFADD: return(itoa(atoi(arg1) + atoi(arg2)));
+ case UFSUB: return(itoa(atoi(arg1) - atoi(arg2)));
+ case UFTIMES: return(itoa(atoi(arg1) * atoi(arg2)));
+ case UFDIV: return(itoa(atoi(arg1) / atoi(arg2)));
+ case UFMOD: return(itoa(atoi(arg1) % atoi(arg2)));
+ case UFNEG: return(itoa(-atoi(arg1)));
+ case UFCAT: strcpy(result, arg1);
+ return(strcat(result, arg2));
+ case UFLEFT: return(strncpy(result, arg1, atoi(arg2)));
+ case UFRIGHT: return(strcpy(result,
+ &arg1[(strlen(arg1) - atoi(arg2))]));
+ case UFMID: return(strncpy(result, &arg1[atoi(arg2)-1],
+ atoi(arg3)));
+ case UFNOT: return(ltos(stol(arg1) == FALSE));
+ case UFEQUAL: return(ltos(atoi(arg1) == atoi(arg2)));
+ case UFLESS: return(ltos(atoi(arg1) < atoi(arg2)));
+ case UFGREATER: return(ltos(atoi(arg1) > atoi(arg2)));
+ case UFSEQUAL: return(ltos(strcmp(arg1, arg2) == 0));
+ case UFSLESS: return(ltos(strcmp(arg1, arg2) < 0));
+ case UFSGREAT: return(ltos(strcmp(arg1, arg2) > 0));
+ case UFIND: return(strcpy(result, getval(arg1)));
+ case UFAND: return(ltos(stol(arg1) && stol(arg2)));
+ case UFOR: return(ltos(stol(arg1) || stol(arg2)));
+ case UFLENGTH: return(itoa(strlen(arg1)));
+ case UFUPPER: return(mkupper(arg1));
+ case UFLOWER: return(mklower(arg1));
+ case UFTRUTH: return(ltos(atoi(arg1) == 42));
+ case UFASCII: return(itoa((int)arg1[0]));
+ case UFCHR: result[0] = atoi(arg1);
+ result[1] = 0;
+ return(result);
+ case UFGTKEY: result[0] = tgetc();
+ result[1] = 0;
+ return(result);
+ case UFRND: return(itoa((ernd() % abs(atoi(arg1))) + 1));
+ case UFABS: return(itoa(abs(atoi(arg1))));
+ case UFSINDEX: return(itoa(sindex(arg1, arg2)));
+ case UFENV:
+#if ENVFUNC
+ tsp = getenv(arg1);
+ return(tsp == NULL ? "" : tsp);
+#else
+ return("");
+#endif
+ case UFBIND: return(transbind(arg1));
+ case UFEXIST: return(ltos(fexist(arg1)));
+ case UFFIND:
+ tsp = flook(arg1, TRUE);
+ return(tsp == NULL ? "" : tsp);
+ case UFBAND: return(itoa(atoi(arg1) & atoi(arg2)));
+ case UFBOR: return(itoa(atoi(arg1) | atoi(arg2)));
+ case UFBXOR: return(itoa(atoi(arg1) ^ atoi(arg2)));
+ case UFBNOT: return(itoa(~atoi(arg1)));
+ case UFXLATE: return(xlat(arg1, arg2, arg3));
+ }
+
+ exit(-11); /* never should get here */
+}
+
+char *gtusr(vname) /* look up a user var's value */
+
+char *vname; /* name of user variable to fetch */
+
+{
+
+ register int vnum; /* ordinal number of user var */
+
+ /* scan the list looking for the user var name */
+ for (vnum = 0; vnum < MAXVARS; vnum++) {
+ if (uv[vnum].u_name[0] == 0)
+ return(errorm);
+ if (strcmp(vname, uv[vnum].u_name) == 0)
+ return(uv[vnum].u_value);
+ }
+
+ /* return errorm if we run off the end */
+ return(errorm);
+}
+
+char *gtenv(vname)
+
+char *vname; /* name of environment variable to retrieve */
+
+{
+ register int vnum; /* ordinal number of var refrenced */
+ char *getkill();
+
+ /* scan the list, looking for the referenced name */
+ for (vnum = 0; vnum < NEVARS; vnum++)
+ if (strcmp(vname, envars[vnum]) == 0)
+ break;
+
+ /* return errorm on a bad reference */
+ if (vnum == NEVARS)
+#if ENVFUNC
+ {
+ extern char *getenv();
+ char *ename = getenv(vname);
+
+ if (ename != NULL)
+ return(ename);
+ else
+ return(errorm);
+ }
+#else
+ return(errorm);
+#endif
+
+ /* otherwise, fetch the appropriate value */
+ switch (vnum) {
+ case EVFILLCOL: return(itoa(fillcol));
+ case EVPAGELEN: return(itoa(term.t_nrow + 1));
+ case EVCURCOL: return(itoa(getccol(FALSE)));
+ case EVCURLINE: return(itoa(getcline()));
+ case EVRAM: return(itoa((int)(envram / 1024l)));
+ case EVFLICKER: return(ltos(flickcode));
+ case EVCURWIDTH:return(itoa(term.t_ncol));
+ case EVCBUFNAME:return(curbp->b_bname);
+ case EVCFNAME: return(curbp->b_fname);
+ case EVSRES: return(sres);
+ case EVDEBUG: return(ltos(macbug));
+ case EVSTATUS: return(ltos(cmdstatus));
+ case EVPALETTE: return(palstr);
+ case EVASAVE: return(itoa(gasave));
+ case EVACOUNT: return(itoa(gacount));
+ case EVLASTKEY: return(itoa(lastkey));
+ case EVCURCHAR:
+ return(curwp->w_dotp->l_used ==
+ curwp->w_doto ? itoa('\n') :
+ itoa(lgetc(curwp->w_dotp, curwp->w_doto)));
+ case EVDISCMD: return(ltos(discmd));
+ case EVVERSION: return(VERSION);
+ case EVPROGNAME:return(PROGNAME);
+ case EVSEED: return(itoa(seed));
+ case EVDISINP: return(ltos(disinp));
+ case EVWLINE: return(itoa(curwp->w_ntrows));
+ case EVCWLINE: return(itoa(getwpos()));
+ case EVTARGET: saveflag = lastflag;
+ return(itoa(curgoal));
+ case EVSEARCH: return(pat);
+ case EVREPLACE: return(rpat);
+ case EVMATCH: return((patmatch == NULL)? "": patmatch);
+ case EVKILL: return(getkill());
+ case EVCMODE: return(itoa(curbp->b_mode));
+ case EVGMODE: return(itoa(gmode));
+ case EVTPAUSE: return(itoa(term.t_pause));
+ case EVPENDING:
+#if TYPEAH
+ return(ltos(typahead()));
+#else
+ return(falsem);
+#endif
+ case EVLWIDTH: return(itoa(llength(curwp->w_dotp)));
+ case EVLINE: return(getctext());
+ case EVGFLAGS: return(itoa(gflags));
+ case EVRVAL: return(itoa(rval));
+ case EVTAB: return(itoa(tabmask+1));
+ case EVOVERLAP: return(itoa(overlap));
+ case EVSCROLLCOUNT:
+ return(itoa(scrollcount));
+#if SCROLLCODE
+ case EVSCROLL: return(ltos(term.t_scroll != NULL));
+#else
+ case EVSCROLL: return(ltos(0));
+#endif
+ }
+ exit(-12); /* again, we should never get here */
+}
+
+char *getkill() /* return some of the contents of the kill buffer */
+
+{
+ register int size; /* max number of chars to return */
+ static char value[NSTRING]; /* temp buffer for value */
+
+ if (kbufh == NULL)
+ /* no kill buffer....just a null string */
+ value[0] = 0;
+ else {
+ /* copy in the contents... */
+ if (kused < NSTRING)
+ size = kused;
+ else
+ size = NSTRING - 1;
+ strncpy(value, kbufh->d_chunk, size);
+ }
+
+ /* and return the constructed value */
+ return(value);
+}
+
+int setvar(f, n) /* set a variable */
+
+int f; /* default flag */
+int n; /* numeric arg (can overide prompted value) */
+
+{
+ register int status; /* status return */
+#if DEBUGM
+ register char *sp; /* temp string pointer */
+ register char *ep; /* ptr to end of outline */
+#endif
+ VDESC vd; /* variable num/type */
+ char var[NVSIZE+1]; /* name of variable to fetch */
+ char value[NSTRING]; /* value to set variable to */
+
+ /* first get the variable to set.. */
+ if (clexec == FALSE) {
+ status = mlreply("Variable to set: ", &var[0], NVSIZE);
+ if (status != TRUE)
+ return(status);
+ } else { /* macro line argument */
+ /* grab token and skip it */
+ execstr = token(execstr, var, NVSIZE + 1);
+ }
+
+ /* check the legality and find the var */
+ findvar(var, &vd, NVSIZE + 1);
+
+ /* if its not legal....bitch */
+ if (vd.v_type == -1) {
+ mlwrite("%%No such variable as '%s'", var);
+ return(FALSE);
+ }
+
+ /* get the value for that variable */
+ if (f == TRUE)
+ strcpy(value, itoa(n));
+ else {
+ status = mlreply("Value: ", &value[0], NSTRING);
+ if (status != TRUE)
+ return(status);
+ }
+
+ /* and set the appropriate value */
+ status = svar(&vd, value);
+
+#if DEBUGM
+ /* if $debug == TRUE, every assignment will echo a statment to
+ that effect here. */
+
+ if (macbug) {
+ strcpy(outline, "(((");
+
+ /* assignment status */
+ strcat(outline, ltos(status));
+ strcat(outline, ":");
+
+ /* variable name */
+ strcat(outline, var);
+ strcat(outline, ":");
+
+ /* and lastly the value we tried to assign */
+ strcat(outline, value);
+ strcat(outline, ")))");
+
+ /* expand '%' to "%%" so mlwrite wont bitch */
+ sp = outline;
+ while (*sp)
+ if (*sp++ == '%') {
+ /* advance to the end */
+ ep = --sp;
+ while (*ep++)
+ ;
+ /* null terminate the string one out */
+ *(ep + 1) = 0;
+ /* copy backwards */
+ while(ep-- > sp)
+ *(ep + 1) = *ep;
+
+ /* and advance sp past the new % */
+ sp += 2;
+ }
+
+ /* write out the debug line */
+ mlforce(outline);
+ update(TRUE);
+
+ /* and get the keystroke to hold the output */
+ if (get1key() == abortc) {
+ mlforce("(Macro aborted)");
+ status = FALSE;
+ }
+ }
+#endif
+
+ /* and return it */
+ return(status);
+}
+
+findvar(var, vd, size) /* find a variables type and name */
+
+char *var; /* name of var to get */
+VDESC *vd; /* structure to hold type and ptr */
+int size; /* size of var array */
+
+{
+ register int vnum; /* subscript in varable arrays */
+ register int vtype; /* type to return */
+
+fvar: vtype = -1;
+ switch (var[0]) {
+
+ case '$': /* check for legal enviromnent var */
+ for (vnum = 0; vnum < NEVARS; vnum++)
+ if (strcmp(&var[1], envars[vnum]) == 0) {
+ vtype = TKENV;
+ break;
+ }
+ break;
+
+ case '%': /* check for existing legal user variable */
+ for (vnum = 0; vnum < MAXVARS; vnum++)
+ if (strcmp(&var[1], uv[vnum].u_name) == 0) {
+ vtype = TKVAR;
+ break;
+ }
+ if (vnum < MAXVARS)
+ break;
+
+ /* create a new one??? */
+ for (vnum = 0; vnum < MAXVARS; vnum++)
+ if (uv[vnum].u_name[0] == 0) {
+ vtype = TKVAR;
+ strcpy(uv[vnum].u_name, &var[1]);
+ break;
+ }
+ break;
+
+ case '&': /* indirect operator? */
+ var[4] = 0;
+ if (strcmp(&var[1], "ind") == 0) {
+ /* grab token, and eval it */
+ execstr = token(execstr, var, size);
+ strcpy(var, getval(var));
+ goto fvar;
+ }
+ }
+
+ /* return the results */
+ vd->v_num = vnum;
+ vd->v_type = vtype;
+ return;
+}
+
+int svar(var, value) /* set a variable */
+
+VDESC *var; /* variable to set */
+char *value; /* value to set to */
+
+{
+ register int vnum; /* ordinal number of var refrenced */
+ register int vtype; /* type of variable to set */
+ register int status; /* status return */
+ register int c; /* translated character */
+ register char * sp; /* scratch string pointer */
+
+ /* simplify the vd structure (we are gonna look at it a lot) */
+ vnum = var->v_num;
+ vtype = var->v_type;
+
+ /* and set the appropriate value */
+ status = TRUE;
+ switch (vtype) {
+ case TKVAR: /* set a user variable */
+ if (uv[vnum].u_value != NULL)
+ free(uv[vnum].u_value);
+ sp = malloc(strlen(value) + 1);
+ if (sp == NULL)
+ return(FALSE);
+ strcpy(sp, value);
+ uv[vnum].u_value = sp;
+ break;
+
+ case TKENV: /* set an environment variable */
+ status = TRUE; /* by default */
+ switch (vnum) {
+ case EVFILLCOL: fillcol = atoi(value);
+ break;
+ case EVPAGELEN: status = newsize(TRUE, atoi(value));
+ break;
+ case EVCURCOL: status = setccol(atoi(value));
+ break;
+ case EVCURLINE: status = gotoline(TRUE, atoi(value));
+ break;
+ case EVRAM: break;
+ case EVFLICKER: flickcode = stol(value);
+ break;
+ case EVCURWIDTH:status = newwidth(TRUE, atoi(value));
+ break;
+ case EVCBUFNAME:strcpy(curbp->b_bname, value);
+ curwp->w_flag |= WFMODE;
+ break;
+ case EVCFNAME: strcpy(curbp->b_fname, value);
+ curwp->w_flag |= WFMODE;
+ break;
+ case EVSRES: status = TTrez(value);
+ break;
+ case EVDEBUG: macbug = stol(value);
+ break;
+ case EVSTATUS: cmdstatus = stol(value);
+ break;
+ case EVPALETTE: strncpy(palstr, value, 48);
+ spal(palstr);
+ break;
+ case EVASAVE: gasave = atoi(value);
+ break;
+ case EVACOUNT: gacount = atoi(value);
+ break;
+ case EVLASTKEY: lastkey = atoi(value);
+ break;
+ case EVCURCHAR: ldelete(1L, FALSE); /* delete 1 char */
+ c = atoi(value);
+ if (c == '\n')
+ lnewline(FALSE, 1);
+ else
+ linsert(1, c);
+ backchar(FALSE, 1);
+ break;
+ case EVDISCMD: discmd = stol(value);
+ break;
+ case EVVERSION: break;
+ case EVPROGNAME:break;
+ case EVSEED: seed = atoi(value);
+ break;
+ case EVDISINP: disinp = stol(value);
+ break;
+ case EVWLINE: status = resize(TRUE, atoi(value));
+ break;
+ case EVCWLINE: status = forwline(TRUE,
+ atoi(value) - getwpos());
+ break;
+ case EVTARGET: curgoal = atoi(value);
+ thisflag = saveflag;
+ break;
+ case EVSEARCH: strcpy(pat, value);
+ rvstrcpy(tap, pat);
+#if MAGIC
+ mcclear();
+#endif
+ break;
+ case EVREPLACE: strcpy(rpat, value);
+ break;
+ case EVMATCH: break;
+ case EVKILL: break;
+ case EVCMODE: curbp->b_mode = atoi(value);
+ curwp->w_flag |= WFMODE;
+ break;
+ case EVGMODE: gmode = atoi(value);
+ break;
+ case EVTPAUSE: term.t_pause = atoi(value);
+ break;
+ case EVPENDING: break;
+ case EVLWIDTH: break;
+ case EVLINE: putctext(value);
+ case EVGFLAGS: gflags = atoi(value);
+ break;
+ case EVRVAL: break;
+ case EVTAB: tabmask = atoi(value)-1;
+ if (tabmask != 0x07 && tabmask != 0x03)
+ tabmask = 0x07;
+ curwp->w_flag |= WFHARD;
+ break;
+ case EVOVERLAP: overlap = atoi(value);
+ break;
+ case EVSCROLLCOUNT:
+ scrollcount = atoi(value);
+ break;
+ case EVSCROLL:
+#if SCROLLCODE
+ if (! stol(value))
+ term.t_scroll = NULL;
+#endif
+ break;
+ }
+ break;
+ }
+ return(status);
+}
+
+/* atoi: ascii string to integer......This is too
+ inconsistant to use the system's */
+
+atoi(st)
+
+char *st;
+
+{
+ int result; /* resulting number */
+ int sign; /* sign of resulting number */
+ char c; /* current char being examined */
+
+ result = 0;
+ sign = 1;
+
+ /* skip preceding whitespace */
+ while (*st == ' ' || *st == '\t')
+ ++st;
+
+ /* check for sign */
+ if (*st == '-') {
+ sign = -1;
+ ++st;
+ }
+ if (*st == '+')
+ ++st;
+
+ /* scan digits, build value */
+ while ((c = *st++))
+ if (c >= '0' && c <= '9')
+ result = result * 10 + c - '0';
+ else
+ return(0);
+
+ return(result * sign);
+}
+
+/* itoa: integer to ascii string.......... This is too
+ inconsistant to use the system's */
+
+char *itoa(i)
+
+int i; /* integer to translate to a string */
+
+{
+ register int digit; /* current digit being used */
+ register char *sp; /* pointer into result */
+ register int sign; /* sign of resulting number */
+ static char result[INTWIDTH+1]; /* resulting string */
+
+ /* record the sign...*/
+ sign = 1;
+ if (i < 0) {
+ sign = -1;
+ i = -i;
+ }
+
+ /* and build the string (backwards!) */
+ sp = result + INTWIDTH;
+ *sp = 0;
+ do {
+ digit = i % 10;
+ *(--sp) = '0' + digit; /* and install the new digit */
+ i = i / 10;
+ } while (i);
+
+ /* and fix the sign */
+ if (sign == -1) {
+ *(--sp) = '-'; /* and install the minus sign */
+ }
+
+ return(sp);
+}
+
+int gettyp(token) /* find the type of a passed token */
+
+char *token; /* token to analyze */
+
+{
+ register char c; /* first char in token */
+
+ /* grab the first char (this is all we need) */
+ c = *token;
+
+ /* no blanks!!! */
+ if (c == 0)
+ return(TKNUL);
+
+ /* a numeric literal? */
+ if (c >= '0' && c <= '9')
+ return(TKLIT);
+
+ switch (c) {
+ case '"': return(TKSTR);
+
+ case '!': return(TKDIR);
+ case '@': return(TKARG);
+ case '#': return(TKBUF);
+ case '$': return(TKENV);
+ case '%': return(TKVAR);
+ case '&': return(TKFUN);
+ case '*': return(TKLBL);
+
+ default: return(TKCMD);
+ }
+}
+
+char *getval(token) /* find the value of a token */
+
+char *token; /* token to evaluate */
+
+{
+ register int status; /* error return */
+ register BUFFER *bp; /* temp buffer pointer */
+ register int blen; /* length of buffer argument */
+ register int distmp; /* temporary discmd flag */
+ static char buf[NSTRING];/* string buffer for some returns */
+
+ switch (gettyp(token)) {
+ case TKNUL: return("");
+
+ case TKARG: /* interactive argument */
+ strcpy(token, getval(&token[1]));
+ distmp = discmd; /* echo it always! */
+ discmd = TRUE;
+ status = getstring(token,
+ buf, NSTRING, ctoec('\n'));
+ discmd = distmp;
+ if (status == ABORT)
+ return(errorm);
+ return(buf);
+
+ case TKBUF: /* buffer contents fetch */
+
+ /* grab the right buffer */
+ strcpy(token, getval(&token[1]));
+ bp = bfind(token, FALSE, 0);
+ if (bp == NULL)
+ return(errorm);
+
+ /* if the buffer is displayed, get the window
+ vars instead of the buffer vars */
+ if (bp->b_nwnd > 0) {
+ curbp->b_dotp = curwp->w_dotp;
+ curbp->b_doto = curwp->w_doto;
+ }
+
+ /* make sure we are not at the end */
+ if (bp->b_linep == bp->b_dotp)
+ return(errorm);
+
+ /* grab the line as an argument */
+ blen = bp->b_dotp->l_used - bp->b_doto;
+ if (blen > NSTRING)
+ blen = NSTRING;
+ strncpy(buf, bp->b_dotp->l_text + bp->b_doto,
+ blen);
+ buf[blen] = 0;
+
+ /* and step the buffer's line ptr ahead a line */
+ bp->b_dotp = bp->b_dotp->l_fp;
+ bp->b_doto = 0;
+
+ /* if displayed buffer, reset window ptr vars*/
+ if (bp->b_nwnd > 0) {
+ curwp->w_dotp = curbp->b_dotp;
+ curwp->w_doto = 0;
+ curwp->w_flag |= WFMOVE;
+ }
+
+ /* and return the spoils */
+ return(buf);
+
+ case TKVAR: return(gtusr(token+1));
+ case TKENV: return(gtenv(token+1));
+ case TKFUN: return(gtfun(token+1));
+ case TKDIR: return(errorm);
+ case TKLBL: return(errorm);
+ case TKLIT: return(token);
+ case TKSTR: return(token+1);
+ case TKCMD: return(token);
+ }
+}
+
+int stol(val) /* convert a string to a numeric logical */
+
+char *val; /* value to check for stol */
+
+{
+ /* check for logical values */
+ if (val[0] == 'F')
+ return(FALSE);
+ if (val[0] == 'T')
+ return(TRUE);
+
+ /* check for numeric truth (!= 0) */
+ return((atoi(val) != 0));
+}
+
+char *ltos(val) /* numeric logical to string logical */
+
+int val; /* value to translate */
+
+{
+ if (val)
+ return(truem);
+ else
+ return(falsem);
+}
+
+char *mkupper(str) /* make a string upper case */
+
+char *str; /* string to upper case */
+
+{
+ char *sp;
+
+ sp = str;
+ while (*sp) {
+ if ('a' <= *sp && *sp <= 'z')
+ *sp += 'A' - 'a';
+ ++sp;
+ }
+ return(str);
+}
+
+char *mklower(str) /* make a string lower case */
+
+char *str; /* string to lower case */
+
+{
+ char *sp;
+
+ sp = str;
+ while (*sp) {
+ if ('A' <= *sp && *sp <= 'Z')
+ *sp += 'a' - 'A';
+ ++sp;
+ }
+ return(str);
+}
+
+int abs(x) /* take the absolute value of an integer */
+
+int x;
+
+{
+ return(x < 0 ? -x : x);
+}
+
+int ernd() /* returns a random integer */
+
+{
+ seed = abs(seed * 1721 + 10007);
+ return(seed);
+}
+
+int sindex(source, pattern) /* find pattern within source */
+
+char *source; /* source string to search */
+char *pattern; /* string to look for */
+
+{
+ char *sp; /* ptr to current position to scan */
+ char *csp; /* ptr to source string during comparison */
+ char *cp; /* ptr to place to check for equality */
+
+ /* scanning through the source string */
+ sp = source;
+ while (*sp) {
+ /* scan through the pattern */
+ cp = pattern;
+ csp = sp;
+ while (*cp) {
+ if (!eq(*cp, *csp))
+ break;
+ ++cp;
+ ++csp;
+ }
+
+ /* was it a match? */
+ if (*cp == 0)
+ return((int)(sp - source) + 1);
+ ++sp;
+ }
+
+ /* no match at all.. */
+ return(0);
+}
+
+/* Filter a string through a translation table */
+
+char *xlat(source, lookup, trans)
+
+char *source; /* string to filter */
+char *lookup; /* characters to translate */
+char *trans; /* resulting translated characters */
+
+{
+ register char *sp; /* pointer into source table */
+ register char *lp; /* pointer into lookup table */
+ register char *rp; /* pointer into result */
+ static char result[NSTRING]; /* temporary result */
+
+ /* scan source string */
+ sp = source;
+ rp = result;
+ while (*sp) {
+ /* scan lookup table for a match */
+ lp = lookup;
+ while (*lp) {
+ if (*sp == *lp) {
+ *rp++ = trans[lp - lookup];
+ goto xnext;
+ }
+ ++lp;
+ }
+
+ /* no match, copy in the source char untranslated */
+ *rp++ = *sp;
+
+xnext: ++sp;
+ }
+
+ /* terminate and return the result */
+ *rp = 0;
+ return(result);
+}
diff --git a/evar.h b/evar.h
new file mode 100644
index 0000000..d4c0919
--- /dev/null
+++ b/evar.h
@@ -0,0 +1,212 @@
+/* EVAR.H
+ *
+ * Environment and user variable definitions
+ *
+ * written 1986 by Daniel Lawrence
+ * modified by Petri Kutvonen
+ */
+
+/* structure to hold user variables and their definitions */
+
+typedef struct UVAR {
+ char u_name[NVSIZE + 1]; /* name of user variable */
+ char *u_value; /* value (string) */
+} UVAR;
+
+/* current user variables (This structure will probably change) */
+
+#define MAXVARS 255
+
+UVAR uv[MAXVARS + 1]; /* user variables */
+
+/* list of recognized environment variables */
+
+char *envars[] = {
+ "fillcol", /* current fill column */
+ "pagelen", /* number of lines used by editor */
+ "curcol", /* current column pos of cursor */
+ "curline", /* current line in file */
+ "ram", /* ram in use by malloc */
+ "flicker", /* flicker supression */
+ "curwidth", /* current screen width */
+ "cbufname", /* current buffer name */
+ "cfname", /* current file name */
+ "sres", /* current screen resolution */
+ "debug", /* macro debugging */
+ "status", /* returns the status of the last command */
+ "palette", /* current palette string */
+ "asave", /* # of chars between auto-saves */
+ "acount", /* # of chars until next auto-save */
+ "lastkey", /* last keyboard char struck */
+ "curchar", /* current character under the cursor */
+ "discmd", /* display commands on command line */
+ "version", /* current version number */
+ "progname", /* returns current prog name - "MicroEMACS" */
+ "seed", /* current random number seed */
+ "disinp", /* display command line input characters */
+ "wline", /* # of lines in current window */
+ "cwline", /* current screen line in window */
+ "target", /* target for line moves */
+ "search", /* search pattern */
+ "replace", /* replacement pattern */
+ "match", /* last matched magic pattern */
+ "kill", /* kill buffer (read only) */
+ "cmode", /* mode of current buffer */
+ "gmode", /* global modes */
+ "tpause", /* length to pause for paren matching */
+ "pending", /* type ahead pending flag */
+ "lwidth", /* width of current line */
+ "line", /* text of current line */
+ "gflags", /* global internal emacs flags */
+ "rval", /* child process return value */
+ "tab", /* tab 4 or 8 */
+ "overlap",
+ "jump",
+#if SCROLLCODE
+ "scroll", /* scroll enabled */
+#endif
+};
+
+#define NEVARS sizeof(envars) / sizeof(char *)
+
+/* and its preprocesor definitions */
+
+#define EVFILLCOL 0
+#define EVPAGELEN 1
+#define EVCURCOL 2
+#define EVCURLINE 3
+#define EVRAM 4
+#define EVFLICKER 5
+#define EVCURWIDTH 6
+#define EVCBUFNAME 7
+#define EVCFNAME 8
+#define EVSRES 9
+#define EVDEBUG 10
+#define EVSTATUS 11
+#define EVPALETTE 12
+#define EVASAVE 13
+#define EVACOUNT 14
+#define EVLASTKEY 15
+#define EVCURCHAR 16
+#define EVDISCMD 17
+#define EVVERSION 18
+#define EVPROGNAME 19
+#define EVSEED 20
+#define EVDISINP 21
+#define EVWLINE 22
+#define EVCWLINE 23
+#define EVTARGET 24
+#define EVSEARCH 25
+#define EVREPLACE 26
+#define EVMATCH 27
+#define EVKILL 28
+#define EVCMODE 29
+#define EVGMODE 30
+#define EVTPAUSE 31
+#define EVPENDING 32
+#define EVLWIDTH 33
+#define EVLINE 34
+#define EVGFLAGS 35
+#define EVRVAL 36
+#define EVTAB 37
+#define EVOVERLAP 38
+#define EVSCROLLCOUNT 39
+#define EVSCROLL 40
+
+/* list of recognized user functions */
+
+typedef struct UFUNC {
+ char *f_name; /* name of function */
+ int f_type; /* 1 = monamic, 2 = dynamic */
+} UFUNC;
+
+#define NILNAMIC 0
+#define MONAMIC 1
+#define DYNAMIC 2
+#define TRINAMIC 3
+
+UFUNC funcs[] = {
+ "add", DYNAMIC, /* add two numbers together */
+ "sub", DYNAMIC, /* subtraction */
+ "tim", DYNAMIC, /* multiplication */
+ "div", DYNAMIC, /* division */
+ "mod", DYNAMIC, /* mod */
+ "neg", MONAMIC, /* negate */
+ "cat", DYNAMIC, /* concatinate string */
+ "lef", DYNAMIC, /* left string(string, len) */
+ "rig", DYNAMIC, /* right string(string, pos) */
+ "mid", TRINAMIC, /* mid string(string, pos, len) */
+ "not", MONAMIC, /* logical not */
+ "equ", DYNAMIC, /* logical equality check */
+ "les", DYNAMIC, /* logical less than */
+ "gre", DYNAMIC, /* logical greater than */
+ "seq", DYNAMIC, /* string logical equality check */
+ "sle", DYNAMIC, /* string logical less than */
+ "sgr", DYNAMIC, /* string logical greater than */
+ "ind", MONAMIC, /* evaluate indirect value */
+ "and", DYNAMIC, /* logical and */
+ "or", DYNAMIC, /* logical or */
+ "len", MONAMIC, /* string length */
+ "upp", MONAMIC, /* uppercase string */
+ "low", MONAMIC, /* lower case string */
+ "tru", MONAMIC, /* Truth of the universe logical test */
+ "asc", MONAMIC, /* char to integer conversion */
+ "chr", MONAMIC, /* integer to char conversion */
+ "gtk", NILNAMIC, /* get 1 charater */
+ "rnd", MONAMIC, /* get a random number */
+ "abs", MONAMIC, /* absolute value of a number */
+ "sin", DYNAMIC, /* find the index of one string in another */
+ "env", MONAMIC, /* retrieve a system environment var */
+ "bin", MONAMIC, /* loopup what function name is bound to a key */
+ "exi", MONAMIC, /* check if a file exists */
+ "fin", MONAMIC, /* look for a file on the path... */
+ "ban", DYNAMIC, /* bitwise and 9-10-87 jwm */
+ "bor", DYNAMIC, /* bitwise or 9-10-87 jwm */
+ "bxo", DYNAMIC, /* bitwise xor 9-10-87 jwm */
+ "bno", MONAMIC, /* bitwise not */
+ "xla", TRINAMIC, /* XLATE character string translation */
+};
+
+#define NFUNCS sizeof(funcs) / sizeof(UFUNC)
+
+/* and its preprocesor definitions */
+
+#define UFADD 0
+#define UFSUB 1
+#define UFTIMES 2
+#define UFDIV 3
+#define UFMOD 4
+#define UFNEG 5
+#define UFCAT 6
+#define UFLEFT 7
+#define UFRIGHT 8
+#define UFMID 9
+#define UFNOT 10
+#define UFEQUAL 11
+#define UFLESS 12
+#define UFGREATER 13
+#define UFSEQUAL 14
+#define UFSLESS 15
+#define UFSGREAT 16
+#define UFIND 17
+#define UFAND 18
+#define UFOR 19
+#define UFLENGTH 20
+#define UFUPPER 21
+#define UFLOWER 22
+#define UFTRUTH 23
+#define UFASCII 24
+#define UFCHR 25
+#define UFGTKEY 26
+#define UFRND 27
+#define UFABS 28
+#define UFSINDEX 29
+#define UFENV 30
+#define UFBIND 31
+#define UFEXIST 32
+#define UFFIND 33
+#define UFBAND 34
+#define UFBOR 35
+#define UFBXOR 36
+#define UFBNOT 37
+#define UFXLATE 38
diff --git a/exec.c b/exec.c
new file mode 100644
index 0000000..4003462
--- /dev/null
+++ b/exec.c
@@ -0,0 +1,1148 @@
+/* EXEC.C
+ *
+ * This file is for functions dealing with execution of
+ * commands, command lines, buffers, files and startup files
+ *
+ * written 1986 by Daniel Lawrence
+ * modified by Petri Kutvonen
+ */
+
+#include <stdio.h>
+#include "estruct.h"
+#include "edef.h"
+
+/* namedcmd: execute a named command even if it is not bound */
+
+namedcmd(f, n)
+
+int f, n; /* command arguments [passed through to command executed] */
+
+{
+ register int (*kfunc)(); /* ptr to the requexted function to bind to */
+ int (*getname())();
+
+ /* prompt the user to type a named command */
+ mlwrite(": ");
+
+ /* and now get the function name to execute */
+ kfunc = getname();
+ if (kfunc == NULL) {
+ mlwrite("(No such function)");
+ return(FALSE);
+ }
+
+ /* and then execute the command */
+ return((*kfunc)(f, n));
+}
+
+/* execcmd: Execute a command line command to be typed in
+ by the user */
+
+execcmd(f, n)
+
+int f, n; /* default Flag and Numeric argument */
+
+{
+ register int status; /* status return */
+ char cmdstr[NSTRING]; /* string holding command to execute */
+
+ /* get the line wanted */
+ if ((status = mlreply(": ", cmdstr, NSTRING)) != TRUE)
+ return(status);
+
+ execlevel = 0;
+ return(docmd(cmdstr));
+}
+
+/* docmd: take a passed string as a command line and translate
+ it to be executed as a command. This function will be
+ used by execute-command-line and by all source and
+ startup files. Lastflag/thisflag is also updated.
+
+ format of the command line is:
+
+ {# arg} <command-name> {<argument string(s)>}
+
+*/
+
+docmd(cline)
+
+char *cline; /* command line to execute */
+
+{
+ register int f; /* default argument flag */
+ register int n; /* numeric repeat value */
+ int (*fnc)(); /* function to execute */
+ int status; /* return status of function */
+ int oldcle; /* old contents of clexec flag */
+ char *oldestr; /* original exec string */
+ char tkn[NSTRING]; /* next token off of command line */
+ int (*fncmatch())();
+
+ /* if we are scanning and not executing..go back here */
+ if (execlevel)
+ return(TRUE);
+
+ oldestr = execstr; /* save last ptr to string to execute */
+ execstr = cline; /* and set this one as current */
+
+ /* first set up the default command values */
+ f = FALSE;
+ n = 1;
+ lastflag = thisflag;
+ thisflag = 0;
+
+ if ((status = macarg(tkn)) != TRUE) { /* and grab the first token */
+ execstr = oldestr;
+ return(status);
+ }
+
+ /* process leadin argument */
+ if (gettyp(tkn) != TKCMD) {
+ f = TRUE;
+ strcpy(tkn, getval(tkn));
+ n = atoi(tkn);
+
+ /* and now get the command to execute */
+ if ((status = macarg(tkn)) != TRUE) {
+ execstr = oldestr;
+ return(status);
+ }
+ }
+
+ /* and match the token to see if it exists */
+ if ((fnc = fncmatch(tkn)) == NULL) {
+ mlwrite("(No such Function)");
+ execstr = oldestr;
+ return(FALSE);
+ }
+
+ /* save the arguments and go execute the command */
+ oldcle = clexec; /* save old clexec flag */
+ clexec = TRUE; /* in cline execution */
+ status = (*fnc)(f, n); /* call the function */
+ cmdstatus = status; /* save the status */
+ clexec = oldcle; /* restore clexec flag */
+ execstr = oldestr;
+ return(status);
+}
+
+/* token: chop a token off a string
+ return a pointer past the token
+*/
+
+char *token(src, tok, size)
+
+char *src, *tok; /* source string, destination token string */
+int size; /* maximum size of token */
+
+{
+ register int quotef; /* is the current string quoted? */
+ register char c; /* temporary character */
+
+ /* first scan past any whitespace in the source string */
+ while (*src == ' ' || *src == '\t')
+ ++src;
+
+ /* scan through the source string */
+ quotef = FALSE;
+ while (*src) {
+ /* process special characters */
+ if (*src == '~') {
+ ++src;
+ if (*src == 0)
+ break;
+ switch (*src++) {
+ case 'r': c = 13; break;
+ case 'n': c = 10; break;
+ case 't': c = 9; break;
+ case 'b': c = 8; break;
+ case 'f': c = 12; break;
+ default: c = *(src-1);
+ }
+ if (--size > 0) {
+ *tok++ = c;
+ }
+ } else {
+ /* check for the end of the token */
+ if (quotef) {
+ if (*src == '"')
+ break;
+ } else {
+ if (*src == ' ' || *src == '\t')
+ break;
+ }
+
+ /* set quote mode if quote found */
+ if (*src == '"')
+ quotef = TRUE;
+
+ /* record the character */
+ c = *src++;
+ if (--size > 0)
+ *tok++ = c;
+ }
+ }
+
+ /* terminate the token and exit */
+ if (*src)
+ ++src;
+ *tok = 0;
+ return(src);
+}
+
+macarg(tok) /* get a macro line argument */
+
+char *tok; /* buffer to place argument */
+
+{
+ int savcle; /* buffer to store original clexec */
+ int status;
+
+ savcle = clexec; /* save execution mode */
+ clexec = TRUE; /* get the argument */
+ status = nextarg("", tok, NSTRING, ctoec('\n'));
+ clexec = savcle; /* restore execution mode */
+ return(status);
+}
+
+/* nextarg: get the next argument */
+
+nextarg(prompt, buffer, size, terminator)
+
+char *prompt; /* prompt to use if we must be interactive */
+char *buffer; /* buffer to put token into */
+int size; /* size of the buffer */
+int terminator; /* terminating char to be used on interactive fetch */
+
+{
+ /* if we are interactive, go get it! */
+ if (clexec == FALSE)
+ return(getstring(prompt, buffer, size, terminator));
+
+ /* grab token and advance past */
+ execstr = token(execstr, buffer, size);
+
+ /* evaluate it */
+ strcpy(buffer, getval(buffer));
+ return(TRUE);
+}
+
+/* storemac: Set up a macro buffer and flag to store all
+ executed command lines there */
+
+storemac(f, n)
+
+int f; /* default flag */
+int n; /* macro number to use */
+
+{
+ register struct BUFFER *bp; /* pointer to macro buffer */
+ char bname[NBUFN]; /* name of buffer to use */
+
+ /* must have a numeric argument to this function */
+ if (f == FALSE) {
+ mlwrite("No macro specified");
+ return(FALSE);
+ }
+
+ /* range check the macro number */
+ if (n < 1 || n > 40) {
+ mlwrite("Macro number out of range");
+ return(FALSE);
+ }
+
+ /* construct the macro buffer name */
+ strcpy(bname, "*Macro xx*");
+ bname[7] = '0' + (n / 10);
+ bname[8] = '0' + (n % 10);
+
+ /* set up the new macro buffer */
+ if ((bp = bfind(bname, TRUE, BFINVS)) == NULL) {
+ mlwrite("Can not create macro");
+ return(FALSE);
+ }
+
+ /* and make sure it is empty */
+ bclear(bp);
+
+ /* and set the macro store pointers to it */
+ mstore = TRUE;
+ bstore = bp;
+ return(TRUE);
+}
+
+#if PROC
+/* storeproc: Set up a procedure buffer and flag to store all
+ executed command lines there */
+
+storeproc(f, n)
+
+int f; /* default flag */
+int n; /* macro number to use */
+
+{
+ register struct BUFFER *bp; /* pointer to macro buffer */
+ register int status; /* return status */
+ char bname[NBUFN]; /* name of buffer to use */
+
+ /* a numeric argument means its a numbered macro */
+ if (f == TRUE)
+ return(storemac(f, n));
+
+ /* get the name of the procedure */
+ if ((status = mlreply("Procedure name: ", &bname[1], NBUFN-2)) != TRUE)
+ return(status);
+
+ /* construct the macro buffer name */
+ bname[0] = '*';
+ strcat(bname, "*");
+
+ /* set up the new macro buffer */
+ if ((bp = bfind(bname, TRUE, BFINVS)) == NULL) {
+ mlwrite("Can not create macro");
+ return(FALSE);
+ }
+
+ /* and make sure it is empty */
+ bclear(bp);
+
+ /* and set the macro store pointers to it */
+ mstore = TRUE;
+ bstore = bp;
+ return(TRUE);
+}
+
+/* execproc: Execute a procedure */
+
+execproc(f, n)
+
+int f, n; /* default flag and numeric arg */
+
+{
+ register BUFFER *bp; /* ptr to buffer to execute */
+ register int status; /* status return */
+ char bufn[NBUFN+2]; /* name of buffer to execute */
+
+ /* find out what buffer the user wants to execute */
+ if ((status = mlreply("Execute procedure: ", &bufn[1], NBUFN)) != TRUE)
+ return(status);
+
+ /* construct the buffer name */
+ bufn[0] = '*';
+ strcat(bufn, "*");
+
+ /* find the pointer to that buffer */
+ if ((bp=bfind(bufn, FALSE, 0)) == NULL) {
+ mlwrite("No such procedure");
+ return(FALSE);
+ }
+
+ /* and now execute it as asked */
+ while (n-- > 0)
+ if ((status = dobuf(bp)) != TRUE)
+ return(status);
+ return(TRUE);
+}
+#endif
+
+/* execbuf: Execute the contents of a buffer of commands */
+
+execbuf(f, n)
+
+int f, n; /* default flag and numeric arg */
+
+{
+ register BUFFER *bp; /* ptr to buffer to execute */
+ register int status; /* status return */
+ char bufn[NSTRING]; /* name of buffer to execute */
+
+ /* find out what buffer the user wants to execute */
+ if ((status = mlreply("Execute buffer: ", bufn, NBUFN)) != TRUE)
+ return(status);
+
+ /* find the pointer to that buffer */
+ if ((bp=bfind(bufn, FALSE, 0)) == NULL) {
+ mlwrite("No such buffer");
+ return(FALSE);
+ }
+
+ /* and now execute it as asked */
+ while (n-- > 0)
+ if ((status = dobuf(bp)) != TRUE)
+ return(status);
+ return(TRUE);
+}
+
+/* dobuf: execute the contents of the buffer pointed to
+ by the passed BP
+
+ Directives start with a "!" and include:
+
+ !endm End a macro
+ !if (cond) conditional execution
+ !else
+ !endif
+ !return Return (terminating current macro)
+ !goto <label> Jump to a label in the current macro
+ !force Force macro to continue...even if command fails
+ !while (cond) Execute a loop if the condition is true
+ !endwhile
+
+ Line Labels begin with a "*" as the first nonblank char, like:
+
+ *LBL01
+*/
+
+dobuf(bp)
+
+BUFFER *bp; /* buffer to execute */
+
+{
+ register int status; /* status return */
+ register LINE *lp; /* pointer to line to execute */
+ register LINE *hlp; /* pointer to line header */
+ register LINE *glp; /* line to goto */
+ LINE *mp; /* Macro line storage temp */
+ int dirnum; /* directive index */
+ int linlen; /* length of line to execute */
+ int i; /* index */
+ int c; /* temp character */
+ int force; /* force TRUE result? */
+ WINDOW *wp; /* ptr to windows to scan */
+ WHBLOCK *whlist; /* ptr to !WHILE list */
+ WHBLOCK *scanner; /* ptr during scan */
+ WHBLOCK *whtemp; /* temporary ptr to a WHBLOCK */
+ char *einit; /* initial value of eline */
+ char *eline; /* text of line to execute */
+ char tkn[NSTRING]; /* buffer to evaluate an expresion in */
+
+#if DEBUGM
+ char *sp; /* temp for building debug string */
+ register char *ep; /* ptr to end of outline */
+#endif
+
+ /* clear IF level flags/while ptr */
+ execlevel = 0;
+ whlist = NULL;
+ scanner = NULL;
+
+ /* scan the buffer to execute, building WHILE header blocks */
+ hlp = bp->b_linep;
+ lp = hlp->l_fp;
+ while (lp != hlp) {
+ /* scan the current line */
+ eline = lp->l_text;
+ i = lp->l_used;
+
+ /* trim leading whitespace */
+ while (i-- > 0 && (*eline == ' ' || *eline == '\t'))
+ ++eline;
+
+ /* if theres nothing here, don't bother */
+ if (i <= 0)
+ goto nxtscan;
+
+ /* if is a while directive, make a block... */
+ if (eline[0] == '!' && eline[1] == 'w' && eline[2] == 'h') {
+ whtemp = (WHBLOCK *)malloc(sizeof(WHBLOCK));
+ if (whtemp == NULL) {
+noram: mlwrite("%%Out of memory during while scan");
+failexit: freewhile(scanner);
+ freewhile(whlist);
+ return(FALSE);
+ }
+ whtemp->w_begin = lp;
+ whtemp->w_type = BTWHILE;
+ whtemp->w_next = scanner;
+ scanner = whtemp;
+ }
+
+ /* if is a BREAK directive, make a block... */
+ if (eline[0] == '!' && eline[1] == 'b' && eline[2] == 'r') {
+ if (scanner == NULL) {
+ mlwrite("%%!BREAK outside of any !WHILE loop");
+ goto failexit;
+ }
+ whtemp = (WHBLOCK *)malloc(sizeof(WHBLOCK));
+ if (whtemp == NULL)
+ goto noram;
+ whtemp->w_begin = lp;
+ whtemp->w_type = BTBREAK;
+ whtemp->w_next = scanner;
+ scanner = whtemp;
+ }
+
+ /* if it is an endwhile directive, record the spot... */
+ if (eline[0] == '!' && strncmp(&eline[1], "endw", 4) == 0) {
+ if (scanner == NULL) {
+ mlwrite("%%!ENDWHILE with no preceding !WHILE in '%s'",
+ bp->b_bname);
+ goto failexit;
+ }
+ /* move top records from the scanner list to the
+ whlist until we have moved all BREAK records
+ and one WHILE record */
+ do {
+ scanner->w_end = lp;
+ whtemp = whlist;
+ whlist = scanner;
+ scanner = scanner->w_next;
+ whlist->w_next = whtemp;
+ } while (whlist->w_type == BTBREAK);
+ }
+
+nxtscan: /* on to the next line */
+ lp = lp->l_fp;
+ }
+
+ /* while and endwhile should match! */
+ if (scanner != NULL) {
+ mlwrite("%%!WHILE with no matching !ENDWHILE in '%s'",
+ bp->b_bname);
+ goto failexit;
+ }
+
+ /* let the first command inherit the flags from the last one..*/
+ thisflag = lastflag;
+
+ /* starting at the beginning of the buffer */
+ hlp = bp->b_linep;
+ lp = hlp->l_fp;
+ while (lp != hlp) {
+ /* allocate eline and copy macro line to it */
+ linlen = lp->l_used;
+ if ((einit = eline = malloc(linlen+1)) == NULL) {
+ mlwrite("%%Out of Memory during macro execution");
+ freewhile(whlist);
+ return(FALSE);
+ }
+ strncpy(eline, lp->l_text, linlen);
+ eline[linlen] = 0; /* make sure it ends */
+
+ /* trim leading whitespace */
+ while (*eline == ' ' || *eline == '\t')
+ ++eline;
+
+ /* dump comments and blank lines */
+ if (*eline == ';' || *eline == 0)
+ goto onward;
+
+#if DEBUGM
+ /* if $debug == TRUE, every line to execute
+ gets echoed and a key needs to be pressed to continue
+ ^G will abort the command */
+
+ if (macbug) {
+ strcpy(outline, "<<<");
+
+ /* debug macro name */
+ strcat(outline, bp->b_bname);
+ strcat(outline, ":");
+
+ /* debug if levels */
+ strcat(outline, itoa(execlevel));
+ strcat(outline, ":");
+
+ /* and lastly the line */
+ strcat(outline, eline);
+ strcat(outline, ">>>");
+
+ /* change all '%' to ':' so mlwrite won't expect arguments */
+ sp = outline;
+ while (*sp)
+ if (*sp++ == '%') {
+ /* advance to the end */
+ ep = --sp;
+ while (*ep++)
+ ;
+ /* null terminate the string one out */
+ *(ep + 1) = 0;
+ /* copy backwards */
+ while(ep-- > sp)
+ *(ep + 1) = *ep;
+
+ /* and advance sp past the new % */
+ sp += 2;
+ }
+
+ /* write out the debug line */
+ mlforce(outline);
+ update(TRUE);
+
+ /* and get the keystroke */
+ if ((c = get1key()) == abortc) {
+ mlforce("(Macro aborted)");
+ freewhile(whlist);
+ return(FALSE);
+ }
+
+ if (c == metac)
+ macbug = FALSE;
+ }
+#endif
+
+ /* Parse directives here.... */
+ dirnum = -1;
+ if (*eline == '!') {
+ /* Find out which directive this is */
+ ++eline;
+ for (dirnum = 0; dirnum < NUMDIRS; dirnum++)
+ if (strncmp(eline, dname[dirnum],
+ strlen(dname[dirnum])) == 0)
+ break;
+
+ /* and bitch if it's illegal */
+ if (dirnum == NUMDIRS) {
+ mlwrite("%%Unknown Directive");
+ freewhile(whlist);
+ return(FALSE);
+ }
+
+ /* service only the !ENDM macro here */
+ if (dirnum == DENDM) {
+ mstore = FALSE;
+ bstore = NULL;
+ goto onward;
+ }
+
+ /* restore the original eline....*/
+ --eline;
+ }
+
+ /* if macro store is on, just salt this away */
+ if (mstore) {
+ /* allocate the space for the line */
+ linlen = strlen(eline);
+ if ((mp=lalloc(linlen)) == NULL) {
+ mlwrite("Out of memory while storing macro");
+ return (FALSE);
+ }
+
+ /* copy the text into the new line */
+ for (i=0; i<linlen; ++i)
+ lputc(mp, i, eline[i]);
+
+ /* attach the line to the end of the buffer */
+ bstore->b_linep->l_bp->l_fp = mp;
+ mp->l_bp = bstore->b_linep->l_bp;
+ bstore->b_linep->l_bp = mp;
+ mp->l_fp = bstore->b_linep;
+ goto onward;
+ }
+
+
+ force = FALSE;
+
+ /* dump comments */
+ if (*eline == '*')
+ goto onward;
+
+ /* now, execute directives */
+ if (dirnum != -1) {
+ /* skip past the directive */
+ while (*eline && *eline != ' ' && *eline != '\t')
+ ++eline;
+ execstr = eline;
+
+ switch (dirnum) {
+ case DIF: /* IF directive */
+ /* grab the value of the logical exp */
+ if (execlevel == 0) {
+ if (macarg(tkn) != TRUE)
+ goto eexec;
+ if (stol(tkn) == FALSE)
+ ++execlevel;
+ } else
+ ++execlevel;
+ goto onward;
+
+ case DWHILE: /* WHILE directive */
+ /* grab the value of the logical exp */
+ if (execlevel == 0) {
+ if (macarg(tkn) != TRUE)
+ goto eexec;
+ if (stol(tkn) == TRUE)
+ goto onward;
+ }
+ /* drop down and act just like !BREAK */
+
+ case DBREAK: /* BREAK directive */
+ if (dirnum == DBREAK && execlevel)
+ goto onward;
+
+ /* jump down to the endwhile */
+ /* find the right while loop */
+ whtemp = whlist;
+ while (whtemp) {
+ if (whtemp->w_begin == lp)
+ break;
+ whtemp = whtemp->w_next;
+ }
+
+ if (whtemp == NULL) {
+ mlwrite("%%Internal While loop error");
+ freewhile(whlist);
+ return(FALSE);
+ }
+
+ /* reset the line pointer back.. */
+ lp = whtemp->w_end;
+ goto onward;
+
+ case DELSE: /* ELSE directive */
+ if (execlevel == 1)
+ --execlevel;
+ else if (execlevel == 0 )
+ ++execlevel;
+ goto onward;
+
+ case DENDIF: /* ENDIF directive */
+ if (execlevel)
+ --execlevel;
+ goto onward;
+
+ case DGOTO: /* GOTO directive */
+ /* .....only if we are currently executing */
+ if (execlevel == 0) {
+
+ /* grab label to jump to */
+ eline = token(eline, golabel, NPAT);
+ linlen = strlen(golabel);
+ glp = hlp->l_fp;
+ while (glp != hlp) {
+ if (*glp->l_text == '*' &&
+ (strncmp(&glp->l_text[1], golabel,
+ linlen) == 0)) {
+ lp = glp;
+ goto onward;
+ }
+ glp = glp->l_fp;
+ }
+ mlwrite("%%No such label");
+ freewhile(whlist);
+ return(FALSE);
+ }
+ goto onward;
+
+ case DRETURN: /* RETURN directive */
+ if (execlevel == 0)
+ goto eexec;
+ goto onward;
+
+ case DENDWHILE: /* ENDWHILE directive */
+ if (execlevel) {
+ --execlevel;
+ goto onward;
+ } else {
+ /* find the right while loop */
+ whtemp = whlist;
+ while (whtemp) {
+ if (whtemp->w_type == BTWHILE &&
+ whtemp->w_end == lp)
+ break;
+ whtemp = whtemp->w_next;
+ }
+
+ if (whtemp == NULL) {
+ mlwrite("%%Internal While loop error");
+ freewhile(whlist);
+ return(FALSE);
+ }
+
+ /* reset the line pointer back.. */
+ lp = whtemp->w_begin->l_bp;
+ goto onward;
+ }
+
+ case DFORCE: /* FORCE directive */
+ force = TRUE;
+
+ }
+ }
+
+ /* execute the statement */
+ status = docmd(eline);
+ if (force) /* force the status */
+ status = TRUE;
+
+ /* check for a command error */
+ if (status != TRUE) {
+ /* look if buffer is showing */
+ wp = wheadp;
+ while (wp != NULL) {
+ if (wp->w_bufp == bp) {
+ /* and point it */
+ wp->w_dotp = lp;
+ wp->w_doto = 0;
+ wp->w_flag |= WFHARD;
+ }
+ wp = wp->w_wndp;
+ }
+ /* in any case set the buffer . */
+ bp->b_dotp = lp;
+ bp->b_doto = 0;
+ free(einit);
+ execlevel = 0;
+ freewhile(whlist);
+ return(status);
+ }
+
+onward: /* on to the next line */
+ free(einit);
+ lp = lp->l_fp;
+ }
+
+eexec: /* exit the current function */
+ execlevel = 0;
+ freewhile(whlist);
+ return(TRUE);
+}
+
+freewhile(wp) /* free a list of while block pointers */
+
+WHBLOCK *wp; /* head of structure to free */
+
+{
+ if (wp == NULL)
+ return;
+ if (wp->w_next)
+ freewhile(wp->w_next);
+ free(wp);
+}
+
+execfile(f, n) /* execute a series of commands in a file */
+
+int f, n; /* default flag and numeric arg to pass on to file */
+
+{
+ register int status; /* return status of name query */
+ char fname[NSTRING]; /* name of file to execute */
+ char *fspec; /* full file spec */
+
+ if ((status = mlreply("File to execute: ", fname, NSTRING -1)) != TRUE)
+ return(status);
+
+#if 1
+ /* look up the path for the file */
+ fspec = flook(fname, FALSE); /* used to by TRUE, P.K. */
+
+ /* if it isn't around */
+ if (fspec == NULL)
+ return(FALSE);
+
+#endif
+ /* otherwise, execute it */
+ while (n-- > 0)
+ if ((status=dofile(fspec)) != TRUE)
+ return(status);
+
+ return(TRUE);
+}
+
+/* dofile: yank a file into a buffer and execute it
+ if there are no errors, delete the buffer on exit */
+
+dofile(fname)
+
+char *fname; /* file name to execute */
+
+{
+ register BUFFER *bp; /* buffer to place file to exeute */
+ register BUFFER *cb; /* temp to hold current buf while we read */
+ register int status; /* results of various calls */
+ char bname[NBUFN]; /* name of buffer */
+
+ makename(bname, fname); /* derive the name of the buffer */
+ unqname(bname); /* make sure we don't stomp things */
+ if ((bp = bfind(bname, TRUE, 0)) == NULL) /* get the needed buffer */
+ return(FALSE);
+
+ bp->b_mode = MDVIEW; /* mark the buffer as read only */
+ cb = curbp; /* save the old buffer */
+ curbp = bp; /* make this one current */
+ /* and try to read in the file to execute */
+ if ((status = readin(fname, FALSE)) != TRUE) {
+ curbp = cb; /* restore the current buffer */
+ return(status);
+ }
+
+ /* go execute it! */
+ curbp = cb; /* restore the current buffer */
+ if ((status = dobuf(bp)) != TRUE)
+ return(status);
+
+ /* if not displayed, remove the now unneeded buffer and exit */
+ if (bp->b_nwnd == 0)
+ zotbuf(bp);
+ return(TRUE);
+}
+
+/* cbuf: Execute the contents of a numbered buffer */
+
+cbuf(f, n, bufnum)
+
+int f, n; /* default flag and numeric arg */
+int bufnum; /* number of buffer to execute */
+
+{
+ register BUFFER *bp; /* ptr to buffer to execute */
+ register int status; /* status return */
+ static char bufname[] = "*Macro xx*";
+
+ /* make the buffer name */
+ bufname[7] = '0' + (bufnum / 10);
+ bufname[8] = '0' + (bufnum % 10);
+
+ /* find the pointer to that buffer */
+ if ((bp=bfind(bufname, FALSE, 0)) == NULL) {
+ mlwrite("Macro not defined");
+ return(FALSE);
+ }
+
+ /* and now execute it as asked */
+ while (n-- > 0)
+ if ((status = dobuf(bp)) != TRUE)
+ return(status);
+ return(TRUE);
+}
+
+cbuf1(f, n)
+
+{
+ return cbuf(f, n, 1);
+}
+
+cbuf2(f, n)
+
+{
+ return cbuf(f, n, 2);
+}
+
+cbuf3(f, n)
+
+{
+ return cbuf(f, n, 3);
+}
+
+cbuf4(f, n)
+
+{
+ return cbuf(f, n, 4);
+}
+
+cbuf5(f, n)
+
+{
+ return cbuf(f, n, 5);
+}
+
+cbuf6(f, n)
+
+{
+ return cbuf(f, n, 6);
+}
+
+cbuf7(f, n)
+
+{
+ return cbuf(f, n, 7);
+}
+
+cbuf8(f, n)
+
+{
+ return cbuf(f, n, 8);
+}
+
+cbuf9(f, n)
+
+{
+ return cbuf(f, n, 9);
+}
+
+cbuf10(f, n)
+
+{
+ return cbuf(f, n, 10);
+}
+
+cbuf11(f, n)
+
+{
+ return cbuf(f, n, 11);
+}
+
+cbuf12(f, n)
+
+{
+ return cbuf(f, n, 12);
+}
+
+cbuf13(f, n)
+
+{
+ return cbuf(f, n, 13);
+}
+
+cbuf14(f, n)
+
+{
+ return cbuf(f, n, 14);
+}
+
+cbuf15(f, n)
+
+{
+ return cbuf(f, n, 15);
+}
+
+cbuf16(f, n)
+
+{
+ return cbuf(f, n, 16);
+}
+
+cbuf17(f, n)
+
+{
+ return cbuf(f, n, 17);
+}
+
+cbuf18(f, n)
+
+{
+ return cbuf(f, n, 18);
+}
+
+cbuf19(f, n)
+
+{
+ return cbuf(f, n, 19);
+}
+
+cbuf20(f, n)
+
+{
+ return cbuf(f, n, 20);
+}
+
+cbuf21(f, n)
+
+{
+ return cbuf(f, n, 21);
+}
+
+cbuf22(f, n)
+
+{
+ return cbuf(f, n, 22);
+}
+
+cbuf23(f, n)
+
+{
+ return cbuf(f, n, 23);
+}
+
+cbuf24(f, n)
+
+{
+ return cbuf(f, n, 24);
+}
+
+cbuf25(f, n)
+
+{
+ return cbuf(f, n, 25);
+}
+
+cbuf26(f, n)
+
+{
+ return cbuf(f, n, 26);
+}
+
+cbuf27(f, n)
+
+{
+ return cbuf(f, n, 27);
+}
+
+cbuf28(f, n)
+
+{
+ return cbuf(f, n, 28);
+}
+
+cbuf29(f, n)
+
+{
+ return cbuf(f, n, 29);
+}
+
+cbuf30(f, n)
+
+{
+ return cbuf(f, n, 30);
+}
+
+cbuf31(f, n)
+
+{
+ return cbuf(f, n, 31);
+}
+
+cbuf32(f, n)
+
+{
+ return cbuf(f, n, 32);
+}
+
+cbuf33(f, n)
+
+{
+ return cbuf(f, n, 33);
+}
+
+cbuf34(f, n)
+
+{
+ return cbuf(f, n, 34);
+}
+
+cbuf35(f, n)
+
+{
+ return cbuf(f, n, 35);
+}
+
+cbuf36(f, n)
+
+{
+ return cbuf(f, n, 36);
+}
+
+cbuf37(f, n)
+
+{
+ return cbuf(f, n, 37);
+}
+
+cbuf38(f, n)
+
+{
+ return cbuf(f, n, 38);
+}
+
+cbuf39(f, n)
+
+{
+ return cbuf(f, n, 39);
+}
+
+cbuf40(f, n)
+
+{
+ return cbuf(f, n, 40);
+}
diff --git a/file.c b/file.c
new file mode 100644
index 0000000..bc64ded
--- /dev/null
+++ b/file.c
@@ -0,0 +1,635 @@
+/* FILE.C
+ *
+ * The routines in this file handle the reading, writing
+ * and lookup of disk files. All of details about the
+ * reading and writing of the disk are in "fileio.c".
+ *
+ * modified by Petri Kutvonen
+ */
+
+#include <stdio.h>
+#include "estruct.h"
+#include "edef.h"
+
+/*
+ * Read a file into the current
+ * buffer. This is really easy; all you do it
+ * find the name of the file, and call the standard
+ * "read a file into the current buffer" code.
+ * Bound to "C-X C-R".
+ */
+fileread(f, n)
+{
+ register int s;
+ char fname[NFILEN];
+
+ if (restflag) /* don't allow this command if restricted */
+ return(resterr());
+ if ((s=mlreply("Read file: ", fname, NFILEN)) != TRUE)
+ return(s);
+ return(readin(fname, TRUE));
+}
+
+/*
+ * Insert a file into the current
+ * buffer. This is really easy; all you do it
+ * find the name of the file, and call the standard
+ * "insert a file into the current buffer" code.
+ * Bound to "C-X C-I".
+ */
+insfile(f, n)
+{
+ register int s;
+ char fname[NFILEN];
+
+ if (restflag) /* don't allow this command if restricted */
+ return(resterr());
+ if (curbp->b_mode&MDVIEW) /* don't allow this command if */
+ return(rdonly()); /* we are in read only mode */
+ if ((s=mlreply("Insert file: ", fname, NFILEN)) != TRUE)
+ return(s);
+ if ((s=ifile(fname)) != TRUE)
+ return(s);
+ return(reposition(TRUE, -1));
+}
+
+/*
+ * Select a file for editing.
+ * Look around to see if you can find the
+ * fine in another buffer; if you can find it
+ * just switch to the buffer. If you cannot find
+ * the file, create a new buffer, read in the
+ * text, and switch to the new buffer.
+ * Bound to C-X C-F.
+ */
+filefind(f, n)
+{
+ char fname[NFILEN]; /* file user wishes to find */
+ register int s; /* status return */
+
+ if (restflag) /* don't allow this command if restricted */
+ return(resterr());
+ if ((s=mlreply("Find file: ", fname, NFILEN)) != TRUE)
+ return(s);
+ return(getfile(fname, TRUE));
+}
+
+viewfile(f, n) /* visit a file in VIEW mode */
+{
+ char fname[NFILEN]; /* file user wishes to find */
+ register int s; /* status return */
+ register WINDOW *wp; /* scan for windows that need updating */
+
+ if (restflag) /* don't allow this command if restricted */
+ return(resterr());
+ if ((s=mlreply("View file: ", fname, NFILEN)) != TRUE)
+ return (s);
+ s = getfile(fname, FALSE);
+ if (s) { /* if we succeed, put it in view mode */
+ curwp->w_bufp->b_mode |= MDVIEW;
+
+ /* scan through and update mode lines of all windows */
+ wp = wheadp;
+ while (wp != NULL) {
+ wp->w_flag |= WFMODE;
+ wp = wp->w_wndp;
+ }
+ }
+ return(s);
+}
+
+#if CRYPT
+resetkey() /* reset the encryption key if needed */
+
+{
+ register int s; /* return status */
+
+ /* turn off the encryption flag */
+ cryptflag = FALSE;
+
+ /* if we are in crypt mode */
+ if (curbp->b_mode & MDCRYPT) {
+ if (curbp->b_key[0] == 0) {
+ s = setkey(FALSE, 0);
+ if (s != TRUE)
+ return(s);
+ }
+
+ /* let others know... */
+ cryptflag = TRUE;
+
+ /* and set up the key to be used! */
+ /* de-encrypt it */
+ crypt((char *)NULL, 0);
+ crypt(curbp->b_key, strlen(curbp->b_key));
+
+ /* re-encrypt it...seeding it to start */
+ crypt((char *)NULL, 0);
+ crypt(curbp->b_key, strlen(curbp->b_key));
+ }
+
+ return(TRUE);
+}
+#endif
+
+getfile(fname, lockfl)
+
+char fname[]; /* file name to find */
+int lockfl; /* check the file for locks? */
+
+{
+ register BUFFER *bp;
+ register LINE *lp;
+ register int i;
+ register int s;
+ char bname[NBUFN]; /* buffer name to put file */
+
+#if MSDOS
+ mklower(fname); /* msdos isn't case sensitive */
+#endif
+ for (bp=bheadp; bp!=NULL; bp=bp->b_bufp) {
+ if ((bp->b_flag&BFINVS)==0 && strcmp(bp->b_fname, fname)==0) {
+ swbuffer(bp);
+ lp = curwp->w_dotp;
+ i = curwp->w_ntrows/2;
+ while (i-- && lback(lp)!=curbp->b_linep)
+ lp = lback(lp);
+ curwp->w_linep = lp;
+ curwp->w_flag |= WFMODE|WFHARD;
+ cknewwindow();
+ mlwrite("(Old buffer)");
+ return (TRUE);
+ }
+ }
+ makename(bname, fname); /* New buffer name. */
+ while ((bp=bfind(bname, FALSE, 0)) != NULL) {
+ /* old buffer name conflict code */
+ s = mlreply("Buffer name: ", bname, NBUFN);
+ if (s == ABORT) /* ^G to just quit */
+ return (s);
+ if (s == FALSE) { /* CR to clobber it */
+ makename(bname, fname);
+ break;
+ }
+ }
+ if (bp==NULL && (bp=bfind(bname, TRUE, 0))==NULL) {
+ mlwrite("Cannot create buffer");
+ return (FALSE);
+ }
+ if (--curbp->b_nwnd == 0) { /* Undisplay. */
+ curbp->b_dotp = curwp->w_dotp;
+ curbp->b_doto = curwp->w_doto;
+ curbp->b_markp = curwp->w_markp;
+ curbp->b_marko = curwp->w_marko;
+ }
+ curbp = bp; /* Switch to it. */
+ curwp->w_bufp = bp;
+ curbp->b_nwnd++;
+ s = readin(fname, lockfl); /* Read it in. */
+ cknewwindow();
+ return s;
+}
+
+/*
+ Read file "fname" into the current buffer, blowing away any text
+ found there. Called by both the read and find commands. Return
+ the final status of the read. Also called by the mainline, to
+ read in a file specified on the command line as an argument.
+ The command bound to M-FNR is called after the buffer is set up
+ and before it is read.
+*/
+
+readin(fname, lockfl)
+
+char fname[]; /* name of file to read */
+int lockfl; /* check for file locks? */
+
+{
+ register LINE *lp1;
+ register LINE *lp2;
+ register int i;
+ register WINDOW *wp;
+ register BUFFER *bp;
+ register int s;
+ register int nbytes;
+ register int nline;
+ int lflag; /* any lines longer than allowed? */
+ char mesg[NSTRING];
+
+#if (FILOCK && BSD) || SVR4
+ if (lockfl && lockchk(fname) == ABORT)
+#if PKCODE
+ {
+ s = FIOFNF;
+ bp = curbp;
+ strcpy(bp->b_fname, "");
+ goto out;
+ }
+#else
+ return(ABORT);
+#endif
+#endif
+#if CRYPT
+ s = resetkey();
+ if (s != TRUE)
+ return(s);
+#endif
+ bp = curbp; /* Cheap. */
+ if ((s=bclear(bp)) != TRUE) /* Might be old. */
+ return (s);
+ bp->b_flag &= ~(BFINVS|BFCHG);
+ strcpy(bp->b_fname, fname);
+
+ /* let a user macro get hold of things...if he wants */
+ execute(META|SPEC|'R', FALSE, 1);
+
+ /* turn off ALL keyboard translation in case we get a dos error */
+ TTkclose();
+
+ if ((s=ffropen(fname)) == FIOERR) /* Hard file open. */
+ goto out;
+
+ if (s == FIOFNF) { /* File not found. */
+ mlwrite("(New file)");
+ goto out;
+ }
+
+ /* read the file in */
+ mlwrite("(Reading file)");
+ nline = 0;
+ lflag = FALSE;
+ while ((s=ffgetline()) == FIOSUC) {
+ nbytes = strlen(fline);
+ if ((lp1=lalloc(nbytes)) == NULL) {
+ s = FIOMEM; /* Keep message on the */
+ break; /* display. */
+ }
+#if PKCODE
+ if (nline > MAXNLINE) {
+ s = FIOMEM;
+ break;
+ }
+#endif
+ lp2 = lback(curbp->b_linep);
+ lp2->l_fp = lp1;
+ lp1->l_fp = curbp->b_linep;
+ lp1->l_bp = lp2;
+ curbp->b_linep->l_bp = lp1;
+ for (i=0; i<nbytes; ++i)
+ lputc(lp1, i, fline[i]);
+ ++nline;
+ }
+ ffclose(); /* Ignore errors. */
+ strcpy(mesg, "(");
+ if (s==FIOERR) {
+ strcat(mesg, "I/O ERROR, ");
+ curbp->b_flag |= BFTRUNC;
+ }
+ if (s == FIOMEM) {
+ strcat(mesg, "OUT OF MEMORY, ");
+ curbp->b_flag |= BFTRUNC;
+ }
+ sprintf(&mesg[strlen(mesg)], "Read %d line", nline);
+ if (nline != 1)
+ strcat(mesg, "s");
+ strcat(mesg, ")");
+ mlwrite(mesg);
+
+out:
+ TTkopen(); /* open the keyboard again */
+ for (wp=wheadp; wp!=NULL; wp=wp->w_wndp) {
+ if (wp->w_bufp == curbp) {
+ wp->w_linep = lforw(curbp->b_linep);
+ wp->w_dotp = lforw(curbp->b_linep);
+ wp->w_doto = 0;
+ wp->w_markp = NULL;
+ wp->w_marko = 0;
+ wp->w_flag |= WFMODE|WFHARD;
+ }
+ }
+ if (s == FIOERR || s == FIOFNF) /* False if error. */
+ return(FALSE);
+#if 0
+ if (s == ABORT)
+ return(ABORT);
+#endif
+ return (TRUE);
+}
+
+/*
+ * Take a file name, and from it
+ * fabricate a buffer name. This routine knows
+ * about the syntax of file names on the target system.
+ * I suppose that this information could be put in
+ * a better place than a line of code.
+ */
+makename(bname, fname)
+char bname[];
+char fname[];
+{
+ register char *cp1;
+ register char *cp2;
+
+ cp1 = &fname[0];
+ while (*cp1 != 0)
+ ++cp1;
+
+#if VMS
+#if PKCODE
+ while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!=']' && cp1[-1]!='>')
+#else
+ while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!=']')
+#endif
+ --cp1;
+#endif
+#if MSDOS
+ while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!='\\'&&cp1[-1]!='/')
+ --cp1;
+#endif
+#if V7 | USG | BSD
+ while (cp1!=&fname[0] && cp1[-1]!='/')
+ --cp1;
+#endif
+ cp2 = &bname[0];
+ while (cp2!=&bname[NBUFN-1] && *cp1!=0 && *cp1!=';')
+ *cp2++ = *cp1++;
+ *cp2 = 0;
+}
+
+unqname(name) /* make sure a buffer name is unique */
+
+char *name; /* name to check on */
+
+{
+ register char *sp;
+
+ /* check to see if it is in the buffer list */
+ while (bfind(name, 0, FALSE) != NULL) {
+
+ /* go to the end of the name */
+ sp = name;
+ while (*sp)
+ ++sp;
+ if (sp == name || (*(sp-1) <'0' || *(sp-1) > '8')) {
+ *sp++ = '0';
+ *sp = 0;
+ } else
+ *(--sp) += 1;
+ }
+}
+
+/*
+ * Ask for a file name, and write the
+ * contents of the current buffer to that file.
+ * Update the remembered file name and clear the
+ * buffer changed flag. This handling of file names
+ * is different from the earlier versions, and
+ * is more compatable with Gosling EMACS than
+ * with ITS EMACS. Bound to "C-X C-W".
+ */
+filewrite(f, n)
+{
+ register WINDOW *wp;
+ register int s;
+ char fname[NFILEN];
+
+ if (restflag) /* don't allow this command if restricted */
+ return(resterr());
+ if ((s=mlreply("Write file: ", fname, NFILEN)) != TRUE)
+ return (s);
+ if ((s=writeout(fname)) == TRUE) {
+ strcpy(curbp->b_fname, fname);
+ curbp->b_flag &= ~BFCHG;
+ wp = wheadp; /* Update mode lines. */
+ while (wp != NULL) {
+ if (wp->w_bufp == curbp)
+ wp->w_flag |= WFMODE;
+ wp = wp->w_wndp;
+ }
+ }
+ return (s);
+}
+
+/*
+ * Save the contents of the current
+ * buffer in its associatd file. No nothing
+ * if nothing has changed (this may be a bug, not a
+ * feature). Error if there is no remembered file
+ * name for the buffer. Bound to "C-X C-S". May
+ * get called by "C-Z".
+ */
+filesave(f, n)
+{
+ register WINDOW *wp;
+ register int s;
+
+ if (curbp->b_mode&MDVIEW) /* don't allow this command if */
+ return(rdonly()); /* we are in read only mode */
+ if ((curbp->b_flag&BFCHG) == 0) /* Return, no changes. */
+ return (TRUE);
+ if (curbp->b_fname[0] == 0) { /* Must have a name. */
+ mlwrite("No file name");
+ return (FALSE);
+ }
+
+ /* complain about truncated files */
+ if ((curbp->b_flag&BFTRUNC) != 0) {
+ if (mlyesno("Truncated file ... write it out") == FALSE) {
+ mlwrite("(Aborted)");
+ return(FALSE);
+ }
+ }
+
+ if ((s=writeout(curbp->b_fname)) == TRUE) {
+ curbp->b_flag &= ~BFCHG;
+ wp = wheadp; /* Update mode lines. */
+ while (wp != NULL) {
+ if (wp->w_bufp == curbp)
+ wp->w_flag |= WFMODE;
+ wp = wp->w_wndp;
+ }
+ }
+ return (s);
+}
+
+/*
+ * This function performs the details of file
+ * writing. Uses the file management routines in the
+ * "fileio.c" package. The number of lines written is
+ * displayed. Sadly, it looks inside a LINE; provide
+ * a macro for this. Most of the grief is error
+ * checking of some sort.
+ */
+writeout(fn)
+char *fn;
+{
+ register int s;
+ register LINE *lp;
+ register int nline;
+
+#if CRYPT
+ s = resetkey();
+ if (s != TRUE)
+ return(s);
+#endif
+ /* turn off ALL keyboard translation in case we get a dos error */
+ TTkclose();
+
+ if ((s=ffwopen(fn)) != FIOSUC) { /* Open writes message. */
+ TTkopen();
+ return (FALSE);
+ }
+ mlwrite("(Writing...)"); /* tell us were writing */
+ lp = lforw(curbp->b_linep); /* First line. */
+ nline = 0; /* Number of lines. */
+ while (lp != curbp->b_linep) {
+ if ((s=ffputline(&lp->l_text[0], llength(lp))) != FIOSUC)
+ break;
+ ++nline;
+ lp = lforw(lp);
+ }
+ if (s == FIOSUC) { /* No write error. */
+ s = ffclose();
+ if (s == FIOSUC) { /* No close error. */
+ if (nline == 1)
+ mlwrite("(Wrote 1 line)");
+ else
+ mlwrite("(Wrote %d lines)", nline);
+ }
+ } else /* Ignore close error */
+ ffclose(); /* if a write error. */
+ TTkopen();
+ if (s != FIOSUC) /* Some sort of error. */
+ return (FALSE);
+ return (TRUE);
+}
+
+/*
+ * The command allows the user
+ * to modify the file name associated with
+ * the current buffer. It is like the "f" command
+ * in UNIX "ed". The operation is simple; just zap
+ * the name in the BUFFER structure, and mark the windows
+ * as needing an update. You can type a blank line at the
+ * prompt if you wish.
+ */
+filename(f, n)
+{
+ register WINDOW *wp;
+ register int s;
+ char fname[NFILEN];
+
+ if (restflag) /* don't allow this command if restricted */
+ return(resterr());
+ if ((s=mlreply("Name: ", fname, NFILEN)) == ABORT)
+ return (s);
+ if (s == FALSE)
+ strcpy(curbp->b_fname, "");
+ else
+ strcpy(curbp->b_fname, fname);
+ wp = wheadp; /* Update mode lines. */
+ while (wp != NULL) {
+ if (wp->w_bufp == curbp)
+ wp->w_flag |= WFMODE;
+ wp = wp->w_wndp;
+ }
+ curbp->b_mode &= ~MDVIEW; /* no longer read only mode */
+ return (TRUE);
+}
+
+/*
+ * Insert file "fname" into the current
+ * buffer, Called by insert file command. Return the final
+ * status of the read.
+ */
+ifile(fname)
+char fname[];
+{
+ register LINE *lp0;
+ register LINE *lp1;
+ register LINE *lp2;
+ register int i;
+ register BUFFER *bp;
+ register int s;
+ register int nbytes;
+ register int nline;
+ int lflag; /* any lines longer than allowed? */
+ char mesg[NSTRING];
+
+ bp = curbp; /* Cheap. */
+ bp->b_flag |= BFCHG; /* we have changed */
+ bp->b_flag &= ~BFINVS; /* and are not temporary*/
+ if ((s=ffropen(fname)) == FIOERR) /* Hard file open. */
+ goto out;
+ if (s == FIOFNF) { /* File not found. */
+ mlwrite("(No such file)");
+ return(FALSE);
+ }
+ mlwrite("(Inserting file)");
+
+#if CRYPT
+ s = resetkey();
+ if (s != TRUE)
+ return(s);
+#endif
+ /* back up a line and save the mark here */
+ curwp->w_dotp = lback(curwp->w_dotp);
+ curwp->w_doto = 0;
+ curwp->w_markp = curwp->w_dotp;
+ curwp->w_marko = 0;
+
+ nline = 0;
+ lflag = FALSE;
+ while ((s=ffgetline()) == FIOSUC) {
+ nbytes = strlen(fline);
+ if ((lp1=lalloc(nbytes)) == NULL) {
+ s = FIOMEM; /* Keep message on the */
+ break; /* display. */
+ }
+ lp0 = curwp->w_dotp; /* line previous to insert */
+ lp2 = lp0->l_fp; /* line after insert */
+
+ /* re-link new line between lp0 and lp2 */
+ lp2->l_bp = lp1;
+ lp0->l_fp = lp1;
+ lp1->l_bp = lp0;
+ lp1->l_fp = lp2;
+
+ /* and advance and write out the current line */
+ curwp->w_dotp = lp1;
+ for (i=0; i<nbytes; ++i)
+ lputc(lp1, i, fline[i]);
+ ++nline;
+ }
+ ffclose(); /* Ignore errors. */
+ curwp->w_markp = lforw(curwp->w_markp);
+ strcpy(mesg, "(");
+ if (s==FIOERR) {
+ strcat(mesg, "I/O ERROR, ");
+ curbp->b_flag |= BFTRUNC;
+ }
+ if (s == FIOMEM) {
+ strcat(mesg, "OUT OF MEMORY, ");
+ curbp->b_flag |= BFTRUNC;
+ }
+ sprintf(&mesg[strlen(mesg)], "Inserted %d line", nline);
+ if (nline > 1)
+ strcat(mesg, "s");
+ strcat(mesg, ")");
+ mlwrite(mesg);
+
+out:
+ /* advance to the next line and mark the window for changes */
+ curwp->w_dotp = lforw(curwp->w_dotp);
+ curwp->w_flag |= WFHARD | WFMODE;
+
+ /* copy window parameters back to the buffer structure */
+ curbp->b_dotp = curwp->w_dotp;
+ curbp->b_doto = curwp->w_doto;
+ curbp->b_markp = curwp->w_markp;
+ curbp->b_marko = curwp->w_marko;
+
+ if (s == FIOERR) /* False if error. */
+ return (FALSE);
+ return (TRUE);
+}
diff --git a/fileio.c b/fileio.c
new file mode 100644
index 0000000..55e571a
--- /dev/null
+++ b/fileio.c
@@ -0,0 +1,228 @@
+/* FILEIO.C
+ *
+ * The routines in this file read and write ASCII files from the disk. All of
+ * the knowledge about files are here.
+ *
+ * modified by Petri Kutvonen
+ */
+
+#include <stdio.h>
+#include "estruct.h"
+#include "edef.h"
+
+#if PKCODE
+extern int nullflag;
+#endif
+
+FILE *ffp; /* File pointer, all functions. */
+int eofflag; /* end-of-file flag */
+
+/*
+ * Open a file for reading.
+ */
+ffropen(fn)
+char *fn;
+{
+ if ((ffp=fopen(fn, "r")) == NULL)
+ return (FIOFNF);
+ eofflag = FALSE;
+ return (FIOSUC);
+}
+
+/*
+ * Open a file for writing. Return TRUE if all is well, and FALSE on error
+ * (cannot create).
+ */
+ffwopen(fn)
+char *fn;
+{
+#if VMS
+ register int fd;
+
+ if ((fd=creat(fn, 0666, "rfm=var", "rat=cr")) < 0
+ || (ffp=fdopen(fd, "w")) == NULL) {
+#else
+ if ((ffp=fopen(fn, "w")) == NULL) {
+#endif
+ mlwrite("Cannot open file for writing");
+ return (FIOERR);
+ }
+ return (FIOSUC);
+}
+
+/*
+ * Close a file. Should look at the status in all systems.
+ */
+ffclose()
+{
+ /* free this since we do not need it anymore */
+ if (fline) {
+ free(fline);
+ fline = NULL;
+ }
+ eofflag = FALSE;
+
+#if MSDOS & CTRLZ
+ fputc(26, ffp); /* add a ^Z at the end of the file */
+#endif
+
+#if V7 | USG | BSD | (MSDOS & (MSC | TURBO))
+ if (fclose(ffp) != FALSE) {
+ mlwrite("Error closing file");
+ return(FIOERR);
+ }
+ return(FIOSUC);
+#else
+ fclose(ffp);
+ return (FIOSUC);
+#endif
+}
+
+/*
+ * Write a line to the already opened file. The "buf" points to the buffer,
+ * and the "nbuf" is its length, less the free newline. Return the status.
+ * Check only at the newline.
+ */
+ffputline(buf, nbuf)
+char buf[];
+{
+ register int i;
+#if CRYPT
+ char c; /* character to translate */
+
+ if (cryptflag) {
+ for (i = 0; i < nbuf; ++i) {
+ c = buf[i] & 0xff;
+ crypt(&c, 1);
+ fputc(c, ffp);
+ }
+ } else
+ for (i = 0; i < nbuf; ++i)
+ fputc(buf[i]&0xFF, ffp);
+#else
+ for (i = 0; i < nbuf; ++i)
+ fputc(buf[i]&0xFF, ffp);
+#endif
+
+ fputc('\n', ffp);
+
+ if (ferror(ffp)) {
+ mlwrite("Write I/O error");
+ return (FIOERR);
+ }
+
+ return (FIOSUC);
+}
+
+/*
+ * Read a line from a file, and store the bytes in the supplied buffer. The
+ * "nbuf" is the length of the buffer. Complain about long lines and lines
+ * at the end of the file that don't have a newline present. Check for I/O
+ * errors too. Return status.
+ */
+ffgetline()
+
+{
+ register int c; /* current character read */
+ register int i; /* current index into fline */
+ register char *tmpline; /* temp storage for expanding line */
+
+ /* if we are at the end...return it */
+ if (eofflag)
+ return(FIOEOF);
+
+ /* dump fline if it ended up too big */
+ if (flen > NSTRING) {
+ free(fline);
+ fline = NULL;
+ }
+
+ /* if we don't have an fline, allocate one */
+ if (fline == NULL)
+ if ((fline = malloc(flen = NSTRING)) == NULL)
+ return(FIOMEM);
+
+ /* read the line in */
+#if PKCODE
+ if (!nullflag) {
+ if (fgets(fline, NSTRING, ffp) == (char *)NULL) { /* EOF ? */
+ i = 0;
+ c = EOF;
+ }
+ else {
+ i = strlen(fline);
+ c = 0;
+ if (i > 0) {
+ c = fline[i-1];
+ i--;
+ }
+ }
+ }
+ else {
+ i = 0;
+ c = fgetc(ffp);
+ }
+ while (c != EOF && c != '\n') {
+#else
+ i = 0;
+ while ((c = fgetc(ffp)) != EOF && c != '\n') {
+#endif
+#if PKCODE
+ if (c) {
+#endif
+ fline[i++] = c;
+ /* if it's longer, get more room */
+ if (i >= flen) {
+ if ((tmpline = malloc(flen+NSTRING)) == NULL)
+ return(FIOMEM);
+ strncpy(tmpline, fline, flen);
+ flen += NSTRING;
+ free(fline);
+ fline = tmpline;
+ }
+#if PKCODE
+ }
+ c = fgetc(ffp);
+#endif
+ }
+
+ /* test for any errors that may have occured */
+ if (c == EOF) {
+ if (ferror(ffp)) {
+ mlwrite("File read error");
+ return(FIOERR);
+ }
+
+ if (i != 0)
+ eofflag = TRUE;
+ else
+ return(FIOEOF);
+ }
+
+ /* terminate and decrypt the string */
+ fline[i] = 0;
+#if CRYPT
+ if (cryptflag)
+ crypt(fline, strlen(fline));
+#endif
+ return(FIOSUC);
+}
+
+int fexist(fname) /* does <fname> exist on disk? */
+
+char *fname; /* file to check for existance */
+
+{
+ FILE *fp;
+
+ /* try to open the file for reading */
+ fp = fopen(fname, "r");
+
+ /* if it fails, just return false! */
+ if (fp == NULL)
+ return(FALSE);
+
+ /* otherwise, close it and report true */
+ fclose(fp);
+ return(TRUE);
+}
diff --git a/ibmpc.c b/ibmpc.c
new file mode 100644
index 0000000..37ddde9
--- /dev/null
+++ b/ibmpc.c
@@ -0,0 +1,517 @@
+/* IBMPC.C
+ *
+ * The routines in this file provide support for the IBM-PC and other
+ * compatible terminals. It goes directly to the graphics RAM to do
+ * screen output. It compiles into nothing if not an IBM-PC driver
+ * Supported monitor cards include CGA, MONO and EGA.
+ *
+ * modified by Petri Kutvonen
+ */
+
+#define termdef 1 /* don't define "term" external */
+
+#include <stdio.h>
+#include "estruct.h"
+#include "edef.h"
+
+#if IBMPC
+#if PKCODE
+#define NROW 50
+#else
+#define NROW 43 /* Max Screen size. */
+#endif
+#define NCOL 80 /* Edit if you want to. */
+#define MARGIN 8 /* size of minimim margin and */
+#define SCRSIZ 64 /* scroll size for extended lines */
+#define NPAUSE 200 /* # times thru update to pause */
+#define BEL 0x07 /* BEL character. */
+#define ESC 0x1B /* ESC character. */
+#define SPACE 32 /* space character */
+
+#define SCADC 0xb8000000L /* CGA address of screen RAM */
+#define SCADM 0xb0000000L /* MONO address of screen RAM */
+#define SCADE 0xb8000000L /* EGA address of screen RAM */
+
+#define MONOCRSR 0x0B0D /* monochrome cursor */
+#define CGACRSR 0x0607 /* CGA cursor */
+#define EGACRSR 0x0709 /* EGA cursor */
+
+#define CDCGA 0 /* color graphics card */
+#define CDMONO 1 /* monochrome text card */
+#define CDEGA 2 /* EGA color adapter */
+#if PKCODE
+#define CDVGA 3
+#endif
+#define CDSENSE 9 /* detect the card type */
+
+#if PKCODE
+#define NDRIVE 4
+#else
+#define NDRIVE 3 /* number of screen drivers */
+#endif
+
+int dtype = -1; /* current display type */
+char drvname[][8] = { /* screen resolution names */
+ "CGA", "MONO", "EGA"
+#if PKCODE
+ ,"VGA"
+#endif
+};
+long scadd; /* address of screen ram */
+int *scptr[NROW]; /* pointer to screen lines */
+unsigned int sline[NCOL]; /* screen line image */
+int egaexist = FALSE; /* is an EGA card available? */
+extern union REGS rg; /* cpu register for use of DOS calls */
+
+extern int ttopen(); /* Forward references. */
+extern int ttgetc();
+extern int ttputc();
+extern int ttflush();
+extern int ttclose();
+extern int ibmmove();
+extern int ibmeeol();
+extern int ibmeeop();
+extern int ibmbeep();
+extern int ibmopen();
+extern int ibmrev();
+extern int ibmcres();
+extern int ibmclose();
+extern int ibmputc();
+extern int ibmkopen();
+extern int ibmkclose();
+
+#if COLOR
+extern int ibmfcol();
+extern int ibmbcol();
+extern int ibmscroll_reg();
+
+int cfcolor = -1; /* current forground color */
+int cbcolor = -1; /* current background color */
+int ctrans[] = /* ansi to ibm color translation table */
+#if PKCODE
+ {0, 4, 2, 6, 1, 5, 3, 7, 15};
+#else
+ {0, 4, 2, 6, 1, 5, 3, 7};
+#endif
+#endif
+
+/*
+ * Standard terminal interface dispatch table. Most of the fields point into
+ * "termio" code.
+ */
+TERM term = {
+ NROW-1,
+ NROW-1,
+ NCOL,
+ NCOL,
+ MARGIN,
+ SCRSIZ,
+ NPAUSE,
+ ibmopen,
+ ibmclose,
+ ibmkopen,
+ ibmkclose,
+ ttgetc,
+ ibmputc,
+ ttflush,
+ ibmmove,
+ ibmeeol,
+ ibmeeop,
+ ibmbeep,
+ ibmrev,
+ ibmcres
+#if COLOR
+ , ibmfcol,
+ ibmbcol
+#endif
+#if SCROLLCODE
+ , ibmscroll_reg
+#endif
+};
+
+#if COLOR
+ibmfcol(color) /* set the current output color */
+
+int color; /* color to set */
+
+{
+ cfcolor = ctrans[color];
+}
+
+ibmbcol(color) /* set the current background color */
+
+int color; /* color to set */
+
+{
+ cbcolor = ctrans[color];
+}
+#endif
+
+ibmmove(row, col)
+{
+ rg.h.ah = 2; /* set cursor position function code */
+ rg.h.dl = col;
+ rg.h.dh = row;
+ rg.h.bh = 0; /* set screen page number */
+ int86(0x10, &rg, &rg);
+}
+
+ibmeeol() /* erase to the end of the line */
+
+{
+ unsigned int attr; /* attribute byte mask to place in RAM */
+ unsigned int *lnptr; /* pointer to the destination line */
+ int i;
+ int ccol; /* current column cursor lives */
+ int crow; /* row */
+
+ /* find the current cursor position */
+ rg.h.ah = 3; /* read cursor position function code */
+ rg.h.bh = 0; /* current video page */
+ int86(0x10, &rg, &rg);
+ ccol = rg.h.dl; /* record current column */
+ crow = rg.h.dh; /* and row */
+
+ /* build the attribute byte and setup the screen pointer */
+#if COLOR
+ if (dtype != CDMONO)
+ attr = (((cbcolor & 15) << 4) | (cfcolor & 15)) << 8;
+ else
+ attr = 0x0700;
+#else
+ attr = 0x0700;
+#endif
+ lnptr = &sline[0];
+ for (i=0; i < term.t_ncol; i++)
+ *lnptr++ = SPACE | attr;
+
+ if (flickcode && (dtype == CDCGA)) {
+ /* wait for vertical retrace to be off */
+ while ((inp(0x3da) & 8))
+ ;
+
+ /* and to be back on */
+ while ((inp(0x3da) & 8) == 0)
+ ;
+ }
+
+ /* and send the string out */
+ movmem(&sline[0], scptr[crow]+ccol, (term.t_ncol-ccol)*2);
+
+}
+
+ibmputc(ch) /* put a character at the current position in the
+ current colors */
+
+int ch;
+
+{
+ rg.h.ah = 14; /* write char to screen with current attrs */
+ rg.h.al = ch;
+#if COLOR
+ if (dtype != CDMONO)
+ rg.h.bl = cfcolor;
+ else
+ rg.h.bl = 0x07;
+#else
+ rg.h.bl = 0x07;
+#endif
+ int86(0x10, &rg, &rg);
+}
+
+ibmeeop()
+{
+ int attr; /* attribute to fill screen with */
+
+ rg.h.ah = 6; /* scroll page up function code */
+ rg.h.al = 0; /* # lines to scroll (clear it) */
+ rg.x.cx = 0; /* upper left corner of scroll */
+ rg.x.dx = (term.t_nrow << 8) | (term.t_ncol - 1);
+ /* lower right corner of scroll */
+#if COLOR
+ if (dtype != CDMONO)
+ attr = ((ctrans[gbcolor] & 15) << 4) | (ctrans[gfcolor] & 15);
+ else
+ attr = 0;
+#else
+ attr = 0;
+#endif
+ rg.h.bh = attr;
+ int86(0x10, &rg, &rg);
+}
+
+ibmrev(state) /* change reverse video state */
+
+int state; /* TRUE = reverse, FALSE = normal */
+
+{
+ /* This never gets used under the IBM-PC driver */
+}
+
+ibmcres(res) /* change screen resolution */
+
+char *res; /* resolution to change to */
+
+{
+ int i; /* index */
+
+ for (i = 0; i < NDRIVE; i++)
+ if (strcmp(res, drvname[i]) == 0) {
+ scinit(i);
+ return(TRUE);
+ }
+ return(FALSE);
+}
+
+#if SCROLLCODE
+
+/* move howmany lines starting at from to to */
+ibmscroll_reg(from, to, howmany)
+{
+ int i;
+
+ if (to < from)
+ for (i = 0; i < howmany; i++)
+ movmem(scptr[from+i], scptr[to+i], term.t_ncol*2);
+ else
+ if (to > from)
+ for (i = howmany-1; i >= 0; i--)
+ movmem(scptr[from+i], scptr[to+i], term.t_ncol*2);
+ return;
+}
+
+#endif
+
+spal() /* reset the pallette registers */
+
+{
+ /* nothin here now..... */
+}
+
+ibmbeep()
+{
+ bdos(6, BEL, 0);
+}
+
+ibmopen()
+{
+ scinit(CDSENSE);
+ revexist = TRUE;
+ ttopen();
+}
+
+ibmclose()
+
+{
+#if COLOR
+ ibmfcol(7);
+ ibmbcol(0);
+#endif
+ /* if we had the EGA open... close it */
+ if (dtype == CDEGA)
+ egaclose();
+#if PKCODE
+ if (dtype == CDVGA)
+ egaclose();
+#endif
+
+ ttclose();
+}
+
+ibmkopen() /* open the keyboard */
+
+{
+}
+
+ibmkclose() /* close the keyboard */
+
+{
+}
+
+scinit(type) /* initialize the screen head pointers */
+
+int type; /* type of adapter to init for */
+
+{
+ union {
+ long laddr; /* long form of address */
+ int *paddr; /* pointer form of address */
+ } addr;
+ int i;
+
+ /* if asked...find out what display is connected */
+ if (type == CDSENSE)
+ type = getboard();
+
+ /* if we have nothing to do....don't do it */
+ if (dtype == type)
+ return(TRUE);
+
+ /* if we try to switch to EGA and there is none, don't */
+ if (type == CDEGA && egaexist != TRUE)
+ return(FALSE);
+
+ /* if we had the EGA open... close it */
+ if (dtype == CDEGA)
+ egaclose();
+#if PKCODE
+ if (dtype == CDVGA)
+ egaclose();
+#endif
+
+ /* and set up the various parameters as needed */
+ switch (type) {
+ case CDMONO: /* Monochrome adapter */
+ scadd = SCADM;
+ newsize(TRUE, 25);
+ break;
+
+ case CDCGA: /* Color graphics adapter */
+ scadd = SCADC;
+ newsize(TRUE, 25);
+ break;
+
+ case CDEGA: /* Enhanced graphics adapter */
+ scadd = SCADE;
+ egaopen();
+ newsize(TRUE, 43);
+ break;
+ case CDVGA: /* Enhanced graphics adapter */
+ scadd = SCADE;
+ egaopen();
+ newsize(TRUE, 50);
+ break;
+ }
+
+ /* reset the $sres environment variable */
+ strcpy(sres, drvname[type]);
+ dtype = type;
+
+ /* initialize the screen pointer array */
+ for (i = 0; i < NROW; i++) {
+ addr.laddr = scadd + (long)(NCOL * i * 2);
+ scptr[i] = addr.paddr;
+ }
+ return(TRUE);
+}
+
+/* getboard: Determine which type of display board is attached.
+ Current known types include:
+
+ CDMONO Monochrome graphics adapter
+ CDCGA Color Graphics Adapter
+ CDEGA Extended graphics Adapter
+*/
+
+/* getboard: Detect the current display adapter
+ if MONO set to MONO
+ CGA set to CGA EGAexist = FALSE
+ EGA set to CGA EGAexist = TRUE
+*/
+
+int getboard()
+
+{
+ int type; /* board type to return */
+
+ type = CDCGA;
+ int86(0x11, &rg, &rg);
+ if ((((rg.x.ax >> 4) & 3) == 3))
+ type = CDMONO;
+
+ /* test if EGA present */
+ rg.x.ax = 0x1200;
+ rg.x.bx = 0xff10;
+ int86(0x10,&rg, &rg); /* If EGA, bh=0-1 and bl=0-3 */
+ egaexist = !(rg.x.bx & 0xfefc); /* Yes, it's EGA */
+ return(type);
+}
+
+egaopen() /* init the computer to work with the EGA */
+
+{
+ /* put the beast into EGA 43 row mode */
+ rg.x.ax = 3;
+ int86(16, &rg, &rg);
+
+ rg.h.ah = 17; /* set char. generator function code */
+ rg.h.al = 18; /* to 8 by 8 double dot ROM */
+ rg.h.bl = 0; /* block 0 */
+ int86(16, &rg, &rg);
+
+ rg.h.ah = 18; /* alternate select function code */
+ rg.h.al = 0; /* clear AL for no good reason */
+ rg.h.bl = 32; /* alt. print screen routine */
+ int86(16, &rg, &rg);
+
+ rg.h.ah = 1; /* set cursor size function code */
+ rg.x.cx = 0x0607; /* turn cursor on code */
+ int86(0x10, &rg, &rg);
+
+ outp(0x3d4, 10); /* video bios bug patch */
+ outp(0x3d5, 6);
+}
+
+egaclose()
+
+{
+ /* put the beast into 80 column mode */
+ rg.x.ax = 3;
+ int86(16, &rg, &rg);
+}
+
+scwrite(row, outstr, forg, bacg) /* write a line out*/
+
+int row; /* row of screen to place outstr on */
+char *outstr; /* string to write out (must be term.t_ncol long) */
+int forg; /* forground color of string to write */
+int bacg; /* background color */
+
+{
+ unsigned int attr; /* attribute byte mask to place in RAM */
+ unsigned int *lnptr; /* pointer to the destination line */
+ int i;
+
+ /* build the attribute byte and setup the screen pointer */
+#if COLOR
+ if (dtype != CDMONO)
+ attr = (((ctrans[bacg] & 15) << 4) | (ctrans[forg] & 15)) << 8;
+ else
+ attr = (((bacg & 15) << 4) | (forg & 15)) << 8;
+#else
+ attr = (((bacg & 15) << 4) | (forg & 15)) << 8;
+#endif
+ lnptr = &sline[0];
+ for (i=0; i<term.t_ncol; i++)
+ *lnptr++ = (outstr[i] & 255) | attr;
+
+ if (flickcode && (dtype == CDCGA)) {
+ /* wait for vertical retrace to be off */
+ while ((inp(0x3da) & 8))
+ ;
+
+ /* and to be back on */
+ while ((inp(0x3da) & 8) == 0)
+ ;
+ }
+
+ /* and send the string out */
+ movmem(&sline[0], scptr[row], term.t_ncol*2);
+}
+
+#if FNLABEL
+fnclabel(f, n) /* label a function key */
+
+int f,n; /* default flag, numeric argument [unused] */
+
+{
+ /* on machines with no function keys...don't bother */
+ return(TRUE);
+}
+#endif
+#else
+ibmhello()
+{
+}
+#endif
+
diff --git a/input.c b/input.c
new file mode 100644
index 0000000..180c55a
--- /dev/null
+++ b/input.c
@@ -0,0 +1,713 @@
+/* INPUT.C
+ *
+ * Various input routines
+ *
+ * written by Daniel Lawrence 5/9/86
+ * modified by Petri Kutvonen
+ */
+
+#include <stdio.h>
+#include "estruct.h"
+#include "edef.h"
+
+#if PKCODE
+#if MSDOS && TURBO
+#include <dir.h>
+#endif
+#endif
+
+#if PKCODE && (UNIX || (MSDOS && TURBO))
+#define COMPLC 1
+#else
+#define COMPLC 0
+#endif
+
+/*
+ * Ask a yes or no question in the message line. Return either TRUE, FALSE, or
+ * ABORT. The ABORT status is returned if the user bumps out of the question
+ * with a ^G. Used any time a confirmation is required.
+ */
+
+mlyesno(prompt)
+
+char *prompt;
+
+{
+ char c; /* input character */
+ char buf[NPAT]; /* prompt to user */
+
+ for (;;) {
+ /* build and prompt the user */
+ strcpy(buf, prompt);
+ strcat(buf, " (y/n)? ");
+ mlwrite(buf);
+
+ /* get the responce */
+ c = tgetc();
+
+ if (c == ectoc(abortc)) /* Bail out! */
+ return(ABORT);
+
+ if (c=='y' || c=='Y')
+ return(TRUE);
+
+ if (c=='n' || c=='N')
+ return(FALSE);
+ }
+}
+
+/*
+ * Write a prompt into the message line, then read back a response. Keep
+ * track of the physical position of the cursor. If we are in a keyboard
+ * macro throw the prompt away, and return the remembered response. This
+ * lets macros run at full speed. The reply is always terminated by a carriage
+ * return. Handle erase, kill, and abort keys.
+ */
+
+mlreply(prompt, buf, nbuf)
+ char *prompt;
+ char *buf;
+{
+ return(nextarg(prompt, buf, nbuf, ctoec('\n')));
+}
+
+mlreplyt(prompt, buf, nbuf, eolchar)
+
+char *prompt;
+char *buf;
+int eolchar;
+
+{
+ return(nextarg(prompt, buf, nbuf, eolchar));
+}
+
+/* ectoc: expanded character to character
+ colapse the CONTROL and SPEC flags back into an ascii code */
+
+ectoc(c)
+
+int c;
+
+{
+ if (c & CONTROL)
+ c = c & ~(CONTROL | 0x40);
+ if (c & SPEC)
+ c= c & 255;
+ return(c);
+}
+
+/* ctoec: character to extended character
+ pull out the CONTROL and SPEC prefixes (if possible) */
+
+ctoec(c)
+
+int c;
+
+{
+ if (c>=0x00 && c<=0x1F)
+ c = CONTROL | (c+'@');
+ return (c);
+}
+
+/* get a command name from the command line. Command completion means
+ that pressing a <SPACE> will attempt to complete an unfinished command
+ name if it is unique.
+*/
+
+int (*getname())()
+
+{
+ register int cpos; /* current column on screen output */
+ register int c;
+ register char *sp; /* pointer to string for output */
+ register NBIND *ffp; /* first ptr to entry in name binding table */
+ register NBIND *cffp; /* current ptr to entry in name binding table */
+ register NBIND *lffp; /* last ptr to entry in name binding table */
+ char buf[NSTRING]; /* buffer to hold tentative command name */
+ int (*fncmatch())();
+
+ /* starting at the beginning of the string buffer */
+ cpos = 0;
+
+ /* if we are executing a command line get the next arg and match it */
+ if (clexec) {
+ if (macarg(buf) != TRUE)
+ return(FALSE);
+ return(fncmatch(&buf[0]));
+ }
+
+ /* build a name string from the keyboard */
+ while (TRUE) {
+ c = tgetc();
+
+ /* if we are at the end, just match it */
+ if (c == 0x0d) {
+ buf[cpos] = 0;
+
+ /* and match it off */
+ return(fncmatch(&buf[0]));
+
+ } else if (c == ectoc(abortc)) { /* Bell, abort */
+ ctrlg(FALSE, 0);
+ TTflush();
+ return( (int (*)()) NULL);
+
+ } else if (c == 0x7F || c == 0x08) { /* rubout/erase */
+ if (cpos != 0) {
+ TTputc('\b');
+ TTputc(' ');
+ TTputc('\b');
+ --ttcol;
+ --cpos;
+ TTflush();
+ }
+
+ } else if (c == 0x15) { /* C-U, kill */
+ while (cpos != 0) {
+ TTputc('\b');
+ TTputc(' ');
+ TTputc('\b');
+ --cpos;
+ --ttcol;
+ }
+
+ TTflush();
+
+ } else if (c == ' ' || c == 0x1b || c == 0x09) {
+/* <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */
+ /* attempt a completion */
+ buf[cpos] = 0; /* terminate it for us */
+ ffp = &names[0]; /* scan for matches */
+ while (ffp->n_func != NULL) {
+ if (strncmp(buf, ffp->n_name, strlen(buf)) == 0) {
+ /* a possible match! More than one? */
+ if ((ffp + 1)->n_func == NULL ||
+ (strncmp(buf, (ffp+1)->n_name, strlen(buf)) != 0)) {
+ /* no...we match, print it */
+ sp = ffp->n_name + cpos;
+ while (*sp)
+ TTputc(*sp++);
+ TTflush();
+ return(ffp->n_func);
+ } else {
+/* << << << << << << << << << << << << << << << << << */
+ /* try for a partial match against the list */
+
+ /* first scan down until we no longer match the current input */
+ lffp = (ffp + 1);
+ while ((lffp+1)->n_func != NULL) {
+ if (strncmp(buf, (lffp+1)->n_name, strlen(buf)) != 0)
+ break;
+ ++lffp;
+ }
+
+ /* and now, attempt to partial complete the string, char at a time */
+ while (TRUE) {
+ /* add the next char in */
+ buf[cpos] = ffp->n_name[cpos];
+
+ /* scan through the candidates */
+ cffp = ffp + 1;
+ while (cffp <= lffp) {
+ if (cffp->n_name[cpos] != buf[cpos])
+ goto onward;
+ ++cffp;
+ }
+
+ /* add the character */
+ TTputc(buf[cpos++]);
+ }
+/* << << << << << << << << << << << << << << << << << */
+ }
+ }
+ ++ffp;
+ }
+
+ /* no match.....beep and onward */
+ TTbeep();
+onward:;
+ TTflush();
+/* <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */
+ } else {
+ if (cpos < NSTRING-1 && c > ' ') {
+ buf[cpos++] = c;
+ TTputc(c);
+ }
+
+ ++ttcol;
+ TTflush();
+ }
+ }
+}
+
+/* tgetc: Get a key from the terminal driver, resolve any keyboard
+ macro action */
+
+int tgetc()
+
+{
+ int c; /* fetched character */
+
+ /* if we are playing a keyboard macro back, */
+ if (kbdmode == PLAY) {
+
+ /* if there is some left... */
+ if (kbdptr < kbdend)
+ return((int)*kbdptr++);
+
+ /* at the end of last repitition? */
+ if (--kbdrep < 1) {
+ kbdmode = STOP;
+#if VISMAC == 0
+ /* force a screen update after all is done */
+ update(FALSE);
+#endif
+ } else {
+
+ /* reset the macro to the begining for the next rep */
+ kbdptr = &kbdm[0];
+ return((int)*kbdptr++);
+ }
+ }
+
+ /* fetch a character from the terminal driver */
+ c = TTgetc();
+
+ /* record it for $lastkey */
+ lastkey = c;
+
+ /* save it if we need to */
+ if (kbdmode == RECORD) {
+ *kbdptr++ = c;
+ kbdend = kbdptr;
+
+ /* don't overrun the buffer */
+ if (kbdptr == &kbdm[NKBDM - 1]) {
+ kbdmode = STOP;
+ TTbeep();
+ }
+ }
+
+ /* and finally give the char back */
+ return(c);
+}
+
+/* GET1KEY: Get one keystroke. The only prefixs legal here
+ are the SPEC and CONTROL prefixes.
+ */
+
+get1key()
+
+{
+ int c;
+
+ /* get a keystroke */
+ c = tgetc();
+
+#if MSDOS
+ if (c == 0) { /* Apply SPEC prefix */
+ c = tgetc();
+ if (c>=0x00 && c<=0x1F) /* control key? */
+ c = CONTROL | (c+'@');
+ return(SPEC | c);
+ }
+#endif
+
+ if (c>=0x00 && c<=0x1F) /* C0 control -> C- */
+ c = CONTROL | (c+'@');
+ return (c);
+}
+
+/* GETCMD: Get a command from the keyboard. Process all applicable
+ prefix keys
+ */
+getcmd()
+
+{
+ int c; /* fetched keystroke */
+#if VT220
+ int d; /* second character P.K. */
+ int cmask = 0;
+#endif
+ /* get initial character */
+ c = get1key();
+
+#if VT220
+proc_metac:
+#endif
+ /* process META prefix */
+ if (c == (CONTROL | '[')) {
+ c = get1key();
+#if VT220
+ if (c == '[' || c == 'O') { /* CSI P.K. */
+ c = get1key();
+ if (c >= 'A' && c <= 'D')
+ return(SPEC | c | cmask);
+ if (c >= 'E' && c <= 'z' && c != 'i' && c != 'c')
+ return(SPEC | c | cmask);
+ d = get1key();
+ if (d == '~') /* ESC [ n ~ P.K. */
+ return(SPEC | c | cmask);
+ switch (c) { /* ESC [ n n ~ P.K. */
+ case '1': c = d + 32;
+ break;
+ case '2': c = d + 48;
+ break;
+ case '3': c = d + 64;
+ break;
+ default: c = '?';
+ break;
+ }
+ if (d != '~') /* eat tilde P.K. */
+ get1key();
+ if (c == 'i') { /* DO key P.K. */
+ c = ctlxc;
+ goto proc_ctlxc;
+ }
+ else if (c == 'c') /* ESC key P.K. */
+ c = get1key();
+ else
+ return(SPEC | c | cmask);
+ }
+#endif
+#if VT220
+ if (c == (CONTROL | '[')) {
+ cmask = META;
+ goto proc_metac;
+ }
+#endif
+ if (islower(c)) /* Force to upper */
+ c ^= DIFCASE;
+ if (c>=0x00 && c<=0x1F) /* control key */
+ c = CONTROL | (c+'@');
+ return(META | c );
+ }
+#if PKCODE
+ else
+ if (c == metac) {
+ c = get1key();
+#if VT220
+ if (c == (CONTROL | '[')) {
+ cmask = META;
+ goto proc_metac;
+ }
+#endif
+ if (islower(c)) /* Force to upper */
+ c ^= DIFCASE;
+ if (c>=0x00 && c<=0x1F) /* control key */
+ c = CONTROL | (c+'@');
+ return(META | c );
+ }
+#endif
+
+
+#if VT220
+proc_ctlxc:
+#endif
+ /* process CTLX prefix */
+ if (c == ctlxc) {
+ c = get1key();
+#if VT220
+ if (c == (CONTROL | '[')) {
+ cmask = CTLX;
+ goto proc_metac;
+ }
+#endif
+ if (c>='a' && c<='z') /* Force to upper */
+ c -= 0x20;
+ if (c>=0x00 && c<=0x1F) /* control key */
+ c = CONTROL | (c+'@');
+ return(CTLX | c);
+ }
+
+ /* otherwise, just return it */
+ return(c);
+}
+
+/* A more generalized prompt/reply function allowing the caller
+ to specify the proper terminator. If the terminator is not
+ a return ('\n') it will echo as "<NL>"
+ */
+getstring(prompt, buf, nbuf, eolchar)
+
+char *prompt; char *buf; int eolchar;
+
+{
+ register int cpos; /* current character position in string */
+ register int c;
+ register int quotef; /* are we quoting the next char? */
+#if COMPLC
+ int ffile, ocpos, nskip, didtry = 0;
+#if MSDOS
+ struct ffblk ffblk;
+ char *fcp;
+#endif
+#if UNIX
+ static char tmp[] = "/tmp/meXXXXXX";
+ FILE *tmpf = NULL;
+#endif
+ ffile = (strcmp(prompt, "Find file: ") == 0
+ || strcmp(prompt, "View file: ") == 0
+ || strcmp(prompt, "Insert file: ") == 0
+ || strcmp(prompt, "Write file: ") == 0
+ || strcmp(prompt, "Read file: ") == 0
+ || strcmp(prompt, "File to execute: ") == 0);
+#endif
+
+ cpos = 0;
+ quotef = FALSE;
+
+ /* prompt the user for the input string */
+ mlwrite(prompt);
+
+ for (;;) {
+#if COMPLC
+ if (! didtry)
+ nskip = -1;
+ didtry = 0;
+#endif
+ /* get a character from the user */
+ c = get1key();
+
+ /* If it is a <ret>, change it to a <NL> */
+#if PKCODE
+ if (c == (CONTROL | 0x4d) && !quotef)
+#else
+ if (c == (CONTROL | 0x4d))
+#endif
+ c = CONTROL | 0x40 | '\n';
+
+ /* if they hit the line terminate, wrap it up */
+ if (c == eolchar && quotef == FALSE) {
+ buf[cpos++] = 0;
+
+ /* clear the message line */
+ mlwrite("");
+ TTflush();
+
+ /* if we default the buffer, return FALSE */
+ if (buf[0] == 0)
+ return(FALSE);
+
+ return(TRUE);
+ }
+
+ /* change from command form back to character form */
+ c = ectoc(c);
+
+ if (c == ectoc(abortc) && quotef == FALSE) {
+ /* Abort the input? */
+ ctrlg(FALSE, 0);
+ TTflush();
+ return(ABORT);
+ } else if ((c==0x7F || c==0x08) && quotef==FALSE) {
+ /* rubout/erase */
+ if (cpos != 0) {
+ outstring("\b \b");
+ --ttcol;
+
+ if (buf[--cpos] < 0x20) {
+ outstring("\b \b");
+ --ttcol;
+ }
+ if (buf[cpos] == '\n') {
+ outstring("\b\b \b\b");
+ ttcol -= 2;
+ }
+
+ TTflush();
+ }
+
+ } else if (c == 0x15 && quotef == FALSE) {
+ /* C-U, kill */
+ while (cpos != 0) {
+ outstring("\b \b");
+ --ttcol;
+
+ if (buf[--cpos] < 0x20) {
+ outstring("\b \b");
+ --ttcol;
+ }
+ if (buf[cpos] == '\n') {
+ outstring("\b\b \b\b");
+ ttcol -= 2;
+ }
+ }
+ TTflush();
+
+#if COMPLC
+ } else if ((c == 0x09 || c == ' ') && quotef == FALSE && ffile) {
+ /* TAB, complete file name */
+ char ffbuf[255];
+#if MSDOS
+ char sffbuf[128];
+ int lsav = -1;
+#endif
+ int n, iswild = 0;
+
+ didtry = 1;
+ ocpos = cpos;
+ while (cpos != 0) {
+ outstring("\b \b");
+ --ttcol;
+
+ if (buf[--cpos] < 0x20) {
+ outstring("\b \b");
+ --ttcol;
+ }
+ if (buf[cpos] == '\n') {
+ outstring("\b\b \b\b");
+ ttcol -= 2;
+ }
+ if (buf[cpos] == '*' || buf[cpos] == '?')
+ iswild = 1;
+#if MSDOS
+ if (lsav < 0 && (buf[cpos] == '\\' ||
+ buf[cpos] == '/' ||
+ buf[cpos] == ':' && cpos == 1))
+ lsav = cpos;
+#endif
+ }
+ TTflush();
+ if (nskip < 0)
+ {
+ buf[ocpos] = 0;
+#if UNIX
+ if (tmpf != NULL)
+ fclose(tmpf);
+ strcpy(tmp, "/tmp/meXXXXXX");
+ strcpy(ffbuf, "echo ");
+ strcat(ffbuf, buf);
+ if (! iswild)
+ strcat(ffbuf,"*");
+ strcat(ffbuf, " >");
+ mktemp(tmp);
+ strcat(ffbuf, tmp);
+ strcat(ffbuf, " 2>&1");
+ system(ffbuf);
+ tmpf = fopen(tmp, "r");
+#endif
+#if MSDOS
+ strcpy(sffbuf, buf);
+ if (! iswild)
+ strcat(sffbuf,"*.*");
+#endif
+ nskip = 0;
+ }
+#if UNIX
+ c = ' ';
+ for (n = nskip; n > 0; n--)
+ while ((c = getc(tmpf)) != EOF && c != ' ');
+#endif
+#if MSDOS
+ if (nskip == 0)
+ {
+ strcpy(ffbuf, sffbuf);
+ c = findfirst(ffbuf, &ffblk, FA_DIREC) ? '*' : ' ';
+ }
+ else if (nskip > 0)
+ c = findnext(&ffblk) ? 0 : ' ';
+#endif
+ nskip++;
+
+ if (c != ' ')
+ {
+ TTbeep();
+ nskip = 0;
+ }
+
+#if UNIX
+ while ((c = getc(tmpf)) != EOF && c != '\n' && c != ' ' && c != '*')
+#endif
+#if MSDOS
+ if (c == '*')
+ fcp = sffbuf;
+ else
+ {
+ strncpy(buf, sffbuf, lsav+1);
+ cpos = lsav+1;
+ fcp = ffblk.ff_name;
+ }
+ while (c != 0 && (c = *fcp++) != 0 && c != '*')
+#endif
+ {
+ if (cpos < nbuf-1)
+ buf[cpos++] = c;
+ }
+#if UNIX
+ if (c == '*')
+ TTbeep();
+#endif
+
+ for (n = 0; n < cpos; n++)
+ {
+ c = buf[n];
+ if ((c < ' ') && (c != '\n')) {
+ outstring("^");
+ ++ttcol;
+ c ^= 0x40;
+ }
+
+ if (c != '\n') {
+ if (disinp)
+ TTputc(c);
+ } else { /* put out <NL> for <ret> */
+ outstring("<NL>");
+ ttcol += 3;
+ }
+ ++ttcol;
+ }
+ TTflush();
+#if UNIX
+ rewind(tmpf);
+ unlink(tmp);
+#endif
+#endif
+
+ } else if ((c == quotec || c == 0x16) && quotef == FALSE) {
+ quotef = TRUE;
+ } else {
+ quotef = FALSE;
+ if (cpos < nbuf-1) {
+ buf[cpos++] = c;
+
+ if ((c < ' ') && (c != '\n')) {
+ outstring("^");
+ ++ttcol;
+ c ^= 0x40;
+ }
+
+ if (c != '\n') {
+ if (disinp)
+ TTputc(c);
+ } else { /* put out <NL> for <ret> */
+ outstring("<NL>");
+ ttcol += 3;
+ }
+ ++ttcol;
+ TTflush();
+ }
+ }
+ }
+}
+
+outstring(s) /* output a string of characters */
+
+char *s; /* string to output */
+
+{
+ if (disinp)
+ while (*s)
+ TTputc(*s++);
+}
+
+ostring(s) /* output a string of output characters */
+
+char *s; /* string to output */
+
+{
+ if (discmd)
+ while (*s)
+ TTputc(*s++);
+}
+
diff --git a/isearch.c b/isearch.c
new file mode 100644
index 0000000..0f65069
--- /dev/null
+++ b/isearch.c
@@ -0,0 +1,521 @@
+/* ISEARCH.C
+ *
+ * The functions in this file implement commands that perform incremental
+ * searches in the forward and backward directions. This "ISearch" command
+ * is intended to emulate the same command from the original EMACS
+ * implementation (ITS). Contains references to routines internal to
+ * SEARCH.C.
+ *
+ * REVISION HISTORY:
+ *
+ * D. R. Banks 9-May-86
+ * - added ITS EMACSlike ISearch
+ *
+ * John M. Gamble 5-Oct-86
+ * - Made iterative search use search.c's scanner() routine.
+ * This allowed the elimination of bakscan().
+ * - Put isearch constants into estruct.h
+ * - Eliminated the passing of 'status' to scanmore() and
+ * checknext(), since there were no circumstances where
+ * it ever equalled FALSE.
+ *
+ * modified by Petri Kutvonen
+ */
+
+#include <stdio.h>
+#include "estruct.h"
+#include "edef.h"
+
+#if ISRCH
+
+extern int scanner(); /* Handy search routine */
+extern int eq(); /* Compare chars, match case */
+
+/* A couple of "own" variables for re-eat */
+
+int (*saved_get_char)(); /* Get character routine */
+int eaten_char = -1; /* Re-eaten char */
+
+/* A couple more "own" variables for the command string */
+
+int cmd_buff[CMDBUFLEN]; /* Save the command args here */
+int cmd_offset; /* Current offset into command buff */
+int cmd_reexecute = -1; /* > 0 if re-executing command */
+
+
+/*
+ * Subroutine to do incremental reverse search. It actually uses the
+ * same code as the normal incremental search, as both can go both ways.
+ */
+
+int risearch(f, n)
+{
+ LINE *curline; /* Current line on entry */
+ int curoff; /* Current offset on entry */
+
+ /* remember the initial . on entry: */
+
+ curline = curwp->w_dotp; /* Save the current line pointer */
+ curoff = curwp->w_doto; /* Save the current offset */
+
+ /* Make sure the search doesn't match where we already are: */
+
+ backchar(TRUE, 1); /* Back up a character */
+
+ if (!(isearch(f, -n))) /* Call ISearch backwards */
+ { /* If error in search: */
+ curwp->w_dotp = curline; /* Reset the line pointer */
+ curwp->w_doto = curoff; /* and the offset to original value */
+ curwp->w_flag |= WFMOVE; /* Say we've moved */
+ update(FALSE); /* And force an update */
+ mlwrite ("(search failed)"); /* Say we died */
+#if PKCODE
+ matchlen = strlen(pat);
+#endif
+ } else mlerase (); /* If happy, just erase the cmd line */
+#if PKCODE
+ matchlen = strlen(pat);
+#endif
+}
+
+/* Again, but for the forward direction */
+
+int fisearch(f, n)
+{
+ LINE *curline; /* Current line on entry */
+ int curoff; /* Current offset on entry */
+
+ /* remember the initial . on entry: */
+
+ curline = curwp->w_dotp; /* Save the current line pointer */
+ curoff = curwp->w_doto; /* Save the current offset */
+
+ /* do the search */
+
+ if (!(isearch(f, n))) /* Call ISearch forwards */
+ { /* If error in search: */
+ curwp->w_dotp = curline; /* Reset the line pointer */
+ curwp->w_doto = curoff; /* and the offset to original value */
+ curwp->w_flag |= WFMOVE; /* Say we've moved */
+ update(FALSE); /* And force an update */
+ mlwrite ("(search failed)"); /* Say we died */
+#if PKCODE
+ matchlen = strlen(pat);
+#endif
+ } else mlerase (); /* If happy, just erase the cmd line */
+#if PKCODE
+ matchlen = strlen(pat);
+#endif
+}
+
+/*
+ * Subroutine to do an incremental search. In general, this works similarly
+ * to the older micro-emacs search function, except that the search happens
+ * as each character is typed, with the screen and cursor updated with each
+ * new search character.
+ *
+ * While searching forward, each successive character will leave the cursor
+ * at the end of the entire matched string. Typing a Control-S or Control-X
+ * will cause the next occurrence of the string to be searched for (where the
+ * next occurrence does NOT overlap the current occurrence). A Control-R will
+ * change to a backwards search, META will terminate the search and Control-G
+ * will abort the search. Rubout will back up to the previous match of the
+ * string, or if the starting point is reached first, it will delete the
+ * last character from the search string.
+ *
+ * While searching backward, each successive character will leave the cursor
+ * at the beginning of the matched string. Typing a Control-R will search
+ * backward for the next occurrence of the string. Control-S or Control-X
+ * will revert the search to the forward direction. In general, the reverse
+ * incremental search is just like the forward incremental search inverted.
+ *
+ * In all cases, if the search fails, the user will be feeped, and the search
+ * will stall until the pattern string is edited back into something that
+ * exists (or until the search is aborted).
+ */
+
+isearch(f, n)
+{
+ int status; /* Search status */
+ int col; /* prompt column */
+ register int cpos; /* character number in search string */
+ register int c; /* current input character */
+ register int expc; /* function expanded input char */
+ char pat_save[NPAT]; /* Saved copy of the old pattern str */
+ LINE *curline; /* Current line on entry */
+ int curoff; /* Current offset on entry */
+ int init_direction; /* The initial search direction */
+
+ /* Initialize starting conditions */
+
+ cmd_reexecute = -1; /* We're not re-executing (yet?) */
+ cmd_offset = 0; /* Start at the beginning of the buff */
+ cmd_buff[0] = '\0'; /* Init the command buffer */
+ strncpy (pat_save, pat, NPAT); /* Save the old pattern string */
+ curline = curwp->w_dotp; /* Save the current line pointer */
+ curoff = curwp->w_doto; /* Save the current offset */
+ init_direction = n; /* Save the initial search direction */
+
+ /* This is a good place to start a re-execution: */
+
+start_over:
+
+ /* ask the user for the text of a pattern */
+ col = promptpattern("ISearch: "); /* Prompt, remember the col */
+
+ cpos = 0; /* Start afresh */
+ status = TRUE; /* Assume everything's cool */
+
+ /*
+ Get the first character in the pattern. If we get an initial Control-S
+ or Control-R, re-use the old search string and find the first occurrence
+ */
+
+ c = ectoc(expc = get_char()); /* Get the first character */
+ if ((c == IS_FORWARD) ||
+ (c == IS_REVERSE) ||
+ (c == IS_VMSFORW)) /* Reuse old search string? */
+ {
+ for (cpos = 0; pat[cpos] != 0; cpos++) /* Yup, find the length */
+ col = echochar(pat[cpos],col); /* and re-echo the string */
+ if (c == IS_REVERSE) { /* forward search? */
+ n = -1; /* No, search in reverse */
+ backchar (TRUE, 1); /* Be defensive about EOB */
+ } else
+ n = 1; /* Yes, search forward */
+ status = scanmore(pat, n); /* Do the search */
+ c = ectoc(expc = get_char()); /* Get another character */
+ }
+
+ /* Top of the per character loop */
+
+ for (;;) /* ISearch per character loop */
+ {
+ /* Check for special characters first: */
+ /* Most cases here change the search */
+
+ if (expc == metac) /* Want to quit searching? */
+ return (TRUE); /* Quit searching now */
+
+ switch (c) /* dispatch on the input char */
+ {
+ case IS_ABORT: /* If abort search request */
+ return(FALSE); /* Quit searching again */
+
+ case IS_REVERSE: /* If backward search */
+ case IS_FORWARD: /* If forward search */
+ case IS_VMSFORW: /* of either flavor */
+ if (c == IS_REVERSE) /* If reverse search */
+ n = -1; /* Set the reverse direction */
+ else /* Otherwise, */
+ n = 1; /* go forward */
+ status = scanmore(pat, n); /* Start the search again */
+ c = ectoc(expc = get_char()); /* Get the next char */
+ continue; /* Go continue with the search*/
+
+ case IS_NEWLINE: /* Carriage return */
+ c = '\n'; /* Make it a new line */
+ break; /* Make sure we use it */
+
+ case IS_QUOTE: /* Quote character */
+ case IS_VMSQUOTE: /* of either variety */
+ c = ectoc(expc = get_char()); /* Get the next char */
+
+ case IS_TAB: /* Generically allowed */
+ case '\n': /* controlled characters */
+ break; /* Make sure we use it */
+
+ case IS_BACKSP: /* If a backspace: */
+ case IS_RUBOUT: /* or if a Rubout: */
+ if (cmd_offset <= 1) /* Anything to delete? */
+ return (TRUE); /* No, just exit */
+ --cmd_offset; /* Back up over the Rubout */
+ cmd_buff[--cmd_offset] = '\0'; /* Yes, delete last char */
+ curwp->w_dotp = curline; /* Reset the line pointer */
+ curwp->w_doto = curoff; /* and the offset */
+ n = init_direction; /* Reset the search direction */
+ strncpy (pat, pat_save, NPAT); /* Restore the old search str */
+ cmd_reexecute = 0; /* Start the whole mess over */
+ goto start_over; /* Let it take care of itself */
+
+ /* Presumably a quasi-normal character comes here */
+
+ default: /* All other chars */
+ if (c < ' ') /* Is it printable? */
+ { /* Nope. */
+ reeat (c); /* Re-eat the char */
+ return (TRUE); /* And return the last status */
+ }
+ } /* Switch */
+
+ /* I guess we got something to search for, so search for it */
+
+ pat[cpos++] = c; /* put the char in the buffer */
+ if (cpos >= NPAT) /* too many chars in string? */
+ { /* Yup. Complain about it */
+ mlwrite("? Search string too long");
+ return(TRUE); /* Return an error */
+ }
+ pat[cpos] = 0; /* null terminate the buffer */
+ col = echochar(c,col); /* Echo the character */
+ if (!status) { /* If we lost last time */
+ TTputc(BELL); /* Feep again */
+ TTflush(); /* see that the feep feeps */
+ } else /* Otherwise, we must have won*/
+ if (!(status = checknext(c, pat, n))) /* See if match */
+ status = scanmore(pat, n); /* or find the next match */
+ c = ectoc(expc = get_char()); /* Get the next char */
+ } /* for {;;} */
+}
+
+/*
+ * Trivial routine to insure that the next character in the search string is
+ * still true to whatever we're pointing to in the buffer. This routine will
+ * not attempt to move the "point" if the match fails, although it will
+ * implicitly move the "point" if we're forward searching, and find a match,
+ * since that's the way forward isearch works.
+ *
+ * If the compare fails, we return FALSE and assume the caller will call
+ * scanmore or something.
+ */
+
+int checknext (chr, patrn, dir) /* Check next character in search string */
+char chr; /* Next char to look for */
+char *patrn; /* The entire search string (incl chr) */
+int dir; /* Search direction */
+{
+ register LINE *curline; /* current line during scan */
+ register int curoff; /* position within current line */
+ register int buffchar; /* character at current position */
+ int status; /* how well things go */
+
+
+ /* setup the local scan pointer to current "." */
+
+ curline = curwp->w_dotp; /* Get the current line structure */
+ curoff = curwp->w_doto; /* Get the offset within that line */
+
+ if (dir > 0) /* If searching forward */
+ {
+ if (curoff == llength(curline)) /* If at end of line */
+ {
+ curline = lforw(curline); /* Skip to the next line */
+ if (curline == curbp->b_linep)
+ return (FALSE); /* Abort if at end of buffer */
+ curoff = 0; /* Start at the beginning of the line */
+ buffchar = '\n'; /* And say the next char is NL */
+ } else
+ buffchar = lgetc(curline, curoff++); /* Get the next char */
+ if (status = eq(buffchar, chr)) /* Is it what we're looking for? */
+ {
+ curwp->w_dotp = curline; /* Yes, set the buffer's point */
+ curwp->w_doto = curoff; /* to the matched character */
+ curwp->w_flag |= WFMOVE; /* Say that we've moved */
+ }
+ return (status); /* And return the status */
+ } else /* Else, if reverse search: */
+ return (match_pat (patrn)); /* See if we're in the right place */
+}
+
+/*
+ * This hack will search for the next occurrence of <pat> in the buffer, either
+ * forward or backward. It is called with the status of the prior search
+ * attempt, so that it knows not to bother if it didn't work last time. If
+ * we can't find any more matches, "point" is left where it was before. If
+ * we do find a match, "point" will be at the end of the matched string for
+ * forward searches and at the beginning of the matched string for reverse
+ * searches.
+ */
+
+int scanmore(patrn, dir) /* search forward or back for a pattern */
+char *patrn; /* string to scan for */
+int dir; /* direction to search */
+{
+ int sts; /* search status */
+
+ if (dir < 0) /* reverse search? */
+ {
+ rvstrcpy(tap, patrn); /* Put reversed string in tap */
+ sts = scanner(tap, REVERSE, PTBEG);
+ }
+ else
+ sts = scanner(patrn, FORWARD, PTEND); /* Nope. Go forward */
+
+ if (!sts)
+ {
+ TTputc(BELL); /* Feep if search fails */
+ TTflush(); /* see that the feep feeps */
+ }
+
+ return(sts); /* else, don't even try */
+}
+
+/*
+ * The following is a worker subroutine used by the reverse search. It
+ * compares the pattern string with the characters at "." for equality. If
+ * any characters mismatch, it will return FALSE.
+ *
+ * This isn't used for forward searches, because forward searches leave "."
+ * at the end of the search string (instead of in front), so all that needs to
+ * be done is match the last char input.
+ */
+
+int match_pat (patrn) /* See if the pattern string matches string at "." */
+char *patrn; /* String to match to buffer */
+{
+ register int i; /* Generic loop index/offset */
+ register int buffchar; /* character at current position */
+ register LINE *curline; /* current line during scan */
+ register int curoff; /* position within current line */
+
+ /* setup the local scan pointer to current "." */
+
+ curline = curwp->w_dotp; /* Get the current line structure */
+ curoff = curwp->w_doto; /* Get the offset within that line */
+
+ /* top of per character compare loop: */
+
+ for (i = 0; i < strlen(patrn); i++) /* Loop for all characters in patrn */
+ {
+ if (curoff == llength(curline)) /* If at end of line */
+ {
+ curline = lforw(curline); /* Skip to the next line */
+ curoff = 0; /* Start at the beginning of the line */
+ if (curline == curbp->b_linep)
+ return (FALSE); /* Abort if at end of buffer */
+ buffchar = '\n'; /* And say the next char is NL */
+ } else
+ buffchar = lgetc(curline, curoff++); /* Get the next char */
+ if (!eq(buffchar, patrn[i])) /* Is it what we're looking for? */
+ return (FALSE); /* Nope, just punt it then */
+ }
+ return (TRUE); /* Everything matched? Let's celebrate*/
+}
+
+/* Routine to prompt for I-Search string. */
+
+int promptpattern(prompt)
+char *prompt;
+{
+ char tpat[NPAT+20];
+
+ strcpy(tpat, prompt); /* copy prompt to output string */
+ strcat(tpat, " ("); /* build new prompt string */
+ expandp(pat, &tpat[strlen(tpat)], NPAT/2); /* add old pattern */
+ strcat(tpat, ")<Meta>: ");
+
+ /* check to see if we are executing a command line */
+ if (!clexec) {
+ mlwrite(tpat);
+ }
+ return(strlen(tpat));
+}
+
+/* routine to echo i-search characters */
+
+int echochar(c,col)
+int c; /* character to be echoed */
+int col; /* column to be echoed in */
+{
+ movecursor(term.t_nrow,col); /* Position the cursor */
+ if ((c < ' ') || (c == 0x7F)) /* Control character? */
+ {
+ switch (c) /* Yes, dispatch special cases*/
+ {
+ case '\n': /* Newline */
+ TTputc('<');
+ TTputc('N');
+ TTputc('L');
+ TTputc('>');
+ col += 3;
+ break;
+
+ case '\t': /* Tab */
+ TTputc('<');
+ TTputc('T');
+ TTputc('A');
+ TTputc('B');
+ TTputc('>');
+ col += 4;
+ break;
+
+ case 0x7F: /* Rubout: */
+ TTputc('^'); /* Output a funny looking */
+ TTputc('?'); /* indication of Rubout */
+ col++; /* Count the extra char */
+ break;
+
+ default: /* Vanilla control char */
+ TTputc('^'); /* Yes, output prefix */
+ TTputc(c+0x40); /* Make it "^X" */
+ col++; /* Count this char */
+ }
+ } else
+ TTputc(c); /* Otherwise, output raw char */
+ TTflush(); /* Flush the output */
+ return(++col); /* return the new column no */
+}
+
+/*
+ * Routine to get the next character from the input stream. If we're reading
+ * from the real terminal, force a screen update before we get the char.
+ * Otherwise, we must be re-executing the command string, so just return the
+ * next character.
+ */
+
+int get_char ()
+{
+ int c; /* A place to get a character */
+
+ /* See if we're re-executing: */
+
+ if (cmd_reexecute >= 0) /* Is there an offset? */
+ if ((c = cmd_buff[cmd_reexecute++]) != 0)
+ return (c); /* Yes, return any character */
+
+ /* We're not re-executing (or aren't any more). Try for a real char */
+
+ cmd_reexecute = -1; /* Say we're in real mode again */
+ update(FALSE); /* Pretty up the screen */
+ if (cmd_offset >= CMDBUFLEN-1) /* If we're getting too big ... */
+ {
+ mlwrite ("? command too long"); /* Complain loudly and bitterly */
+ return (metac); /* And force a quit */
+ }
+ c = get1key(); /* Get the next character */
+ cmd_buff[cmd_offset++] = c; /* Save the char for next time */
+ cmd_buff[cmd_offset] = '\0';/* And terminate the buffer */
+ return (c); /* Return the character */
+}
+
+/*
+ * Hacky routine to re-eat a character. This will save the character to be
+ * re-eaten by redirecting the input call to a routine here. Hack, etc.
+ */
+
+/* Come here on the next term.t_getchar call: */
+
+int uneat()
+{
+ int c;
+
+ term.t_getchar = saved_get_char; /* restore the routine address */
+ c = eaten_char; /* Get the re-eaten char */
+ eaten_char = -1; /* Clear the old char */
+ return(c); /* and return the last char */
+}
+
+int reeat(c)
+int c;
+{
+ if (eaten_char != -1) /* If we've already been here */
+ return/*(NULL)*/; /* Don't do it again */
+ eaten_char = c; /* Else, save the char for later */
+ saved_get_char = term.t_getchar; /* Save the char get routine */
+ term.t_getchar = uneat; /* Replace it with ours */
+}
+#else
+isearch()
+{
+}
+#endif
diff --git a/line.c b/line.c
new file mode 100644
index 0000000..0bbbdc3
--- /dev/null
+++ b/line.c
@@ -0,0 +1,655 @@
+/* LINE.C
+ *
+ * The functions in this file are a general set of line management utilities.
+ * They are the only routines that touch the text. They also touch the buffer
+ * and window structures, to make sure that the necessary updating gets done.
+ * There are routines in this file that handle the kill buffer too. It isn't
+ * here for any good reason.
+ *
+ * Note that this code only updates the dot and mark values in the window list.
+ * Since all the code acts on the current window, the buffer that we are
+ * editing must be being displayed, which means that "b_nwnd" is non zero,
+ * which means that the dot and mark values in the buffer headers are nonsense.
+ *
+ */
+
+#include <stdio.h>
+#include "estruct.h"
+#include "edef.h"
+
+KILL *ykbuf; /* ptr to current kill buffer chunk being yanked */
+int ykboff; /* offset into that chunk */
+
+/*
+ * This routine allocates a block of memory large enough to hold a LINE
+ * containing "used" characters. The block is always rounded up a bit. Return
+ * a pointer to the new block, or NULL if there isn't any memory left. Print a
+ * message in the message line if no space.
+ */
+LINE *lalloc(used)
+
+register int used;
+
+{
+ register LINE *lp;
+ register int size;
+ char *malloc();
+
+ size = (used+NBLOCK-1) & ~(NBLOCK-1);
+ if (size == 0) /* Assume that an empty */
+ size = NBLOCK; /* line is for type-in. */
+ if ((lp = (LINE *) malloc(sizeof(LINE)+size)) == NULL) {
+ mlwrite("(OUT OF MEMORY)");
+ return (NULL);
+ }
+ lp->l_size = size;
+ lp->l_used = used;
+ return (lp);
+}
+
+/*
+ * Delete line "lp". Fix all of the links that might point at it (they are
+ * moved to offset 0 of the next line. Unlink the line from whatever buffer it
+ * might be in. Release the memory. The buffers are updated too; the magic
+ * conditions described in the above comments don't hold here.
+ */
+lfree(lp)
+register LINE *lp;
+{
+ register BUFFER *bp;
+ register WINDOW *wp;
+
+ wp = wheadp;
+ while (wp != NULL) {
+ if (wp->w_linep == lp)
+ wp->w_linep = lp->l_fp;
+ if (wp->w_dotp == lp) {
+ wp->w_dotp = lp->l_fp;
+ wp->w_doto = 0;
+ }
+ if (wp->w_markp == lp) {
+ wp->w_markp = lp->l_fp;
+ wp->w_marko = 0;
+ }
+ wp = wp->w_wndp;
+ }
+ bp = bheadp;
+ while (bp != NULL) {
+ if (bp->b_nwnd == 0) {
+ if (bp->b_dotp == lp) {
+ bp->b_dotp = lp->l_fp;
+ bp->b_doto = 0;
+ }
+ if (bp->b_markp == lp) {
+ bp->b_markp = lp->l_fp;
+ bp->b_marko = 0;
+ }
+ }
+ bp = bp->b_bufp;
+ }
+ lp->l_bp->l_fp = lp->l_fp;
+ lp->l_fp->l_bp = lp->l_bp;
+ free((char *) lp);
+}
+
+/*
+ * This routine gets called when a character is changed in place in the current
+ * buffer. It updates all of the required flags in the buffer and window
+ * system. The flag used is passed as an argument; if the buffer is being
+ * displayed in more than 1 window we change EDIT t HARD. Set MODE if the
+ * mode line needs to be updated (the "*" has to be set).
+ */
+lchange(flag)
+register int flag;
+{
+ register WINDOW *wp;
+
+ if (curbp->b_nwnd != 1) /* Ensure hard. */
+ flag = WFHARD;
+ if ((curbp->b_flag&BFCHG) == 0) { /* First change, so */
+ flag |= WFMODE; /* update mode lines. */
+ curbp->b_flag |= BFCHG;
+ }
+ wp = wheadp;
+ while (wp != NULL) {
+ if (wp->w_bufp == curbp)
+ wp->w_flag |= flag;
+ wp = wp->w_wndp;
+ }
+}
+
+insspace(f, n) /* insert spaces forward into text */
+
+int f, n; /* default flag and numeric argument */
+
+{
+ linsert(n, ' ');
+ backchar(f, n);
+}
+
+/*
+ * linstr -- Insert a string at the current point
+ */
+
+linstr(instr)
+char *instr;
+{
+ register int status = TRUE;
+ char tmpc;
+
+ if (instr != NULL)
+ while ((tmpc = *instr) && status == TRUE) {
+ status = (tmpc == '\n'? lnewline(): linsert(1, tmpc));
+
+ /* Insertion error? */
+ if (status != TRUE) {
+ mlwrite("%%Out of memory while inserting");
+ break;
+ }
+ instr++;
+ }
+ return(status);
+}
+
+/*
+ * Insert "n" copies of the character "c" at the current location of dot. In
+ * the easy case all that happens is the text is stored in the line. In the
+ * hard case, the line has to be reallocated. When the window list is updated,
+ * take special care; I screwed it up once. You always update dot in the
+ * current window. You update mark, and a dot in another window, if it is
+ * greater than the place where you did the insert. Return TRUE if all is
+ * well, and FALSE on errors.
+ */
+
+linsert(n, c)
+{
+ register char *cp1;
+ register char *cp2;
+ register LINE *lp1;
+ register LINE *lp2;
+ register LINE *lp3;
+ register int doto;
+ register int i;
+ register WINDOW *wp;
+
+ if (curbp->b_mode&MDVIEW) /* don't allow this command if */
+ return(rdonly()); /* we are in read only mode */
+ lchange(WFEDIT);
+ lp1 = curwp->w_dotp; /* Current line */
+ if (lp1 == curbp->b_linep) { /* At the end: special */
+ if (curwp->w_doto != 0) {
+ mlwrite("bug: linsert");
+ return (FALSE);
+ }
+ if ((lp2=lalloc(n)) == NULL) /* Allocate new line */
+ return (FALSE);
+ lp3 = lp1->l_bp; /* Previous line */
+ lp3->l_fp = lp2; /* Link in */
+ lp2->l_fp = lp1;
+ lp1->l_bp = lp2;
+ lp2->l_bp = lp3;
+ for (i=0; i<n; ++i)
+ lp2->l_text[i] = c;
+ curwp->w_dotp = lp2;
+ curwp->w_doto = n;
+ return (TRUE);
+ }
+ doto = curwp->w_doto; /* Save for later. */
+ if (lp1->l_used+n > lp1->l_size) { /* Hard: reallocate */
+ if ((lp2=lalloc(lp1->l_used+n)) == NULL)
+ return (FALSE);
+ cp1 = &lp1->l_text[0];
+ cp2 = &lp2->l_text[0];
+ while (cp1 != &lp1->l_text[doto])
+ *cp2++ = *cp1++;
+ cp2 += n;
+ while (cp1 != &lp1->l_text[lp1->l_used])
+ *cp2++ = *cp1++;
+ lp1->l_bp->l_fp = lp2;
+ lp2->l_fp = lp1->l_fp;
+ lp1->l_fp->l_bp = lp2;
+ lp2->l_bp = lp1->l_bp;
+ free((char *) lp1);
+ } else { /* Easy: in place */
+ lp2 = lp1; /* Pretend new line */
+ lp2->l_used += n;
+ cp2 = &lp1->l_text[lp1->l_used];
+ cp1 = cp2-n;
+ while (cp1 != &lp1->l_text[doto])
+ *--cp2 = *--cp1;
+ }
+ for (i=0; i<n; ++i) /* Add the characters */
+ lp2->l_text[doto+i] = c;
+ wp = wheadp; /* Update windows */
+ while (wp != NULL) {
+ if (wp->w_linep == lp1)
+ wp->w_linep = lp2;
+ if (wp->w_dotp == lp1) {
+ wp->w_dotp = lp2;
+ if (wp==curwp || wp->w_doto>doto)
+ wp->w_doto += n;
+ }
+ if (wp->w_markp == lp1) {
+ wp->w_markp = lp2;
+ if (wp->w_marko > doto)
+ wp->w_marko += n;
+ }
+ wp = wp->w_wndp;
+ }
+ return (TRUE);
+}
+
+/*
+ * Overwrite a character into the current line at the current position
+ *
+ */
+
+lowrite(c)
+
+char c; /* character to overwrite on current position */
+
+{
+ if (curwp->w_doto < curwp->w_dotp->l_used &&
+ (lgetc(curwp->w_dotp, curwp->w_doto) != '\t' ||
+ ((curwp->w_doto) & tabmask) == tabmask))
+ ldelete(1L, FALSE);
+ return(linsert(1, c));
+}
+
+/*
+ * lover -- Overwrite a string at the current point
+ */
+
+lover(ostr)
+
+char *ostr;
+
+{
+ register int status = TRUE;
+ char tmpc;
+
+ if (ostr != NULL)
+ while ((tmpc = *ostr) && status == TRUE) {
+ status = (tmpc == '\n'? lnewline(): lowrite(tmpc));
+
+ /* Insertion error? */
+ if (status != TRUE) {
+ mlwrite("%%Out of memory while overwriting");
+ break;
+ }
+ ostr++;
+ }
+ return(status);
+}
+
+/*
+ * Insert a newline into the buffer at the current location of dot in the
+ * current window. The funny ass-backwards way it does things is not a botch;
+ * it just makes the last line in the file not a special case. Return TRUE if
+ * everything works out and FALSE on error (memory allocation failure). The
+ * update of dot and mark is a bit easier then in the above case, because the
+ * split forces more updating.
+ */
+lnewline()
+{
+ register char *cp1;
+ register char *cp2;
+ register LINE *lp1;
+ register LINE *lp2;
+ register int doto;
+ register WINDOW *wp;
+
+ if (curbp->b_mode&MDVIEW) /* don't allow this command if */
+ return(rdonly()); /* we are in read only mode */
+#if SCROLLCODE
+ lchange(WFHARD|WFINS);
+#else
+ lchange(WFHARD);
+#endif
+ lp1 = curwp->w_dotp; /* Get the address and */
+ doto = curwp->w_doto; /* offset of "." */
+ if ((lp2=lalloc(doto)) == NULL) /* New first half line */
+ return (FALSE);
+ cp1 = &lp1->l_text[0]; /* Shuffle text around */
+ cp2 = &lp2->l_text[0];
+ while (cp1 != &lp1->l_text[doto])
+ *cp2++ = *cp1++;
+ cp2 = &lp1->l_text[0];
+ while (cp1 != &lp1->l_text[lp1->l_used])
+ *cp2++ = *cp1++;
+ lp1->l_used -= doto;
+ lp2->l_bp = lp1->l_bp;
+ lp1->l_bp = lp2;
+ lp2->l_bp->l_fp = lp2;
+ lp2->l_fp = lp1;
+ wp = wheadp; /* Windows */
+ while (wp != NULL) {
+ if (wp->w_linep == lp1)
+ wp->w_linep = lp2;
+ if (wp->w_dotp == lp1) {
+ if (wp->w_doto < doto)
+ wp->w_dotp = lp2;
+ else
+ wp->w_doto -= doto;
+ }
+ if (wp->w_markp == lp1) {
+ if (wp->w_marko < doto)
+ wp->w_markp = lp2;
+ else
+ wp->w_marko -= doto;
+ }
+ wp = wp->w_wndp;
+ }
+ return (TRUE);
+}
+
+/*
+ * This function deletes "n" bytes, starting at dot. It understands how do deal
+ * with end of lines, etc. It returns TRUE if all of the characters were
+ * deleted, and FALSE if they were not (because dot ran into the end of the
+ * buffer. The "kflag" is TRUE if the text should be put in the kill buffer.
+ */
+ldelete(n, kflag)
+
+long n; /* # of chars to delete */
+int kflag; /* put killed text in kill buffer flag */
+
+{
+ register char *cp1;
+ register char *cp2;
+ register LINE *dotp;
+ register int doto;
+ register int chunk;
+ register WINDOW *wp;
+
+ if (curbp->b_mode&MDVIEW) /* don't allow this command if */
+ return(rdonly()); /* we are in read only mode */
+ while (n != 0) {
+ dotp = curwp->w_dotp;
+ doto = curwp->w_doto;
+ if (dotp == curbp->b_linep) /* Hit end of buffer. */
+ return (FALSE);
+ chunk = dotp->l_used-doto; /* Size of chunk. */
+ if (chunk > n)
+ chunk = n;
+ if (chunk == 0) { /* End of line, merge. */
+#if SCROLLCODE
+ lchange(WFHARD|WFKILLS);
+#else
+ lchange(WFHARD);
+#endif
+ if (ldelnewline() == FALSE
+ || (kflag!=FALSE && kinsert('\n')==FALSE))
+ return (FALSE);
+ --n;
+ continue;
+ }
+ lchange(WFEDIT);
+ cp1 = &dotp->l_text[doto]; /* Scrunch text. */
+ cp2 = cp1 + chunk;
+ if (kflag != FALSE) { /* Kill? */
+ while (cp1 != cp2) {
+ if (kinsert(*cp1) == FALSE)
+ return (FALSE);
+ ++cp1;
+ }
+ cp1 = &dotp->l_text[doto];
+ }
+ while (cp2 != &dotp->l_text[dotp->l_used])
+ *cp1++ = *cp2++;
+ dotp->l_used -= chunk;
+ wp = wheadp; /* Fix windows */
+ while (wp != NULL) {
+ if (wp->w_dotp==dotp && wp->w_doto>=doto) {
+ wp->w_doto -= chunk;
+ if (wp->w_doto < doto)
+ wp->w_doto = doto;
+ }
+ if (wp->w_markp==dotp && wp->w_marko>=doto) {
+ wp->w_marko -= chunk;
+ if (wp->w_marko < doto)
+ wp->w_marko = doto;
+ }
+ wp = wp->w_wndp;
+ }
+ n -= chunk;
+ }
+ return (TRUE);
+}
+
+/* getctext: grab and return a string with the text of
+ the current line
+*/
+
+char *getctext()
+
+{
+ register LINE *lp; /* line to copy */
+ register int size; /* length of line to return */
+ register char *sp; /* string pointer into line */
+ register char *dp; /* string pointer into returned line */
+ static char rline[NSTRING]; /* line to return */
+
+ /* find the contents of the current line and its length */
+ lp = curwp->w_dotp;
+ sp = lp->l_text;
+ size = lp->l_used;
+ if (size >= NSTRING)
+ size = NSTRING - 1;
+
+ /* copy it across */
+ dp = rline;
+ while (size--)
+ *dp++ = *sp++;
+ *dp = 0;
+ return(rline);
+}
+
+/* putctext: replace the current line with the passed in text */
+
+putctext(iline)
+
+char *iline; /* contents of new line */
+
+{
+ register int status;
+
+ /* delete the current line */
+ curwp->w_doto = 0; /* starting at the beginning of the line */
+ if ((status = killtext(TRUE, 1)) != TRUE)
+ return(status);
+
+ /* insert the new line */
+ if ((status = linstr(iline)) != TRUE)
+ return(status);
+ status = lnewline();
+ backline(TRUE, 1);
+ return(status);
+}
+
+/*
+ * Delete a newline. Join the current line with the next line. If the next line
+ * is the magic header line always return TRUE; merging the last line with the
+ * header line can be thought of as always being a successful operation, even
+ * if nothing is done, and this makes the kill buffer work "right". Easy cases
+ * can be done by shuffling data around. Hard cases require that lines be moved
+ * about in memory. Return FALSE on error and TRUE if all looks ok. Called by
+ * "ldelete" only.
+ */
+ldelnewline()
+{
+ register char *cp1;
+ register char *cp2;
+ register LINE *lp1;
+ register LINE *lp2;
+ register LINE *lp3;
+ register WINDOW *wp;
+
+ if (curbp->b_mode&MDVIEW) /* don't allow this command if */
+ return(rdonly()); /* we are in read only mode */
+ lp1 = curwp->w_dotp;
+ lp2 = lp1->l_fp;
+ if (lp2 == curbp->b_linep) { /* At the buffer end. */
+ if (lp1->l_used == 0) /* Blank line. */
+ lfree(lp1);
+ return (TRUE);
+ }
+ if (lp2->l_used <= lp1->l_size-lp1->l_used) {
+ cp1 = &lp1->l_text[lp1->l_used];
+ cp2 = &lp2->l_text[0];
+ while (cp2 != &lp2->l_text[lp2->l_used])
+ *cp1++ = *cp2++;
+ wp = wheadp;
+ while (wp != NULL) {
+ if (wp->w_linep == lp2)
+ wp->w_linep = lp1;
+ if (wp->w_dotp == lp2) {
+ wp->w_dotp = lp1;
+ wp->w_doto += lp1->l_used;
+ }
+ if (wp->w_markp == lp2) {
+ wp->w_markp = lp1;
+ wp->w_marko += lp1->l_used;
+ }
+ wp = wp->w_wndp;
+ }
+ lp1->l_used += lp2->l_used;
+ lp1->l_fp = lp2->l_fp;
+ lp2->l_fp->l_bp = lp1;
+ free((char *) lp2);
+ return (TRUE);
+ }
+ if ((lp3=lalloc(lp1->l_used+lp2->l_used)) == NULL)
+ return (FALSE);
+ cp1 = &lp1->l_text[0];
+ cp2 = &lp3->l_text[0];
+ while (cp1 != &lp1->l_text[lp1->l_used])
+ *cp2++ = *cp1++;
+ cp1 = &lp2->l_text[0];
+ while (cp1 != &lp2->l_text[lp2->l_used])
+ *cp2++ = *cp1++;
+ lp1->l_bp->l_fp = lp3;
+ lp3->l_fp = lp2->l_fp;
+ lp2->l_fp->l_bp = lp3;
+ lp3->l_bp = lp1->l_bp;
+ wp = wheadp;
+ while (wp != NULL) {
+ if (wp->w_linep==lp1 || wp->w_linep==lp2)
+ wp->w_linep = lp3;
+ if (wp->w_dotp == lp1)
+ wp->w_dotp = lp3;
+ else if (wp->w_dotp == lp2) {
+ wp->w_dotp = lp3;
+ wp->w_doto += lp1->l_used;
+ }
+ if (wp->w_markp == lp1)
+ wp->w_markp = lp3;
+ else if (wp->w_markp == lp2) {
+ wp->w_markp = lp3;
+ wp->w_marko += lp1->l_used;
+ }
+ wp = wp->w_wndp;
+ }
+ free((char *) lp1);
+ free((char *) lp2);
+ return (TRUE);
+}
+
+/*
+ * Delete all of the text saved in the kill buffer. Called by commands when a
+ * new kill context is being created. The kill buffer array is released, just
+ * in case the buffer has grown to immense size. No errors.
+ */
+kdelete()
+{
+ KILL *kp; /* ptr to scan kill buffer chunk list */
+
+ if (kbufh != NULL) {
+
+ /* first, delete all the chunks */
+ kbufp = kbufh;
+ while (kbufp != NULL) {
+ kp = kbufp->d_next;
+ free(kbufp);
+ kbufp = kp;
+ }
+
+ /* and reset all the kill buffer pointers */
+ kbufh = kbufp = NULL;
+ kused = KBLOCK;
+ }
+}
+
+/*
+ * Insert a character to the kill buffer, allocating new chunks as needed.
+ * Return TRUE if all is well, and FALSE on errors.
+ */
+
+kinsert(c)
+
+int c; /* character to insert in the kill buffer */
+
+{
+ KILL *nchunk; /* ptr to newly malloced chunk */
+
+ /* check to see if we need a new chunk */
+ if (kused >= KBLOCK) {
+ if ((nchunk = (KILL *)malloc(sizeof(KILL))) == NULL)
+ return(FALSE);
+ if (kbufh == NULL) /* set head ptr if first time */
+ kbufh = nchunk;
+ if (kbufp != NULL) /* point the current to this new one */
+ kbufp->d_next = nchunk;
+ kbufp = nchunk;
+ kbufp->d_next = NULL;
+ kused = 0;
+ }
+
+ /* and now insert the character */
+ kbufp->d_chunk[kused++] = c;
+ return(TRUE);
+}
+
+/*
+ * Yank text back from the kill buffer. This is really easy. All of the work
+ * is done by the standard insert routines. All you do is run the loop, and
+ * check for errors. Bound to "C-Y".
+ */
+yank(f, n)
+{
+ register int c;
+ register int i;
+ register char *sp; /* pointer into string to insert */
+ KILL *kp; /* pointer into kill buffer */
+
+ if (curbp->b_mode&MDVIEW) /* don't allow this command if */
+ return(rdonly()); /* we are in read only mode */
+ if (n < 0)
+ return (FALSE);
+ /* make sure there is something to yank */
+ if (kbufh == NULL)
+ return(TRUE); /* not an error, just nothing */
+
+ /* for each time.... */
+ while (n--) {
+ kp = kbufh;
+ while (kp != NULL) {
+ if (kp->d_next == NULL)
+ i = kused;
+ else
+ i = KBLOCK;
+ sp = kp->d_chunk;
+ while (i--) {
+ if ((c = *sp++) == '\n') {
+ if (lnewline() == FALSE)
+ return (FALSE);
+ } else {
+ if (linsert(1, c) == FALSE)
+ return (FALSE);
+ }
+ }
+ kp = kp->d_next;
+ }
+ }
+ return (TRUE);
+}
diff --git a/lock.c b/lock.c
new file mode 100644
index 0000000..76d838c
--- /dev/null
+++ b/lock.c
@@ -0,0 +1,166 @@
+/* LOCK.C
+ *
+ * File locking command routines
+ *
+ * written by Daniel Lawrence
+ */
+
+#include <stdio.h>
+#include "estruct.h"
+#include "edef.h"
+
+#if FILOCK
+#if BSD | SVR4
+#include <sys/errno.h>
+
+extern int sys_nerr; /* number of system error messages defined */
+extern int errno; /* current error */
+
+char *lname[NLOCKS]; /* names of all locked files */
+int numlocks; /* # of current locks active */
+
+/* lockchk: check a file for locking and add it to the list */
+
+lockchk(fname)
+
+char *fname; /* file to check for a lock */
+
+{
+ register int i; /* loop indexes */
+ register int status; /* return status */
+ char *undolock();
+
+ /* check to see if that file is already locked here */
+ if (numlocks > 0)
+ for (i=0; i < numlocks; ++i)
+ if (strcmp(fname, lname[i]) == 0)
+ return(TRUE);
+
+ /* if we have a full locking table, bitch and leave */
+ if (numlocks == NLOCKS) {
+ mlwrite("LOCK ERROR: Lock table full");
+ return(ABORT);
+ }
+
+ /* next, try to lock it */
+ status = lock(fname);
+ if (status == ABORT) /* file is locked, no override */
+ return(ABORT);
+ if (status == FALSE) /* locked, overriden, dont add to table */
+ return(TRUE);
+
+ /* we have now locked it, add it to our table */
+ lname[++numlocks - 1] = (char *)malloc(strlen(fname) + 1);
+ if (lname[numlocks - 1] == NULL) { /* malloc failure */
+ undolock(fname); /* free the lock */
+ mlwrite("Cannot lock, out of memory");
+ --numlocks;
+ return(ABORT);
+ }
+
+ /* everthing is cool, add it to the table */
+ strcpy(lname[numlocks-1], fname);
+ return(TRUE);
+}
+
+/* lockrel: release all the file locks so others may edit */
+
+lockrel()
+
+{
+ register int i; /* loop index */
+ register int status; /* status of locks */
+ register int s; /* status of one unlock */
+
+ status = TRUE;
+ if (numlocks > 0)
+ for (i=0; i < numlocks; ++i) {
+ if ((s = unlock(lname[i])) != TRUE)
+ status = s;
+ free(lname[i]);
+ }
+ numlocks = 0;
+ return(status);
+}
+
+/* lock: Check and lock a file from access by others
+ returns TRUE = files was not locked and now is
+ FALSE = file was locked and overridden
+ ABORT = file was locked, abort command
+*/
+
+lock(fname)
+
+char *fname; /* file name to lock */
+
+{
+ register char *locker; /* lock error message */
+ register int status; /* return status */
+ char msg[NSTRING]; /* message string */
+ char *dolock();
+
+ /* attempt to lock the file */
+ locker = dolock(fname);
+ if (locker == NULL) /* we win */
+ return(TRUE);
+
+ /* file failed...abort */
+ if (strncmp(locker, "LOCK", 4) == 0) {
+ lckerror(locker);
+ return(ABORT);
+ }
+
+ /* someone else has it....override? */
+ strcpy(msg, "File in use by ");
+ strcat(msg, locker);
+ strcat(msg, ", override?");
+ status = mlyesno(msg); /* ask them */
+ if (status == TRUE)
+ return(FALSE);
+ else
+ return(ABORT);
+}
+
+/* unlock: Unlock a file
+ this only warns the user if it fails
+ */
+
+unlock(fname)
+
+char *fname; /* file to unlock */
+
+{
+ register char *locker; /* undolock return string */
+ char *undolock();
+
+ /* unclock and return */
+ locker = undolock(fname);
+ if (locker == NULL)
+ return(TRUE);
+
+ /* report the error and come back */
+ lckerror(locker);
+ return(FALSE);
+}
+
+lckerror(errstr) /* report a lock error */
+
+char *errstr; /* lock error string to print out */
+
+{
+ char obuf[NSTRING]; /* output buffer for error message */
+
+ strcpy(obuf, errstr);
+ strcat(obuf, " - ");
+ if (errno < sys_nerr)
+ strcat(obuf, sys_errlist[errno]);
+ else
+ strcat(obuf, "(can not get system error message)");
+ mlwrite(obuf);
+}
+#endif
+#else
+lckhello() /* dummy function */
+{
+}
+#endif
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..800a7b0
--- /dev/null
+++ b/main.c
@@ -0,0 +1,895 @@
+/*
+ * uEmacs/PK 4.0
+ *
+ * based on
+ *
+ * MicroEMACS 3.9
+ * written by Dave G. Conroy.
+ * substatially modified by Daniel M. Lawrence
+ * modified by Petri Kutvonen
+ *
+ * MicroEMACS 3.9 (C)opyright 1987 by Daniel M. Lawrence
+ *
+ * Original statement of copying policy:
+ *
+ * MicroEMACS 3.9 can be copied and distributed freely for any
+ * non-commercial purposes. MicroEMACS 3.9 can only be incorporated
+ * into commercial software with the permission of the current author.
+ *
+ * No copyright claimed for modifications made by Petri Kutvonen.
+ *
+ * MAIN.C
+ *
+ * This file contains the main driving routine, and some keyboard
+ * processing code.
+ *
+ * REVISION HISTORY:
+ *
+ * 1.0 Steve Wilhite, 30-Nov-85
+ *
+ * 2.0 George Jones, 12-Dec-85
+ *
+ * 3.0 Daniel Lawrence, 29-Dec-85
+ *
+ * 3.2-3.6 Daniel Lawrence, Feb...Apr-86
+ *
+ * 3.7 Daniel Lawrence, 14-May-86
+ *
+ * 3.8 Daniel Lawrence, 18-Jan-87
+ *
+ * 3.9 Daniel Lawrence, 16-Jul-87
+ *
+ * 3.9e Daniel Lawrence, 16-Nov-87
+ *
+ * After that versions 3.X and Daniel Lawrence went their own ways.
+ * A modified 3.9e/PK was heavily used at the University of Helsinki
+ * for several years on different UNIX, VMS, and MSDOS platforms.
+ *
+ * This modified version is now called eEmacs/PK.
+ *
+ * 4.0 Petri Kutvonen, 1-Sep-91
+ *
+ */
+
+#include <stdio.h>
+
+/* make global definitions not external */
+#define maindef
+
+#include "estruct.h" /* global structures and defines */
+#include "efunc.h" /* function declarations and name table */
+#include "edef.h" /* global definitions */
+#include "ebind.h" /* default key bindings */
+
+/* for MSDOS, increase the default stack space */
+
+#if MSDOS & TURBO
+#if PKCODE
+extern unsigned _stklen = 20000;
+#else
+extern unsigned _stklen = 32766;
+#endif
+#endif
+
+#if VMS
+#include <ssdef.h>
+#define GOOD (SS$_NORMAL)
+#endif
+
+#ifndef GOOD
+#define GOOD 0
+#endif
+
+#if UNIX
+#include <signal.h>
+#endif
+
+#if CALLED
+emacs(argc, argv)
+#else
+main(argc, argv)
+#endif
+int argc; /* # of arguments */
+char *argv[]; /* argument strings */
+
+{
+ register int c; /* command character */
+ register int f; /* default flag */
+ register int n; /* numeric repeat count */
+ register int mflag; /* negative flag on repeat */
+ register BUFFER *bp; /* temp buffer pointer */
+ register int firstfile; /* first file flag */
+ register int carg; /* current arg to scan */
+ register int startflag; /* startup executed flag */
+ BUFFER *firstbp = NULL; /* ptr to first buffer in cmd line */
+ int basec; /* c stripped of meta character */
+ int viewflag; /* are we starting in view mode? */
+ int gotoflag; /* do we need to goto a line at start? */
+ int gline; /* if so, what line? */
+ int searchflag; /* Do we need to search at start? */
+ int saveflag; /* temp store for lastflag */
+ int errflag; /* C error processing? */
+ char bname[NBUFN]; /* buffer name of file to read */
+#if CRYPT
+ int cryptflag; /* encrypting on the way in? */
+ char ekey[NPAT]; /* startup encryption key */
+#endif
+ char *strncpy();
+ extern *pathname[]; /* startup file path/name array */
+ int newc;
+#if PKCODE
+ int (*getbind())();
+ int (*execfunc)(); /* ptr to function to execute */
+#endif
+
+#if UNIX
+ static void emergencyexit();
+#ifdef SIGWINCH
+ extern void sizesignal();
+#endif
+#endif
+
+#if PKCODE & VMS
+ (void) umask(-1); /* use old protection (this is at wrong place) */
+#endif
+
+#if PKCODE & BSD
+ sleep(1); /* time for window manager */
+#endif
+
+#if UNIX
+#ifdef SIGWINCH
+ signal(SIGWINCH, sizesignal);
+#endif
+#endif
+
+ /* initialize the editor */
+ vtinit(); /* Display */
+ edinit("main"); /* Buffers, windows */
+ varinit(); /* user variables */
+
+ viewflag = FALSE; /* view mode defaults off in command line */
+ gotoflag = FALSE; /* set to off to begin with */
+ searchflag = FALSE; /* set to off to begin with */
+ firstfile = TRUE; /* no file to edit yet */
+ startflag = FALSE; /* startup file not executed yet */
+ errflag = FALSE; /* not doing C error parsing */
+#if CRYPT
+ cryptflag = FALSE; /* no encryption by default */
+#endif
+#if CALLED
+ eexitflag = FALSE; /* not time to exit yet */
+#endif
+
+ /* Parse the command line */
+ for (carg = 1; carg < argc; ++carg) {
+
+ /* Process Switches */
+#if PKCODE
+ if (argv[carg][0] == '+') {
+ gotoflag = TRUE;
+ gline = atoi(&argv[carg][1]);
+ } else
+#endif
+ if (argv[carg][0] == '-') {
+ switch (argv[carg][1]) {
+ /* Process Startup macroes */
+ case 'a': /* process error file */
+ case 'A':
+ errflag = TRUE;
+ break;
+ case 'e': /* -e for Edit file */
+ case 'E':
+ viewflag = FALSE;
+ break;
+ case 'g': /* -g for initial goto */
+ case 'G':
+ gotoflag = TRUE;
+ gline = atoi(&argv[carg][2]);
+ break;
+#if CRYPT
+ case 'k': /* -k<key> for code key */
+ case 'K':
+ cryptflag = TRUE;
+ strcpy(ekey, &argv[carg][2]);
+ break;
+#endif
+#if PKCODE
+ case 'n': /* -n accept null chars */
+ case 'N':
+ nullflag = TRUE;
+ break;
+#endif
+ case 'r': /* -r restrictive use */
+ case 'R':
+ restflag = TRUE;
+ break;
+ case 's': /* -s for initial search string */
+ case 'S':
+ searchflag = TRUE;
+ strncpy(pat,&argv[carg][2],NPAT);
+ break;
+ case 'v': /* -v for View File */
+ case 'V':
+ viewflag = TRUE;
+ break;
+ default: /* unknown switch */
+ /* ignore this for now */
+ break;
+ }
+
+ } else if (argv[carg][0]== '@') {
+
+ /* Process Startup macroes */
+ if (startup(&argv[carg][1]) == TRUE)
+ /* don't execute emacs.rc */
+ startflag = TRUE;
+
+ } else {
+
+ /* Process an input file */
+
+ /* set up a buffer for this file */
+ makename(bname, argv[carg]);
+ unqname(bname);
+
+ /* set this to inactive */
+ bp = bfind(bname, TRUE, 0);
+ strcpy(bp->b_fname, argv[carg]);
+ bp->b_active = FALSE;
+ if (firstfile) {
+ firstbp = bp;
+ firstfile = FALSE;
+ }
+
+ /* set the modes appropriatly */
+ if (viewflag)
+ bp->b_mode |= MDVIEW;
+#if CRYPT
+ if (cryptflag) {
+ bp->b_mode |= MDCRYPT;
+ crypt((char *)NULL, 0);
+ crypt(ekey, strlen(ekey));
+ strncpy(bp->b_key, ekey, NPAT);
+ }
+#endif
+ }
+ }
+
+#if UNIX
+ signal(SIGHUP, emergencyexit);
+ signal(SIGTERM, emergencyexit);
+#endif
+
+ /* if we are C error parsing... run it! */
+ if (errflag) {
+ if (startup("error.cmd") == TRUE)
+ startflag = TRUE;
+ }
+
+ /* if invoked with no other startup files,
+ run the system startup file here */
+ if (startflag == FALSE) {
+ startup("");
+ startflag = TRUE;
+ }
+ discmd = TRUE; /* P.K. */
+
+ /* if there are any files to read, read the first one! */
+ bp = bfind("main", FALSE, 0);
+ if (firstfile == FALSE && (gflags & GFREAD)) {
+ swbuffer(firstbp);
+ zotbuf(bp);
+ } else
+ bp->b_mode |= gmode;
+
+ /* Deal with startup gotos and searches */
+ if (gotoflag && searchflag) {
+ update(FALSE);
+ mlwrite("(Can not search and goto at the same time!)");
+ }
+ else if (gotoflag) {
+ if (gotoline(TRUE,gline) == FALSE) {
+ update(FALSE);
+ mlwrite("(Bogus goto argument)");
+ }
+ } else if (searchflag) {
+ if (forwhunt(FALSE, 0) == FALSE)
+ update(FALSE);
+ }
+
+ /* setup to process commands */
+ lastflag = 0; /* Fake last flags. */
+
+loop:
+
+#if CALLED
+ /* if we were called as a subroutine and want to leave, do so */
+ if (eexitflag)
+ return(eexitval);
+#endif
+
+ /* execute the "command" macro...normally null */
+ saveflag = lastflag; /* preserve lastflag through this */
+ execute(META|SPEC|'C', FALSE, 1);
+ lastflag = saveflag;
+
+#if TYPEAH && PKCODE
+ if (typahead())
+ {
+ newc = getcmd();
+ update(FALSE);
+ do
+ {
+ if (c == newc && (execfunc = getbind(c)) != NULL
+ && execfunc != newline
+ && execfunc != tab)
+ newc = getcmd();
+ else
+ break;
+ } while (typahead());
+ c = newc;
+ }
+ else
+ {
+ update(FALSE);
+ c = getcmd();
+ }
+#else
+ /* Fix up the screen */
+ update(FALSE);
+
+ /* get the next command from the keyboard */
+ c = getcmd();
+#endif
+ /* if there is something on the command line, clear it */
+ if (mpresf != FALSE) {
+ mlerase();
+ update(FALSE);
+#if CLRMSG
+ if (c == ' ') /* ITS EMACS does this */
+ goto loop;
+#endif
+ }
+ f = FALSE;
+ n = 1;
+
+ /* do META-# processing if needed */
+
+ basec = c & ~META; /* strip meta char off if there */
+ if ((c & META) && ((basec >= '0' && basec <= '9') || basec == '-')) {
+ f = TRUE; /* there is a # arg */
+ n = 0; /* start with a zero default */
+ mflag = 1; /* current minus flag */
+ c = basec; /* strip the META */
+ while ((c >= '0' && c <= '9') || (c == '-')) {
+ if (c == '-') {
+ /* already hit a minus or digit? */
+ if ((mflag == -1) || (n != 0))
+ break;
+ mflag = -1;
+ } else {
+ n = n * 10 + (c - '0');
+ }
+ if ((n == 0) && (mflag == -1)) /* lonely - */
+ mlwrite("Arg:");
+ else
+ mlwrite("Arg: %d",n * mflag);
+
+ c = getcmd(); /* get the next key */
+ }
+ n = n * mflag; /* figure in the sign */
+ }
+
+ /* do ^U repeat argument processing */
+
+ if (c == reptc) { /* ^U, start argument */
+ f = TRUE;
+ n = 4; /* with argument of 4 */
+ mflag = 0; /* that can be discarded. */
+ mlwrite("Arg: 4");
+ while ((c=getcmd()) >='0' && c<='9' || c==reptc || c=='-'){
+ if (c == reptc)
+ if ((n > 0) == ((n*4) > 0))
+ n = n*4;
+ else
+ n = 1;
+ /*
+ * If dash, and start of argument string, set arg.
+ * to -1. Otherwise, insert it.
+ */
+ else if (c == '-') {
+ if (mflag)
+ break;
+ n = 0;
+ mflag = -1;
+ }
+ /*
+ * If first digit entered, replace previous argument
+ * with digit and set sign. Otherwise, append to arg.
+ */
+ else {
+ if (!mflag) {
+ n = 0;
+ mflag = 1;
+ }
+ n = 10*n + c - '0';
+ }
+ mlwrite("Arg: %d", (mflag >=0) ? n : (n ? -n : -1));
+ }
+ /*
+ * Make arguments preceded by a minus sign negative and change
+ * the special argument "^U -" to an effective "^U -1".
+ */
+ if (mflag == -1) {
+ if (n == 0)
+ n++;
+ n = -n;
+ }
+ }
+
+ /* and execute the command */
+ execute(c, f, n);
+ goto loop;
+}
+
+/*
+ * Initialize all of the buffers and windows. The buffer name is passed down
+ * as an argument, because the main routine may have been told to read in a
+ * file by default, and we want the buffer name to be right.
+ */
+edinit(bname)
+char bname[];
+{
+ register BUFFER *bp;
+ register WINDOW *wp;
+ char *malloc();
+
+ bp = bfind(bname, TRUE, 0); /* First buffer */
+ blistp = bfind("*List*", TRUE, BFINVS); /* Buffer list buffer */
+ wp = (WINDOW *) malloc(sizeof(WINDOW)); /* First window */
+ if (bp==NULL || wp==NULL || blistp==NULL)
+ exit(1);
+ curbp = bp; /* Make this current */
+ wheadp = wp;
+ curwp = wp;
+ wp->w_wndp = NULL; /* Initialize window */
+ wp->w_bufp = bp;
+ bp->b_nwnd = 1; /* Displayed. */
+ wp->w_linep = bp->b_linep;
+ wp->w_dotp = bp->b_linep;
+ wp->w_doto = 0;
+ wp->w_markp = NULL;
+ wp->w_marko = 0;
+ wp->w_toprow = 0;
+#if COLOR
+ /* initalize colors to global defaults */
+ wp->w_fcolor = gfcolor;
+ wp->w_bcolor = gbcolor;
+#endif
+ wp->w_ntrows = term.t_nrow-1; /* "-1" for mode line. */
+ wp->w_force = 0;
+ wp->w_flag = WFMODE|WFHARD; /* Full. */
+}
+
+/*
+ * This is the general command execution routine. It handles the fake binding
+ * of all the keys to "self-insert". It also clears out the "thisflag" word,
+ * and arranges to move it to the "lastflag", so that the next command can
+ * look at it. Return the status of command.
+ */
+execute(c, f, n)
+{
+ register int status;
+ int (*execfunc)(); /* ptr to function to execute */
+ int (*getbind())();
+
+ /* if the keystroke is a bound function...do it */
+ execfunc = getbind(c);
+ if (execfunc != NULL) {
+ thisflag = 0;
+ status = (*execfunc)(f, n);
+ lastflag = thisflag;
+ return (status);
+ }
+
+ /*
+ * If a space was typed, fill column is defined, the argument is non-
+ * negative, wrap mode is enabled, and we are now past fill column,
+ * and we are not read-only, perform word wrap.
+ */
+ if (c == ' ' && (curwp->w_bufp->b_mode & MDWRAP) && fillcol > 0 &&
+ n >= 0 && getccol(FALSE) > fillcol &&
+ (curwp->w_bufp->b_mode & MDVIEW) == FALSE)
+ execute(META|SPEC|'W', FALSE, 1);
+
+#if PKCODE
+ if ((c>=0x20 && c<=0x7E) /* Self inserting. */
+#if IBMPC
+ || (c>=0x80 && c<=0xFE)) {
+#else
+#if VMS || BSD || USG /* 8BIT P.K. */
+ || (c>=0xA0 && c<=0xFE)) {
+#else
+ ) {
+#endif
+#endif
+#else
+ if ((c>=0x20 && c<=0xFF)) { /* Self inserting. */
+#endif
+ if (n <= 0) { /* Fenceposts. */
+ lastflag = 0;
+ return (n<0 ? FALSE : TRUE);
+ }
+ thisflag = 0; /* For the future. */
+
+ /* if we are in overwrite mode, not at eol,
+ and next char is not a tab or we are at a tab stop,
+ delete a char forword */
+ if (curwp->w_bufp->b_mode & MDOVER &&
+ curwp->w_doto < curwp->w_dotp->l_used &&
+ (lgetc(curwp->w_dotp, curwp->w_doto) != '\t' ||
+ (curwp->w_doto) % 8 == 7))
+ ldelete(1L, FALSE);
+
+ /* do the appropriate insertion */
+ if (c == '}' && (curbp->b_mode & MDCMOD) != 0)
+ status = insbrace(n, c);
+ else if (c == '#' && (curbp->b_mode & MDCMOD) != 0)
+ status = inspound();
+ else
+ status = linsert(n, c);
+
+#if CFENCE
+ /* check for CMODE fence matching */
+ if ((c == '}' || c == ')' || c == ']') &&
+ (curbp->b_mode & MDCMOD) != 0)
+ fmatch(c);
+#endif
+
+ /* check auto-save mode */
+ if (curbp->b_mode & MDASAVE)
+ if (--gacount == 0) {
+ /* and save the file if needed */
+ upscreen(FALSE, 0);
+ filesave(FALSE, 0);
+ gacount = gasave;
+ }
+
+ lastflag = thisflag;
+ return (status);
+ }
+ TTbeep();
+ mlwrite("(Key not bound)"); /* complain */
+ lastflag = 0; /* Fake last flags. */
+ return (FALSE);
+}
+
+/*
+ * Fancy quit command, as implemented by Norm. If the any buffer has
+ * changed do a write on that buffer and exit emacs, otherwise simply exit.
+ */
+quickexit(f, n)
+{
+ register BUFFER *bp; /* scanning pointer to buffers */
+ register BUFFER *oldcb; /* original current buffer */
+ register int status;
+
+ oldcb = curbp; /* save in case we fail */
+
+ bp = bheadp;
+ while (bp != NULL) {
+ if ((bp->b_flag&BFCHG) != 0 /* Changed. */
+ && (bp->b_flag&BFTRUNC) == 0 /* Not truncated P.K. */
+ && (bp->b_flag&BFINVS) == 0) { /* Real. */
+ curbp = bp; /* make that buffer cur */
+ mlwrite("(Saving %s)",bp->b_fname);
+#if PKCODE
+#else
+ mlwrite("\n");
+#endif
+ if ((status = filesave(f, n)) != TRUE) {
+ curbp = oldcb; /* restore curbp */
+ return(status);
+ }
+ }
+ bp = bp->b_bufp; /* on to the next buffer */
+ }
+ quit(f, n); /* conditionally quit */
+ return(TRUE);
+}
+
+static void emergencyexit(signr)
+int signr;
+{
+ quickexit(FALSE, 0);
+ quit(TRUE, 0);
+}
+
+/*
+ * Quit command. If an argument, always quit. Otherwise confirm if a buffer
+ * has been changed and not written out. Normally bound to "C-X C-C".
+ */
+quit(f, n)
+{
+ register int s;
+
+ if (f != FALSE /* Argument forces it. */
+ || anycb() == FALSE /* All buffers clean. */
+ /* User says it's OK. */
+ || (s=mlyesno("Modified buffers exist. Leave anyway")) == TRUE) {
+#if (FILOCK && BSD) || SVR4
+ if (lockrel() != TRUE) {
+ TTputc('\n');
+ TTputc('\r');
+ TTclose();
+ TTkclose();
+ exit(1);
+ }
+#endif
+ vttidy();
+ if (f)
+ exit(n);
+ else
+ exit(GOOD);
+ }
+ mlwrite("");
+ return(s);
+}
+
+/*
+ * Begin a keyboard macro.
+ * Error if not at the top level in keyboard processing. Set up variables and
+ * return.
+ */
+ctlxlp(f, n)
+{
+ if (kbdmode != STOP) {
+ mlwrite("%%Macro already active");
+ return(FALSE);
+ }
+ mlwrite("(Start macro)");
+ kbdptr = &kbdm[0];
+ kbdend = kbdptr;
+ kbdmode = RECORD;
+ return (TRUE);
+}
+
+/*
+ * End keyboard macro. Check for the same limit conditions as the above
+ * routine. Set up the variables and return to the caller.
+ */
+ctlxrp(f, n)
+{
+ if (kbdmode == STOP) {
+ mlwrite("%%Macro not active");
+ return(FALSE);
+ }
+ if (kbdmode == RECORD) {
+ mlwrite("(End macro)");
+ kbdmode = STOP;
+ }
+ return(TRUE);
+}
+
+/*
+ * Execute a macro.
+ * The command argument is the number of times to loop. Quit as soon as a
+ * command gets an error. Return TRUE if all ok, else FALSE.
+ */
+ctlxe(f, n)
+{
+ if (kbdmode != STOP) {
+ mlwrite("%%Macro already active");
+ return(FALSE);
+ }
+ if (n <= 0)
+ return (TRUE);
+ kbdrep = n; /* remember how many times to execute */
+ kbdmode = PLAY; /* start us in play mode */
+ kbdptr = &kbdm[0]; /* at the beginning */
+ return(TRUE);
+}
+
+/*
+ * Abort.
+ * Beep the beeper. Kill off any keyboard macro, etc., that is in progress.
+ * Sometimes called as a routine, to do general aborting of stuff.
+ */
+ctrlg(f, n)
+{
+ TTbeep();
+ kbdmode = STOP;
+ mlwrite("(Aborted)");
+ return(ABORT);
+}
+
+/* tell the user that this command is illegal while we are in
+ VIEW (read-only) mode */
+
+rdonly()
+
+{
+ TTbeep();
+ mlwrite("(Key illegal in VIEW mode)");
+ return(FALSE);
+}
+
+resterr()
+
+{
+ TTbeep();
+ mlwrite("(That command is RESTRICTED)");
+ return(FALSE);
+}
+
+nullproc() /* user function that does NOTHING */
+
+{
+}
+
+meta() /* dummy function for binding to meta prefix */
+{
+}
+
+cex() /* dummy function for binding to control-x prefix */
+{
+}
+
+unarg() /* dummy function for binding to universal-argument */
+{
+}
+
+/***** Compiler specific Library functions ****/
+
+#if MSDOS || PKCODE
+/* strncpy: copy a string...with length restrictions
+ ALWAYS null terminate
+*/
+
+char *strncpy(dst, src, maxlen)
+
+char *dst; /* destination of copied string */
+char *src; /* source */
+int maxlen; /* maximum length */
+
+{
+ char *dptr; /* ptr into dst */
+
+ dptr = dst;
+/* while (*src && (maxlen-- > 0))
+ *dptr++ = *src++; */
+ while ((maxlen > 0) && *src) {
+ *dptr++ = *src++;
+ maxlen--;
+ }
+
+ *dptr = 0; /* orig */
+/* if (maxlen > 0)
+ *dptr = 0; */
+ return(dst);
+}
+#endif
+
+#if RAMSIZE
+/* These routines will allow me to track memory usage by placing
+ a layer on top of the standard system malloc() and free() calls.
+ with this code defined, the environment variable, $RAM, will
+ report on the number of bytes allocated via malloc.
+
+ with SHOWRAM defined, the number is also posted on the
+ end of the bottom mode line and is updated whenever it is changed.
+*/
+
+#undef malloc
+#undef free
+
+char *allocate(nbytes) /* allocate nbytes and track */
+
+unsigned nbytes; /* # of bytes to allocate */
+
+{
+ char *mp; /* ptr returned from malloc */
+ char *malloc();
+
+ mp = malloc(nbytes);
+ if (mp) {
+ envram += nbytes;
+#if RAMSHOW
+ dspram();
+#endif
+ }
+
+ return(mp);
+}
+
+release(mp) /* release malloced memory and track */
+
+char *mp; /* chunk of RAM to release */
+
+{
+ unsigned *lp; /* ptr to the long containing the block size */
+
+ if (mp) {
+ /* update amount of ram currently malloced */
+ lp = ((unsigned *)mp) - 1;
+ envram -= (long)*lp - 2;
+ free(mp);
+#if RAMSHOW
+ dspram();
+#endif
+ }
+}
+
+#if RAMSHOW
+dspram() /* display the amount of RAM currently malloced */
+
+{
+ char mbuf[20];
+ char *sp;
+
+ TTmove(term.t_nrow - 1, 70);
+#if COLOR
+ TTforg(7);
+ TTbacg(0);
+#endif
+ sprintf(mbuf, "[%lu]", envram);
+ sp = &mbuf[0];
+ while (*sp)
+ TTputc(*sp++);
+ TTmove(term.t_nrow, 0);
+ movecursor(term.t_nrow, 0);
+}
+#endif
+#endif
+
+/* On some primitave operation systems, and when emacs is used as
+ a subprogram to a larger project, emacs needs to de-alloc its
+ own used memory
+*/
+
+#if CLEAN
+cexit(status)
+
+int status; /* return status of emacs */
+
+{
+ register BUFFER *bp; /* buffer list pointer */
+ register WINDOW *wp; /* window list pointer */
+ register WINDOW *tp; /* temporary window pointer */
+
+ /* first clean up the windows */
+ wp = wheadp;
+ while (wp) {
+ tp = wp->w_wndp;
+ free(wp);
+ wp = tp;
+ }
+ wheadp = NULL;
+
+ /* then the buffers */
+ bp = bheadp;
+ while (bp) {
+ bp->b_nwnd = 0;
+ bp->b_flag = 0; /* don't say anything about a changed buffer! */
+ zotbuf(bp);
+ bp = bheadp;
+ }
+
+ /* and the kill buffer */
+ kdelete();
+
+ /* and the video buffers */
+ vtfree();
+
+ /* and now.. we leave [pick the return if we are a subprogram] */
+#if CALLED
+ eexitflag = TRUE; /* flag a program exit */
+ eexitval = status;
+ return(status);
+#else
+#undef exit
+ exit(status);
+#endif
+}
+#endif
diff --git a/makefile b/makefile
new file mode 100644
index 0000000..beb0ffd
--- /dev/null
+++ b/makefile
@@ -0,0 +1,124 @@
+# makefile for emacs, updated Sun Apr 28 17:59:07 EET DST 1996
+
+SRC=ansi.c basic.c bind.c buffer.c crypt.c display.c eval.c exec.c \
+ file.c fileio.c ibmpc.c input.c isearch.c line.c lock.c main.c \
+ pklock.c posix.c random.c region.c search.c spawn.c tcap.c \
+ termio.c vmsvt.c vt52.c window.c word.c
+
+OBJ=ansi.o basic.o bind.o buffer.o crypt.o display.o eval.o exec.o \
+ file.o fileio.o ibmpc.o input.o isearch.o line.o lock.o main.o \
+ pklock.o posix.o random.o region.o search.o spawn.o tcap.o \
+ termio.o vmsvt.o vt52.o window.o word.o
+
+HDR=ebind.h edef.h efunc.h epath.h estruct.h evar.h
+
+# DO NOT ADD OR MODIFY ANY LINES ABOVE THIS -- make source creates them
+
+CC=gcc
+CFLAGS=-O4
+#CC=c89 +O3 # HP
+#CFLAGS= -D_HPUX_SOURCE -DSYSV
+#CFLAGS=-O4 -DSVR4 # Sun
+#CFLAGS=-O -qchars=signed # RS/6000
+DEFINES=-DAUTOCONF -DPOSIX -DUSG # Linux
+#DEFINES=-DAUTOCONF
+#LIBS=-ltermcap # BSD
+#LIBS=-lcurses # SYSV
+#LIBS=-ltermlib
+LIBS=-L/usr/lib/termcap -ltermcap
+LFLAGS=-hbx
+BINDIR=/usr/bin
+LIBDIR=/usr/lib
+
+em: ${OBJ}
+ ${CC} ${DEFINES} -o em ${OBJ} ${LIBS}
+
+clean:
+ rm -f core lintout makeout tags makefile.bak *.o
+
+install: em
+ strip em
+ cp em ${BINDIR}
+ cp emacs.hlp ${LIBDIR}
+ cp emacs.rc ${LIBDIR}/.emacsrc
+ chmod 755 ${BINDIR}/em
+ chmod 644 ${LIBDIR}/emacs.hlp ${LIBDIR}/.emacsrc
+
+lint: ${SRC}
+ @rm -f lintout
+ lint ${LFLAGS} ${SRC} >lintout
+ cat lintout
+
+errs:
+ @rm -f makeout
+ make em >makeout
+
+tags: ${SRC}
+ @rm -f tags
+ ctags ${SRC}
+
+source:
+ @mv makefile makefile.bak
+ @echo "# makefile for emacs, updated `date`" >makefile
+ @echo '' >>makefile
+ @echo SRC=`ls *.c` >>makefile
+ @echo OBJ=`ls *.c | sed s/c$$/o/` >>makefile
+ @echo HDR=`ls *.h` >>makefile
+ @echo '' >>makefile
+ @sed -n -e '/^# DO NOT ADD OR MODIFY/,$$p' <makefile.bak >>makefile
+
+depend: ${SRC}
+ @for i in ${SRC}; do\
+ cc ${DEFINES} -M $$i | sed -e 's, \./, ,' | grep -v '/usr/include' | \
+ awk '{ if ($$1 != prev) { if (rec != "") print rec; \
+ rec = $$0; prev = $$1; } \
+ else { if (length(rec $$2) > 78) { print rec; rec = $$0; } \
+ else rec = rec " " $$2 } } \
+ END { print rec }'; done >makedep
+ @echo '/^# DO NOT DELETE THIS LINE/+2,$$d' >eddep
+ @echo '$$r ./makedep' >>eddep
+ @echo 'w' >>eddep
+ @cp makefile makefile.bak
+ @ed - makefile <eddep
+ @rm eddep makedep
+ @echo '' >>makefile
+ @echo '# DEPENDENCIES MUST END AT END OF FILE' >>makefile
+ @echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >>makefile
+ @echo '# see make depend above' >>makefile
+
+.c.o:
+ ${CC} ${CFLAGS} ${DEFINES} -c $*.c
+
+# DO NOT DELETE THIS LINE -- make depend uses it
+
+ansi.o: ansi.c estruct.h edef.h
+basic.o: basic.c estruct.h edef.h
+bind.o: bind.c estruct.h edef.h epath.h
+buffer.o: buffer.c estruct.h edef.h
+crypt.o: crypt.c estruct.h edef.h
+display.o: display.c estruct.h edef.h
+eval.o: eval.c estruct.h edef.h evar.h
+exec.o: exec.c estruct.h edef.h
+file.o: file.c estruct.h edef.h
+fileio.o: fileio.c estruct.h edef.h
+ibmpc.o: ibmpc.c estruct.h edef.h
+input.o: input.c estruct.h edef.h
+isearch.o: isearch.c estruct.h edef.h
+line.o: line.c estruct.h edef.h
+lock.o: lock.c estruct.h edef.h
+main.o: main.c estruct.h efunc.h edef.h ebind.h
+pklock.o: pklock.c estruct.h
+random.o: random.c estruct.h edef.h
+region.o: region.c estruct.h edef.h
+search.o: search.c estruct.h edef.h
+spawn.o: spawn.c estruct.h edef.h
+tcap.o: tcap.c estruct.h edef.h
+termio.o: termio.c estruct.h edef.h
+vmsvt.o: vmsvt.c estruct.h edef.h
+vt52.o: vt52.c estruct.h edef.h
+window.o: window.c estruct.h edef.h
+word.o: word.c estruct.h edef.h
+
+# DEPENDENCIES MUST END AT END OF FILE
+# IF YOU PUT STUFF HERE IT WILL GO AWAY
+# see make depend above
diff --git a/makefile.dos b/makefile.dos
new file mode 100644
index 0000000..ba9969a
--- /dev/null
+++ b/makefile.dos
@@ -0,0 +1,22 @@
+CFLAGS= -AL -ot -Gs
+
+OFILES= ansi.obj basic.obj bind.obj buffer.obj crypt.obj \
+ display.obj eval.obj exec.obj file.obj fileio.obj \
+ ibmpc.obj input.obj isearch.obj line.obj \
+ lock.obj main.obj random.obj region.obj search.obj spawn.obj \
+ tcap.obj termio.obj vmsvt.obj vt52.obj \
+ window.obj word.obj pklock.obj
+
+CFILES= ansi.c basic.c bind.c buffer.c crypt.c \
+ display.c eval.c exec.c file.c fileio.c \
+ ibmpc.c input.c isearch.c line.c \
+ lock.c main.c random.c region.c search.c spawn.c \
+ tcap.c termio.c vmsvt.c vt52.c \
+ window.c word.c pklock.c
+
+HFILES= estruct.h edef.h efunc.h epath.h ebind.h evar.h
+
+emacs.exe: $(OFILES)
+ link @emacso.lnk
+
+$(OFILES): $(HFILES)
diff --git a/makefile.unx b/makefile.unx
new file mode 100644
index 0000000..4c17816
--- /dev/null
+++ b/makefile.unx
@@ -0,0 +1,121 @@
+#
+# makefile for uEmacs/PK 4.0
+#
+
+SRC=ansi.c basic.c bind.c buffer.c crypt.c display.c eval.c exec.c file.c \
+ fileio.c ibmpc.c input.c isearch.c line.c lock.c main.c pklock.c \
+ random.c region.c search.c spawn.c tcap.c termio.c vmsvt.c vt52.c \
+ window.c word.c
+OBJ=ansi.o basic.o bind.o buffer.o crypt.o display.o eval.o exec.o file.o \
+ fileio.o ibmpc.o input.o isearch.o line.o lock.o main.o pklock.o \
+ random.o region.o search.o spawn.o tcap.o termio.o vmsvt.o vt52.o \
+ window.o word.o
+HDR=ebind.h edef.h efunc.h epath.h estruct.h evar.h
+
+# DO NOT ADD OR MODIFY ANY LINES ABOVE THIS -- make source creates them
+
+CC=gcc
+CFLAGS=-O
+#CC=c89 +O3 # HP
+#CFLAGS= -D_HPUX_SOURCE -DSYSV
+#CFLAGS=-O4 # Sun
+#CFLAGS=-O -qchars=signed # RS/6000
+DEFINES=-DAUTOCONF
+LIBS=-ltermcap # BSD
+#LIBS=-lcurses # SYSV
+LFLAGS=-hbx
+BINDIR=/usr/local/bin
+LIBDIR=/usr/local/lib
+
+emacs: ${OBJ}
+ ${CC} ${DEFINES} -o emacs ${OBJ} ${LIBS}
+
+clean:
+ rm -f core lintout makeout tags makefile.bak *.o
+
+install: emacs
+ strip emacs
+ cp emacs ${BINDIR}
+ cp emacs.hlp ${LIBDIR}
+ cp emacs.rc ${LIBDIR}/.emacsrc
+ chmod 755 ${BINDIR}/emacs
+ chmod 644 ${LIBDIR}/emacs.hlp ${LIBDIR}/.emacsrc
+
+lint: ${SRC}
+ @rm -f lintout
+ lint ${LFLAGS} ${SRC} >lintout
+ cat lintout
+
+errs:
+ @rm -f makeout
+ make emacs >makeout
+
+tags: ${SRC}
+ @rm -f tags
+ ctags ${SRC}
+
+source:
+ @mv makefile makefile.bak
+ @echo "# makefile for emacs, updated `date`" >makefile
+ @echo '' >>makefile
+ @echo SRC=`ls *.c` >>makefile
+ @echo OBJ=`ls *.c | sed s/c$$/o/` >>makefile
+ @echo HDR=`ls *.h` >>makefile
+ @echo '' >>makefile
+ @sed -n -e '/^# DO NOT ADD OR MODIFY/,$$p' <makefile.bak >>makefile
+
+depend: ${SRC}
+ @for i in ${SRC}; do\
+ cc ${DEFINES} -M $$i | sed -e 's, \./, ,' | grep -v '/usr/include' | \
+ awk '{ if ($$1 != prev) { if (rec != "") print rec; \
+ rec = $$0; prev = $$1; } \
+ else { if (length(rec $$2) > 78) { print rec; rec = $$0; } \
+ else rec = rec " " $$2 } } \
+ END { print rec }'; done >makedep
+ @echo '/^# DO NOT DELETE THIS LINE/+2,$$d' >eddep
+ @echo '$$r ./makedep' >>eddep
+ @echo 'w' >>eddep
+ @cp makefile makefile.bak
+ @ed - makefile <eddep
+ @rm eddep makedep
+ @echo '' >>makefile
+ @echo '# DEPENDENCIES MUST END AT END OF FILE' >>makefile
+ @echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >>makefile
+ @echo '# see make depend above' >>makefile
+
+.c.o:
+ ${CC} ${CFLAGS} ${DEFINES} -c $*.c
+
+# DO NOT DELETE THIS LINE -- make depend uses it
+
+ansi.o: ansi.c estruct.h edef.h
+basic.o: basic.c estruct.h edef.h
+bind.o: bind.c estruct.h edef.h epath.h
+buffer.o: buffer.c estruct.h edef.h
+crypt.o: crypt.c estruct.h edef.h
+display.o: display.c estruct.h edef.h
+eval.o: eval.c estruct.h edef.h evar.h
+exec.o: exec.c estruct.h edef.h
+file.o: file.c estruct.h edef.h
+fileio.o: fileio.c estruct.h edef.h
+ibmpc.o: ibmpc.c estruct.h edef.h
+input.o: input.c estruct.h edef.h
+isearch.o: isearch.c estruct.h edef.h
+line.o: line.c estruct.h edef.h
+lock.o: lock.c estruct.h edef.h
+main.o: main.c estruct.h efunc.h edef.h ebind.h
+pklock.o: pklock.c estruct.h
+random.o: random.c estruct.h edef.h
+region.o: region.c estruct.h edef.h
+search.o: search.c estruct.h edef.h
+spawn.o: spawn.c estruct.h edef.h
+tcap.o: tcap.c estruct.h edef.h
+termio.o: termio.c estruct.h edef.h
+vmsvt.o: vmsvt.c estruct.h edef.h
+vt52.o: vt52.c estruct.h edef.h
+window.o: window.c estruct.h edef.h
+word.o: word.c estruct.h edef.h
+
+# DEPENDENCIES MUST END AT END OF FILE
+# IF YOU PUT STUFF HERE IT WILL GO AWAY
+# see make depend above
diff --git a/makefilepatch b/makefilepatch
new file mode 100644
index 0000000..afda676
--- /dev/null
+++ b/makefilepatch
@@ -0,0 +1,61 @@
+***************
+*** 1,29 ****
+- #
+- # makefile for uEmacs/PK 4.0
+- #
+
+- SRC=ansi.c basic.c bind.c buffer.c crypt.c display.c eval.c exec.c file.c \
+- fileio.c ibmpc.c input.c isearch.c line.c lock.c main.c pklock.c \
+- random.c region.c search.c spawn.c tcap.c termio.c vmsvt.c vt52.c \
+- window.c word.c
+- OBJ=ansi.o basic.o bind.o buffer.o crypt.o display.o eval.o exec.o file.o \
+- fileio.o ibmpc.o input.o isearch.o line.o lock.o main.o pklock.o \
+- random.o region.o search.o spawn.o tcap.o termio.o vmsvt.o vt52.o \
+- window.o word.o
+ HDR=ebind.h edef.h efunc.h epath.h estruct.h evar.h
+
+ # DO NOT ADD OR MODIFY ANY LINES ABOVE THIS -- make source creates them
+
+- CC=cc
+- CFLAGS=-O
+ #CC=c89 +O3 # HP
+ #CFLAGS= -D_HPUX_SOURCE -DSYSV
+- CFLAGS=-O4 -DSVR4 # Sun
+ #CFLAGS=-O -qchars=signed # RS/6000
+- DEFINES=-DAUTOCONF
+- #LIBS=-ltermcap # BSD
+ #LIBS=-lcurses # SYSV
+- LIBS=-ltermlib
+ LFLAGS=-hbx
+ BINDIR=/usr/local/bin
+ LIBDIR=/usr/local/lib
+--- 1,29 ----
++ # makefile for emacs, updated Sun Apr 28 17:59:07 EET DST 1996
++
++ SRC=ansi.c basic.c bind.c buffer.c crypt.c display.c eval.c exec.c \
++ file.c fileio.c ibmpc.c input.c isearch.c line.c lock.c main.c \
++ pklock.c posix.c random.c region.c search.c spawn.c tcap.c \
++ termio.c vmsvt.c vt52.c window.c word.c
++
++ OBJ=ansi.o basic.o bind.o buffer.o crypt.o display.o eval.o exec.o \
++ file.o fileio.o ibmpc.o input.o isearch.o line.o lock.o main.o \
++ pklock.o posix.o random.o region.o search.o spawn.o tcap.o \
++ termio.o vmsvt.o vt52.o window.o word.o
+
+ HDR=ebind.h edef.h efunc.h epath.h estruct.h evar.h
+
+ # DO NOT ADD OR MODIFY ANY LINES ABOVE THIS -- make source creates them
+
++ CC=gcc
++ CFLAGS=-O4
+ #CC=c89 +O3 # HP
+ #CFLAGS= -D_HPUX_SOURCE -DSYSV
++ #CFLAGS=-O4 -DSVR4 # Sun
+ #CFLAGS=-O -qchars=signed # RS/6000
++ DEFINES=-DAUTOCONF -DPOSIX -DUSG
++ LIBS=-ltermcap # BSD
+ #LIBS=-lcurses # SYSV
++ #LIBS=-ltermlib
+ LFLAGS=-hbx
+ BINDIR=/usr/local/bin
+ LIBDIR=/usr/local/lib
diff --git a/pklock.c b/pklock.c
new file mode 100644
index 0000000..79bf19b
--- /dev/null
+++ b/pklock.c
@@ -0,0 +1,125 @@
+/* PKLOCK.C
+ *
+ * locking routines as modified by Petri Kutvonen
+ */
+
+#include "estruct.h"
+
+#if (FILOCK && BSD) || SVR4
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <fcntl.h>
+#ifdef SVR4
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+#include <errno.h>
+
+#define MAXLOCK 512
+#define MAXNAME 128
+
+#if defined(SVR4) && ! defined(__linux__)
+#include <sys/systeminfo.h>
+
+int gethostname(char *name, int namelen)
+{
+ return(sysinfo(SI_HOSTNAME, name, namelen));
+}
+#endif
+
+
+
+/**********************
+ *
+ * if successful, returns NULL
+ * if file locked, returns username of person locking the file
+ * if other error, returns "LOCK ERROR: explanation"
+ *
+ *********************/
+char *dolock(fname)
+ char *fname;
+{
+ int fd, lk, n;
+ static char lname[MAXLOCK], locker[MAXNAME+1];
+ int mask;
+ struct stat sbuf;
+
+ strcat(strcpy(lname, fname), ".lock~");
+
+ /* check that we are not being cheated, qname must point to */
+ /* a regular file - even this code leaves a small window of */
+ /* vulnerability but it is rather hard to exploit it */
+
+#if defined(S_IFLNK)
+ if (lstat(lname, &sbuf) == 0)
+#else
+ if (stat(lname, &sbuf) == 0)
+#endif
+#if defined(S_ISREG)
+ if (! S_ISREG(sbuf.st_mode))
+#else
+ if (! (((sbuf.st_mode) & 070000) == 0)) /* SysV R2 */
+#endif
+ return "LOCK ERROR: not a regular file";
+
+ mask = umask(0);
+ fd = open(lname, O_RDWR | O_CREAT, 0666);
+ umask(mask);
+ if (fd < 0)
+ {
+ if (errno == EACCES)
+ return NULL;
+#ifdef EROFS
+ if (errno == EROFS)
+ return NULL;
+#endif
+ return "LOCK ERROR: cannot access lock file";
+ }
+ if ((n = read(fd, locker, MAXNAME)) < 1)
+ {
+ lseek(fd, 0, SEEK_SET);
+/* strcpy(locker, getlogin()); */
+ cuserid(locker);
+ strcat(locker+strlen(locker), "@");
+ gethostname(locker+strlen(locker), 64);
+ write(fd, locker, strlen(locker));
+ close(fd);
+ return NULL;
+ }
+ locker[n > MAXNAME ? MAXNAME : n] = 0;
+ return locker;
+}
+
+
+/*********************
+ *
+ * undolock -- unlock the file fname
+ *
+ * if successful, returns NULL
+ * if other error, returns "LOCK ERROR: explanation"
+ *
+ *********************/
+
+char *undolock(fname)
+ char *fname;
+{
+ int fd, lk;
+ static char lname[MAXLOCK];
+
+ strcat(strcpy(lname, fname), ".lock~");
+ if (unlink(lname) != 0)
+ {
+ if (errno == EACCES || errno == ENOENT)
+ return NULL;
+#ifdef EROFS
+ if (errno == EROFS)
+ return NULL;
+#endif
+ return "LOCK ERROR: cannot remove lock file";
+ }
+ return NULL;
+}
+#endif
diff --git a/posix.c b/posix.c
new file mode 100644
index 0000000..c56d558
--- /dev/null
+++ b/posix.c
@@ -0,0 +1,159 @@
+/* POSIX.C
+ *
+ * The functions in this file negotiate with the operating system for
+ * characters, and write characters in a barely buffered fashion on the display.
+ * All operating systems.
+ *
+ * modified by Petri Kutvonen
+ *
+ * based on termio.c, with all the old cruft removed, and
+ * fixed for termios rather than the old termio.. Linus Torvalds
+ */
+
+#ifdef POSIX
+
+#include <stdio.h>
+#include "estruct.h"
+#include "edef.h"
+
+#include <signal.h>
+#include <termios.h>
+#include <fcntl.h>
+#include <errno.h>
+
+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 */
+
+struct termios otermios; /* original terminal characteristics */
+struct termios ntermios; /* charactoristics to use inside */
+
+#define TBUFSIZ 128
+char tobuf[TBUFSIZ]; /* terminal output buffer */
+
+
+/*
+ * This function is called once to set up the terminal device streams.
+ * On VMS, it translates TT until it finds the terminal, then assigns
+ * a channel to it and sets it raw. On CPM it is a no-op.
+ */
+ttopen()
+{
+ tcgetattr(0, &otermios); /* save old settings */
+
+ /*
+ * base new settings on old ones - don't change things
+ * we don't know about
+ */
+ ntermios = otermios;
+
+ /* raw CR/NL etc input handling, but keep ISTRIP if we're on a 7-bit line */
+ ntermios.c_iflag &= ~(IGNBRK | BRKINT | IGNPAR | PARMRK
+ | INPCK | INLCR | IGNCR | ICRNL);
+
+ /* raw CR/NR etc output handling */
+ ntermios.c_oflag &= ~(OPOST | ONLCR | OLCUC | OCRNL | ONOCR | ONLRET);
+
+ /* No signal handling, no echo etc */
+ ntermios.c_lflag &= ~(ISIG | ICANON | XCASE | ECHO | ECHOE | ECHOK
+ | ECHONL | NOFLSH | TOSTOP | ECHOCTL | ECHOPRT
+ | ECHOKE | FLUSHO | PENDIN | IEXTEN);
+
+ /* one character, no timeout */
+ ntermios.c_cc[VMIN] = 1;
+ ntermios.c_cc[VTIME] = 0;
+ tcsetattr(0, TCSADRAIN, &ntermios); /* and activate them */
+
+ /*
+ * provide a smaller terminal output buffer so that
+ * the type ahead detection works better (more often)
+ */
+ setbuffer(stdout, &tobuf[0], TBUFSIZ);
+
+ kbdflgs = fcntl( 0, F_GETFL, 0 );
+ kbdpoll = FALSE;
+
+ /* on all screens we are not sure of the initial position
+ of the cursor */
+ ttrow = 999;
+ ttcol = 999;
+}
+
+/*
+ * This function gets called just before we go back home to the command
+ * interpreter. On VMS it puts the terminal back in a reasonable state.
+ * Another no-operation on CPM.
+ */
+ttclose()
+{
+ tcsetattr(0, TCSADRAIN, &otermios); /* restore terminal settings */
+}
+
+/*
+ * Write a character to the display. On VMS, terminal output is buffered, and
+ * we just put the characters in the big array, after checking for overflow.
+ * On CPM terminal I/O unbuffered, so we just write the byte out. Ditto on
+ * MS-DOS (use the very very raw console output routine).
+ */
+ttputc(c)
+{
+ fputc(c, stdout);
+}
+
+/*
+ * Flush terminal buffer. Does real work where the terminal output is buffered
+ * up. A no-operation on systems where byte at a time terminal I/O is done.
+ */
+ttflush()
+{
+/*
+ * Add some terminal output success checking, sometimes an orphaned
+ * process may be left looping on SunOS 4.1.
+ *
+ * How to recover here, or is it best just to exit and lose
+ * everything?
+ *
+ * jph, 8-Oct-1993
+ * Jani Jaakkola suggested using select after EAGAIN but let's just wait a bit
+ *
+ */
+ int status;
+
+ status = fflush(stdout);
+ while (status < 0 && errno == EAGAIN) {
+ sleep(1);
+ status = fflush(stdout);
+ }
+ if (status < 0)
+ exit(15);
+}
+
+/*
+ * Read a character from the terminal, performing no editing and doing no echo
+ * at all. More complex in VMS that almost anyplace else, which figures. Very
+ * simple on CPM, because the system can do exactly what you want.
+ */
+ttgetc()
+{
+ return(255 & fgetc(stdin)); /* 8BIT P.K. */
+}
+
+/* typahead: Check to see if any characters are already in the
+ keyboard buffer
+*/
+
+typahead()
+{
+ int x; /* holds # of pending chars */
+
+#ifdef FIONREAD
+ if (ioctl(0,FIONREAD,&x) < 0)
+ x = 0;
+#else
+ x = 0;
+#endif
+ return x;
+}
+
+#endif /* POSIX */
diff --git a/random.c b/random.c
new file mode 100644
index 0000000..cfb68fc
--- /dev/null
+++ b/random.c
@@ -0,0 +1,1221 @@
+/* RANDOM.C
+ *
+ * This file contains the command processing functions for a number of random
+ * commands. There is no functional grouping here, for sure.
+ *
+ * modified by Petri Kutvonen
+ */
+
+#include <stdio.h>
+#include "estruct.h"
+#include "edef.h"
+
+int tabsize; /* Tab size (0: use real tabs) */
+
+/*
+ * Set fill column to n.
+ */
+setfillcol(f, n)
+{
+ fillcol = n;
+ mlwrite("(Fill column is %d)",n);
+ return(TRUE);
+}
+
+/*
+ * Display the current position of the cursor, in origin 1 X-Y coordinates,
+ * the character that is under the cursor (in hex), and the fraction of the
+ * text that is before the cursor. The displayed column is not the current
+ * column, but the column that would be used on an infinite width display.
+ * Normally this is bound to "C-X =".
+ */
+showcpos(f, n)
+{
+ register LINE *lp; /* current line */
+ register long numchars; /* # of chars in file */
+ register int numlines; /* # of lines in file */
+ register long predchars; /* # chars preceding point */
+ register int predlines; /* # lines preceding point */
+ register int curchar; /* character under cursor */
+ int ratio;
+ int col;
+ int savepos; /* temp save for current offset */
+ int ecol; /* column pos/end of current line */
+
+#if PKCODE
+ struct {
+ int pk_clin;
+ int pk_tlin;
+ int pk_ccol;
+ int pk_tcol;
+ long pk_cchr;
+ long pk_tchr;
+ int pk_perc;
+ int pk_char;
+ } pk_mlrec;
+#endif
+ /* starting at the beginning of the buffer */
+ lp = lforw(curbp->b_linep);
+
+ /* start counting chars and lines */
+ numchars = 0;
+ numlines = 0;
+ while (lp != curbp->b_linep) {
+ /* if we are on the current line, record it */
+ if (lp == curwp->w_dotp) {
+ predlines = numlines;
+ predchars = numchars + curwp->w_doto;
+ if ((curwp->w_doto) == llength(lp))
+ curchar = '\n';
+ else
+ curchar = lgetc(lp, curwp->w_doto);
+ }
+ /* on to the next line */
+ ++numlines;
+ numchars += llength(lp) + 1;
+ lp = lforw(lp);
+ }
+
+ /* if at end of file, record it */
+ if (curwp->w_dotp == curbp->b_linep) {
+ predlines = numlines;
+ predchars = numchars;
+#if PKCODE
+ curchar = 0;
+#endif
+ }
+
+ /* Get real column and end-of-line column. */
+ col = getccol(FALSE);
+ savepos = curwp->w_doto;
+ curwp->w_doto = llength(curwp->w_dotp);
+ ecol = getccol(FALSE);
+ curwp->w_doto = savepos;
+
+ ratio = 0; /* Ratio before dot. */
+ if (numchars != 0)
+ ratio = (100L*predchars) / numchars;
+
+ /* summarize and report the info */
+#if PKCODE
+ pk_mlrec.pk_clin = predlines+1;
+ pk_mlrec.pk_tlin = numlines+1;
+ pk_mlrec.pk_ccol = col;
+ pk_mlrec.pk_tcol = ecol;
+ pk_mlrec.pk_cchr = predchars;
+ pk_mlrec.pk_tchr = numchars;
+ pk_mlrec.pk_perc = ratio;
+ pk_mlrec.pk_char = curchar;
+ mlwrite("%*Line %d/%d Col %d/%d Char %D/%D (%d%%) char = 0x%x",
+ &pk_mlrec);
+#else
+ mlwrite("Line %d/%d Col %d/%d Char %D/%D (%d%%) char = 0x%x",
+ predlines+1, numlines+1, col, ecol,
+ predchars, numchars, ratio, curchar);
+#endif
+ return (TRUE);
+}
+
+getcline() /* get the current line number */
+
+{
+ register LINE *lp; /* current line */
+ register int numlines; /* # of lines before point */
+
+ /* starting at the beginning of the buffer */
+ lp = lforw(curbp->b_linep);
+
+ /* start counting lines */
+ numlines = 0;
+ while (lp != curbp->b_linep) {
+ /* if we are on the current line, record it */
+ if (lp == curwp->w_dotp)
+ break;
+ ++numlines;
+ lp = lforw(lp);
+ }
+
+ /* and return the resulting count */
+ return(numlines + 1);
+}
+
+/*
+ * Return current column. Stop at first non-blank given TRUE argument.
+ */
+getccol(bflg)
+int bflg;
+{
+ register int c, i, col;
+ col = 0;
+ for (i=0; i<curwp->w_doto; ++i) {
+ c = lgetc(curwp->w_dotp, i);
+ if (c!=' ' && c!='\t' && bflg)
+ break;
+ if (c == '\t')
+ col |= tabmask;
+ else if (c<0x20 || c==0x7F)
+ ++col;
+ ++col;
+ }
+ return(col);
+}
+
+/*
+ * Set current column.
+ */
+setccol(pos)
+
+int pos; /* position to set cursor */
+
+{
+ register int c; /* character being scanned */
+ register int i; /* index into current line */
+ register int col; /* current cursor column */
+ register int llen; /* length of line in bytes */
+
+ col = 0;
+ llen = llength(curwp->w_dotp);
+
+ /* scan the line until we are at or past the target column */
+ for (i = 0; i < llen; ++i) {
+ /* upon reaching the target, drop out */
+ if (col >= pos)
+ break;
+
+ /* advance one character */
+ c = lgetc(curwp->w_dotp, i);
+ if (c == '\t')
+ col |= tabmask;
+ else if (c<0x20 || c==0x7F)
+ ++col;
+ ++col;
+ }
+
+ /* set us at the new position */
+ curwp->w_doto = i;
+
+ /* and tell weather we made it */
+ return(col >= pos);
+}
+
+/*
+ * Twiddle the two characters on either side of dot. If dot is at the end of
+ * the line twiddle the two characters before it. Return with an error if dot
+ * is at the beginning of line; it seems to be a bit pointless to make this
+ * work. This fixes up a very common typo with a single stroke. Normally bound
+ * to "C-T". This always works within a line, so "WFEDIT" is good enough.
+ */
+twiddle(f, n)
+{
+ register LINE *dotp;
+ register int doto;
+ register int cl;
+ register int cr;
+
+ if (curbp->b_mode&MDVIEW) /* don't allow this command if */
+ return(rdonly()); /* we are in read only mode */
+ dotp = curwp->w_dotp;
+ doto = curwp->w_doto;
+ if (doto==llength(dotp) && --doto<0)
+ return (FALSE);
+ cr = lgetc(dotp, doto);
+ if (--doto < 0)
+ return (FALSE);
+ cl = lgetc(dotp, doto);
+ lputc(dotp, doto+0, cr);
+ lputc(dotp, doto+1, cl);
+ lchange(WFEDIT);
+ return (TRUE);
+}
+
+/*
+ * Quote the next character, and insert it into the buffer. All the characters
+ * are taken literally, with the exception of the newline, which always has
+ * its line splitting meaning. The character is always read, even if it is
+ * inserted 0 times, for regularity. Bound to "C-Q"
+ */
+quote(f, n)
+{
+ register int s;
+ register int c;
+
+ if (curbp->b_mode&MDVIEW) /* don't allow this command if */
+ return(rdonly()); /* we are in read only mode */
+ c = tgetc();
+ if (n < 0)
+ return (FALSE);
+ if (n == 0)
+ return (TRUE);
+ if (c == '\n') {
+ do {
+ s = lnewline();
+ } while (s==TRUE && --n);
+ return (s);
+ }
+ return (linsert(n, c));
+}
+
+/*
+ * Set tab size if given non-default argument (n <> 1). Otherwise, insert a
+ * tab into file. If given argument, n, of zero, change to true tabs.
+ * If n > 1, simulate tab stop every n-characters using spaces. This has to be
+ * done in this slightly funny way because the tab (in ASCII) has been turned
+ * into "C-I" (in 10 bit code) already. Bound to "C-I".
+ */
+tab(f, n)
+{
+ if (n < 0)
+ return (FALSE);
+ if (n == 0 || n > 1) {
+ tabsize = n;
+ return(TRUE);
+ }
+ if (! tabsize)
+ return(linsert(1, '\t'));
+ return(linsert(tabsize - (getccol(FALSE) % tabsize), ' '));
+}
+
+#if AEDIT
+detab(f, n) /* change tabs to spaces */
+
+int f,n; /* default flag and numeric repeat count */
+
+{
+ register int inc; /* increment to next line [sgn(n)] */
+
+ if (curbp->b_mode&MDVIEW) /* don't allow this command if */
+ return(rdonly()); /* we are in read only mode */
+
+ if (f == FALSE)
+ n = 1;
+
+ /* loop thru detabbing n lines */
+ inc = ((n > 0) ? 1 : -1);
+ while (n) {
+ curwp->w_doto = 0; /* start at the beginning */
+
+ /* detab the entire current line */
+ while (curwp->w_doto < llength(curwp->w_dotp)) {
+ /* if we have a tab */
+ if (lgetc(curwp->w_dotp, curwp->w_doto) == '\t') {
+ ldelete(1L, FALSE);
+ insspace(TRUE, (tabmask+1) - (curwp->w_doto & tabmask));
+ }
+ forwchar(FALSE, 1);
+ }
+
+ /* advance/or back to the next line */
+ forwline(TRUE, inc);
+ n -= inc;
+ }
+ curwp->w_doto = 0; /* to the begining of the line */
+ thisflag &= ~CFCPCN; /* flag that this resets the goal column */
+ lchange(WFEDIT); /* yes, we have made at least an edit */
+ return(TRUE);
+}
+
+entab(f, n) /* change spaces to tabs where posible */
+
+int f,n; /* default flag and numeric repeat count */
+
+{
+ register int inc; /* increment to next line [sgn(n)] */
+ register int fspace; /* pointer to first space if in a run */
+ register int ccol; /* current cursor column */
+ register char cchar; /* current character */
+
+ if (curbp->b_mode&MDVIEW) /* don't allow this command if */
+ return(rdonly()); /* we are in read only mode */
+
+ if (f == FALSE)
+ n = 1;
+
+ /* loop thru entabbing n lines */
+ inc = ((n > 0) ? 1 : -1);
+ while (n) {
+ curwp->w_doto = 0; /* start at the beginning */
+
+ /* entab the entire current line */
+ fspace = -1;
+ ccol = 0;
+ while (curwp->w_doto < llength(curwp->w_dotp)) {
+ /* see if it is time to compress */
+ if ((fspace >= 0) && (nextab(fspace) <= ccol))
+ if (ccol - fspace < 2)
+ fspace = -1;
+ else {
+ /* there is a bug here dealing with mixed space/tabed
+ lines.......it will get fixed */
+ backchar(TRUE, ccol - fspace);
+ ldelete((long)(ccol - fspace), FALSE);
+ linsert(1, '\t');
+ fspace = -1;
+ }
+
+ /* get the current character */
+ cchar = lgetc(curwp->w_dotp, curwp->w_doto);
+
+ switch (cchar) {
+ case '\t': /* a tab...count em up */
+ ccol = nextab(ccol);
+ break;
+
+ case ' ': /* a space...compress? */
+ if (fspace == -1)
+ fspace = ccol;
+ ccol++;
+ break;
+
+ default: /* any other char...just count */
+ ccol++;
+ fspace = -1;
+ break;
+ }
+ forwchar(FALSE, 1);
+ }
+
+ /* advance/or back to the next line */
+ forwline(TRUE, inc);
+ n -= inc;
+ }
+ curwp->w_doto = 0; /* to the begining of the line */
+ thisflag &= ~CFCPCN; /* flag that this resets the goal column */
+ lchange(WFEDIT); /* yes, we have made at least an edit */
+ return(TRUE);
+}
+
+trim(f, n) /* trim trailing whitespace from the point to eol */
+
+int f,n; /* default flag and numeric repeat count */
+
+{
+ register LINE *lp; /* current line pointer */
+ register int offset; /* original line offset position */
+ register int length; /* current length */
+ register int inc; /* increment to next line [sgn(n)] */
+
+ if (curbp->b_mode&MDVIEW) /* don't allow this command if */
+ return(rdonly()); /* we are in read only mode */
+
+ if (f == FALSE)
+ n = 1;
+
+ /* loop thru trimming n lines */
+ inc = ((n > 0) ? 1 : -1);
+ while (n) {
+ lp = curwp->w_dotp; /* find current line text */
+ offset = curwp->w_doto; /* save original offset */
+ length = lp->l_used; /* find current length */
+
+ /* trim the current line */
+ while (length > offset) {
+ if (lgetc(lp, length-1) != ' ' &&
+ lgetc(lp, length-1) != '\t')
+ break;
+ length--;
+ }
+ lp->l_used = length;
+
+ /* advance/or back to the next line */
+ forwline(TRUE, inc);
+ n -= inc;
+ }
+ lchange(WFEDIT);
+ thisflag &= ~CFCPCN; /* flag that this resets the goal column */
+ return(TRUE);
+}
+#endif
+
+/*
+ * Open up some blank space. The basic plan is to insert a bunch of newlines,
+ * and then back up over them. Everything is done by the subcommand
+ * procerssors. They even handle the looping. Normally this is bound to "C-O".
+ */
+openline(f, n)
+{
+ register int i;
+ register int s;
+
+ if (curbp->b_mode&MDVIEW) /* don't allow this command if */
+ return(rdonly()); /* we are in read only mode */
+ if (n < 0)
+ return (FALSE);
+ if (n == 0)
+ return (TRUE);
+ i = n; /* Insert newlines. */
+ do {
+ s = lnewline();
+ } while (s==TRUE && --i);
+ if (s == TRUE) /* Then back up overtop */
+ s = backchar(f, n); /* of them all. */
+ return (s);
+}
+
+/*
+ * Insert a newline. Bound to "C-M". If we are in CMODE, do automatic
+ * indentation as specified.
+ */
+newline(f, n)
+{
+ register int s;
+
+ if (curbp->b_mode&MDVIEW) /* don't allow this command if */
+ return(rdonly()); /* we are in read only mode */
+ if (n < 0)
+ return (FALSE);
+
+ /* if we are in C mode and this is a default <NL> */
+ if (n == 1 && (curbp->b_mode & MDCMOD) &&
+ curwp->w_dotp != curbp->b_linep)
+ return(cinsert());
+
+ /*
+ * If a newline was typed, fill column is defined, the argument is non-
+ * negative, wrap mode is enabled, and we are now past fill column,
+ * and we are not read-only, perform word wrap.
+ */
+ if ((curwp->w_bufp->b_mode & MDWRAP) && fillcol > 0 &&
+ getccol(FALSE) > fillcol &&
+ (curwp->w_bufp->b_mode & MDVIEW) == FALSE)
+ execute(META|SPEC|'W', FALSE, 1);
+
+ /* insert some lines */
+ while (n--) {
+ if ((s=lnewline()) != TRUE)
+ return (s);
+#if SCROLLCODE
+ curwp->w_flag |= WFINS;
+#endif
+ }
+ return (TRUE);
+}
+
+cinsert() /* insert a newline and indentation for C */
+
+{
+ register char *cptr; /* string pointer into text to copy */
+ register int tptr; /* index to scan into line */
+ register int bracef; /* was there a brace at the end of line? */
+ register int i;
+ char ichar[NSTRING]; /* buffer to hold indent of last line */
+
+ /* grab a pointer to text to copy indentation from */
+ cptr = &curwp->w_dotp->l_text[0];
+
+ /* check for a brace */
+ tptr = curwp->w_doto - 1;
+ bracef = (cptr[tptr] == '{');
+
+ /* save the indent of the previous line */
+ i = 0;
+ while ((i < tptr) && (cptr[i] == ' ' || cptr[i] == '\t')
+ && (i < NSTRING - 1)) {
+ ichar[i] = cptr[i];
+ ++i;
+ }
+ ichar[i] = 0; /* terminate it */
+
+ /* put in the newline */
+ if (lnewline() == FALSE)
+ return(FALSE);
+
+ /* and the saved indentation */
+ linstr(ichar);
+
+ /* and one more tab for a brace */
+ if (bracef)
+ tab(FALSE, 1);
+
+#if SCROLLCODE
+ curwp->w_flag |= WFINS;
+#endif
+ return(TRUE);
+}
+
+#if NBRACE
+insbrace(n, c) /* insert a brace into the text here...we are in CMODE */
+
+int n; /* repeat count */
+int c; /* brace to insert (always } for now) */
+
+{
+ register int ch; /* last character before input */
+ register int oc; /* caractere oppose a c */
+ register int i, count;
+ register int target; /* column brace should go after */
+ register LINE *oldlp;
+ register int oldoff;
+
+ /* if we aren't at the beginning of the line... */
+ if (curwp->w_doto != 0)
+
+ /* scan to see if all space before this is white space */
+ for (i = curwp->w_doto - 1; i >= 0; --i) {
+ ch = lgetc(curwp->w_dotp, i);
+ if (ch != ' ' && ch != '\t')
+ return(linsert(n, c));
+ }
+
+ /* chercher le caractere oppose correspondant */
+ switch (c) {
+ case '}': oc = '{'; break;
+ case ']': oc = '['; break;
+ case ')': oc = '('; break;
+ default: return(FALSE);
+ }
+
+ oldlp = curwp->w_dotp;
+ oldoff = curwp->w_doto;
+
+ count = 1; backchar(FALSE, 1);
+
+ while (count > 0) {
+ if (curwp->w_doto == llength(curwp->w_dotp))
+ ch = '\n';
+ else
+ ch = lgetc(curwp->w_dotp, curwp->w_doto);
+
+ if (ch == c) ++count;
+ if (ch == oc) --count;
+
+ backchar(FALSE, 1);
+ if (boundry(curwp->w_dotp, curwp->w_doto, REVERSE))
+ break;
+ }
+
+ if (count != 0) { /* no match */
+ curwp->w_dotp = oldlp;
+ curwp->w_doto = oldoff;
+ return(linsert(n, c));
+ }
+
+ curwp->w_doto = 0; /* debut de ligne */
+ /* aller au debut de la ligne apres la tabulation */
+ while ((ch = lgetc(curwp->w_dotp, curwp->w_doto)) == ' ' || ch == '\t')
+ forwchar(FALSE, 1);
+
+ /* delete back first */
+ target = getccol(FALSE); /* c'est l'indent que l'on doit avoir */
+ curwp->w_dotp = oldlp;
+ curwp->w_doto = oldoff;
+
+ while (target != getccol(FALSE)) {
+ if (target < getccol(FALSE)) /* on doit detruire des caracteres */
+ while (getccol(FALSE) > target)
+ backdel(FALSE, 1);
+ else { /* on doit en inserer */
+ while (target - getccol(FALSE) >= 8)
+ linsert(1,'\t');
+ linsert(target - getccol(FALSE), ' ');
+ }
+ }
+
+ /* and insert the required brace(s) */
+ return(linsert(n, c));
+}
+#else
+insbrace(n, c) /* insert a brace into the text here...we are in CMODE */
+
+int n; /* repeat count */
+int c; /* brace to insert (always { for now) */
+
+{
+ register int ch; /* last character before input */
+ register int i;
+ register int target; /* column brace should go after */
+
+ /* if we are at the beginning of the line, no go */
+ if (curwp->w_doto == 0)
+ return(linsert(n,c));
+
+ /* scan to see if all space before this is white space */
+ for (i = curwp->w_doto - 1; i >= 0; --i) {
+ ch = lgetc(curwp->w_dotp, i);
+ if (ch != ' ' && ch != '\t')
+ return(linsert(n, c));
+ }
+
+ /* delete back first */
+ target = getccol(FALSE); /* calc where we will delete to */
+ target -= 1;
+ target -= target % (tabsize == 0 ? 8 : tabsize);
+ while (getccol(FALSE) > target)
+ backdel(FALSE, 1);
+
+ /* and insert the required brace(s) */
+ return(linsert(n, c));
+}
+#endif
+
+inspound() /* insert a # into the text here...we are in CMODE */
+
+{
+ register int ch; /* last character before input */
+ register int i;
+
+ /* if we are at the beginning of the line, no go */
+ if (curwp->w_doto == 0)
+ return(linsert(1,'#'));
+
+ /* scan to see if all space before this is white space */
+ for (i = curwp->w_doto - 1; i >= 0; --i) {
+ ch = lgetc(curwp->w_dotp, i);
+ if (ch != ' ' && ch != '\t')
+ return(linsert(1, '#'));
+ }
+
+ /* delete back first */
+ while (getccol(FALSE) >= 1)
+ backdel(FALSE, 1);
+
+ /* and insert the required pound */
+ return(linsert(1, '#'));
+}
+
+/*
+ * Delete blank lines around dot. What this command does depends if dot is
+ * sitting on a blank line. If dot is sitting on a blank line, this command
+ * deletes all the blank lines above and below the current line. If it is
+ * sitting on a non blank line then it deletes all of the blank lines after
+ * the line. Normally this command is bound to "C-X C-O". Any argument is
+ * ignored.
+ */
+deblank(f, n)
+{
+ register LINE *lp1;
+ register LINE *lp2;
+ long nld;
+
+ if (curbp->b_mode&MDVIEW) /* don't allow this command if */
+ return(rdonly()); /* we are in read only mode */
+ lp1 = curwp->w_dotp;
+ while (llength(lp1)==0 && (lp2=lback(lp1))!=curbp->b_linep)
+ lp1 = lp2;
+ lp2 = lp1;
+ nld = 0;
+ while ((lp2=lforw(lp2))!=curbp->b_linep && llength(lp2)==0)
+ ++nld;
+ if (nld == 0)
+ return (TRUE);
+ curwp->w_dotp = lforw(lp1);
+ curwp->w_doto = 0;
+ return (ldelete(nld, FALSE));
+}
+
+/*
+ * Insert a newline, then enough tabs and spaces to duplicate the indentation
+ * of the previous line. Assumes tabs are every eight characters. Quite simple.
+ * Figure out the indentation of the current line. Insert a newline by calling
+ * the standard routine. Insert the indentation by inserting the right number
+ * of tabs and spaces. Return TRUE if all ok. Return FALSE if one of the
+ * subcomands failed. Normally bound to "C-J".
+ */
+indent(f, n)
+{
+ register int nicol;
+ register int c;
+ register int i;
+
+ if (curbp->b_mode&MDVIEW) /* don't allow this command if */
+ return(rdonly()); /* we are in read only mode */
+ if (n < 0)
+ return (FALSE);
+ while (n--) {
+ nicol = 0;
+ for (i=0; i<llength(curwp->w_dotp); ++i) {
+ c = lgetc(curwp->w_dotp, i);
+ if (c!=' ' && c!='\t')
+ break;
+ if (c == '\t')
+ nicol |= tabmask;
+ ++nicol;
+ }
+ if (lnewline() == FALSE
+ || ((i=nicol/8)!=0 && linsert(i, '\t')==FALSE)
+ || ((i=nicol%8)!=0 && linsert(i, ' ')==FALSE))
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+/*
+ * Delete forward. This is real easy, because the basic delete routine does
+ * all of the work. Watches for negative arguments, and does the right thing.
+ * If any argument is present, it kills rather than deletes, to prevent loss
+ * of text if typed with a big argument. Normally bound to "C-D".
+ */
+forwdel(f, n)
+{
+ if (curbp->b_mode&MDVIEW) /* don't allow this command if */
+ return(rdonly()); /* we are in read only mode */
+ if (n < 0)
+ return (backdel(f, -n));
+ if (f != FALSE) { /* Really a kill. */
+ if ((lastflag&CFKILL) == 0)
+ kdelete();
+ thisflag |= CFKILL;
+ }
+ return (ldelete((long)n, f));
+}
+
+/*
+ * Delete backwards. This is quite easy too, because it's all done with other
+ * functions. Just move the cursor back, and delete forwards. Like delete
+ * forward, this actually does a kill if presented with an argument. Bound to
+ * both "RUBOUT" and "C-H".
+ */
+backdel(f, n)
+{
+ register int s;
+
+ if (curbp->b_mode&MDVIEW) /* don't allow this command if */
+ return(rdonly()); /* we are in read only mode */
+ if (n < 0)
+ return (forwdel(f, -n));
+ if (f != FALSE) { /* Really a kill. */
+ if ((lastflag&CFKILL) == 0)
+ kdelete();
+ thisflag |= CFKILL;
+ }
+ if ((s=backchar(f, n)) == TRUE)
+ s = ldelete((long)n, f);
+ return (s);
+}
+
+/*
+ * Kill text. If called without an argument, it kills from dot to the end of
+ * the line, unless it is at the end of the line, when it kills the newline.
+ * If called with an argument of 0, it kills from the start of the line to dot.
+ * If called with a positive argument, it kills from dot forward over that
+ * number of newlines. If called with a negative argument it kills backwards
+ * that number of newlines. Normally bound to "C-K".
+ */
+killtext(f, n)
+{
+ register LINE *nextp;
+ long chunk;
+
+ if (curbp->b_mode&MDVIEW) /* don't allow this command if */
+ return(rdonly()); /* we are in read only mode */
+ if ((lastflag&CFKILL) == 0) /* Clear kill buffer if */
+ kdelete(); /* last wasn't a kill. */
+ thisflag |= CFKILL;
+ if (f == FALSE) {
+ chunk = llength(curwp->w_dotp)-curwp->w_doto;
+ if (chunk == 0)
+ chunk = 1;
+ } else if (n == 0) {
+ chunk = curwp->w_doto;
+ curwp->w_doto = 0;
+ } else if (n > 0) {
+ chunk = llength(curwp->w_dotp)-curwp->w_doto+1;
+ nextp = lforw(curwp->w_dotp);
+ while (--n) {
+ if (nextp == curbp->b_linep)
+ return (FALSE);
+ chunk += llength(nextp)+1;
+ nextp = lforw(nextp);
+ }
+ } else {
+ mlwrite("neg kill");
+ return (FALSE);
+ }
+ return(ldelete(chunk, TRUE));
+}
+
+setmode(f, n) /* prompt and set an editor mode */
+
+int f, n; /* default and argument */
+
+{
+#if PKCODE
+ return adjustmode(TRUE, FALSE);
+#else
+ adjustmode(TRUE, FALSE);
+#endif
+}
+
+delmode(f, n) /* prompt and delete an editor mode */
+
+int f, n; /* default and argument */
+
+{
+#if PKCODE
+ return adjustmode(FALSE, FALSE);
+#else
+ adjustmode(FALSE, FALSE);
+#endif
+}
+
+setgmode(f, n) /* prompt and set a global editor mode */
+
+int f, n; /* default and argument */
+
+{
+#if PKCODE
+ return adjustmode(TRUE, TRUE);
+#else
+ adjustmode(TRUE, TRUE);
+#endif
+}
+
+delgmode(f, n) /* prompt and delete a global editor mode */
+
+int f, n; /* default and argument */
+
+{
+#if PKCODE
+ return adjustmode(FALSE, TRUE);
+#else
+ adjustmode(FALSE, TRUE);
+#endif
+}
+
+adjustmode(kind, global) /* change the editor mode status */
+
+int kind; /* true = set, false = delete */
+int global; /* true = global flag, false = current buffer flag */
+{
+ register char *scan; /* scanning pointer to convert prompt */
+ register int i; /* loop index */
+ register int status; /* error return on input */
+#if COLOR
+ register int uflag; /* was modename uppercase? */
+#endif
+ char prompt[50]; /* string to prompt user with */
+ char cbuf[NPAT]; /* buffer to recieve mode name into */
+
+ /* build the proper prompt string */
+ if (global)
+ strcpy(prompt,"Global mode to ");
+ else
+ strcpy(prompt,"Mode to ");
+
+ if (kind == TRUE)
+ strcat(prompt, "add: ");
+ else
+ strcat(prompt, "delete: ");
+
+ /* prompt the user and get an answer */
+
+ status = mlreply(prompt, cbuf, NPAT - 1);
+ if (status != TRUE)
+ return(status);
+
+ /* make it uppercase */
+
+ scan = cbuf;
+#if COLOR
+ uflag = (*scan >= 'A' && *scan <= 'Z');
+#endif
+ while (*scan != 0) {
+ if (*scan >= 'a' && *scan <= 'z')
+ *scan = *scan - 32;
+ scan++;
+ }
+
+ /* test it first against the colors we know */
+#if PKCODE & IBMPC
+ for (i=0; i<=NCOLORS; i++) {
+#else
+ for (i=0; i<NCOLORS; i++) {
+#endif
+ if (strcmp(cbuf, cname[i]) == 0) {
+ /* finding the match, we set the color */
+#if COLOR
+ if (uflag)
+ {
+ if (global)
+ gfcolor = i;
+#if PKCODE == 0
+ else
+#endif
+ curwp->w_fcolor = i;
+ }
+ else
+ {
+ if (global)
+ gbcolor = i;
+#if PKCODE == 0
+ else
+#endif
+ curwp->w_bcolor = i;
+ }
+
+ curwp->w_flag |= WFCOLR;
+#endif
+ mlerase();
+ return(TRUE);
+ }
+ }
+
+ /* test it against the modes we know */
+
+ for (i=0; i < NUMMODES; i++) {
+ if (strcmp(cbuf, modename[i]) == 0) {
+ /* finding a match, we process it */
+ if (kind == TRUE)
+ if (global)
+ gmode |= (1 << i);
+ else
+ curbp->b_mode |= (1 << i);
+ else
+ if (global)
+ gmode &= ~(1 << i);
+ else
+ curbp->b_mode &= ~(1 << i);
+ /* display new mode line */
+ if (global == 0)
+ upmode();
+ mlerase(); /* erase the junk */
+ return(TRUE);
+ }
+ }
+
+ mlwrite("No such mode!");
+ return(FALSE);
+}
+
+/* This function simply clears the message line,
+ mainly for macro usage */
+
+clrmes(f, n)
+
+int f, n; /* arguments ignored */
+
+{
+ mlforce("");
+ return(TRUE);
+}
+
+/* This function writes a string on the message line
+ mainly for macro usage */
+
+writemsg(f, n)
+
+int f, n; /* arguments ignored */
+
+{
+ register char *sp; /* pointer into buf to expand %s */
+ register char *np; /* ptr into nbuf */
+ register int status;
+ char buf[NPAT]; /* buffer to recieve message into */
+ char nbuf[NPAT*2]; /* buffer to expand string into */
+
+ if ((status = mlreply("Message to write: ", buf, NPAT - 1)) != TRUE)
+ return(status);
+
+ /* expand all '%' to "%%" so mlwrite won't expect arguments */
+ sp = buf;
+ np = nbuf;
+ while (*sp) {
+ *np++ = *sp;
+ if (*sp++ == '%')
+ *np++ = '%';
+ }
+ *np = '\0';
+
+ /* write the message out */
+ mlforce(nbuf);
+ return(TRUE);
+}
+
+#if CFENCE
+/* the cursor is moved to a matching fence */
+
+getfence(f, n)
+
+int f, n; /* not used */
+
+{
+ register LINE *oldlp; /* original line pointer */
+ register int oldoff; /* and offset */
+ register int sdir; /* direction of search (1/-1) */
+ register int count; /* current fence level count */
+ register char ch; /* fence type to match against */
+ register char ofence; /* open fence */
+ register char c; /* current character in scan */
+
+ /* save the original cursor position */
+ oldlp = curwp->w_dotp;
+ oldoff = curwp->w_doto;
+
+ /* get the current character */
+ if (oldoff == llength(oldlp))
+ ch = '\n';
+ else
+ ch = lgetc(oldlp, oldoff);
+
+ /* setup proper matching fence */
+ switch (ch) {
+ case '(': ofence = ')'; sdir = FORWARD; break;
+ case '{': ofence = '}'; sdir = FORWARD; break;
+ case '[': ofence = ']'; sdir = FORWARD; break;
+ case ')': ofence = '('; sdir = REVERSE; break;
+ case '}': ofence = '{'; sdir = REVERSE; break;
+ case ']': ofence = '['; sdir = REVERSE; break;
+ default: TTbeep(); return(FALSE);
+ }
+
+ /* set up for scan */
+ count = 1;
+ if (sdir == REVERSE)
+ backchar(FALSE, 1);
+ else
+ forwchar(FALSE, 1);
+
+ /* scan until we find it, or reach the end of file */
+ while (count > 0) {
+ if (curwp->w_doto == llength(curwp->w_dotp))
+ c = '\n';
+ else
+ c = lgetc(curwp->w_dotp, curwp->w_doto);
+ if (c == ch)
+ ++count;
+ if (c == ofence)
+ --count;
+ if (sdir == FORWARD)
+ forwchar(FALSE, 1);
+ else
+ backchar(FALSE, 1);
+ if (boundry(curwp->w_dotp, curwp->w_doto, sdir))
+ break;
+ }
+
+ /* if count is zero, we have a match, move the sucker */
+ if (count == 0) {
+ if (sdir == FORWARD)
+ backchar(FALSE, 1);
+ else
+ forwchar(FALSE, 1);
+ curwp->w_flag |= WFMOVE;
+ return(TRUE);
+ }
+
+ /* restore the current position */
+ curwp->w_dotp = oldlp;
+ curwp->w_doto = oldoff;
+ TTbeep();
+ return(FALSE);
+}
+#endif
+
+/* Close fences are matched against their partners, and if
+ on screen the cursor briefly lights there */
+
+fmatch(ch)
+
+char ch; /* fence type to match against */
+
+{
+ register LINE *oldlp; /* original line pointer */
+ register int oldoff; /* and offset */
+ register LINE *toplp; /* top line in current window */
+ register int count; /* current fence level count */
+ register char opench; /* open fence */
+ register char c; /* current character in scan */
+ register int i;
+
+ /* first get the display update out there */
+ update(FALSE);
+
+ /* save the original cursor position */
+ oldlp = curwp->w_dotp;
+ oldoff = curwp->w_doto;
+
+ /* setup proper open fence for passed close fence */
+ if (ch == ')')
+ opench = '(';
+ else if (ch == '}')
+ opench = '{';
+ else
+ opench = '[';
+
+ /* find the top line and set up for scan */
+ toplp = curwp->w_linep->l_bp;
+ count = 1;
+ backchar(FALSE, 2);
+
+ /* scan back until we find it, or reach past the top of the window */
+ while (count > 0 && curwp->w_dotp != toplp) {
+ if (curwp->w_doto == llength(curwp->w_dotp))
+ c = '\n';
+ else
+ c = lgetc(curwp->w_dotp, curwp->w_doto);
+ if (c == ch)
+ ++count;
+ if (c == opench)
+ --count;
+ backchar(FALSE, 1);
+ if (curwp->w_dotp == curwp->w_bufp->b_linep->l_fp &&
+ curwp->w_doto == 0)
+ break;
+ }
+
+ /* if count is zero, we have a match, display the sucker */
+ /* there is a real machine dependant timing problem here we have
+ yet to solve......... */
+ if (count == 0) {
+ forwchar(FALSE, 1);
+ for (i = 0; i < term.t_pause; i++)
+ update(FALSE);
+ }
+
+ /* restore the current position */
+ curwp->w_dotp = oldlp;
+ curwp->w_doto = oldoff;
+ return(TRUE);
+}
+
+istring(f, n) /* ask for and insert a string into the current
+ buffer at the current point */
+
+int f, n; /* ignored arguments */
+
+{
+ register int status; /* status return code */
+ char tstring[NPAT+1]; /* string to add */
+
+ /* ask for string to insert */
+ status = mlreplyt("String to insert<META>: ", tstring, NPAT, metac);
+ if (status != TRUE)
+ return(status);
+
+ if (f == FALSE)
+ n = 1;
+
+ if (n < 0)
+ n = - n;
+
+ /* insert it */
+ while (n-- && (status = linstr(tstring)))
+ ;
+ return(status);
+}
+
+ovstring(f, n) /* ask for and overwite a string into the current
+ buffer at the current point */
+
+int f, n; /* ignored arguments */
+
+{
+ register int status; /* status return code */
+ char tstring[NPAT+1]; /* string to add */
+
+ /* ask for string to insert */
+ status = mlreplyt("String to overwrite<META>: ", tstring, NPAT, metac);
+ if (status != TRUE)
+ return(status);
+
+ if (f == FALSE)
+ n = 1;
+
+ if (n < 0)
+ n = - n;
+
+ /* insert it */
+ while (n-- && (status = lover(tstring)))
+ ;
+ return(status);
+}
+
diff --git a/readme b/readme
new file mode 100644
index 0000000..ed22b86
--- /dev/null
+++ b/readme
@@ -0,0 +1,182 @@
++---------------+
+| uEmacs/PK 4.0 |
++---------------+
+
+ Full screen editor based on MicroEMACS 3.9e
+
+ MicroEMACS was written by Dave G. Conroy and
+ greatly modified by Daniel M. Lawrence
+
+ Copyright Notices:
+
+ MicroEMACS 3.9 (c) Copyright 1987 Daniel M. Lawrence.
+ Reference Manual Copyright 1987 by Brian Straight and
+ Daniel M. Lawrence. No copyright claimed for modifications
+ made by Petri H. Kutvonen.
+
+ Original statement of copying policy:
+
+ MicroEMACS 3.9 can be copied and distributed freely for any
+ non-commercial purposes. MicroEMACS 3.9 can only be incorporated
+ into commercial software with the permission of the current author
+ [Daniel M. Lawrence].
+
+
+WHAT IS uEmacs/PK?
+
+uEmacs/PK 4.0 is an enhanced version of MicroEMACS 3.9e. Enhancements
+have been incorporated by Petri H. Kutvonen, University of Helsinki,
+Finland <kutvonen@cs.Helsinki.FI>.
+
+
+WHY IS IT BASED ON AN OLD VERSION OF MicroEMACS?
+
+In my opinion 3.9e was the best of all MicroEMACSes. Creeping
+featurism, growing size, and reduced portability made versions 3.10 and
+3.11 less attractive. MicroEMACS 3.9e was one of the few editors that
+were truly portable between different flavours of UNIX, PC/MS-DOS, and
+VAX/VMS. It was pretty robust - although not flawless. uEmacs/PK 4.0
+includes numerous bug fixes, adds some new functionality and comfort but
+does not sacrifice the best things (small size and portability).
+
+
+WHAT IS NEW - COMPARED TO MicroEMACS 3.9e?
+
+Enhachements:
+
+o advisory file locking on BSD-derived systems
+o new screen update algorithm, borrowed largely form "vile" by
+ Paul G. Fox <pgf@cayman.com>, uEmacs can now be used on slow (1200 bps)
+ connections because it uses terminal scrolling capabilities
+o new variables $scroll, $jump, and $overlap to control scrolling
+o uEmacs reacts to windows size change signals (UNIX), also from "vile"
+o automatic file name completion, works under UNIX and PC/MS-DOS
+o functions keys on VT200 style keyboards can be used
+o new command: justify-paragraph (Meta J)
+o something important for us Europeans: allow the use of 8 bit ISO Latin 1
+ alphabet (UNIX and VMS), on an IBM-PC the accented characters are
+ interpreted as letters too
+o the characters {|}[\] can be interpreted as letters, these are
+ frequently used as "national replacement characters" especially in
+ the Nordic countries
+o allow use of XON/XOFF flow control: alternative key sequences for
+ ^S and ^Q, don't disable flow control
+o speed up reading of files (under VMS especially)
+o new variable $tab, hardware tab stop (4 or 8)
+o automatic configuration on some common systems
+o new style mode line, includes percentage indicator
+o new help file
+
+Bug fixes - not very interesting:
+
+o use TI and TE termcap strings, uEmacs works now correctly under
+ Sunview and OpenWindows
+o use old protection mask on existing files (VMS)
+o catch data overrun errors (VMS)
+o allow VMS file names with characters < and >, replacements for [ and ]
+o allow ANSI screens larger than 24 lines
+o fix add/delete(-global)-mode
+o display EOF as char = 0x0, not as garbage
+o allow upper case letters in answers
+o fix command interpreter spawning
+o don't use reverse video on some (TVI925 style) terminals
+o fix message line writing
+o fix replace/undo
+o fix &left and &mid functions
+o fix documentation
+o smaller bug fixes are too numerous to mention
+
+Something is gone:
+
+o removed (obsolete and untested) support for Amiga, Atari, and Mac
+
+
+WHERE HAS IT BEEN TESTED?
+
+uEmacs/PK 4.0 has been tested by myself on the following platforms:
+
+ IBM PC and compatibles, PC/MS-DOS 3.2 and up
+ Sun 3, SunOS 4.1.1
+ SPARC, SunOS 4.1.X and 5.{2|3|4|5} (Solaris 2)
+ VAX 8800 and 6000-420, VMS 5.4
+ DECstation 3100, Ultrix V4.1
+ IBM RS/6000, AIX 3.1.5
+ IBM PS/2, UNIX System V/386 Release 3.2
+ uVAX II, Ultrix V2.0
+ AT&T 3B2/400, UNIX System V Release 2.0
+ Various Toshiba i486 laptops, Linux 0.99pl13 thru 2.0.21
+
+I have no reason to believe that there would be any problems to port
+uEmacs/PK 4.0 to any reasonable BSD-, OSF/1-, or SVR4-based UNIX system.
+
+
+HOW CAN I GET IT?
+
+uEmacs/PK is available by anonymous FTP from ftp.cs.Helsinki.FI (IP
+address can change) in the directory pub/Software/Local/uEmacs-PK. You
+cannot get it by email of uucp. Hopefully it will bee soon available
+from other file servers too.
+
+
+WHAT IS IN THE PACKAGE
+
+o em-4.0.<x>.tar.gz: full source, make and command files to build the
+ editor, reference manual as a MS-Write document,
+ tarred and gzipped, for patchlevel <x>
+
+o there used to be a packages with binaries for PC/MS-DOS,
+ SPARC/SunOS4, Sun 3, MIPS/Ultrix, 386/ix, IBM RS/6000, VAX/VMS,
+ if you are really desperate you can try contacting me for an old
+ version of these
+
+
+HOW TO INSTALL uEmacs/PK?
+
+o PC/MS-DOS: Compile the package with using Turbo C 2.0 or MSC 6.0.
+ (Pretty obsolete both of these.) There are some support files
+ you might find useful in the full distribution.
+
+o UNIX: Copy makefile.unx to makefile, edit to taste, look at estruct.h,
+ do a 'make', test the editor, 'make install'.
+
+o VMS: To compile use '@VMSMAKE', install manually, uEmacs/PK uses a
+ logical name EMACS_DIR to locate its initialization files.
+
+
+CONTACT INFORMATION
+
+There will probably not be many new versions of uEmacs/PK, maybe just
+some bug fixes. I have no intention to develope the code any further.
+However, if you have some comments or good suggestions, you may find
+the email address below useful.
+
+Petri H. Kutvonen
+Department of Computer Science
+P.O.Box 26 (Teollisuuskatu 23)
+FIN-00014 UNIVERSTITY OF HELSINKI
+Finland
+
+email: kutvonen@cs.Helsinki.FI
+fax: +358 9 70844441
+
+
+ACKNOWLEDGEMENTS AND STATUS
+
+I would like to thank Linus Torvalds and Jyrki Havia for their work on
+some bugs. uEmacs/PK 4.0.10 included fixes for a number of bugs and it
+was assumed to be the final release for the UNIX platform. However,
+there has been a couple of maintenance releases, so the final version is
+4.0.13. On other platforms there has been no new releases since 4.0.3 in
+1991.
+
+April 23, 1995
+
+And yet another release (thanks Linus)! This is most definitely the
+really last (not latest) version, 4.0.14. Hmm ... 14 looks nicer than 13.
+
+May 2, 1996
+
+Still one more release - or actually a small patch - which closes a
+potential security hole. Now we are at 4.0.15. This IS the FINAL release!
+
+September 25, 1996
diff --git a/readme.39e b/readme.39e
new file mode 100644
index 0000000..8049f26
--- /dev/null
+++ b/readme.39e
@@ -0,0 +1,331 @@
+ MicroEMACS 3.9 Release Notes July 22, 1987
+
+**********************************************************************
+
+ (C)opyright 1987 by Daniel M. Lawrence
+ MicroEMACS 3.9 can be copied and distributed freely for any
+ non-commercial purposes. MicroEMACS 3.9 can only be incorporated
+ into commercial software with the permission of the current author.
+
+**********************************************************************
+
+ MicroEMACS 3.9 is availible in a couple of different ways.
+First, it is availible via my bulletin board system.....
+
+ The Programmer's Room
+ FIDO 201/2
+ (317) 742-5533
+ 24 hours 300/1200 baud
+
+ Also it should be online on the following BBS's:
+
+ The Starship Trooper Fido 201/1 (317) 423-2281 2400
+
+ [These following two are open from 10pm till 5pm
+ and only while Purdue is in session]
+ The NightStaff Fido 201/4 (317) 495-4270 1200
+ The Access Violation Fido 201/5 (317) 495-4270 9600
+
+ There it is arranged as three MSDOS .ARC files, EMACSDOC.ARC
+which contains the documentation and command files, EMACSSRC.ARC which
+contains the sources and the UNIX Makefile, and EMACSEXE.EXE which
+contains the MSDOS executables. Also all the various executables are
+available individually.
+
+EMACSDOC.ARC includes the files:
+
+ README This file
+
+ (These four files should be in your path for the standard setup)
+ EMACS.RC Standard startup file
+ NEWPAGE.CMD Shifted Function key Pager
+ PPAGE.CMD Programming page
+ WPAGE.CMD Word processing page
+ BPAGE.CMD Block and box manipulation page
+
+ ME110.RC HP110 startup file
+ ME150.RC HP150 startup file
+ AMIGA.RC AMIGA ".emacsrc" startup file
+ ST520.RC ATARI ST startup file
+
+ EMACS.HLP Online help file
+ EMACS.MSS MicroSCRIBE format of EMACS.TXT
+ EMACS.TXT EMACS BEGINNER'S/REFERENCE MANUAL
+
+ AZMAP.CMD Translate AZTEC .SYM files to .MAP
+ BDATA.CMD BASIC Data statement builder
+ FINDCOM.CMD Find mismatched C comments
+ FUNC.CMD Allow function keys on systems with non (like UNIX)
+ MENU.CMD Sample Menu system
+ MENU1 datafile for menu system
+ SHELL.CMD Sample interactive MSDOS shell
+ TRAND.CMD Generate random numbers and do statistics on them
+
+EMACSSRC.ARC includes the files:
+
+ ALINE.H Atari ST graphic header file
+ ANSI.C ANSI screen driver
+ BASIC.C basic cursor movement
+ BIND.C key binding commands
+ BUFFER.C buffer manipulation commands
+ CRYPT.C encryption functions
+ DOLOCK file locking stub routines
+ DG10.C Data General 10 screen driver
+ DISPLAY.C main display driver
+ EBIND.H binding list
+ EDEF.H global variable declarations
+ EFUNC.H function name list
+ EPATH.H default path settings
+ ESTRUCT.H configuration and structure definitions
+ EVAL.C expression evaluator
+ EVAR.H EMACS macro variable declarations
+ EXEC.C macro execution functions
+ FILE.C user file functions
+ FILEIO.C low level file I/O driver
+ HP110.C HP110 screen driver
+ HP150.C HP150(A or C) screen driver
+ IBMPC.C IBM-PC CGA and MONOCHROME driver
+ INPUT.C low level user input driver
+ ISEARCH.C incremental search functions
+ LINE.C text line manipulation functions
+ LOCK.C file locking functions
+ MAIN.C argument parsing and command loop
+ RANDOM.C other random user functions
+ REGION.C region cut & paste functions
+ SEARCH.C search and replace functions
+ SPAWN.C OS interface driver
+ ST520.C ATARI ST1040 screen driver
+ TCAP.C Termcap screen driver
+ TERMIO.C low level I/O driver
+ TIPC.C TI-PC screen driver
+ VMSVT.C VMS screen driver
+ VT52.C VT52 screen driver
+ WINDOW.C window manipulation functions
+ WORD.C word manipulation functions
+ Z309.C Zenith 100 PC series terminal driver
+
+EMACSEXE.ARC includes the files:
+
+ MEIBM.EXE IBM-PC CGA/MONO/EGA version
+ MEANSI.EXE MSDOS ANSI graphics version
+ ME110.EXE HP110 portable version
+ ME150.EXE HP150 version
+ ME309.EXE Zenith 100 PC series version
+ ME520.PRG Atari 520/1040ST version
+ MEAMIGA. Amiga 1000 version
+
+ Recently, MicroSPELL 1.0 has been released. This program allows
+you to spell check text files and uses MicroEMACS to scan the file,
+doing various corrections.
+
+ MicroSCRIBE, a fairly SCRIBE compatible text formatter to go
+along with these programs will probably be available for beta testing
+early spring 1988. This program is turning out to be a lot more complex
+than I thought it would be, and is taking more time to get out.
+
+ I have in my possesion a port of MicroEMACS 3.8i to the
+Macintosh, and I will be incorporating the needed changes for the current
+version to support the Macintosh.
+
+ As before, I will continue to support these programs, and
+encourage everyone to spread them around as much as they can. If you
+make what you think are changes that are useful to many, send me the
+updates, and as time permits, I will incorporate the ones I understand,
+and agree with into the master sources.
+
+ MicroEMACS is available on disk directly from my by sending me
+$25 per order and a note specifying the disk format and the product that
+you need. I can fill orders for IBM-PC high/low density 5 1/4 and 3
+1/5, ATARI ST single and double density, AMIGA disks and HP150 disks.
+(You do not need to send disks or mailers, I will provide these.) The
+distribution set includes on disk all docs, executables and sources.
+Also I will register you and you will receive automatic notices of new
+versions of all the programs I am releasing.
+
+ Commercial lisences to allow MicroEMACS to be incorporated into
+other software packages are also available at a reasonable per package
+price. Also I am available to do customization of MicroEMACS at an
+hourly rate. Send all requests to the address below:
+
+ USmail: Daniel Lawrence
+ 617 New York St
+ Lafayette, IN 47901
+
+ UUCP: pur-ee!j.cc.purdue.edu!nwd
+ ARPA: nwd@j.cc.purdue.edu
+ FIDO: The Programmer's Room 201/2
+ (317) 742-5533
+ ATT: (317) 742-5153
+
+
+ New Features since version 3.8i
+ ===============================
+
+** New standard startup file
+
+ The new emacs.rc file is segmented into more parts and loads much
+faster than before. Separate "pages" of shifted function keys are
+available. Users can write their own "pages".
+
+*** New Variables (there are a lot...)
+
+ $status returns status of last command
+ $palette color palette settings
+ $lastkey returns last keystroke
+ $curchar returns and set the ascii number of the
+ character under the point
+ $progname always returns "MicroEMACS"
+ $version always returns the current version ("3.9")
+ $discmd sets display of messages on the command
+ line (except via the write-message command)
+ $disinp sets echoing of characters during input on the
+ command line
+ $wline returns and sets # lines in current window
+ $cwline returns and set current line within window
+ $target returns/sets target for line moves
+ $search returns/sets default search string
+ $replace returns/sets default replace string
+ $match returns last matched string in magic search
+ $cmode returns/sets encoded mode of current buffer
+ $gmode returns/sets encoded global mode (see appendix E
+ in emacs.mss to decode this)
+ $tpause returns/sets the pause for fence matching
+ (this is in rather arbitrary units which
+ WILL vary from machine to machine)
+ $line return/sets the contents of the current line
+ $gflags global operations flag (see emacs.txt Appendix G)
+ $rval child process return value
+
+*** New computers supported
+
+ Atari 1040ST all three graphics modes and 50 line mode on a
+ monochrome monitor. The mouse is bound to the
+ cursor keys for now.
+
+*** New Compilers supported
+
+ Turbo C v1.0 under MSDOS is now a supported compiler.
+ Mark Williams C on the Atari ST is also supported.
+
+** New directives
+
+ !while <condition> loops while <cond> is true
+
+ !break breaks out of the innermost !while
+
+ !endwhile delimits the end of a !while loop
+
+ All !gotos are legal into and out of a !while loop.
+
+*** Autosave mode
+
+ This mode saves the file out to disk every time 256 have been
+inserted. $asave controls the # of characters between saves, $acount
+controls the # of chars to the next save.
+
+*** New functions
+
+ &and <log> <log> Logical AND
+ &or <log> <log> Logical OR
+ &len <str> returns length of <str>
+ &lower <str> lowercase <str>
+ &upper <str> uppercase <str>
+ &rnd <int> generate a random integer between 1 and <int>
+ &sindex <str1> <str2> search for string 2 within string 1
+ returning its position, or zero if it fails
+ &env <str> return value of DOS environment
+ variable <str>
+ &bind <str> returns the function name bound to the
+ key <str>
+ &exist <str> Does file <str> exist?
+ &find <str> find file <str> along the PATH
+ &band <num> <num> bitwise and
+ &bor <num> <num> bitwise or
+ &bxor <num> <num> bitwise xor
+ &bnot <num> bitwise not
+ &xlate <str1> <str2> <str3>
+ scan <str1> replacing characters in
+ <str2> with the coresponding characters
+ in <str3>
+
+*** Advanced word processing commands
+
+ ^X^T trim-line trim all trailing whitespace
+ ^X^E entab-line change all multiple char runs to tabs
+ ^X^D detab-line change all tabs to multiple spaces
+
+*** Merged EGA driver
+
+ The EGA driver is now part of the IBM-PC driver. This driver now
+supports MONO, CGA and EGA cards/modes. (settable by using the $sres
+variable)
+
+*** 8 bit characters fully supported
+
+ Eight bit characters (including foreign language and line
+drawing characters) are now supported on the various micro environments)
+
+*** List Buffers expanded
+
+ Given a numeric argument, ^X^B (list-buffers) will now also list
+all the hidden internal buffers.
+
+*** -k switch enhanced
+
+ If you use the -k (encrypted file) switch on the command line
+without a key immediatly following it, it will prompt you for the key to
+use to decrypt with.
+
+*** word delete enhanced
+
+ with a zero (0) argument, M-D (delete-next-word) deletes the
+next word and not any intervening whitespace or special characters.
+
+*** New File read hook
+
+ Whenever MicroEMACS reads a file from disk, right before it is
+read, whatever function is bound to M-FNR (which is an illegal
+keystroke) will execute. By default this would be (nop), but the
+standard emacs.rc binds this to a file that examines the file name and
+places the buffer int CMODE if the extension ends in a .c or .h. You can
+of course redefine this macro to taste.
+
+*** Search Path modified
+
+ The order in which emacs looks for all .rc (startup) and
+.cmd (command macros) is as follows:
+
+ $HOME (the HOME environment variable if it exists)
+ the current directory
+ $PATH (executable PATH)
+ default list contained in epath.h
+
+*** Line length limits removed
+
+ Lines of arbitrary length may be read, edited, and written.
+
+*** Out of memory handling improved
+
+ EMACS will announce "OUT OF MEMORY" when it runs out of dynamic
+memory while reading files or inserting new text. It should then be
+safe to save buffers out IF THE CONTENTS OF THE BUFFER ARE COMPLETE at
+that time. When a buffer has been truncated while reading, a pound sign
+"#" will appear in the first position of the mode line. Also a # will
+appear in a buffer listing. If you attempt to save a truncated buffer,
+EMACS will ask if you are certain before allowing the truncated file to
+be written. As before, still beware of killing blocks of text after you
+have run out of memory.
+
+*** DENSE mode on the Atari ST
+
+ On an Atari ST monochrome monitor, setting $sres to "DENSE" will
+result in a 50 line display.
+
+*** Execute command
+
+ Execute-program (^X-$) will execute an external program without
+calling up an intervening shell is possible.
+
+*** Better close braces in CMODE
+
+ The name says it all, try it.
diff --git a/region.c b/region.c
new file mode 100644
index 0000000..b133f0b
--- /dev/null
+++ b/region.c
@@ -0,0 +1,212 @@
+/* REGION.C
+ *
+ * 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.
+ *
+ * modified by Petri Kutvonen
+ */
+
+#include <stdio.h>
+#include "estruct.h"
+#include "edef.h"
+
+/*
+ * Kill the region. Ask "getregion"
+ * to figure out the bounds of the region.
+ * Move "." to the start, and kill the characters.
+ * Bound to "C-W".
+ */
+killregion(f, n)
+{
+ register int s;
+ REGION region;
+
+ if (curbp->b_mode&MDVIEW) /* don't allow this command if */
+ return(rdonly()); /* we are in read only mode */
+ if ((s=getregion(&region)) != 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, TRUE));
+}
+
+/*
+ * Copy all of the characters in the
+ * region to the kill buffer. Don't move dot
+ * at all. This is a bit like a kill region followed
+ * by a yank. Bound to "M-W".
+ */
+copyregion(f, n)
+{
+ register LINE *linep;
+ register int loffs;
+ register int s;
+ REGION region;
+
+ if ((s=getregion(&region)) != TRUE)
+ return (s);
+ if ((lastflag&CFKILL) == 0) /* Kill type command. */
+ kdelete();
+ thisflag |= CFKILL;
+ linep = region.r_linep; /* Current line. */
+ loffs = region.r_offset; /* Current offset. */
+ while (region.r_size--) {
+ if (loffs == llength(linep)) { /* End of line. */
+ if ((s=kinsert('\n')) != TRUE)
+ return (s);
+ linep = lforw(linep);
+ loffs = 0;
+ } else { /* Middle of line. */
+ if ((s=kinsert(lgetc(linep, loffs))) != TRUE)
+ return (s);
+ ++loffs;
+ }
+ }
+ mlwrite("(region copied)");
+ return (TRUE);
+}
+
+/*
+ * Lower case region. Zap all of the upper
+ * case characters in the region to lower case. Use
+ * the region code to set the limits. Scan the buffer,
+ * doing the changes. Call "lchange" to ensure that
+ * redisplay is done in all buffers. Bound to
+ * "C-X C-L".
+ */
+lowerregion(f, n)
+{
+ register LINE *linep;
+ register int loffs;
+ register int c;
+ register int s;
+ REGION region;
+
+ if (curbp->b_mode&MDVIEW) /* don't allow this command if */
+ return(rdonly()); /* we are in read only mode */
+ if ((s=getregion(&region)) != TRUE)
+ return (s);
+ lchange(WFHARD);
+ linep = region.r_linep;
+ loffs = region.r_offset;
+ while (region.r_size--) {
+ if (loffs == llength(linep)) {
+ linep = lforw(linep);
+ loffs = 0;
+ } else {
+ c = lgetc(linep, loffs);
+ if (c>='A' && c<='Z')
+ lputc(linep, loffs, c+'a'-'A');
+ ++loffs;
+ }
+ }
+ return (TRUE);
+}
+
+/*
+ * Upper case region. Zap all of the lower
+ * case characters in the region to upper case. Use
+ * the region code to set the limits. Scan the buffer,
+ * doing the changes. Call "lchange" to ensure that
+ * redisplay is done in all buffers. Bound to
+ * "C-X C-L".
+ */
+upperregion(f, n)
+{
+ register LINE *linep;
+ register int loffs;
+ register int c;
+ register int s;
+ REGION region;
+
+ if (curbp->b_mode&MDVIEW) /* don't allow this command if */
+ return(rdonly()); /* we are in read only mode */
+ if ((s=getregion(&region)) != TRUE)
+ return (s);
+ lchange(WFHARD);
+ linep = region.r_linep;
+ loffs = region.r_offset;
+ while (region.r_size--) {
+ if (loffs == llength(linep)) {
+ linep = lforw(linep);
+ loffs = 0;
+ } else {
+ c = lgetc(linep, loffs);
+ if (c>='a' && c<='z')
+ lputc(linep, loffs, c-'a'+'A');
+ ++loffs;
+ }
+ }
+ return (TRUE);
+}
+
+/*
+ * This routine figures out the
+ * bounds of the region in the current window, and
+ * fills in the fields of the "REGION" structure pointed
+ * to by "rp". Because the dot and mark are usually very
+ * close together, we scan outward from dot looking for
+ * mark. This should save time. Return a standard code.
+ * Callers of this routine should be prepared to get
+ * an "ABORT" status; we might make this have the
+ * conform thing later.
+ */
+getregion(rp)
+register REGION *rp;
+{
+ register LINE *flp;
+ register LINE *blp;
+ long fsize;
+ long bsize;
+
+ if (curwp->w_markp == NULL) {
+ mlwrite("No mark set in this window");
+ return (FALSE);
+ }
+ if (curwp->w_dotp == curwp->w_markp) {
+ rp->r_linep = curwp->w_dotp;
+ if (curwp->w_doto < curwp->w_marko) {
+ rp->r_offset = curwp->w_doto;
+ rp->r_size = (long)(curwp->w_marko-curwp->w_doto);
+ } else {
+ rp->r_offset = curwp->w_marko;
+ rp->r_size = (long)(curwp->w_doto-curwp->w_marko);
+ }
+ return (TRUE);
+ }
+ blp = curwp->w_dotp;
+ bsize = (long)curwp->w_doto;
+ flp = curwp->w_dotp;
+ fsize = (long)(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;
+ rp->r_size = fsize+curwp->w_marko;
+ return (TRUE);
+ }
+ 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;
+ rp->r_size = bsize - curwp->w_marko;
+ return (TRUE);
+ }
+ }
+ }
+ mlwrite("Bug: lost mark");
+ return (FALSE);
+}
+
diff --git a/search.c b/search.c
new file mode 100644
index 0000000..7ca9370
--- /dev/null
+++ b/search.c
@@ -0,0 +1,1585 @@
+/* SEARCH.C
+ *
+ * The functions in this file implement commands that search in the forward
+ * and backward directions. There are no special characters in the search
+ * strings. Probably should have a regular expression search, or something
+ * like that.
+ *
+ * Aug. 1986 John M. Gamble:
+ * Made forward and reverse search use the same scan routine.
+ *
+ * Added a limited number of regular expressions - 'any',
+ * 'character class', 'closure', 'beginning of line', and
+ * 'end of line'.
+ *
+ * Replacement metacharacters will have to wait for a re-write of
+ * the replaces function, and a new variation of ldelete().
+ *
+ * For those curious as to my references, i made use of
+ * Kernighan & Plauger's "Software Tools."
+ * I deliberately did not look at any published grep or editor
+ * source (aside from this one) for inspiration. I did make use of
+ * Allen Hollub's bitmap routines as published in Doctor Dobb's Journal,
+ * June, 1985 and modified them for the limited needs of character class
+ * matching. Any inefficiences, bugs, stupid coding examples, etc.,
+ * are therefore my own responsibility.
+ *
+ * April 1987: John M. Gamble
+ * Deleted the "if (n == 0) n = 1;" statements in front of the
+ * search/hunt routines. Since we now use a do loop, these
+ * checks are unnecessary. Consolidated common code into the
+ * function delins(). Renamed global mclen matchlen,
+ * and added the globals matchline, matchoff, patmatch, and
+ * mlenold.
+ * This gave us the ability to unreplace regular expression searches,
+ * and to put the matched string into an evironment variable.
+ * SOON TO COME: Meta-replacement characters!
+ *
+ * 25-apr-87 DML
+ * - cleaned up an unneccessary if/else in forwsearch() and
+ * backsearch()
+ * - savematch() failed to malloc room for the terminating byte
+ * of the match string (stomp...stomp...). It does now. Also
+ * it now returns gracefully if malloc fails
+ *
+ * July 1987: John M. Gamble
+ * Set the variables matchlen and matchoff in the 'unreplace'
+ * section of replaces(). The function savematch() would
+ * get confused if you replaced, unreplaced, then replaced
+ * again (serves you right for being so wishy-washy...)
+ *
+ * August 1987: John M. Gamble
+ * Put in new function rmcstr() to create the replacement
+ * meta-character array. Modified delins() so that it knows
+ * whether or not to make use of the array. And, put in the
+ * appropriate new structures and variables.
+ *
+ * modified by Petri Kutvonen
+ */
+
+#include <stdio.h>
+#include "estruct.h"
+#include "edef.h"
+
+static int readpattern();
+static int replaces();
+static int nextch();
+#if MAGIC
+static int cclmake();
+static int mcstr();
+static int rmcstr();
+static int mceq();
+static void setbit();
+static int amatch();
+static int biteq();
+static BITMAP clearbits();
+#endif
+
+/*
+ * forwsearch -- Search forward. Get a search string from the user, and
+ * search for the string. If found, reset the "." to be just after
+ * the match string, and (perhaps) repaint the display.
+ */
+forwsearch(f, n)
+int f, n; /* default flag / numeric argument */
+{
+ register int status = TRUE;
+
+ /* If n is negative, search backwards.
+ * Otherwise proceed by asking for the search string.
+ */
+ if (n < 0)
+ return(backsearch(f, -n));
+
+ /* Ask the user for the text of a pattern. If the
+ * response is TRUE (responses other than FALSE are
+ * possible), search for the pattern for as long as
+ * n is positive (n == 0 will go through once, which
+ * is just fine).
+ */
+ if ((status = readpattern("Search", &pat[0], TRUE)) == TRUE) {
+ do {
+#if MAGIC
+ if ((magical && curwp->w_bufp->b_mode & MDMAGIC) != 0)
+ status = mcscanner(&mcpat[0], FORWARD, PTEND);
+ else
+#endif
+ status = scanner(&pat[0], FORWARD, PTEND);
+ } while ((--n > 0) && status);
+
+ /* Save away the match, or complain
+ * if not there.
+ */
+ if (status == TRUE)
+ savematch();
+ else
+ mlwrite("Not found");
+ }
+ return(status);
+}
+
+/*
+ * forwhunt -- Search forward for a previously acquired search string.
+ * If found, reset the "." to be just after the match string,
+ * and (perhaps) repaint the display.
+ */
+
+forwhunt(f, n)
+int f, n; /* default flag / numeric argument */
+{
+ register int status = TRUE;
+
+ if (n < 0) /* search backwards */
+ return(backhunt(f, -n));
+
+ /* Make sure a pattern exists, or that we didn't switch
+ * into MAGIC mode until after we entered the pattern.
+ */
+ if (pat[0] == '\0')
+ {
+ mlwrite("No pattern set");
+ return FALSE;
+ }
+#if MAGIC
+ if ((curwp->w_bufp->b_mode & MDMAGIC) != 0 &&
+ mcpat[0].mc_type == MCNIL)
+ {
+ if (!mcstr())
+ return FALSE;
+ }
+#endif
+
+ /* Search for the pattern for as long as
+ * n is positive (n == 0 will go through once, which
+ * is just fine).
+ */
+ do
+ {
+#if MAGIC
+ if ((magical && curwp->w_bufp->b_mode & MDMAGIC) != 0)
+ status = mcscanner(&mcpat[0], FORWARD, PTEND);
+ else
+#endif
+ status = scanner(&pat[0], FORWARD, PTEND);
+ } while ((--n > 0) && status);
+
+ /* Save away the match, or complain
+ * if not there.
+ */
+ if (status == TRUE)
+ savematch();
+ else
+ mlwrite("Not found");
+
+ return(status);
+}
+
+/*
+ * backsearch -- 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).
+ */
+backsearch(f, n)
+int f, n; /* default flag / numeric argument */
+{
+ register int status = TRUE;
+
+ /* If n is negative, search forwards.
+ * Otherwise proceed by asking for the search string.
+ */
+ if (n < 0)
+ return(forwsearch(f, -n));
+
+ /* Ask the user for the text of a pattern. If the
+ * response is TRUE (responses other than FALSE are
+ * possible), search for the pattern for as long as
+ * n is positive (n == 0 will go through once, which
+ * is just fine).
+ */
+ if ((status = readpattern("Reverse search", &pat[0], TRUE)) == TRUE) {
+ do {
+#if MAGIC
+ if ((magical && curwp->w_bufp->b_mode & MDMAGIC) != 0)
+ status = mcscanner(&tapcm[0], REVERSE, PTBEG);
+ else
+#endif
+ status = scanner(&tap[0], REVERSE, PTBEG);
+ } while ((--n > 0) && status);
+
+ /* Save away the match, or complain
+ * if not there.
+ */
+ if (status == TRUE)
+ savematch();
+ else
+ mlwrite("Not found");
+ }
+ return(status);
+}
+
+/*
+ * backhunt -- Reverse search for a previously acquired search string,
+ * 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).
+ */
+backhunt(f, n)
+int f, n; /* default flag / numeric argument */
+{
+ register int status = TRUE;
+
+ if (n < 0)
+ return(forwhunt(f, -n));
+
+ /* Make sure a pattern exists, or that we didn't switch
+ * into MAGIC mode until after we entered the pattern.
+ */
+ if (tap[0] == '\0')
+ {
+ mlwrite("No pattern set");
+ return FALSE;
+ }
+#if MAGIC
+ if ((curwp->w_bufp->b_mode & MDMAGIC) != 0 &&
+ tapcm[0].mc_type == MCNIL)
+ {
+ if (!mcstr())
+ return FALSE;
+ }
+#endif
+
+ /* Go search for it for as long as
+ * n is positive (n == 0 will go through once, which
+ * is just fine).
+ */
+ do
+ {
+#if MAGIC
+ if ((magical && curwp->w_bufp->b_mode & MDMAGIC) != 0)
+ status = mcscanner(&tapcm[0], REVERSE, PTBEG);
+ else
+#endif
+ status = scanner(&tap[0], REVERSE, PTBEG);
+ } while ((--n > 0) && status);
+
+ /* Save away the match, or complain
+ * if not there.
+ */
+ if (status == TRUE)
+ savematch();
+ else
+ mlwrite("Not found");
+
+ return(status);
+}
+
+#if MAGIC
+/*
+ * mcscanner -- Search for a meta-pattern in either direction. If found,
+ * reset the "." to be at the start or just after the match string,
+ * and (perhaps) repaint the display.
+ */
+int mcscanner(mcpatrn, direct, beg_or_end)
+MC *mcpatrn; /* pointer into pattern */
+int direct; /* which way to go.*/
+int beg_or_end; /* put point at beginning or end of pattern.*/
+{
+ LINE *curline; /* current line during scan */
+ int curoff; /* position within current line */
+
+ /* If we are going in reverse, then the 'end' is actually
+ * the beginning of the pattern. Toggle it.
+ */
+ beg_or_end ^= direct;
+
+ /*
+ * Save the old matchlen length, in case it is
+ * very different (closure) from the old length.
+ * This is important for query-replace undo
+ * command.
+ */
+ mlenold = matchlen;
+
+ /* Setup local scan pointers to global ".".
+ */
+ curline = curwp->w_dotp;
+ curoff = curwp->w_doto;
+
+ /* Scan each character until we hit the head link record.
+ */
+ while (!boundry(curline, curoff, direct))
+ {
+ /* Save the current position in case we need to
+ * restore it on a match, and initialize matchlen to
+ * zero in case we are doing a search for replacement.
+ */
+ matchline = curline;
+ matchoff = curoff;
+ matchlen = 0;
+
+ if (amatch(mcpatrn, direct, &curline, &curoff))
+ {
+ /* A SUCCESSFULL MATCH!!!
+ * reset the global "." pointers.
+ */
+ if (beg_or_end == PTEND) /* at end of string */
+ {
+ curwp->w_dotp = curline;
+ curwp->w_doto = curoff;
+ }
+ else /* at beginning of string */
+ {
+ curwp->w_dotp = matchline;
+ curwp->w_doto = matchoff;
+ }
+
+ curwp->w_flag |= WFMOVE; /* flag that we have moved */
+ return TRUE;
+ }
+
+ /* Advance the cursor.
+ */
+ nextch(&curline, &curoff, direct);
+ }
+
+ return FALSE; /* We could not find a match.*/
+}
+
+/*
+ * amatch -- Search for a meta-pattern in either direction. Based on the
+ * recursive routine amatch() (for "anchored match") in
+ * Kernighan & Plauger's "Software Tools".
+ */
+static int amatch(mcptr, direct, pcwline, pcwoff)
+register MC *mcptr; /* string to scan for */
+int direct; /* which way to go.*/
+LINE **pcwline; /* current line during scan */
+int *pcwoff; /* position within current line */
+{
+ register int c; /* character at current position */
+ LINE *curline; /* current line during scan */
+ int curoff; /* position within current line */
+ int nchars;
+
+ /* Set up local scan pointers to ".", and get
+ * the current character. Then loop around
+ * the pattern pointer until success or failure.
+ */
+ curline = *pcwline;
+ curoff = *pcwoff;
+
+ /* The beginning-of-line and end-of-line metacharacters
+ * do not compare against characters, they compare
+ * against positions.
+ * BOL is guaranteed to be at the start of the pattern
+ * for forward searches, and at the end of the pattern
+ * for reverse searches. The reverse is true for EOL.
+ * So, for a start, we check for them on entry.
+ */
+ if (mcptr->mc_type == BOL)
+ {
+ if (curoff != 0)
+ return FALSE;
+ mcptr++;
+ }
+
+ if (mcptr->mc_type == EOL)
+ {
+ if (curoff != llength(curline))
+ return FALSE;
+ mcptr++;
+ }
+
+ while (mcptr->mc_type != MCNIL)
+ {
+ c = nextch(&curline, &curoff, direct);
+
+ if (mcptr->mc_type & CLOSURE)
+ {
+ /* Try to match as many characters as possible
+ * against the current meta-character. A
+ * newline never matches a closure.
+ */
+ nchars = 0;
+ while (c != '\n' && mceq(c, mcptr))
+ {
+ c = nextch(&curline, &curoff, direct);
+ nchars++;
+ }
+
+ /* We are now at the character that made us
+ * fail. Try to match the rest of the pattern.
+ * Shrink the closure by one for each failure.
+ * Since closure matches *zero* or more occurences
+ * of a pattern, a match may start even if the
+ * previous loop matched no characters.
+ */
+ mcptr++;
+
+ for (;;)
+ {
+ c = nextch(&curline, &curoff, direct ^ REVERSE);
+
+ if (amatch(mcptr, direct, &curline, &curoff))
+ {
+ matchlen += nchars;
+ goto success;
+ }
+
+ if (nchars-- == 0)
+ return FALSE;
+ }
+ }
+ else /* Not closure.*/
+ {
+ /* The only way we'd get a BOL metacharacter
+ * at this point is at the end of the reversed pattern.
+ * The only way we'd get an EOL metacharacter
+ * here is at the end of a regular pattern.
+ * So if we match one or the other, and are at
+ * the appropriate position, we are guaranteed success
+ * (since the next pattern character has to be MCNIL).
+ * Before we report success, however, we back up by
+ * one character, so as to leave the cursor in the
+ * correct position. For example, a search for ")$"
+ * will leave the cursor at the end of the line, while
+ * a search for ")<NL>" will leave the cursor at the
+ * beginning of the next line. This follows the
+ * notion that the meta-character '$' (and likewise
+ * '^') match positions, not characters.
+ */
+ if (mcptr->mc_type == BOL)
+ if (curoff == llength(curline))
+ {
+ c = nextch(&curline, &curoff,
+ direct ^ REVERSE);
+ goto success;
+ }
+ else
+ return FALSE;
+
+ if (mcptr->mc_type == EOL)
+ if (curoff == 0)
+ {
+ c = nextch(&curline, &curoff,
+ direct ^ REVERSE);
+ goto success;
+ }
+ else
+ return FALSE;
+
+ /* Neither BOL nor EOL, so go through
+ * the meta-character equal function.
+ */
+ if (!mceq(c, mcptr))
+ return FALSE;
+ }
+
+ /* Increment the length counter and
+ * advance the pattern pointer.
+ */
+ matchlen++;
+ mcptr++;
+ } /* End of mcptr loop.*/
+
+ /* A SUCCESSFULL MATCH!!!
+ * Reset the "." pointers.
+ */
+success:
+ *pcwline = curline;
+ *pcwoff = curoff;
+
+ return TRUE;
+}
+#endif
+
+/*
+ * scanner -- Search for a pattern in either direction. If found,
+ * reset the "." to be at the start or just after the match string,
+ * and (perhaps) repaint the display.
+ */
+int scanner(patrn, direct, beg_or_end)
+unsigned char *patrn; /* string to scan for */
+int direct; /* which way to go.*/
+int beg_or_end; /* put point at beginning or end of pattern.*/
+{
+ register int c; /* character at current position */
+ register unsigned char *patptr; /* pointer into pattern */
+ LINE *curline; /* current line during scan */
+ int curoff; /* position within current line */
+ LINE *scanline; /* current line during scanning */
+ int scanoff; /* position in scanned line */
+
+ /* If we are going in reverse, then the 'end' is actually
+ * the beginning of the pattern. Toggle it.
+ */
+ beg_or_end ^= direct;
+
+ /* Set up local pointers to global ".".
+ */
+ curline = curwp->w_dotp;
+ curoff = curwp->w_doto;
+
+ /* Scan each character until we hit the head link record.
+ */
+ while (!boundry(curline, curoff, direct))
+ {
+ /* Save the current position in case we match
+ * the search string at this point.
+ */
+ matchline = curline;
+ matchoff = curoff;
+
+ /* Get the character resolving newlines, and
+ * test it against first char in pattern.
+ */
+ c = nextch(&curline, &curoff, direct);
+
+ if (eq(c, patrn[0])) /* if we find it..*/
+ {
+ /* Setup scanning pointers.
+ */
+ scanline = curline;
+ scanoff = curoff;
+ patptr = &patrn[0];
+
+ /* Scan through the pattern for a match.
+ */
+ while (*++patptr != '\0')
+ {
+ c = nextch(&scanline, &scanoff, direct);
+
+ if (!eq(c, *patptr))
+ goto fail;
+ }
+
+ /* A SUCCESSFULL MATCH!!!
+ * reset the global "." pointers
+ */
+ if (beg_or_end == PTEND) /* at end of string */
+ {
+ curwp->w_dotp = scanline;
+ curwp->w_doto = scanoff;
+ }
+ else /* at beginning of string */
+ {
+ curwp->w_dotp = matchline;
+ curwp->w_doto = matchoff;
+ }
+
+ curwp->w_flag |= WFMOVE; /* Flag that we have moved.*/
+ return TRUE;
+
+ }
+fail:; /* continue to search */
+ }
+
+ return FALSE; /* We could not find a match */
+}
+
+/*
+ * eq -- Compare two characters. The "bc" comes from the buffer, "pc"
+ * from the pattern. If we are not in EXACT mode, fold out the case.
+ */
+int eq(bc, pc)
+#if PKCODE
+register char bc;
+register char pc;
+#else
+register int bc;
+register int pc;
+#endif
+{
+ if ((curwp->w_bufp->b_mode & MDEXACT) == 0)
+ {
+ if (islower(bc))
+ bc ^= DIFCASE;
+
+ if (islower(pc))
+ pc ^= DIFCASE;
+ }
+
+ return (bc == pc);
+}
+
+/*
+ * readpattern -- Read a pattern. Stash it in apat. If it is the
+ * search string, create the reverse pattern and the magic
+ * pattern, assuming we are in MAGIC mode (and defined that way).
+ * Apat 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. Change to using
+ * <META> to delimit the end-of-pattern to allow <NL>s in the search
+ * string.
+ */
+static int readpattern(prompt, apat, srch)
+char *prompt;
+char apat[];
+int srch;
+{
+ int status;
+ char tpat[NPAT+20];
+
+ strcpy(tpat, prompt); /* copy prompt to output string */
+ strcat(tpat, " ("); /* build new prompt string */
+ expandp(&apat[0], &tpat[strlen(tpat)], NPAT/2); /* add old pattern */
+ strcat(tpat, ")<Meta>: ");
+
+ /* Read a pattern. Either we get one,
+ * or we just get the META charater, and use the previous pattern.
+ * Then, if it's the search string, make a reversed pattern.
+ * *Then*, make the meta-pattern, if we are defined that way.
+ */
+ if ((status = mlreplyt(tpat, tpat, NPAT, metac)) == TRUE)
+ {
+ strcpy(apat, tpat);
+ if (srch) /* If we are doing the search string.*/
+ {
+ /* Reverse string copy, and remember
+ * the length for substitution purposes.
+ */
+ rvstrcpy(tap, apat);
+ mlenold = matchlen = strlen(apat);
+ }
+#if MAGIC
+ /* Only make the meta-pattern if in magic mode,
+ * since the pattern in question might have an
+ * invalid meta combination.
+ */
+ if ((curwp->w_bufp->b_mode & MDMAGIC) == 0)
+ {
+ mcclear();
+ rmcclear();
+ }
+ else
+ status = srch? mcstr(): rmcstr();
+#endif
+ }
+ else if (status == FALSE && apat[0] != 0) /* Old one */
+ status = TRUE;
+
+ return(status);
+}
+
+/*
+ * savematch -- We found the pattern? Let's save it away.
+ */
+savematch()
+{
+ register char *ptr; /* pointer to last match string */
+ register int j;
+ LINE *curline; /* line of last match */
+ int curoff; /* offset " " */
+
+ /* Free any existing match string, then
+ * attempt to allocate a new one.
+ */
+ if (patmatch != NULL)
+ free(patmatch);
+
+ ptr = patmatch = malloc(matchlen + 1);
+
+ if (ptr != NULL)
+ {
+ curoff = matchoff;
+ curline = matchline;
+
+ for (j = 0; j < matchlen; j++)
+ *ptr++ = nextch(&curline, &curoff, FORWARD);
+
+ *ptr = '\0';
+ }
+}
+
+/*
+ * rvstrcpy -- Reverse string copy.
+ */
+rvstrcpy(rvstr, str)
+register char *rvstr, *str;
+{
+ register int i;
+
+ str += (i = strlen(str));
+
+ while (i-- > 0)
+ *rvstr++ = *--str;
+
+ *rvstr = '\0';
+}
+
+/*
+ * sreplace -- Search and replace.
+ */
+sreplace(f, n)
+int f; /* default flag */
+int n; /* # of repetitions wanted */
+{
+ return(replaces(FALSE, f, n));
+}
+
+/*
+ * qreplace -- search and replace with query.
+ */
+qreplace(f, n)
+int f; /* default flag */
+int n; /* # of repetitions wanted */
+{
+ return(replaces(TRUE, f, n));
+}
+
+/*
+ * replaces -- Search for a string and replace it with another
+ * string. Query might be enabled (according to kind).
+ */
+static int replaces(kind, f, n)
+int kind; /* Query enabled flag */
+int f; /* default flag */
+int n; /* # of repetitions wanted */
+{
+ register int status; /* success flag on pattern inputs */
+ register int rlength; /* length of replacement string */
+ register int numsub; /* number of substitutions */
+ register int nummatch; /* number of found matches */
+ int nlflag; /* last char of search string a <NL>? */
+ int nlrepl; /* was a replace done on the last line? */
+ char c; /* input char for query */
+ char tpat[NPAT]; /* temporary to hold search pattern */
+ LINE *origline; /* original "." position */
+ int origoff; /* and offset (for . query option) */
+ LINE *lastline; /* position of last replace and */
+ int lastoff; /* offset (for 'u' query option) */
+
+ if (curbp->b_mode & MDVIEW) /* don't allow this command if */
+ return(rdonly()); /* we are in read only mode */
+
+ /* Check for negative repetitions.
+ */
+ if (f && n < 0)
+ return(FALSE);
+
+ /* Ask the user for the text of a pattern.
+ */
+ if ((status = readpattern(
+ (kind == FALSE ? "Replace" : "Query replace"), &pat[0], TRUE))
+ != TRUE)
+ return(status);
+
+ /* Ask for the replacement string.
+ */
+ if ((status = readpattern("with", &rpat[0], FALSE)) == ABORT)
+ return(status);
+
+ /* Find the length of the replacement string.
+ */
+ rlength = strlen(&rpat[0]);
+
+ /* Set up flags so we can make sure not to do a recursive
+ * replace on the last line.
+ */
+ nlflag = (pat[matchlen - 1] == '\n');
+ nlrepl = FALSE;
+
+ if (kind)
+ {
+ /* Build query replace question string.
+ */
+ strcpy(tpat, "Replace '");
+ expandp(&pat[0], &tpat[strlen(tpat)], NPAT/3);
+ strcat(tpat, "' with '");
+ expandp(&rpat[0], &tpat[strlen(tpat)], NPAT/3);
+ strcat(tpat, "'? ");
+
+ /* Initialize last replaced pointers.
+ */
+ lastline = NULL;
+ lastoff = 0;
+ }
+
+ /* Save original . position, init the number of matches and
+ * substitutions, and scan through the file.
+ */
+ origline = curwp->w_dotp;
+ origoff = curwp->w_doto;
+ numsub = 0;
+ nummatch = 0;
+
+ while ( (f == FALSE || n > nummatch) &&
+ (nlflag == FALSE || nlrepl == FALSE) )
+ {
+ /* Search for the pattern.
+ * If we search with a regular expression,
+ * matchlen is reset to the true length of
+ * the matched string.
+ */
+#if MAGIC
+ if ((magical && curwp->w_bufp->b_mode & MDMAGIC) != 0)
+ {
+ if (!mcscanner(&mcpat[0], FORWARD, PTBEG))
+ break;
+ }
+ else
+#endif
+ if (!scanner(&pat[0], FORWARD, PTBEG))
+ break; /* all done */
+
+ ++nummatch; /* Increment # of matches */
+
+ /* Check if we are on the last line.
+ */
+ nlrepl = (lforw(curwp->w_dotp) == curwp->w_bufp->b_linep);
+
+ /* Check for query.
+ */
+ if (kind)
+ {
+ /* Get the query.
+ */
+pprompt: mlwrite(&tpat[0], &pat[0], &rpat[0]);
+qprompt:
+ update(TRUE); /* show the proposed place to change */
+ c = tgetc(); /* and input */
+ mlwrite(""); /* and clear it */
+
+ /* And respond appropriately.
+ */
+ switch (c)
+ {
+#if PKCODE
+ case 'Y':
+#endif
+ case 'y': /* yes, substitute */
+ case ' ':
+ savematch();
+ break;
+
+#if PKCODE
+ case 'N':
+#endif
+ case 'n': /* no, onword */
+ forwchar(FALSE, 1);
+ continue;
+
+ case '!': /* yes/stop asking */
+ kind = FALSE;
+ break;
+
+#if PKCODE
+ case 'U':
+#endif
+ case 'u': /* undo last and re-prompt */
+
+ /* Restore old position.
+ */
+ if (lastline == NULL)
+ {
+ /* There is nothing to undo.
+ */
+ TTbeep();
+ goto pprompt;
+ }
+ curwp->w_dotp = lastline;
+ curwp->w_doto = lastoff;
+ lastline = NULL;
+ lastoff = 0;
+
+ /* Delete the new string.
+ */
+ backchar(FALSE, rlength);
+#if PKCODE
+ matchline = curwp->w_dotp;
+ matchoff = curwp->w_doto;
+#endif
+ status = delins(rlength, patmatch, FALSE);
+ if (status != TRUE)
+ return (status);
+
+ /* Record one less substitution,
+ * backup, save our place, and
+ * reprompt.
+ */
+ --numsub;
+ backchar(FALSE, mlenold);
+ matchline = curwp->w_dotp;
+ matchoff = curwp->w_doto;
+ goto pprompt;
+
+ case '.': /* abort! and return */
+ /* restore old position */
+ curwp->w_dotp = origline;
+ curwp->w_doto = origoff;
+ curwp->w_flag |= WFMOVE;
+
+ case BELL: /* abort! and stay */
+ mlwrite("Aborted!");
+ return(FALSE);
+
+ default: /* bitch and beep */
+ TTbeep();
+
+ case '?': /* help me */
+ mlwrite(
+"(Y)es, (N)o, (!)Do rest, (U)ndo last, (^G)Abort, (.)Abort back, (?)Help: ");
+ goto qprompt;
+
+ } /* end of switch */
+ } /* end of "if kind" */
+
+ /*
+ * Delete the sucker, and insert its
+ * replacement.
+ */
+ status = delins(matchlen, &rpat[0], TRUE);
+ if (status != TRUE)
+ return (status);
+
+ /* Save our position, since we may
+ * undo this.
+ */
+ if (kind)
+ {
+ lastline = curwp->w_dotp;
+ lastoff = curwp->w_doto;
+ }
+
+ numsub++; /* increment # of substitutions */
+ }
+
+ /* And report the results.
+ */
+ mlwrite("%d substitutions", numsub);
+ return(TRUE);
+}
+
+/*
+ * delins -- Delete a specified length from the current point
+ * then either insert the string directly, or make use of
+ * replacement meta-array.
+ */
+delins(dlength, instr, use_meta)
+int dlength;
+char *instr;
+int use_meta;
+{
+ int status;
+#if MAGIC
+ RMC *rmcptr;
+#endif
+
+ /* Zap what we gotta,
+ * and insert its replacement.
+ */
+ if ((status = ldelete((long) dlength, FALSE)) != TRUE)
+ mlwrite("%%ERROR while deleting");
+ else
+#if MAGIC
+ if ((rmagical && use_meta) &&
+ (curwp->w_bufp->b_mode & MDMAGIC) != 0) {
+ rmcptr = &rmcpat[0];
+ while (rmcptr->mc_type != MCNIL && status == TRUE) {
+ if (rmcptr->mc_type == LITCHAR)
+ status = linstr(rmcptr->rstr);
+ else
+ status = linstr(patmatch);
+ rmcptr++;
+ }
+ } else
+#endif
+ status = linstr(instr);
+
+ return(status);
+}
+
+/*
+ * expandp -- Expand control key sequences for output.
+ */
+expandp(srcstr, deststr, maxlength)
+char *srcstr; /* string to expand */
+char *deststr; /* destination of expanded string */
+int maxlength; /* maximum chars in destination */
+{
+ unsigned char c; /* current char to translate */
+
+ /* Scan through the string.
+ */
+ while ((c = *srcstr++) != 0)
+ {
+ if (c == '\n') /* it's a newline */
+ {
+ *deststr++ = '<';
+ *deststr++ = 'N';
+ *deststr++ = 'L';
+ *deststr++ = '>';
+ maxlength -= 4;
+ }
+#if PKCODE
+ else if ((c > 0 && c < 0x20) ||
+ c == 0x7f) /* control character */
+#else
+ else if (c < 0x20 || c == 0x7f) /* control character */
+#endif
+ {
+ *deststr++ = '^';
+ *deststr++ = c ^ 0x40;
+ maxlength -= 2;
+ }
+ else if (c == '%')
+ {
+ *deststr++ = '%';
+ *deststr++ = '%';
+ maxlength -= 2;
+ }
+ else /* any other character */
+ {
+ *deststr++ = c;
+ maxlength--;
+ }
+
+ /* check for maxlength */
+ if (maxlength < 4)
+ {
+ *deststr++ = '$';
+ *deststr = '\0';
+ return(FALSE);
+ }
+ }
+ *deststr = '\0';
+ return(TRUE);
+}
+
+/*
+ * boundry -- Return information depending on whether we may search no
+ * further. Beginning of file and end of file are the obvious
+ * cases, but we may want to add further optional boundry restrictions
+ * in future, a' la VMS EDT. At the moment, just return TRUE or
+ * FALSE depending on if a boundry is hit (ouch).
+ */
+int boundry(curline, curoff, dir)
+LINE *curline;
+int curoff, dir;
+{
+ register int border;
+
+ if (dir == FORWARD)
+ {
+ border = (curoff == llength(curline)) &&
+ (lforw(curline) == curbp->b_linep);
+ }
+ else
+ {
+ border = (curoff == 0) &&
+ (lback(curline) == curbp->b_linep);
+ }
+ return (border);
+}
+
+/*
+ * nextch -- retrieve the next/previous character in the buffer,
+ * and advance/retreat the point.
+ * The order in which this is done is significant, and depends
+ * upon the direction of the search. Forward searches look at
+ * the current character and move, reverse searches move and
+ * look at the character.
+ */
+static int nextch(pcurline, pcuroff, dir)
+LINE **pcurline;
+int *pcuroff;
+int dir;
+{
+ register LINE *curline;
+ register int curoff;
+ register int c;
+
+ curline = *pcurline;
+ curoff = *pcuroff;
+
+ if (dir == FORWARD)
+ {
+ if (curoff == llength(curline)) /* if at EOL */
+ {
+ curline = lforw(curline); /* skip to next line */
+ curoff = 0;
+ c = '\n'; /* and return a <NL> */
+ }
+ else
+ c = lgetc(curline, curoff++); /* get the char */
+ }
+ else /* Reverse.*/
+ {
+ if (curoff == 0)
+ {
+ curline = lback(curline);
+ curoff = llength(curline);
+ c = '\n';
+ }
+ else
+ c = lgetc(curline, --curoff);
+
+ }
+ *pcurline = curline;
+ *pcuroff = curoff;
+
+ return (c);
+}
+
+#if MAGIC
+/*
+ * mcstr -- Set up the 'magic' array. The closure symbol is taken as
+ * a literal character when (1) it is the first character in the
+ * pattern, and (2) when preceded by a symbol that does not allow
+ * closure, such as a newline, beginning of line symbol, or another
+ * closure symbol.
+ *
+ * Coding comment (jmg): yes, i know i have gotos that are, strictly
+ * speaking, unnecessary. But right now we are so cramped for
+ * code space that i will grab what i can in order to remain
+ * within the 64K limit. C compilers actually do very little
+ * in the way of optimizing - they expect you to do that.
+ */
+static int mcstr()
+{
+ MC *mcptr, *rtpcm;
+ char *patptr;
+ int mj;
+ int pchr;
+ int status = TRUE;
+ int does_closure = FALSE;
+
+ /* If we had metacharacters in the MC array previously,
+ * free up any bitmaps that may have been allocated.
+ */
+ if (magical)
+ mcclear();
+
+ magical = FALSE;
+ mj = 0;
+ mcptr = &mcpat[0];
+ patptr = &pat[0];
+
+ while ((pchr = *patptr) && status)
+ {
+ switch (pchr)
+ {
+ case MC_CCL:
+ status = cclmake(&patptr, mcptr);
+ magical = TRUE;
+ does_closure = TRUE;
+ break;
+ case MC_BOL:
+ if (mj != 0)
+ goto litcase;
+
+ mcptr->mc_type = BOL;
+ magical = TRUE;
+ does_closure = FALSE;
+ break;
+ case MC_EOL:
+ if (*(patptr + 1) != '\0')
+ goto litcase;
+
+ mcptr->mc_type = EOL;
+ magical = TRUE;
+ does_closure = FALSE;
+ break;
+ case MC_ANY:
+ mcptr->mc_type = ANY;
+ magical = TRUE;
+ does_closure = TRUE;
+ break;
+ case MC_CLOSURE:
+ /* Does the closure symbol mean closure here?
+ * If so, back up to the previous element
+ * and indicate it is enclosed.
+ */
+ if (!does_closure)
+ goto litcase;
+ mj--;
+ mcptr--;
+ mcptr->mc_type |= CLOSURE;
+ magical = TRUE;
+ does_closure = FALSE;
+ break;
+
+ /* Note: no break between MC_ESC case and the default.
+ */
+ case MC_ESC:
+ if (*(patptr + 1) != '\0')
+ {
+ pchr = *++patptr;
+ magical = TRUE;
+ }
+ default:
+litcase: mcptr->mc_type = LITCHAR;
+ mcptr->u.lchar = pchr;
+ does_closure = (pchr != '\n');
+ break;
+ } /* End of switch.*/
+ mcptr++;
+ patptr++;
+ mj++;
+ } /* End of while.*/
+
+ /* Close off the meta-string.
+ */
+ mcptr->mc_type = MCNIL;
+
+ /* Set up the reverse array, if the status is good. Please note the
+ * structure assignment - your compiler may not like that.
+ * If the status is not good, nil out the meta-pattern.
+ * The only way the status would be bad is from the cclmake()
+ * routine, and the bitmap for that member is guarenteed to be
+ * freed. So we stomp a MCNIL value there, and call mcclear()
+ * to free any other bitmaps.
+ */
+ if (status)
+ {
+ rtpcm = &tapcm[0];
+ while (--mj >= 0)
+ {
+#if MSC | TURBO | VMS | USG | BSD | V7
+ *rtpcm++ = *--mcptr;
+#endif
+ }
+ rtpcm->mc_type = MCNIL;
+ }
+ else
+ {
+ (--mcptr)->mc_type = MCNIL;
+ mcclear();
+ }
+
+ return(status);
+}
+
+/*
+ * rmcstr -- Set up the replacement 'magic' array. Note that if there
+ * are no meta-characters encountered in the replacement string,
+ * the array is never actually created - we will just use the
+ * character array rpat[] as the replacement string.
+ */
+static int rmcstr()
+{
+ RMC *rmcptr;
+ char *patptr;
+ int status = TRUE;
+ int mj;
+
+ patptr = &rpat[0];
+ rmcptr = &rmcpat[0];
+ mj = 0;
+ rmagical = FALSE;
+
+ while (*patptr && status == TRUE)
+ {
+ switch (*patptr)
+ {
+ case MC_DITTO:
+
+ /* If there were non-magical characters
+ * in the string before reaching this
+ * character, plunk it in the replacement
+ * array before processing the current
+ * meta-character.
+ */
+ if (mj != 0)
+ {
+ rmcptr->mc_type = LITCHAR;
+ if ((rmcptr->rstr = malloc(mj + 1)) == NULL)
+ {
+ mlwrite("%%Out of memory");
+ status = FALSE;
+ break;
+ }
+ strncpy(rmcptr->rstr, patptr - mj, mj);
+ rmcptr++;
+ mj = 0;
+ }
+ rmcptr->mc_type = DITTO;
+ rmcptr++;
+ rmagical = TRUE;
+ break;
+
+ case MC_ESC:
+ rmcptr->mc_type = LITCHAR;
+
+ /* We malloc mj plus two here, instead
+ * of one, because we have to count the
+ * current character.
+ */
+ if ((rmcptr->rstr = malloc(mj + 2)) == NULL)
+ {
+ mlwrite("%%Out of memory");
+ status = FALSE;
+ break;
+ }
+
+ strncpy(rmcptr->rstr, patptr - mj, mj + 1);
+
+ /* If MC_ESC is not the last character
+ * in the string, find out what it is
+ * escaping, and overwrite the last
+ * character with it.
+ */
+ if (*(patptr + 1) != '\0')
+ *((rmcptr->rstr) + mj) = *++patptr;
+
+ rmcptr++;
+ mj = 0;
+ rmagical = TRUE;
+ break;
+
+ default:
+ mj++;
+ }
+ patptr++;
+ }
+
+ if (rmagical && mj > 0)
+ {
+ rmcptr->mc_type = LITCHAR;
+ if ((rmcptr->rstr = malloc(mj + 1)) == NULL)
+ {
+ mlwrite("%%Out of memory.");
+ status = FALSE;
+ }
+ strncpy(rmcptr->rstr, patptr - mj, mj);
+ rmcptr++;
+ }
+
+ rmcptr->mc_type = MCNIL;
+}
+
+/*
+ * mcclear -- Free up any CCL bitmaps, and MCNIL the MC search arrays.
+ */
+mcclear()
+{
+ register MC *mcptr;
+
+ mcptr = &mcpat[0];
+
+ while (mcptr->mc_type != MCNIL)
+ {
+ if ((mcptr->mc_type & MASKCL) == CCL ||
+ (mcptr->mc_type & MASKCL) == NCCL)
+ free(mcptr->u.cclmap);
+ mcptr++;
+ }
+ mcpat[0].mc_type = tapcm[0].mc_type = MCNIL;
+}
+
+/*
+ * rmcclear -- Free up any strings, and MCNIL the RMC array.
+ */
+rmcclear()
+{
+ register RMC *rmcptr;
+
+ rmcptr = &rmcpat[0];
+
+ while (rmcptr->mc_type != MCNIL)
+ {
+ if (rmcptr->mc_type == LITCHAR)
+ free(rmcptr->rstr);
+ rmcptr++;
+ }
+
+ rmcpat[0].mc_type = MCNIL;
+}
+
+/*
+ * mceq -- meta-character equality with a character. In Kernighan & Plauger's
+ * Software Tools, this is the function omatch(), but i felt there
+ * were too many functions with the 'match' name already.
+ */
+static int mceq(bc, mt)
+int bc;
+MC *mt;
+{
+ register int result;
+
+#if PKCODE
+ bc = bc & 0xFF;
+#endif
+ switch (mt->mc_type & MASKCL)
+ {
+ case LITCHAR:
+ result = eq(bc, mt->u.lchar);
+ break;
+
+ case ANY:
+ result = (bc != '\n');
+ break;
+
+ case CCL:
+ if (!(result = biteq(bc, mt->u.cclmap)))
+ {
+ if ((curwp->w_bufp->b_mode & MDEXACT) == 0 &&
+ (isletter(bc)))
+ {
+ result = biteq(CHCASE(bc), mt->u.cclmap);
+ }
+ }
+ break;
+
+ case NCCL:
+ result = !biteq(bc, mt->u.cclmap);
+
+ if ((curwp->w_bufp->b_mode & MDEXACT) == 0 &&
+ (isletter(bc)))
+ {
+ result &= !biteq(CHCASE(bc), mt->u.cclmap);
+ }
+ break;
+
+ default:
+ mlwrite("mceq: what is %d?", mt->mc_type);
+ result = FALSE;
+ break;
+
+ } /* End of switch.*/
+
+ return (result);
+}
+
+/*
+ * cclmake -- create the bitmap for the character class.
+ * ppatptr is left pointing to the end-of-character-class character,
+ * so that a loop may automatically increment with safety.
+ */
+static int cclmake(ppatptr, mcptr)
+char **ppatptr;
+MC *mcptr;
+{
+ BITMAP clearbits();
+ BITMAP bmap;
+ register char *patptr;
+ register int pchr, ochr;
+
+ if ((bmap = clearbits()) == NULL)
+ {
+ mlwrite("%%Out of memory");
+ return FALSE;
+ }
+
+ mcptr->u.cclmap = bmap;
+ patptr = *ppatptr;
+
+ /*
+ * Test the initial character(s) in ccl for
+ * special cases - negate ccl, or an end ccl
+ * character as a first character. Anything
+ * else gets set in the bitmap.
+ */
+ if (*++patptr == MC_NCCL)
+ {
+ patptr++;
+ mcptr->mc_type = NCCL;
+ }
+ else
+ mcptr->mc_type = CCL;
+
+ if ((ochr = *patptr) == MC_ECCL)
+ {
+ mlwrite("%%No characters in character class");
+ return (FALSE);
+ }
+ else
+ {
+ if (ochr == MC_ESC)
+ ochr = *++patptr;
+
+ setbit(ochr, bmap);
+ patptr++;
+ }
+
+ while (ochr != '\0' && (pchr = *patptr) != MC_ECCL)
+ {
+ switch (pchr)
+ {
+ /* Range character loses its meaning
+ * if it is the last character in
+ * the class.
+ */
+ case MC_RCCL:
+ if (*(patptr + 1) == MC_ECCL)
+ setbit(pchr, bmap);
+ else
+ {
+ pchr = *++patptr;
+ while (++ochr <= pchr)
+ setbit(ochr, bmap);
+ }
+ break;
+
+ /* Note: no break between case MC_ESC and the default.
+ */
+ case MC_ESC:
+ pchr = *++patptr;
+ default:
+ setbit(pchr, bmap);
+ break;
+ }
+ patptr++;
+ ochr = pchr;
+ }
+
+ *ppatptr = patptr;
+
+ if (ochr == '\0')
+ {
+ mlwrite("%%Character class not ended");
+ free(bmap);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/*
+ * biteq -- is the character in the bitmap?
+ */
+static int biteq(bc, cclmap)
+int bc;
+BITMAP cclmap;
+{
+#if PKCODE
+ bc = bc & 0xFF;
+#endif
+ if (bc >= HICHAR)
+ return FALSE;
+
+ return( (*(cclmap + (bc >> 3)) & BIT(bc & 7))? TRUE: FALSE );
+}
+
+/*
+ * clearbits -- Allocate and zero out a CCL bitmap.
+ */
+static BITMAP clearbits()
+{
+ char *malloc();
+
+ BITMAP cclstart, cclmap;
+ register int j;
+
+ if ((cclmap = cclstart = (BITMAP) malloc(HIBYTE)) != NULL)
+ for (j = 0; j < HIBYTE; j++)
+ *cclmap++ = 0;
+
+ return (cclstart);
+}
+
+/*
+ * setbit -- Set a bit (ON only) in the bitmap.
+ */
+static void setbit(bc, cclmap)
+int bc;
+BITMAP cclmap;
+{
+#if PKCODE
+ bc = bc & 0xFF;
+#endif
+ if (bc < HICHAR)
+ *(cclmap + (bc >> 3)) |= BIT(bc & 7);
+}
+#endif
diff --git a/shell.cmd b/shell.cmd
new file mode 100644
index 0000000..e7c9c68
--- /dev/null
+++ b/shell.cmd
@@ -0,0 +1,57 @@
+; OS shell interface, MS-DOS and UNIX
+
+store-procedure prompt
+ set $discmd FALSE
+ end-of-file
+ insert-string "shell% "
+ set-mark
+ set $discmd TRUE
+ unmark-buffer
+!endm
+
+store-procedure getline
+ set $discmd FALSE
+ end-of-file
+ !force backward-character
+ exchange-point-and-mark
+ copy-region
+ set %shline $kill
+ end-of-file
+ set $discmd TRUE
+!endm
+
+store-procedure execline
+; shell-command "echo command not found > shtmp"
+ shell-command &cat %shline " > shtmp"
+ !force insert-file shtmp
+!endm
+
+; prompt and execute a command
+
+10 store-macro
+ run getline
+ !if &not &seq %shline ""
+ run execline
+ !endif
+ run prompt
+!endm
+
+11 store-macro
+ set $discmd FALSE
+ !if &seq $cbufname "*Shell*"
+ bind-to-key execute-macro-10 ^M
+ run prompt
+ !else
+ bind-to-key newline ^M
+ !endif
+ set $discmd TRUE
+!endm
+
+store-procedure openshell
+ set $discmd FALSE
+ bind-to-key execute-macro-11 M-FNX
+ select-buffer "*Shell*"
+ set $discmd TRUE
+!endm
+
+ run openshell
diff --git a/spawn.c b/spawn.c
new file mode 100644
index 0000000..c64969e
--- /dev/null
+++ b/spawn.c
@@ -0,0 +1,628 @@
+/* SPAWN.C
+ * various operating system access commands
+ *
+ * modified by Petri Kutvonen
+ */
+
+#include <stdio.h>
+#include "estruct.h"
+#include "edef.h"
+
+#if VMS
+#define EFN 0 /* Event flag. */
+
+#include <ssdef.h> /* Random headers. */
+#include <stsdef.h>
+#include <descrip.h>
+#include <iodef.h>
+
+extern int oldmode[3]; /* In "termio.c" */
+extern int newmode[3]; /* In "termio.c" */
+extern short iochan; /* In "termio.c" */
+#endif
+
+#if V7 | USG | BSD
+#include <signal.h>
+extern int vttidy();
+#ifdef SIGWINCH
+extern int chg_width, chg_height;
+extern void sizesignal();
+#endif
+#endif
+
+#if MSDOS & (MSC | TURBO)
+#include <process.h>
+#endif
+
+/*
+ * Create a subjob with a copy of the command intrepreter in it. When the
+ * command interpreter exits, mark the screen as garbage so that you do a full
+ * repaint. Bound to "^X C". The message at the start in VMS puts out a newline.
+ * Under some (unknown) condition, you don't get one free when DCL starts up.
+ */
+spawncli(f, n)
+{
+#if V7 | USG | BSD
+ register char *cp;
+ char *getenv();
+#endif
+
+ /* don't allow this command if restricted */
+ if (restflag)
+ return(resterr());
+
+#if VMS
+ movecursor(term.t_nrow, 0); /* In last line. */
+ mlputs("(Starting DCL)\r\n");
+ TTflush(); /* Ignore "ttcol". */
+ sgarbf = TRUE;
+ sys(NULL);
+ sleep(1);
+ mlputs("\r\n(Returning from DCL)\r\n");
+ TTflush();
+ sleep(1);
+ return(TRUE);
+#endif
+#if MSDOS & (MSC | TURBO)
+ movecursor(term.t_nrow, 0); /* Seek to last line. */
+ TTflush();
+ TTkclose();
+ shellprog("");
+ TTkopen();
+ sgarbf = TRUE;
+ return(TRUE);
+#endif
+#if V7 | USG | BSD
+ movecursor(term.t_nrow, 0); /* Seek to last line. */
+ TTflush();
+ TTclose(); /* stty to old settings */
+ if ((cp = getenv("SHELL")) != NULL && *cp != '\0')
+ system(cp);
+ else
+#if BSD
+ system("exec /bin/csh");
+#else
+ system("exec /bin/sh");
+#endif
+ sgarbf = TRUE;
+ sleep(2);
+ TTopen();
+ TTkopen();
+#ifdef SIGWINCH
+/*
+ * This fools the update routines to force a full
+ * redraw with complete window size checking.
+ * -lbt
+ */
+ chg_width = term.t_ncol;
+ chg_height = term.t_nrow+1;
+ term.t_nrow = term.t_ncol = 0;
+#endif
+ return(TRUE);
+#endif
+}
+
+#if BSD | __hpux | SVR4
+
+bktoshell() /* suspend MicroEMACS and wait to wake up */
+{
+ int pid;
+
+ vttidy();
+/******************************
+ pid = getpid();
+ kill(pid,SIGTSTP);
+******************************/
+ kill(0, SIGTSTP);
+}
+
+rtfrmshell()
+{
+ TTopen();
+ curwp->w_flag = WFHARD;
+ sgarbf = TRUE;
+}
+#endif
+
+/*
+ * Run a one-liner in a subjob. When the command returns, wait for a single
+ * character to be typed, then mark the screen as garbage so a full repaint is
+ * done. Bound to "C-X !".
+ */
+spawn(f, n)
+{
+ register int s;
+ char line[NLINE];
+
+ /* don't allow this command if restricted */
+ if (restflag)
+ return(resterr());
+
+#if VMS
+ if ((s=mlreply("!", line, NLINE)) != TRUE)
+ return (s);
+ movecursor(term.t_nrow, 0);
+ TTflush();
+ s = sys(line); /* Run the command. */
+ if (clexec == FALSE) {
+ mlputs("\r\n\n(End)"); /* Pause. */
+ TTflush();
+ tgetc();
+ }
+ sgarbf = TRUE;
+ return (s);
+#endif
+#if MSDOS
+ if ((s=mlreply("!", line, NLINE)) != TRUE)
+ return(s);
+ movecursor(term.t_nrow, 0);
+ TTkclose();
+ shellprog(line);
+ TTkopen();
+ /* if we are interactive, pause here */
+ if (clexec == FALSE) {
+ mlputs("\r\n(End)");
+ tgetc();
+ }
+ sgarbf = TRUE;
+ return (TRUE);
+#endif
+#if V7 | USG | BSD
+ if ((s=mlreply("!", line, NLINE)) != TRUE)
+ return (s);
+ TTflush();
+ TTclose(); /* stty to old modes */
+ TTkclose();
+ system(line);
+ fflush(stdout); /* to be sure P.K. */
+ TTopen();
+
+ if (clexec == FALSE) {
+ mlputs("(End)"); /* Pause. */
+ TTflush();
+ while ((s = tgetc()) != '\r' && s != ' ')
+ ;
+ mlputs("\r\n");
+ }
+ TTkopen();
+ sgarbf = TRUE;
+ return (TRUE);
+#endif
+}
+
+/*
+ * Run an external program with arguments. When it returns, wait for a single
+ * character to be typed, then mark the screen as garbage so a full repaint is
+ * done. Bound to "C-X $".
+ */
+
+execprg(f, n)
+
+{
+ register int s;
+ char line[NLINE];
+
+ /* don't allow this command if restricted */
+ if (restflag)
+ return(resterr());
+
+#if VMS
+ if ((s=mlreply("!", line, NLINE)) != TRUE)
+ return (s);
+ TTflush();
+ s = sys(line); /* Run the command. */
+ mlputs("\r\n\n(End)"); /* Pause. */
+ TTflush();
+ tgetc();
+ sgarbf = TRUE;
+ return (s);
+#endif
+
+#if MSDOS
+ if ((s=mlreply("$", line, NLINE)) != TRUE)
+ return(s);
+ movecursor(term.t_nrow, 0);
+ TTkclose();
+ execprog(line);
+ TTkopen();
+ /* if we are interactive, pause here */
+ if (clexec == FALSE) {
+ mlputs("\r\n(End)");
+ tgetc();
+ }
+ sgarbf = TRUE;
+ return (TRUE);
+#endif
+
+#if V7 | USG | BSD
+ if ((s=mlreply("!", line, NLINE)) != TRUE)
+ return (s);
+ TTputc('\n'); /* Already have '\r' */
+ TTflush();
+ TTclose(); /* stty to old modes */
+ system(line);
+ fflush(stdout); /* to be sure P.K. */
+ TTopen();
+ mlputs("(End)"); /* Pause. */
+ TTflush();
+ while ((s = tgetc()) != '\r' && s != ' ')
+ ;
+ sgarbf = TRUE;
+ return (TRUE);
+#endif
+}
+
+/*
+ * Pipe a one line command into a window
+ * Bound to ^X @
+ */
+pipecmd(f, n)
+{
+ register int s; /* return status from CLI */
+ register WINDOW *wp; /* pointer to new window */
+ register BUFFER *bp; /* pointer to buffer to zot */
+ char line[NLINE]; /* command line send to shell */
+ static char bname[] = "command";
+
+ static char filnam[NSTRING] = "command";
+
+#if MSDOS
+ char *tmp;
+ char *getenv();
+ FILE *fp;
+ FILE *fopen();
+ int len;
+#endif
+
+ /* don't allow this command if restricted */
+ if (restflag)
+ return(resterr());
+
+#if MSDOS
+ if ((tmp = getenv("TMP")) == NULL && (tmp = getenv("TEMP")) == NULL)
+ strcpy(filnam, "command");
+ else {
+ strcpy(filnam, tmp);
+ len = strlen(tmp);
+ if (len <= 0 || filnam[len-1] != '\\' && filnam[len-1] != '/')
+ strcat(filnam,"\\");
+ strcat(filnam,"command");
+ }
+#endif
+
+#if VMS
+ mlwrite("Not available under VMS");
+ return(FALSE);
+#endif
+
+ /* get the command to pipe in */
+ if ((s=mlreply("@", line, NLINE)) != TRUE)
+ return(s);
+
+ /* get rid of the command output buffer if it exists */
+ if ((bp=bfind(bname, FALSE, 0)) != FALSE) {
+ /* try to make sure we are off screen */
+ wp = wheadp;
+ while (wp != NULL) {
+ if (wp->w_bufp == bp) {
+#if PKCODE
+ if (wp == curwp)
+ delwind(FALSE, 1);
+ else
+ onlywind(FALSE, 1);
+ break;
+#else
+ onlywind(FALSE, 1);
+ break;
+#endif
+ }
+ wp = wp->w_wndp;
+ }
+ if (zotbuf(bp) != TRUE)
+
+ return(FALSE);
+ }
+
+#if MSDOS
+ strcat(line," >>");
+ strcat(line,filnam);
+ movecursor(term.t_nrow, 0);
+ TTkclose();
+ shellprog(line);
+ TTkopen();
+ sgarbf = TRUE;
+ if ((fp = fopen(filnam, "r")) == NULL) {
+ s = FALSE;
+ } else {
+ fclose(fp);
+ s = TRUE;
+ }
+#endif
+
+#if V7 | USG | BSD
+ TTflush();
+ TTclose(); /* stty to old modes */
+ strcat(line,">");
+ strcat(line,filnam);
+ system(line);
+ TTopen();
+ TTflush();
+ sgarbf = TRUE;
+ s = TRUE;
+#endif
+
+ if (s != TRUE)
+ return(s);
+
+ /* split the current window to make room for the command output */
+ if (splitwind(FALSE, 1) == FALSE)
+ return(FALSE);
+
+ /* and read the stuff in */
+ if (getfile(filnam, FALSE) == FALSE)
+ return(FALSE);
+
+ /* make this window in VIEW mode, update all mode lines */
+ curwp->w_bufp->b_mode |= MDVIEW;
+ wp = wheadp;
+ while (wp != NULL) {
+ wp->w_flag |= WFMODE;
+ wp = wp->w_wndp;
+ }
+
+ /* and get rid of the temporary file */
+ unlink(filnam);
+ return(TRUE);
+}
+
+/*
+ * filter a buffer through an external DOS program
+ * Bound to ^X #
+ */
+filter(f, n)
+
+{
+ register int s; /* return status from CLI */
+ register BUFFER *bp; /* pointer to buffer to zot */
+ char line[NLINE]; /* command line send to shell */
+ char tmpnam[NFILEN]; /* place to store real file name */
+ static char bname1[] = "fltinp";
+
+ static char filnam1[] = "fltinp";
+ static char filnam2[] = "fltout";
+
+ /* don't allow this command if restricted */
+ if (restflag)
+ return(resterr());
+
+ if (curbp->b_mode&MDVIEW) /* don't allow this command if */
+ return(rdonly()); /* we are in read only mode */
+
+#if VMS
+ mlwrite("Not available under VMS");
+ return(FALSE);
+#endif
+
+ /* get the filter name and its args */
+ if ((s=mlreply("#", line, NLINE)) != TRUE)
+ return(s);
+
+ /* setup the proper file names */
+ bp = curbp;
+ strcpy(tmpnam, bp->b_fname); /* save the original name */
+ strcpy(bp->b_fname, bname1); /* set it to our new one */
+
+ /* write it out, checking for errors */
+ if (writeout(filnam1) != TRUE) {
+ mlwrite("(Cannot write filter file)");
+ strcpy(bp->b_fname, tmpnam);
+ return(FALSE);
+ }
+
+#if MSDOS
+ strcat(line," <fltinp >fltout");
+ movecursor(term.t_nrow - 1, 0);
+ TTkclose();
+ shellprog(line);
+ TTkopen();
+ sgarbf = TRUE;
+ s = TRUE;
+#endif
+
+#if V7 | USG | BSD
+ TTputc('\n'); /* Already have '\r' */
+ TTflush();
+ TTclose(); /* stty to old modes */
+ strcat(line," <fltinp >fltout");
+ system(line);
+ TTopen();
+ TTflush();
+ sgarbf = TRUE;
+ s = TRUE;
+#endif
+
+ /* on failure, escape gracefully */
+ if (s != TRUE || (readin(filnam2,FALSE) == FALSE)) {
+ mlwrite("(Execution failed)");
+ strcpy(bp->b_fname, tmpnam);
+ unlink(filnam1);
+ unlink(filnam2);
+ return(s);
+ }
+
+ /* reset file name */
+ strcpy(bp->b_fname, tmpnam); /* restore name */
+ bp->b_flag |= BFCHG; /* flag it as changed */
+
+ /* and get rid of the temporary file */
+ unlink(filnam1);
+ unlink(filnam2);
+ return(TRUE);
+}
+
+#if VMS
+/*
+ * Run a command. The "cmd" is a pointer to a command string, or NULL if you
+ * want to run a copy of DCL in the subjob (this is how the standard routine
+ * LIB$SPAWN works. You have to do wierd stuff with the terminal on the way in
+ * and the way out, because DCL does not want the channel to be in raw mode.
+ */
+sys(cmd)
+register char *cmd;
+{
+ struct dsc$descriptor cdsc;
+ struct dsc$descriptor *cdscp;
+ long status;
+ long substatus;
+ long iosb[2];
+
+ status = SYS$QIOW(EFN, iochan, IO$_SETMODE, iosb, 0, 0,
+ oldmode, sizeof(oldmode), 0, 0, 0, 0);
+ if (status!=SS$_NORMAL || (iosb[0]&0xFFFF)!=SS$_NORMAL)
+ return (FALSE);
+ cdscp = NULL; /* Assume DCL. */
+ if (cmd != NULL) { /* Build descriptor. */
+ cdsc.dsc$a_pointer = cmd;
+ cdsc.dsc$w_length = strlen(cmd);
+ cdsc.dsc$b_dtype = DSC$K_DTYPE_T;
+ cdsc.dsc$b_class = DSC$K_CLASS_S;
+ cdscp = &cdsc;
+ }
+ status = LIB$SPAWN(cdscp, 0, 0, 0, 0, 0, &substatus, 0, 0, 0);
+ if (status != SS$_NORMAL)
+ substatus = status;
+ status = SYS$QIOW(EFN, iochan, IO$_SETMODE, iosb, 0, 0,
+ newmode, sizeof(newmode), 0, 0, 0, 0);
+ if (status!=SS$_NORMAL || (iosb[0]&0xFFFF)!=SS$_NORMAL)
+ return (FALSE);
+ if ((substatus&STS$M_SUCCESS) == 0) /* Command failed. */
+ return (FALSE);
+ return (TRUE);
+}
+#endif
+
+#if MSDOS & (TURBO | MSC)
+
+/* SHELLPROG: Execute a command in a subshell */
+
+shellprog(cmd)
+
+char *cmd; /* Incoming command line to execute */
+
+{
+ char *shell; /* Name of system command processor */
+ char *p; /* Temporary pointer */
+ char swchar; /* switch character to use */
+ union REGS regs; /* parameters for dos call */
+ char comline[NSTRING]; /* constructed command line */
+ char *getenv();
+
+ /* detect current switch character and set us up to use it */
+ regs.h.ah = 0x37; /* get setting data */
+ regs.h.al = 0x00; /* get switch character */
+ intdos(&regs, &regs);
+ swchar = (char)regs.h.dl;
+
+ /* get name of system shell */
+ if ((shell = getenv("COMSPEC")) == NULL) {
+ return(FALSE); /* No shell located */
+ }
+
+ /* trim leading whitespace off the command */
+ while (*cmd == ' ' || *cmd == '\t') /* find out if null command */
+ cmd++;
+
+ /** If the command line is not empty, bring up the shell **/
+ /** and execute the command. Otherwise, bring up the **/
+ /** shell in interactive mode. **/
+
+ if (*cmd) {
+ strcpy(comline, shell);
+ strcat(comline, " ");
+ comline[strlen(comline) + 1] = 0;
+ comline[strlen(comline)] = swchar;
+ strcat(comline, "c ");
+ strcat(comline, cmd);
+ return(execprog(comline));
+ } else
+ return(execprog(shell));
+}
+
+/* EXECPROG: A function to execute a named program
+ with arguments
+*/
+
+execprog(cmd)
+
+char *cmd; /* Incoming command line to execute */
+
+{
+ char *sp; /* temporary string pointer */
+ char f1[38]; /* FCB1 area (not initialized */
+ char f2[38]; /* FCB2 area (not initialized */
+ char prog[NSTRING]; /* program filespec */
+ char tail[NSTRING]; /* command tail with length byte */
+ union REGS regs; /* parameters for dos call */
+ struct SREGS segreg; /* segment registers for dis call */
+ struct pblock { /* EXEC parameter block */
+ short envptr; /* 2 byte pointer to environment string */
+ char *cline; /* 4 byte pointer to command line */
+ char *fcb1; /* 4 byte pointer to FCB at PSP+5Ch */
+ char *fcb2; /* 4 byte pointer to FCB at PSP+6Ch */
+ } pblock;
+ char *flook();
+
+ /* parse the command name from the command line */
+ sp = prog;
+ while (*cmd && (*cmd != ' ') && (*cmd != '\t'))
+ *sp++ = *cmd++;
+ *sp = 0;
+
+ /* and parse out the command tail */
+ while (*cmd && ((*cmd == ' ') || (*cmd == '\t')))
+ ++cmd;
+ *tail = (char)(strlen(cmd)); /* record the byte length */
+ strcpy(&tail[1], cmd);
+ strcat(&tail[1], "\r");
+
+ /* look up the program on the path trying various extentions */
+ if ((sp = flook(prog, TRUE)) == NULL)
+ if ((sp = flook(strcat(prog, ".exe"), TRUE)) == NULL) {
+ strcpy(&prog[strlen(prog)-4], ".com");
+ if ((sp = flook(prog, TRUE)) == NULL)
+ return(FALSE);
+ }
+ strcpy(prog, sp);
+
+ /* get a pointer to this PSPs environment segment number */
+ segread(&segreg);
+
+ /* set up the EXEC parameter block */
+ pblock.envptr = 0; /* make the child inherit the parents env */
+ pblock.fcb1 = f1; /* point to a blank FCB */
+ pblock.fcb2 = f2; /* point to a blank FCB */
+ pblock.cline = tail; /* parameter line pointer */
+
+ /* and make the call */
+ regs.h.ah = 0x4b; /* EXEC Load or Execute a Program */
+ regs.h.al = 0x00; /* load end execute function subcode */
+ segreg.ds = ((unsigned long)(prog) >> 16); /* program name ptr */
+ regs.x.dx = (unsigned int)(prog);
+ segreg.es = ((unsigned long)(&pblock) >> 16); /* set up param block ptr */
+ regs.x.bx = (unsigned int)(&pblock);
+#if TURBO | MSC
+ intdosx(&regs, &regs, &segreg);
+ if (regs.x.cflag == 0) {
+ regs.h.ah = 0x4d; /* get child process return code */
+ intdos(&regs, &regs); /* go do it */
+ rval = regs.x.ax; /* save child's return code */
+ } else
+#if MSC
+ rval = -1;
+#else
+ rval = -_doserrno; /* failed child call */
+#endif
+#endif
+ return((rval < 0) ? FALSE : TRUE);
+}
+#endif
diff --git a/tcap.c b/tcap.c
new file mode 100644
index 0000000..38c7488
--- /dev/null
+++ b/tcap.c
@@ -0,0 +1,386 @@
+/* TCAP.C
+ *
+ * Unix V7 SysV and BS4 Termcap video driver
+ *
+ * modified by Petri Kutvonen
+ */
+
+/*
+ * defining this to 1 breaks tcapopen() - it doesn't check if the
+ * sceen size has changed.
+ * -lbt
+ */
+#define USE_BROKEN_OPTIMIZATION 0
+#define termdef 1 /* don't define "term" external */
+
+#include <stdio.h>
+#include "estruct.h"
+#include "edef.h"
+
+#if TERMCAP
+
+#if UNIX
+#include <signal.h>
+#endif
+
+#define MARGIN 8
+#define SCRSIZ 64
+#define NPAUSE 10 /* # times thru update to pause */
+#define BEL 0x07
+#define ESC 0x1B
+
+extern int ttopen();
+extern int ttgetc();
+extern int ttputc();
+extern int tgetnum();
+extern int ttflush();
+extern int ttclose();
+extern int tcapkopen();
+extern int tcapkclose();
+extern int tcapmove();
+extern int tcapeeol();
+extern int tcapeeop();
+extern int tcapbeep();
+extern int tcaprev();
+extern int tcapcres();
+extern int tcapopen();
+#if PKCODE
+extern int tcapclose();
+#endif
+extern int tput();
+extern char *tgoto();
+#if COLOR
+extern int tcapfcol();
+extern int tcapbcol();
+#endif
+#if SCROLLCODE
+extern int tcapscroll_reg();
+extern int tcapscroll_delins();
+#endif
+
+
+#define TCAPSLEN 315
+char tcapbuf[TCAPSLEN];
+char *UP, PC, *CM, *CE, *CL, *SO, *SE;
+
+#if PKCODE
+char *TI, *TE;
+int term_init_ok = 0;
+#endif
+
+#if SCROLLCODE
+char *CS, *DL, *AL, *SF, *SR;
+#endif
+
+TERM term = {
+ 0, /* these four values are set dynamically at open time */
+ 0,
+ 0,
+ 0,
+ MARGIN,
+ SCRSIZ,
+ NPAUSE,
+ tcapopen,
+#if PKCODE
+ tcapclose,
+#else
+ ttclose,
+#endif
+ tcapkopen,
+ tcapkclose,
+ ttgetc,
+ ttputc,
+ ttflush,
+ tcapmove,
+ tcapeeol,
+ tcapeeop,
+ tcapbeep,
+ tcaprev,
+ tcapcres
+#if COLOR
+ , tcapfcol,
+ tcapbcol
+#endif
+#if SCROLLCODE
+ , NULL /* set dynamically at open time */
+#endif
+};
+
+tcapopen()
+
+{
+ char *getenv();
+ char *t, *p, *tgetstr();
+ char tcbuf[1024];
+ char *tv_stype;
+ char err_str[72];
+ int int_col, int_row;
+
+#if PKCODE && USE_BROKEN_OPTIMIZATION
+ if (! term_init_ok)
+ {
+#endif
+ if ((tv_stype = getenv("TERM")) == NULL)
+ {
+ puts("Environment variable TERM not defined!");
+ exit(1);
+ }
+
+ if ((tgetent(tcbuf, tv_stype)) != 1)
+ {
+ sprintf(err_str, "Unknown terminal type %s!", tv_stype);
+ puts(err_str);
+ exit(1);
+ }
+
+ /* Get screen size from system, or else from termcap. */
+ getscreensize(&int_col, &int_row);
+ term.t_nrow = int_row-1;
+ term.t_ncol = int_col;
+
+ if ((term.t_nrow <= 0) && (term.t_nrow=(short)tgetnum("li")-1) == -1){
+ puts("termcap entry incomplete (lines)");
+ exit(1);
+ }
+
+ if ((term.t_ncol <= 0) && (term.t_ncol=(short)tgetnum("co")) == -1){
+ puts("Termcap entry incomplete (columns)");
+ exit(1);
+ }
+
+#ifdef SIGWINCH
+ term.t_mrow = MAXROW;
+ term.t_mcol = MAXCOL;
+#else
+ term.t_mrow = term.t_nrow > MAXROW ? MAXROW : term.t_nrow;
+ term.t_mcol = term.t_ncol > MAXCOL ? MAXCOL : term.t_ncol;
+#endif
+ p = tcapbuf;
+ t = tgetstr("pc", &p);
+ if(t)
+ PC = *t;
+ else
+ PC = 0;
+
+ CL = tgetstr("cl", &p);
+ CM = tgetstr("cm", &p);
+ CE = tgetstr("ce", &p);
+ UP = tgetstr("up", &p);
+ SE = tgetstr("se", &p);
+ SO = tgetstr("so", &p);
+ if (SO != NULL)
+ revexist = TRUE;
+#if PKCODE
+ if (tgetnum("sg") > 0) { /* can reverse be used? P.K. */
+ revexist = FALSE;
+ SE = NULL;
+ SO = NULL;
+ }
+ TI = tgetstr("ti", &p); /* terminal init and exit */
+ TE = tgetstr("te", &p);
+#endif
+
+ if(CL == NULL || CM == NULL || UP == NULL)
+ {
+ puts("Incomplete termcap entry\n");
+ exit(1);
+ }
+
+ if (CE == NULL) /* will we be able to use clear to EOL? */
+ eolexist = FALSE;
+#if SCROLLCODE
+ CS = tgetstr("cs", &p);
+ SF = tgetstr("sf", &p);
+ SR = tgetstr("sr", &p);
+ DL = tgetstr("dl", &p);
+ AL = tgetstr("al", &p);
+
+ if (CS && SR) {
+ if (SF == NULL) /* assume '\n' scrolls forward */
+ SF = "\n";
+ term.t_scroll = tcapscroll_reg;
+ } else if (DL && AL) {
+ term.t_scroll = tcapscroll_delins;
+ } else {
+ term.t_scroll = NULL;
+ }
+#endif
+
+ if (p >= &tcapbuf[TCAPSLEN])
+ {
+ puts("Terminal description too big!\n");
+ exit(1);
+ }
+#if PKCODE && USE_BROKEN_OPTIMIZATION
+ term_init_ok = 1;
+ }
+#endif
+ ttopen();
+}
+
+#if PKCODE
+
+tcapclose()
+
+{
+ putpad(tgoto(CM, 0, term.t_nrow));
+ putpad(TE);
+ ttflush();
+ ttclose();
+}
+#endif
+
+tcapkopen()
+
+{
+#if PKCODE
+ putpad(TI);
+ ttflush();
+#endif
+ strcpy(sres, "NORMAL");
+}
+
+tcapkclose()
+
+{
+}
+
+tcapmove(row, col)
+register int row, col;
+{
+ putpad(tgoto(CM, col, row));
+}
+
+tcapeeol()
+{
+ putpad(CE);
+}
+
+tcapeeop()
+{
+ putpad(CL);
+}
+
+tcaprev(state) /* change reverse video status */
+
+int state; /* FALSE = normal video, TRUE = reverse video */
+
+{
+ static int revstate = FALSE;
+ if (state) {
+ if (SO != NULL)
+ putpad(SO);
+ } else
+ if (SE != NULL)
+ putpad(SE);
+}
+
+tcapcres() /* change screen resolution */
+
+{
+ return(TRUE);
+}
+
+#if SCROLLCODE
+
+/* move howmanylines lines starting at from to to */
+tcapscroll_reg(from,to,howmanylines)
+{
+ int i;
+ if (to == from) return;
+ if (to < from) {
+ tcapscrollregion(to, from + howmanylines - 1);
+ tcapmove(from + howmanylines - 1,0);
+ for (i = from - to; i > 0; i--)
+ putpad(SF);
+ } else { /* from < to */
+ tcapscrollregion(from, to + howmanylines - 1);
+ tcapmove(from,0);
+ for (i = to - from; i > 0; i--)
+ putpad(SR);
+ }
+ tcapscrollregion(0, term.t_nrow);
+}
+
+/* move howmanylines lines starting at from to to */
+tcapscroll_delins(from,to,howmanylines)
+{
+ int i;
+ if (to == from) return;
+ if (to < from) {
+ tcapmove(to,0);
+ for (i = from - to; i > 0; i--)
+ putpad(DL);
+ tcapmove(to+howmanylines,0);
+ for (i = from - to; i > 0; i--)
+ putpad(AL);
+ } else {
+ tcapmove(from+howmanylines,0);
+ for (i = to - from; i > 0; i--)
+ putpad(DL);
+ tcapmove(from,0);
+ for (i = to - from; i > 0; i--)
+ putpad(AL);
+ }
+}
+
+/* cs is set up just like cm, so we use tgoto... */
+tcapscrollregion(top,bot)
+{
+ ttputc(PC);
+ putpad(tgoto(CS, bot, top));
+}
+
+#endif
+
+spal(dummy) /* change palette string */
+
+{
+ /* Does nothing here */
+}
+
+#if COLOR
+tcapfcol() /* no colors here, ignore this */
+{
+}
+
+tcapbcol() /* no colors here, ignore this */
+{
+}
+#endif
+
+tcapbeep()
+{
+ ttputc(BEL);
+}
+
+putpad(str)
+char *str;
+{
+ tputs(str, 1, ttputc);
+}
+
+putnpad(str, n)
+char *str;
+{
+ tputs(str, n, ttputc);
+}
+
+
+#if FNLABEL
+fnclabel(f, n) /* label a function key */
+
+int f,n; /* default flag, numeric argument [unused] */
+
+{
+ /* on machines with no function keys...don't bother */
+ return(TRUE);
+}
+#endif
+#else
+
+hello()
+{
+}
+
+#endif
diff --git a/termio.c b/termio.c
new file mode 100644
index 0000000..86abf75
--- /dev/null
+++ b/termio.c
@@ -0,0 +1,451 @@
+
+/* TERMIO.C
+ *
+ * The functions in this file negotiate with the operating system for
+ * characters, and write characters in a barely buffered fashion on the display.
+ * All operating systems.
+ *
+ * modified by Petri Kutvonen
+ */
+
+#ifndef POSIX
+
+#include <stdio.h>
+#include "estruct.h"
+#include "edef.h"
+
+#if VMS
+#include <stsdef.h>
+#include <ssdef.h>
+#include <descrip.h>
+#include <iodef.h>
+#include <ttdef.h>
+#include <tt2def.h>
+
+#define NIBUF 128 /* Input buffer size */
+#define NOBUF 1024 /* MM says bug buffers win! */
+#define EFN 0 /* Event flag */
+
+char obuf[NOBUF]; /* Output buffer */
+int nobuf; /* # of bytes in above */
+char ibuf[NIBUF]; /* Input buffer */
+int nibuf; /* # of bytes in above */
+int ibufi; /* Read index */
+int oldmode[3]; /* Old TTY mode bits */
+int newmode[3]; /* New TTY mode bits */
+short iochan; /* TTY I/O channel */
+#endif
+
+#if MSDOS & (MSC | TURBO)
+union REGS rg; /* cpu register for use of DOS calls */
+int nxtchar = -1; /* character held from type ahead */
+#endif
+
+#if USG /* System V */
+#include <signal.h>
+#include <termio.h>
+#include <fcntl.h>
+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 */
+struct termio otermio; /* original terminal characteristics */
+struct termio ntermio; /* charactoristics to use inside */
+#if XONXOFF
+#define XXMASK 0016000
+#endif
+#endif
+
+#if V7 | BSD
+#include <sgtty.h> /* for stty/gtty functions */
+#include <signal.h>
+struct sgttyb ostate; /* saved tty state */
+struct sgttyb nstate; /* values for editor mode */
+struct tchars otchars; /* Saved terminal special character set */
+#if XONXOFF
+struct tchars ntchars = { 0xff, 0xff, 0x11, 0x13, 0xff, 0xff };
+ /* A lot of nothing and XON/XOFF */
+#else
+struct tchars ntchars = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+ /* A lot of nothing */
+#endif
+#if BSD & PKCODE
+struct ltchars oltchars; /* Saved terminal local special character set */
+struct ltchars nltchars = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+ /* A lot of nothing */
+#endif
+
+#if BSD
+#include <sys/ioctl.h> /* to get at the typeahead */
+extern int rtfrmshell(); /* return from suspended shell */
+#define TBUFSIZ 128
+char tobuf[TBUFSIZ]; /* terminal output buffer */
+#endif
+#endif
+
+#if __hpux | SVR4
+extern int rtfrmshell(); /* return from suspended shell */
+#define TBUFSIZ 128
+char tobuf[TBUFSIZ]; /* terminal output buffer */
+#endif
+
+/*
+ * This function is called once to set up the terminal device streams.
+ * On VMS, it translates TT until it finds the terminal, then assigns
+ * a channel to it and sets it raw. On CPM it is a no-op.
+ */
+ttopen()
+{
+#if VMS
+ struct dsc$descriptor idsc;
+ struct dsc$descriptor odsc;
+ char oname[40];
+ int iosb[2];
+ int status;
+
+ odsc.dsc$a_pointer = "TT";
+ odsc.dsc$w_length = strlen(odsc.dsc$a_pointer);
+ odsc.dsc$b_dtype = DSC$K_DTYPE_T;
+ odsc.dsc$b_class = DSC$K_CLASS_S;
+ idsc.dsc$b_dtype = DSC$K_DTYPE_T;
+ idsc.dsc$b_class = DSC$K_CLASS_S;
+ do {
+ idsc.dsc$a_pointer = odsc.dsc$a_pointer;
+ idsc.dsc$w_length = odsc.dsc$w_length;
+ odsc.dsc$a_pointer = &oname[0];
+ odsc.dsc$w_length = sizeof(oname);
+ status = LIB$SYS_TRNLOG(&idsc, &odsc.dsc$w_length, &odsc);
+ if (status!=SS$_NORMAL && status!=SS$_NOTRAN)
+ exit(status);
+ if (oname[0] == 0x1B) {
+ odsc.dsc$a_pointer += 4;
+ odsc.dsc$w_length -= 4;
+ }
+ } while (status == SS$_NORMAL);
+ status = SYS$ASSIGN(&odsc, &iochan, 0, 0);
+ if (status != SS$_NORMAL)
+ exit(status);
+ status = SYS$QIOW(EFN, iochan, IO$_SENSEMODE, iosb, 0, 0,
+ oldmode, sizeof(oldmode), 0, 0, 0, 0);
+ if (status!=SS$_NORMAL || (iosb[0]&0xFFFF)!=SS$_NORMAL)
+ exit(status);
+ newmode[0] = oldmode[0];
+ newmode[1] = oldmode[1] | TT$M_NOECHO;
+#if XONXOFF
+#else
+ newmode[1] &= ~(TT$M_TTSYNC|TT$M_HOSTSYNC);
+#endif
+ newmode[2] = oldmode[2] | TT2$M_PASTHRU;
+ status = SYS$QIOW(EFN, iochan, IO$_SETMODE, iosb, 0, 0,
+ newmode, sizeof(newmode), 0, 0, 0, 0);
+ if (status!=SS$_NORMAL || (iosb[0]&0xFFFF)!=SS$_NORMAL)
+ exit(status);
+ term.t_nrow = (newmode[1]>>24) - 1;
+ term.t_ncol = newmode[0]>>16;
+
+#endif
+
+#if MSDOS & (TURBO | (PKCODE & MSC))
+ /* kill the CONTROL-break interupt */
+ rg.h.ah = 0x33; /* control-break check dos call */
+ rg.h.al = 1; /* set the current state */
+ rg.h.dl = 0; /* set it OFF */
+ intdos(&rg, &rg); /* go for it! */
+#endif
+
+#if USG
+ ioctl(0, TCGETA, &otermio); /* save old settings */
+ ntermio.c_iflag = 0; /* setup new settings */
+#if XONXOFF
+ ntermio.c_iflag = otermio.c_iflag & XXMASK; /* save XON/XOFF P.K. */
+#endif
+ ntermio.c_oflag = 0;
+ ntermio.c_cflag = otermio.c_cflag;
+ ntermio.c_lflag = 0;
+ ntermio.c_line = otermio.c_line;
+ ntermio.c_cc[VMIN] = 1;
+ ntermio.c_cc[VTIME] = 0;
+#if PKCODE
+ ioctl(0, TCSETAW, &ntermio); /* and activate them */
+#else
+ ioctl(0, TCSETA, &ntermio); /* and activate them */
+#endif
+ kbdflgs = fcntl( 0, F_GETFL, 0 );
+ kbdpoll = FALSE;
+#endif
+
+#if V7 | BSD
+ gtty(0, &ostate); /* save old state */
+ gtty(0, &nstate); /* get base of new state */
+#if XONXOFF
+ nstate.sg_flags |= (CBREAK|TANDEM);
+#else
+ nstate.sg_flags |= RAW;
+#endif
+ nstate.sg_flags &= ~(ECHO|CRMOD); /* no echo for now... */
+ stty(0, &nstate); /* set mode */
+ ioctl(0, TIOCGETC, &otchars); /* Save old characters */
+ ioctl(0, TIOCSETC, &ntchars); /* Place new character into K */
+#if BSD & PKCODE
+ ioctl(0, TIOCGLTC, &oltchars); /* Save old local characters */
+ ioctl(0, TIOCSLTC, &nltchars); /* New local characters */
+#endif
+#if BSD
+ /* provide a smaller terminal output buffer so that
+ the type ahead detection works better (more often) */
+ setbuffer(stdout, &tobuf[0], TBUFSIZ);
+ signal(SIGTSTP,SIG_DFL); /* set signals so that we can */
+ signal(SIGCONT,rtfrmshell); /* suspend & restart emacs */
+#endif
+#endif
+
+#if __hpux | SVR4
+ /* provide a smaller terminal output buffer so that
+ the type ahead detection works better (more often) */
+ setvbuf(stdout, &tobuf[0], _IOFBF, TBUFSIZ);
+ signal(SIGTSTP,SIG_DFL); /* set signals so that we can */
+ signal(SIGCONT,rtfrmshell); /* suspend & restart emacs */
+ TTflush();
+#endif /* __hpux */
+
+ /* on all screens we are not sure of the initial position
+ of the cursor */
+ ttrow = 999;
+ ttcol = 999;
+}
+
+/*
+ * This function gets called just before we go back home to the command
+ * interpreter. On VMS it puts the terminal back in a reasonable state.
+ * Another no-operation on CPM.
+ */
+ttclose()
+{
+#if VMS
+ int status;
+ int iosb[1];
+
+ ttflush();
+ status = SYS$QIOW(EFN, iochan, IO$_SETMODE, iosb, 0, 0,
+ oldmode, sizeof(oldmode), 0, 0, 0, 0);
+ if (status!=SS$_NORMAL || (iosb[0]&0xFFFF)!=SS$_NORMAL)
+ exit(status);
+ status = SYS$DASSGN(iochan);
+ if (status != SS$_NORMAL)
+ exit(status);
+#endif
+#if MSDOS & (TURBO | (PKCODE & MSC))
+ /* restore the CONTROL-break interupt */
+ rg.h.ah = 0x33; /* control-break check dos call */
+ rg.h.al = 1; /* set the current state */
+ rg.h.dl = 1; /* set it ON */
+ intdos(&rg, &rg); /* go for it! */
+#endif
+
+#if USG
+#if PKCODE
+ ioctl(0, TCSETAW, &otermio); /* restore terminal settings */
+#else
+ ioctl(0, TCSETA, &otermio); /* restore terminal settings */
+#endif
+ fcntl(0, F_SETFL, kbdflgs);
+#endif
+
+#if V7 | BSD
+ stty(0, &ostate);
+ ioctl(0, TIOCSETC, &otchars); /* Place old character into K */
+#if BSD & PKCODE
+ ioctl(0, TIOCSLTC, &oltchars); /* Place old local character into K */
+#endif
+#endif
+}
+
+/*
+ * Write a character to the display. On VMS, terminal output is buffered, and
+ * we just put the characters in the big array, after checking for overflow.
+ * On CPM terminal I/O unbuffered, so we just write the byte out. Ditto on
+ * MS-DOS (use the very very raw console output routine).
+ */
+ttputc(c)
+{
+#if VMS
+ if (nobuf >= NOBUF)
+ ttflush();
+ obuf[nobuf++] = c;
+#endif
+
+#if MSDOS & ~IBMPC
+ bdos(6, c, 0);
+#endif
+
+#if V7 | USG | BSD
+ fputc(c, stdout);
+#endif
+}
+
+/*
+ * Flush terminal buffer. Does real work where the terminal output is buffered
+ * up. A no-operation on systems where byte at a time terminal I/O is done.
+ */
+ttflush()
+{
+#if VMS
+ int status;
+ int iosb[2];
+
+ status = SS$_NORMAL;
+ if (nobuf != 0) {
+ status = SYS$QIOW(EFN, iochan, IO$_WRITELBLK|IO$M_NOFORMAT,
+ iosb, 0, 0, obuf, nobuf, 0, 0, 0, 0);
+ if (status == SS$_NORMAL)
+ status = iosb[0] & 0xFFFF;
+ nobuf = 0;
+ }
+ return (status);
+#endif
+
+#if MSDOS
+#endif
+
+#if V7 | USG | BSD
+/*
+ * Add some terminal output success checking, sometimes an orphaned
+ * process may be left looping on SunOS 4.1.
+ *
+ * How to recover here, or is it best just to exit and lose
+ * everything?
+ *
+ * jph, 8-Oct-1993
+ */
+
+#include <errno.h>
+
+ int status;
+
+ status = fflush(stdout);
+
+ if (status != 0 && errno != EAGAIN) {
+ exit(errno);
+ }
+#endif
+}
+
+/*
+ * Read a character from the terminal, performing no editing and doing no echo
+ * at all. More complex in VMS that almost anyplace else, which figures. Very
+ * simple on CPM, because the system can do exactly what you want.
+ */
+ttgetc()
+{
+#if VMS
+ int status;
+ int iosb[2];
+ int term[2];
+
+ while (ibufi >= nibuf) {
+ ibufi = 0;
+ term[0] = 0;
+ term[1] = 0;
+ status = SYS$QIOW(EFN, iochan, IO$_READLBLK|IO$M_TIMED,
+ iosb, 0, 0, ibuf, NIBUF, 0, term, 0, 0);
+ if (status != SS$_NORMAL)
+ exit(status);
+ status = iosb[0] & 0xFFFF;
+ if (status!=SS$_NORMAL && status!=SS$_TIMEOUT &&
+ status!=SS$_DATAOVERUN)
+ exit(status);
+ nibuf = (iosb[0]>>16) + (iosb[1]>>16);
+ if (nibuf == 0) {
+ status = SYS$QIOW(EFN, iochan, IO$_READLBLK,
+ iosb, 0, 0, ibuf, 1, 0, term, 0, 0);
+ if (status != SS$_NORMAL
+ || (status = (iosb[0]&0xFFFF)) != SS$_NORMAL)
+ if (status != SS$_DATAOVERUN)
+ exit(status);
+ nibuf = (iosb[0]>>16) + (iosb[1]>>16);
+ }
+ }
+ return (ibuf[ibufi++] & 0xFF); /* Allow multinational */
+#endif
+
+#if MSDOS & (MSC | TURBO)
+ int c; /* character read */
+
+ /* if a char already is ready, return it */
+ if (nxtchar >= 0) {
+ c = nxtchar;
+ nxtchar = -1;
+ return(c);
+ }
+
+ /* call the dos to get a char */
+ rg.h.ah = 7; /* dos Direct Console Input call */
+ intdos(&rg, &rg);
+ c = rg.h.al; /* grab the char */
+ return(c & 255);
+#endif
+
+#if V7 | BSD
+ return(255 & fgetc(stdin)); /* 8BIT P.K. */
+#endif
+
+#if USG
+ if( kbdqp )
+ kbdqp = FALSE;
+ else
+ {
+ if( kbdpoll && fcntl( 0, F_SETFL, kbdflgs ) < 0 )
+ return FALSE;
+ kbdpoll = FALSE;
+ while (read(0, &kbdq, 1) != 1)
+ ;
+ }
+ return ( kbdq & 255 );
+#endif
+}
+
+#if TYPEAH
+/* typahead: Check to see if any characters are already in the
+ keyboard buffer
+*/
+
+typahead()
+
+{
+#if MSDOS & (MSC | TURBO)
+ if (kbhit() != 0)
+ return(TRUE);
+ else
+ return(FALSE);
+#endif
+
+#if BSD
+ int x; /* holds # of pending chars */
+
+ return((ioctl(0,FIONREAD,&x) < 0) ? 0 : x);
+#endif
+
+#if PKCODE & VMS
+ return(ibufi < nibuf);
+#endif
+
+#if USG
+ if( !kbdqp )
+ {
+ if( !kbdpoll && fcntl( 0, F_SETFL, kbdflgs | O_NDELAY ) < 0 )
+ return(FALSE);
+#if PKCODE
+ kbdpoll = 1;
+#endif
+ kbdqp = (1 == read( 0, &kbdq, 1 ));
+ }
+ return ( kbdqp );
+#endif
+
+#if !UNIX & !VMS & !MSDOS
+ return(FALSE);
+#endif
+}
+#endif
+
+#endif /* not POSIX */
diff --git a/vmslink.com b/vmslink.com
new file mode 100644
index 0000000..1da8fa6
--- /dev/null
+++ b/vmslink.com
@@ -0,0 +1,29 @@
+$ define lnk$library sys$library:vaxcrtl
+$ link /exec=emacs.exe -
+ANSI.OBJ+ -
+BASIC.OBJ+ -
+BIND.OBJ+ -
+BUFFER.OBJ+ -
+CRYPT.OBJ+ -
+DISPLAY.OBJ+ -
+EVAL.OBJ+ -
+EXEC.OBJ+ -
+FILE.OBJ+ -
+FILEIO.OBJ+ -
+IBMPC.OBJ+ -
+INPUT.OBJ+ -
+ISEARCH.OBJ+ -
+LINE.OBJ+ -
+LOCK.OBJ+ -
+MAIN.OBJ+ -
+RANDOM.OBJ+ -
+REGION.OBJ+ -
+SEARCH.OBJ+ -
+SPAWN.OBJ+ -
+TCAP.OBJ+ -
+TERMIO.OBJ+ -
+VMSVT.OBJ+ -
+VT52.OBJ+ -
+WINDOW.OBJ+ -
+WORD.OBJ+ -
+PKLOCK.OBJ
diff --git a/vmsmake.com b/vmsmake.com
new file mode 100644
index 0000000..e07a087
--- /dev/null
+++ b/vmsmake.com
@@ -0,0 +1,28 @@
+$ cc /define=(AUTOCONF) ANSI.c
+$ cc /define=(AUTOCONF) BASIC.c
+$ cc /define=(AUTOCONF) BIND.c
+$ cc /define=(AUTOCONF) BUFFER.c
+$ cc /define=(AUTOCONF) CRYPT.c
+$ cc /define=(AUTOCONF) DISPLAY.c
+$ cc /define=(AUTOCONF) EVAL.c
+$ cc /define=(AUTOCONF) EXEC.c
+$ cc /define=(AUTOCONF) FILE.c
+$ cc /define=(AUTOCONF) FILEIO.c
+$ cc /define=(AUTOCONF) IBMPC.c
+$ cc /define=(AUTOCONF) INPUT.c
+$ cc /define=(AUTOCONF) ISEARCH.c
+$ cc /define=(AUTOCONF) LINE.c
+$ cc /define=(AUTOCONF) LOCK.c
+$ cc /define=(AUTOCONF) MAIN.c
+$ cc /define=(AUTOCONF) RANDOM.c
+$ cc /define=(AUTOCONF) REGION.c
+$ cc /define=(AUTOCONF) SEARCH.c
+$ cc /define=(AUTOCONF) SPAWN.c
+$ cc /define=(AUTOCONF) TCAP.c
+$ cc /define=(AUTOCONF) TERMIO.c
+$ cc /define=(AUTOCONF) VMSVT.c
+$ cc /define=(AUTOCONF) VT52.c
+$ cc /define=(AUTOCONF) WINDOW.c
+$ cc /define=(AUTOCONF) WORD.c
+$ cc /define=(AUTOCONF) PKLOCK.c
+$ @vmslink
diff --git a/vmsvt.c b/vmsvt.c
new file mode 100644
index 0000000..82c5a98
--- /dev/null
+++ b/vmsvt.c
@@ -0,0 +1,519 @@
+/* VMSVT.C
+ *
+ * Advanced VMS terminal driver
+ *
+ * Knows about any terminal defined in SMGTERMS.TXT and TERMTABLE.TXT
+ * located in SYS$SYSTEM.
+ *
+ * Author: Curtis Smith
+ * modified by Petri Kutvonen
+ */
+
+#include <stdio.h> /* Standard I/O package */
+#include "estruct.h" /* Emacs' structures */
+#include "edef.h" /* Emacs' definitions */
+
+#if VMSVT
+
+#include <descrip.h> /* Descriptor definitions */
+
+/* These would normally come from iodef.h and ttdef.h */
+#define IO$_SENSEMODE 0x27 /* Sense mode of terminal */
+#define TT$_UNKNOWN 0x00 /* Unknown terminal */
+#define TT$_VT100 96
+
+/** Forward references **/
+int vmsopen(), ttclose(), vmskopen(), vmskclose(), ttgetc(), ttputc();
+int ttflush(), vmsmove(), vmseeol(), vmseeop(), vmsbeep(), vmsrev();
+int vmscres();
+extern int eolexist, revexist;
+extern char sres[];
+
+#if COLOR
+int vmsfcol(), vmsbcol();
+#endif
+
+/** SMG stuff **/
+static char * begin_reverse, * end_reverse, * erase_to_end_line;
+static char * erase_whole_display;
+static int termtype;
+
+#define SMG$K_BEGIN_REVERSE 0x1bf
+#define SMG$K_END_REVERSE 0x1d6
+#define SMG$K_SET_CURSOR_ABS 0x23a
+#define SMG$K_ERASE_WHOLE_DISPLAY 0x1da
+#define SMG$K_ERASE_TO_END_LINE 0x1d9
+
+#if SCROLLCODE
+
+#define SMG$K_SCROLL_FORWARD 561 /* from sys$library:smgtrmptr.h */
+#define SMG$K_SCROLL_REVERSE 562
+#define SMG$K_SET_SCROLL_REGION 572
+
+static char *scroll_forward, *scroll_reverse;
+
+#endif
+
+/* Dispatch table. All hard fields just point into the terminal I/O code. */
+TERM term = {
+#if PKCODE
+ MAXROW,
+#else
+ 24 - 1, /* Max number of rows allowable */
+#endif
+ /* Filled in */ - 1, /* Current number of rows used */
+ MAXCOL, /* Max number of columns */
+ /* Filled in */ 0, /* Current number of columns */
+ 64, /* Min margin for extended lines*/
+ 8, /* Size of scroll region */
+ 100, /* # times thru update to pause */
+ vmsopen, /* Open terminal at the start */
+ ttclose, /* Close terminal at end */
+ vmskopen, /* Open keyboard */
+ vmskclose, /* Close keyboard */
+ ttgetc, /* Get character from keyboard */
+ ttputc, /* Put character to display */
+ ttflush, /* Flush output buffers */
+ vmsmove, /* Move cursor, origin 0 */
+ vmseeol, /* Erase to end of line */
+ vmseeop, /* Erase to end of page */
+ vmsbeep, /* Beep */
+ vmsrev, /* Set reverse video state */
+ vmscres /* Change screen resolution */
+#if COLOR
+ , vmsfcol, /* Set forground color */
+ vmsbcol /* Set background color */
+#endif
+#if SCROLLCODE
+ , NULL
+#endif
+};
+
+/***
+ * ttputs - Send a string to ttputc
+ *
+ * Nothing returned
+ ***/
+ttputs(string)
+char * string; /* String to write */
+{
+ if (string)
+ while (*string != '\0')
+ ttputc(*string++);
+}
+
+
+/***
+ * vmsmove - Move the cursor (0 origin)
+ *
+ * Nothing returned
+ ***/
+vmsmove(row, col)
+int row; /* Row position */
+int col; /* Column position */
+{
+ char buffer[32];
+ int ret_length;
+ static int request_code = SMG$K_SET_CURSOR_ABS;
+ static int max_buffer_length = sizeof(buffer);
+ static int arg_list[3] = { 2 };
+ register char * cp;
+
+ register int i;
+
+ /* Set the arguments into the arg_list array
+ * SMG assumes the row/column positions are 1 based (boo!)
+ */
+ arg_list[1] = row + 1;
+ arg_list[2] = col + 1;
+
+ if ((smg$get_term_data( /* Get terminal data */
+ &termtype, /* Terminal table address */
+ &request_code, /* Request code */
+ &max_buffer_length, /* Maximum buffer length */
+ &ret_length, /* Return length */
+ buffer, /* Capability data buffer */
+ arg_list) /* Argument list array */
+
+ /* We'll know soon enough if this doesn't work */
+ & 1) == 0) {
+ ttputs("OOPS");
+ return;
+ }
+
+ /* Send out resulting sequence */
+ i = ret_length;
+ cp = buffer;
+ while (i-- > 0)
+ ttputc(*cp++);
+}
+
+#if SCROLLCODE
+
+vmsscroll_reg(from,to,howmany)
+{
+ int i;
+ if (to == from) return;
+ if (to < from) {
+ vmsscrollregion(to, from + howmany - 1);
+ vmsmove(from + howmany - 1,0);
+ for (i = from - to; i > 0; i--)
+ ttputs(scroll_forward);
+ } else { /* from < to */
+ vmsscrollregion(from, to + howmany - 1);
+ vmsmove(from,0);
+ for (i = to - from; i > 0; i--)
+ ttputs(scroll_reverse);
+ }
+ vmsscrollregion(-1, -1);
+}
+
+vmsscrollregion(top, bot)
+int top; /* Top position */
+int bot; /* Bottom position */
+{
+ char buffer[32];
+ int ret_length;
+ static int request_code = SMG$K_SET_SCROLL_REGION;
+ static int max_buffer_length = sizeof(buffer);
+ static int arg_list[3] = { 2 };
+ register char * cp;
+
+ register int i;
+
+ /* Set the arguments into the arg_list array
+ * SMG assumes the row/column positions are 1 based (boo!)
+ */
+ arg_list[1] = top + 1;
+ arg_list[2] = bot + 1;
+
+ if ((smg$get_term_data( /* Get terminal data */
+ &termtype, /* Terminal table address */
+ &request_code, /* Request code */
+ &max_buffer_length, /* Maximum buffer length */
+ &ret_length, /* Return length */
+ buffer, /* Capability data buffer */
+ arg_list) /* Argument list array */
+
+ /* We'll know soon enough if this doesn't work */
+ & 1) == 0) {
+ ttputs("OOPS");
+ return;
+ }
+
+ ttputc(0);
+ /* Send out resulting sequence */
+ i = ret_length;
+ cp = buffer;
+ while (i-- > 0)
+ ttputc(*cp++);
+}
+#endif
+
+/***
+ * vmsrev - Set the reverse video status
+ *
+ * Nothing returned
+ ***/
+vmsrev(status)
+int status; /* TRUE if setting reverse */
+{
+ if (status)
+ ttputs(begin_reverse);
+ else
+ ttputs(end_reverse);
+}
+
+/***
+ * vmscres - Change screen resolution (which it doesn't)
+ *
+ * Nothing returned
+ ***/
+vmscres()
+{
+ /* But it could. For vt100/vt200s, one could switch from
+ 80 and 132 columns modes */
+}
+
+
+#if COLOR
+/***
+ * vmsfcol - Set the forground color (not implimented)
+ *
+ * Nothing returned
+ ***/
+vmsfcol()
+{
+}
+
+/***
+ * vmsbcol - Set the background color (not implimented)
+ *
+ * Nothing returned
+ ***/
+vmsbcol()
+{
+}
+#endif
+
+/***
+ * vmseeol - Erase to end of line
+ *
+ * Nothing returned
+ ***/
+vmseeol()
+{
+ ttputs(erase_to_end_line);
+}
+
+
+/***
+ * vmseeop - Erase to end of page (clear screen)
+ *
+ * Nothing returned
+ ***/
+vmseeop()
+{
+ ttputs(erase_whole_display);
+}
+
+
+/***
+ * vmsbeep - Ring the bell
+ *
+ * Nothing returned
+ ***/
+vmsbeep()
+{
+ ttputc('\007');
+}
+
+
+/***
+ * vmsgetstr - Get an SMG string capability by name
+ *
+ * Returns: Escape sequence
+ * NULL No escape sequence available
+ ***/
+char * vmsgetstr(request_code)
+int request_code; /* Request code */
+{
+ register char * result;
+ static char seq_storage[1024];
+ static char * buffer = seq_storage;
+ static int arg_list[2] = { 1, 1 };
+ int max_buffer_length, ret_length;
+
+ /* Precompute buffer length */
+
+ max_buffer_length = (seq_storage + sizeof(seq_storage)) - buffer;
+
+ /* Get terminal commands sequence from master table */
+
+ if ((smg$get_term_data( /* Get terminal data */
+ &termtype, /* Terminal table address */
+ &request_code, /* Request code */
+ &max_buffer_length,/* Maximum buffer length */
+ &ret_length, /* Return length */
+ buffer, /* Capability data buffer */
+ arg_list) /* Argument list array */
+
+ /* If this doesn't work, try again with no arguments */
+
+ & 1) == 0 &&
+
+ (smg$get_term_data( /* Get terminal data */
+ &termtype, /* Terminal table address */
+ &request_code, /* Request code */
+ &max_buffer_length,/* Maximum buffer length */
+ &ret_length, /* Return length */
+ buffer) /* Capability data buffer */
+
+ /* Return NULL pointer if capability is not available */
+
+ & 1) == 0)
+ return NULL;
+
+ /* Check for empty result */
+ if (ret_length == 0)
+ return NULL;
+
+ /* Save current position so we can return it to caller */
+
+ result = buffer;
+
+ /* NIL terminate the sequence for return */
+
+ buffer[ret_length] = 0;
+
+ /* Advance buffer */
+
+ buffer += ret_length + 1;
+
+ /* Return capability to user */
+ return result;
+}
+
+
+/** I/O information block definitions **/
+struct iosb { /* I/O status block */
+ short i_cond; /* Condition value */
+ short i_xfer; /* Transfer count */
+ long i_info; /* Device information */
+};
+struct termchar { /* Terminal characteristics */
+ char t_class; /* Terminal class */
+ char t_type; /* Terminal type */
+ short t_width; /* Terminal width in characters */
+ long t_mandl; /* Terminal's mode and length */
+ long t_extend; /* Extended terminal characteristics */
+};
+static struct termchar tc; /* Terminal characteristics */
+
+/***
+ * vmsgtty - Get terminal type from system control block
+ *
+ * Nothing returned
+ ***/
+vmsgtty()
+{
+ short fd;
+ int status;
+ struct iosb iostatus;
+ $DESCRIPTOR(devnam, "SYS$INPUT");
+
+ /* Assign input to a channel */
+ status = sys$assign(&devnam, &fd, 0, 0);
+ if ((status & 1) == 0)
+ exit (status);
+
+ /* Get terminal characteristics */
+ status = sys$qiow( /* Queue and wait */
+ 0, /* Wait on event flag zero */
+ fd, /* Channel to input terminal */
+ IO$_SENSEMODE, /* Get current characteristic */
+ &iostatus, /* Status after operation */
+ 0, 0, /* No AST service */
+ &tc, /* Terminal characteristics buf */
+ sizeof(tc), /* Size of the buffer */
+ 0, 0, 0, 0); /* P3-P6 unused */
+
+ /* De-assign the input device */
+ if ((sys$dassgn(fd) & 1) == 0)
+ exit(status);
+
+ /* Jump out if bad status */
+ if ((status & 1) == 0)
+ exit(status);
+ if ((iostatus.i_cond & 1) == 0)
+ exit(iostatus.i_cond);
+}
+
+
+/***
+ * vmsopen - Get terminal type and open terminal
+ *
+ * Nothing returned
+ ***/
+vmsopen()
+{
+ /* Get terminal type */
+ vmsgtty();
+ if (tc.t_type == TT$_UNKNOWN) {
+ printf("Terminal type is unknown!\n");
+ printf("Try set your terminal type with SET TERMINAL/INQUIRE\n");
+ printf("Or get help on SET TERMINAL/DEVICE_TYPE\n");
+ exit(3);
+ }
+
+ /* Access the system terminal definition table for the */
+ /* information of the terminal type returned by IO$_SENSEMODE */
+ if ((smg$init_term_table_by_type(&tc.t_type, &termtype) & 1) == 0)
+ return -1;
+
+ /* Set sizes */
+ term.t_nrow = ((unsigned int) tc.t_mandl >> 24) - 1;
+ term.t_ncol = tc.t_width;
+
+ /* Get some capabilities */
+ begin_reverse = vmsgetstr(SMG$K_BEGIN_REVERSE);
+ end_reverse = vmsgetstr(SMG$K_END_REVERSE);
+ revexist = begin_reverse != NULL && end_reverse != NULL;
+ erase_to_end_line = vmsgetstr(SMG$K_ERASE_TO_END_LINE);
+ eolexist = erase_to_end_line != NULL;
+ erase_whole_display = vmsgetstr(SMG$K_ERASE_WHOLE_DISPLAY);
+
+#if SCROLLCODE
+ scroll_forward = vmsgetstr(SMG$K_SCROLL_FORWARD);
+ scroll_reverse = vmsgetstr(SMG$K_SCROLL_REVERSE);
+ if (tc.t_type < TT$_VT100 || scroll_reverse == NULL ||
+ scroll_forward == NULL)
+ term.t_scroll = NULL;
+ else
+ term.t_scroll = vmsscroll_reg;
+#endif
+
+ /* Set resolution */
+ strcpy(sres, "NORMAL");
+
+ /* Open terminal I/O drivers */
+ ttopen();
+}
+
+
+/***
+ * vmskopen - Open keyboard (not used)
+ *
+ * Nothing returned
+ ***/
+vmskopen()
+{
+}
+
+
+/***
+ * vmskclose - Close keyboard (not used)
+ *
+ * Nothing returned
+ ***/
+vmskclose()
+{
+}
+
+
+/***
+ * fnclabel - Label function keys (not used)
+ *
+ * Nothing returned
+ ***/
+#if FNLABEL
+fnclabel(f, n) /* label a function key */
+int f,n; /* default flag, numeric argument [unused] */
+{
+ /* on machines with no function keys...don't bother */
+ return(TRUE);
+}
+#endif
+
+
+/***
+ * spal - Set palette type (Are you kidding?)
+ *
+ * Nothing returned
+ ***/
+spal()
+{
+}
+
+#else
+
+/***
+ * hellovms - Avoid error because of empty module
+ *
+ * Nothing returned
+ ***/
+hellovms()
+{
+}
+
+#endif
diff --git a/vt52.c b/vt52.c
new file mode 100644
index 0000000..dbff430
--- /dev/null
+++ b/vt52.c
@@ -0,0 +1,190 @@
+/* VT52.C
+ *
+ * The routines in this file
+ * provide support for VT52 style terminals
+ * over a serial line. The serial I/O services are
+ * provided by routines in "termio.c". It compiles
+ * into nothing if not a VT52 style device. The
+ * bell on the VT52 is terrible, so the "beep"
+ * routine is conditionalized on defining BEL.
+ *
+ * modified by Petri Kutvonen
+ */
+
+#define termdef 1 /* don't define "term" external */
+
+#include <stdio.h>
+#include "estruct.h"
+#include "edef.h"
+
+#if VT52
+
+#define NROW 24 /* Screen size. */
+#define NCOL 80 /* Edit if you want to. */
+#define MARGIN 8 /* size of minimim margin and */
+#define SCRSIZ 64 /* scroll size for extended lines */
+#define NPAUSE 100 /* # times thru update to pause */
+#define BIAS 0x20 /* Origin 0 coordinate bias. */
+#define ESC 0x1B /* ESC character. */
+#define BEL 0x07 /* ascii bell character */
+
+extern int ttopen(); /* Forward references. */
+extern int ttgetc();
+extern int ttputc();
+extern int ttflush();
+extern int ttclose();
+extern int vt52move();
+extern int vt52eeol();
+extern int vt52eeop();
+extern int vt52beep();
+extern int vt52open();
+extern int vt52rev();
+extern int vt52cres();
+extern int vt52kopen();
+extern int vt52kclose();
+
+#if COLOR
+extern int vt52fcol();
+extern int vt52bcol();
+#endif
+
+/*
+ * Dispatch table. All the
+ * hard fields just point into the
+ * terminal I/O code.
+ */
+TERM term = {
+ NROW-1,
+ NROW-1,
+ NCOL,
+ NCOL,
+ MARGIN,
+ SCRSIZ,
+ NPAUSE,
+ &vt52open,
+ &ttclose,
+ &vt52kopen,
+ &vt52kclose,
+ &ttgetc,
+ &ttputc,
+ &ttflush,
+ &vt52move,
+ &vt52eeol,
+ &vt52eeop,
+ &vt52beep,
+ &vt52rev,
+ &vt52cres
+#if COLOR
+ , &vt52fcol,
+ &vt52bcol
+#endif
+#if SCROLLCODE
+ , NULL
+#endif
+};
+
+vt52move(row, col)
+{
+ ttputc(ESC);
+ ttputc('Y');
+ ttputc(row+BIAS);
+ ttputc(col+BIAS);
+}
+
+vt52eeol()
+{
+ ttputc(ESC);
+ ttputc('K');
+}
+
+vt52eeop()
+{
+ ttputc(ESC);
+ ttputc('J');
+}
+
+vt52rev(status) /* set the reverse video state */
+
+int status; /* TRUE = reverse video, FALSE = normal video */
+
+{
+ /* can't do this here, so we won't */
+}
+
+vt52cres() /* change screen resolution - (not here though) */
+
+{
+ return(TRUE);
+}
+
+spal() /* change palette string */
+
+{
+ /* Does nothing here */
+}
+
+#if COLOR
+vt52fcol() /* set the forground color [NOT IMPLIMENTED] */
+{
+}
+
+vt52bcol() /* set the background color [NOT IMPLIMENTED] */
+{
+}
+#endif
+
+vt52beep()
+{
+#ifdef BEL
+ ttputc(BEL);
+ ttflush();
+#endif
+}
+
+vt52open()
+{
+#if V7 | BSD
+ register char *cp;
+ char *getenv();
+
+ if ((cp = getenv("TERM")) == NULL) {
+ puts("Shell variable TERM not defined!");
+ exit(1);
+ }
+ if (strcmp(cp, "vt52") != 0 && strcmp(cp, "z19") != 0) {
+ puts("Terminal type not 'vt52'or 'z19' !");
+ exit(1);
+ }
+#endif
+ ttopen();
+}
+
+vt52kopen()
+
+{
+}
+
+vt52kclose()
+
+{
+}
+
+
+#if FNLABEL
+fnclabel(f, n) /* label a function key */
+
+int f,n; /* default flag, numeric argument [unused] */
+
+{
+ /* on machines with no function keys...don't bother */
+ return(TRUE);
+}
+#endif
+#else
+
+vt52hello()
+
+{
+}
+
+#endif
diff --git a/window.c b/window.c
new file mode 100644
index 0000000..8500f12
--- /dev/null
+++ b/window.c
@@ -0,0 +1,733 @@
+/* WINDOW.C
+ *
+ * Window management. Some of the functions are internal, and some are
+ * attached to keys that the user actually types.
+ *
+ */
+
+#include <stdio.h>
+#include "estruct.h"
+#include "edef.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). With no argument it defaults to 0. Bound to M-!.
+ */
+reposition(f, n)
+ {
+ if (f == FALSE) /* default to 0 to center screen */
+ n = 0;
+ curwp->w_force = n;
+ curwp->w_flag |= WFFORCE;
+ return (TRUE);
+ }
+
+/*
+ * Refresh the screen. With no argument, it just does the refresh. With an
+ * argument it recenters "." in the current window. Bound to "C-L".
+ */
+refresh(f, n)
+ {
+ if (f == FALSE)
+ sgarbf = TRUE;
+ else
+ {
+ curwp->w_force = 0; /* Center dot. */
+ curwp->w_flag |= WFFORCE;
+ }
+
+ return (TRUE);
+ }
+
+/*
+ * The command make the next window (next => down the screen) the current
+ * window. There are no real errors, although the command does nothing if
+ * there is only 1 window on the screen. Bound to "C-X C-N".
+ *
+ * with an argument this command finds the <n>th window from the top
+ *
+ */
+nextwind(f, n)
+
+int f, n; /* default flag and numeric argument */
+
+{
+ register WINDOW *wp;
+ register int nwindows; /* total number of windows */
+
+ if (f) {
+
+ /* first count the # of windows */
+ wp = wheadp;
+ nwindows = 1;
+ while (wp->w_wndp != NULL) {
+ nwindows++;
+ wp = wp->w_wndp;
+ }
+
+ /* if the argument is negative, it is the nth window
+ from the bottom of the screen */
+ if (n < 0)
+ n = nwindows + n + 1;
+
+ /* if an argument, give them that window from the top */
+ if (n > 0 && n <= nwindows) {
+ wp = wheadp;
+ while (--n)
+ wp = wp->w_wndp;
+ } else {
+ mlwrite("Window number out of range");
+ return(FALSE);
+ }
+ } else
+ if ((wp = curwp->w_wndp) == NULL)
+ wp = wheadp;
+ curwp = wp;
+ curbp = wp->w_bufp;
+ cknewwindow();
+ upmode();
+ return (TRUE);
+}
+
+/*
+ * This command makes the previous window (previous => up the screen) the
+ * current window. There arn't any errors, although the command does not do a
+ * lot if there is 1 window.
+ */
+prevwind(f, n)
+{
+ register WINDOW *wp1;
+ register WINDOW *wp2;
+
+ /* if we have an argument, we mean the nth window from the bottom */
+ if (f)
+ return(nextwind(f, -n));
+
+ wp1 = wheadp;
+ wp2 = curwp;
+
+ if (wp1 == wp2)
+ wp2 = NULL;
+
+ while (wp1->w_wndp != wp2)
+ wp1 = wp1->w_wndp;
+
+ curwp = wp1;
+ curbp = wp1->w_bufp;
+ cknewwindow();
+ upmode();
+ return (TRUE);
+}
+
+/*
+ * This command moves the current window down by "arg" lines. Recompute the
+ * top line in the window. The move up and move down code is almost completely
+ * the same; most of the work has to do with reframing the window, and picking
+ * a new dot. We share the code by having "move down" just be an interface to
+ * "move up". Magic. Bound to "C-X C-N".
+ */
+mvdnwind(f, n)
+
+int n;
+
+{
+ return (mvupwind(f, -n));
+}
+
+/*
+ * Move the current window up by "arg" lines. Recompute the new top line of
+ * the window. Look to see if "." is still on the screen. If it is, you win.
+ * If it isn't, then move "." to center it in the new framing of the window
+ * (this command does not really move "."; it moves the frame). Bound to
+ * "C-X C-P".
+ */
+mvupwind(f, n)
+ int n;
+
+ {
+ register LINE *lp;
+ register int i;
+
+ lp = curwp->w_linep;
+
+ if (n < 0)
+ {
+ while (n++ && lp!=curbp->b_linep)
+ lp = lforw(lp);
+ }
+ else
+ {
+ while (n-- && lback(lp)!=curbp->b_linep)
+ lp = lback(lp);
+ }
+
+ curwp->w_linep = lp;
+ curwp->w_flag |= WFHARD; /* Mode line is OK. */
+
+ for (i = 0; i < curwp->w_ntrows; ++i)
+ {
+ if (lp == curwp->w_dotp)
+ return (TRUE);
+ if (lp == curbp->b_linep)
+ break;
+ lp = lforw(lp);
+ }
+
+ lp = curwp->w_linep;
+ i = curwp->w_ntrows/2;
+
+ while (i-- && lp != curbp->b_linep)
+ lp = lforw(lp);
+
+ curwp->w_dotp = lp;
+ curwp->w_doto = 0;
+ return (TRUE);
+ }
+
+/*
+ * This command makes the current window the only window on the screen. Bound
+ * to "C-X 1". Try to set the framing so that "." does not have to move on the
+ * display. Some care has to be taken to keep the values of dot and mark in
+ * the buffer structures right if the distruction of a window makes a buffer
+ * become undisplayed.
+ */
+onlywind(f, n)
+{
+ register WINDOW *wp;
+ register LINE *lp;
+ register int i;
+
+ while (wheadp != curwp) {
+ wp = wheadp;
+ wheadp = wp->w_wndp;
+ if (--wp->w_bufp->b_nwnd == 0) {
+ wp->w_bufp->b_dotp = wp->w_dotp;
+ wp->w_bufp->b_doto = wp->w_doto;
+ wp->w_bufp->b_markp = wp->w_markp;
+ wp->w_bufp->b_marko = wp->w_marko;
+ }
+ free((char *) wp);
+ }
+ while (curwp->w_wndp != NULL) {
+ wp = curwp->w_wndp;
+ curwp->w_wndp = wp->w_wndp;
+ if (--wp->w_bufp->b_nwnd == 0) {
+ wp->w_bufp->b_dotp = wp->w_dotp;
+ wp->w_bufp->b_doto = wp->w_doto;
+ wp->w_bufp->b_markp = wp->w_markp;
+ wp->w_bufp->b_marko = wp->w_marko;
+ }
+ free((char *) wp);
+ }
+ lp = curwp->w_linep;
+ i = curwp->w_toprow;
+ while (i!=0 && lback(lp)!=curbp->b_linep) {
+ --i;
+ lp = lback(lp);
+ }
+ curwp->w_toprow = 0;
+ curwp->w_ntrows = term.t_nrow-1;
+ curwp->w_linep = lp;
+ curwp->w_flag |= WFMODE|WFHARD;
+ return (TRUE);
+}
+
+/*
+ * Delete the current window, placing its space in the window above,
+ * or, if it is the top window, the window below. Bound to C-X 0.
+ */
+
+delwind(f,n)
+
+int f, n; /* arguments are ignored for this command */
+
+{
+ register WINDOW *wp; /* window to recieve deleted space */
+ register WINDOW *lwp; /* ptr window before curwp */
+ register int target; /* target line to search for */
+
+ /* if there is only one window, don't delete it */
+ if (wheadp->w_wndp == NULL) {
+ mlwrite("Can not delete this window");
+ return(FALSE);
+ }
+
+ /* find window before curwp in linked list */
+ wp = wheadp;
+ lwp = NULL;
+ while (wp != NULL) {
+ if (wp == curwp)
+ break;
+ lwp = wp;
+ wp = wp->w_wndp;
+ }
+
+ /* find recieving window and give up our space */
+ wp = wheadp;
+ if (curwp->w_toprow == 0) {
+ /* find the next window down */
+ target = curwp->w_ntrows + 1;
+ while (wp != NULL) {
+ if (wp->w_toprow == target)
+ break;
+ wp = wp->w_wndp;
+ }
+ if (wp == NULL)
+ return(FALSE);
+ wp->w_toprow = 0;
+ wp->w_ntrows += target;
+ } else {
+ /* find the next window up */
+ target = curwp->w_toprow - 1;
+ while (wp != NULL) {
+ if ((wp->w_toprow + wp->w_ntrows) == target)
+ break;
+ wp = wp->w_wndp;
+ }
+ if (wp == NULL)
+ return(FALSE);
+ wp->w_ntrows += 1 + curwp->w_ntrows;
+ }
+
+ /* get rid of the current window */
+ if (--curwp->w_bufp->b_nwnd == 0) {
+ curwp->w_bufp->b_dotp = curwp->w_dotp;
+ curwp->w_bufp->b_doto = curwp->w_doto;
+ curwp->w_bufp->b_markp = curwp->w_markp;
+ curwp->w_bufp->b_marko = curwp->w_marko;
+ }
+ if (lwp == NULL)
+ wheadp = curwp->w_wndp;
+ else
+ lwp->w_wndp = curwp->w_wndp;
+ free((char *)curwp);
+ curwp = wp;
+ wp->w_flag |= WFHARD;
+ curbp = wp->w_bufp;
+ cknewwindow();
+ upmode();
+ return(TRUE);
+}
+
+/*
+
+Split the current window. A window smaller than 3 lines cannot be
+split. An argument of 1 forces the cursor into the upper window, an
+argument of two forces the cursor to the lower window. The only other
+error that is possible is a "malloc" failure allocating the structure
+for the new window. Bound to "C-X 2".
+
+ */
+splitwind(f, n)
+
+int f, n; /* default flag and numeric argument */
+
+{
+ register WINDOW *wp;
+ register LINE *lp;
+ register int ntru;
+ register int ntrl;
+ register int ntrd;
+ register WINDOW *wp1;
+ register WINDOW *wp2;
+ char *malloc();
+
+ if (curwp->w_ntrows < 3) {
+ mlwrite("Cannot split a %d line window", curwp->w_ntrows);
+ return (FALSE);
+ }
+ if ((wp = (WINDOW *) malloc(sizeof(WINDOW))) == NULL) {
+ mlwrite("(OUT OF MEMORY)");
+ return (FALSE);
+ }
+ ++curbp->b_nwnd; /* Displayed twice. */
+ wp->w_bufp = curbp;
+ wp->w_dotp = curwp->w_dotp;
+ wp->w_doto = curwp->w_doto;
+ wp->w_markp = curwp->w_markp;
+ wp->w_marko = curwp->w_marko;
+ wp->w_flag = 0;
+ wp->w_force = 0;
+#if COLOR
+ /* set the colors of the new window */
+ wp->w_fcolor = gfcolor;
+ wp->w_bcolor = gbcolor;
+#endif
+ ntru = (curwp->w_ntrows-1) / 2; /* Upper size */
+ ntrl = (curwp->w_ntrows-1) - ntru; /* Lower size */
+ lp = curwp->w_linep;
+ ntrd = 0;
+ while (lp != curwp->w_dotp) {
+ ++ntrd;
+ lp = lforw(lp);
+ }
+ lp = curwp->w_linep;
+ if (((f == FALSE) && (ntrd <= ntru)) || ((f == TRUE) && (n == 1))) {
+ /* Old is upper window. */
+ if (ntrd == ntru) /* Hit mode line. */
+ lp = lforw(lp);
+ curwp->w_ntrows = ntru;
+ wp->w_wndp = curwp->w_wndp;
+ curwp->w_wndp = wp;
+ wp->w_toprow = curwp->w_toprow+ntru+1;
+ wp->w_ntrows = ntrl;
+ } else { /* Old is lower window */
+ wp1 = NULL;
+ wp2 = wheadp;
+ while (wp2 != curwp) {
+ wp1 = wp2;
+ wp2 = wp2->w_wndp;
+ }
+ if (wp1 == NULL)
+ wheadp = wp;
+ else
+ wp1->w_wndp = wp;
+ wp->w_wndp = curwp;
+ wp->w_toprow = curwp->w_toprow;
+ wp->w_ntrows = ntru;
+ ++ntru; /* Mode line. */
+ curwp->w_toprow += ntru;
+ curwp->w_ntrows = ntrl;
+ while (ntru--)
+ lp = lforw(lp);
+ }
+ curwp->w_linep = lp; /* Adjust the top lines */
+ wp->w_linep = lp; /* if necessary. */
+ curwp->w_flag |= WFMODE|WFHARD;
+ wp->w_flag |= WFMODE|WFHARD;
+ return (TRUE);
+}
+
+/*
+ * Enlarge the current window. Find the window that loses space. Make sure it
+ * is big enough. If so, hack the window descriptions, and ask redisplay to do
+ * all the hard work. You don't just set "force reframe" because dot would
+ * move. Bound to "C-X Z".
+ */
+enlargewind(f, n)
+{
+ register WINDOW *adjwp;
+ register LINE *lp;
+ register int i;
+
+ if (n < 0)
+ return (shrinkwind(f, -n));
+ if (wheadp->w_wndp == NULL) {
+ mlwrite("Only one window");
+ return (FALSE);
+ }
+ if ((adjwp=curwp->w_wndp) == NULL) {
+ adjwp = wheadp;
+ while (adjwp->w_wndp != curwp)
+ adjwp = adjwp->w_wndp;
+ }
+ if (adjwp->w_ntrows <= n) {
+ mlwrite("Impossible change");
+ return (FALSE);
+ }
+ if (curwp->w_wndp == adjwp) { /* Shrink below. */
+ lp = adjwp->w_linep;
+ for (i=0; i<n && lp!=adjwp->w_bufp->b_linep; ++i)
+ lp = lforw(lp);
+ adjwp->w_linep = lp;
+ adjwp->w_toprow += n;
+ } else { /* Shrink above. */
+ lp = curwp->w_linep;
+ for (i=0; i<n && lback(lp)!=curbp->b_linep; ++i)
+ lp = lback(lp);
+ curwp->w_linep = lp;
+ curwp->w_toprow -= n;
+ }
+ curwp->w_ntrows += n;
+ adjwp->w_ntrows -= n;
+#if SCROLLCODE
+ curwp->w_flag |= WFMODE|WFHARD|WFINS;
+ adjwp->w_flag |= WFMODE|WFHARD|WFKILLS;
+#else
+ curwp->w_flag |= WFMODE|WFHARD;
+ adjwp->w_flag |= WFMODE|WFHARD;
+#endif
+ return (TRUE);
+}
+
+/*
+ * Shrink the current window. Find the window that gains space. Hack at the
+ * window descriptions. Ask the redisplay to do all the hard work. Bound to
+ * "C-X C-Z".
+ */
+shrinkwind(f, n)
+{
+ register WINDOW *adjwp;
+ register LINE *lp;
+ register int i;
+
+ if (n < 0)
+ return (enlargewind(f, -n));
+ if (wheadp->w_wndp == NULL) {
+ mlwrite("Only one window");
+ return (FALSE);
+ }
+ if ((adjwp=curwp->w_wndp) == NULL) {
+ adjwp = wheadp;
+ while (adjwp->w_wndp != curwp)
+ adjwp = adjwp->w_wndp;
+ }
+ if (curwp->w_ntrows <= n) {
+ mlwrite("Impossible change");
+ return (FALSE);
+ }
+ if (curwp->w_wndp == adjwp) { /* Grow below. */
+ lp = adjwp->w_linep;
+ for (i=0; i<n && lback(lp)!=adjwp->w_bufp->b_linep; ++i)
+ lp = lback(lp);
+ adjwp->w_linep = lp;
+ adjwp->w_toprow -= n;
+ } else { /* Grow above. */
+ lp = curwp->w_linep;
+ for (i=0; i<n && lp!=curbp->b_linep; ++i)
+ lp = lforw(lp);
+ curwp->w_linep = lp;
+ curwp->w_toprow += n;
+ }
+ curwp->w_ntrows -= n;
+ adjwp->w_ntrows += n;
+#if SCROLLCODE
+ curwp->w_flag |= WFMODE|WFHARD|WFKILLS;
+ adjwp->w_flag |= WFMODE|WFHARD|WFINS;
+#else
+ curwp->w_flag |= WFMODE|WFHARD;
+ adjwp->w_flag |= WFMODE|WFHARD;
+#endif
+ return (TRUE);
+}
+
+/* Resize the current window to the requested size */
+
+resize(f, n)
+
+int f, n; /* default flag and numeric argument */
+
+{
+ int clines; /* current # of lines in window */
+
+ /* must have a non-default argument, else ignore call */
+ if (f == FALSE)
+ return(TRUE);
+
+ /* find out what to do */
+ clines = curwp->w_ntrows;
+
+ /* already the right size? */
+ if (clines == n)
+ return(TRUE);
+
+ return(enlargewind(TRUE, n - clines));
+}
+
+/*
+ * Pick a window for a pop-up. Split the screen if there is only one window.
+ * Pick the uppermost window that isn't the current window. An LRU algorithm
+ * might be better. Return a pointer, or NULL on error.
+ */
+WINDOW *
+wpopup()
+{
+ register WINDOW *wp;
+
+ if (wheadp->w_wndp == NULL /* Only 1 window */
+ && splitwind(FALSE, 0) == FALSE) /* and it won't split */
+ return (NULL);
+ wp = wheadp; /* Find window to use */
+ while (wp!=NULL && wp==curwp)
+ wp = wp->w_wndp;
+ return (wp);
+}
+
+scrnextup(f, n) /* scroll the next window up (back) a page */
+
+{
+ nextwind(FALSE, 1);
+ backpage(f, n);
+ prevwind(FALSE, 1);
+}
+
+scrnextdw(f, n) /* scroll the next window down (forward) a page */
+
+{
+ nextwind(FALSE, 1);
+ forwpage(f, n);
+ prevwind(FALSE, 1);
+}
+
+savewnd(f, n) /* save ptr to current window */
+
+{
+ swindow = curwp;
+ return(TRUE);
+}
+
+restwnd(f, n) /* restore the saved screen */
+
+{
+ register WINDOW *wp;
+
+ /* find the window */
+ wp = wheadp;
+ while (wp != NULL) {
+ if (wp == swindow) {
+ curwp = wp;
+ curbp = wp->w_bufp;
+ upmode();
+ return (TRUE);
+ }
+ wp = wp->w_wndp;
+ }
+
+ mlwrite("(No such window exists)");
+ return(FALSE);
+}
+
+newsize(f, n) /* resize the screen, re-writing the screen */
+
+int f; /* default flag */
+int n; /* numeric argument */
+
+{
+ WINDOW *wp; /* current window being examined */
+ WINDOW *nextwp; /* next window to scan */
+ WINDOW *lastwp; /* last window scanned */
+ int lastline; /* screen line of last line of current window */
+
+ /* if the command defaults, assume the largest */
+ if (f == FALSE)
+ n = term.t_mrow + 1;
+
+ /* make sure it's in range */
+ if (n < 3 || n > term.t_mrow + 1) {
+ mlwrite("%%Screen size out of range");
+ return(FALSE);
+ }
+
+ if (term.t_nrow == n - 1)
+ return(TRUE);
+ else if (term.t_nrow < n - 1) {
+
+ /* go to the last window */
+ wp = wheadp;
+ while (wp->w_wndp != NULL)
+ wp = wp->w_wndp;
+
+ /* and enlarge it as needed */
+ wp->w_ntrows = n - wp->w_toprow - 2;
+ wp->w_flag |= WFHARD|WFMODE;
+
+ } else {
+
+ /* rebuild the window structure */
+ nextwp = wheadp;
+ wp = NULL;
+ lastwp = NULL;
+ while (nextwp != NULL) {
+ wp = nextwp;
+ nextwp = wp->w_wndp;
+
+ /* get rid of it if it is too low */
+ if (wp->w_toprow > n - 2) {
+
+ /* save the point/mark if needed */
+ if (--wp->w_bufp->b_nwnd == 0) {
+ wp->w_bufp->b_dotp = wp->w_dotp;
+ wp->w_bufp->b_doto = wp->w_doto;
+ wp->w_bufp->b_markp = wp->w_markp;
+ wp->w_bufp->b_marko = wp->w_marko;
+ }
+
+ /* update curwp and lastwp if needed */
+ if (wp == curwp)
+ curwp = wheadp;
+ curbp = curwp->w_bufp;
+ if (lastwp != NULL)
+ lastwp->w_wndp = NULL;
+
+ /* free the structure */
+ free((char *)wp);
+ wp = NULL;
+
+ } else {
+ /* need to change this window size? */
+ lastline = wp->w_toprow + wp->w_ntrows - 1;
+ if (lastline >= n - 2) {
+ wp->w_ntrows = n - wp->w_toprow - 2;
+ wp->w_flag |= WFHARD|WFMODE;
+ }
+ }
+
+ lastwp = wp;
+ }
+ }
+
+ /* screen is garbage */
+ term.t_nrow = n - 1;
+ sgarbf = TRUE;
+ return(TRUE);
+}
+
+newwidth(f, n) /* resize the screen, re-writing the screen */
+
+int f; /* default flag */
+int n; /* numeric argument */
+
+{
+ register WINDOW *wp;
+
+ /* if the command defaults, assume the largest */
+ if (f == FALSE)
+ n = term.t_mcol;
+
+ /* make sure it's in range */
+ if (n < 10 || n > term.t_mcol) {
+ mlwrite("%%Screen width out of range");
+ return(FALSE);
+ }
+
+ /* otherwise, just re-width it (no big deal) */
+ term.t_ncol = n;
+ term.t_margin = n / 10;
+ term.t_scrsiz = n - (term.t_margin * 2);
+
+ /* florce all windows to redraw */
+ wp = wheadp;
+ while (wp) {
+ wp->w_flag |= WFHARD | WFMOVE | WFMODE;
+ wp = wp->w_wndp;
+ }
+ sgarbf = TRUE;
+
+ return(TRUE);
+}
+
+int getwpos() /* get screen offset of current line in current window */
+
+{
+ register int sline; /* screen line from top of window */
+ register LINE *lp; /* scannile line pointer */
+
+ /* search down the line we want */
+ lp = curwp->w_linep;
+ sline = 1;
+ while (lp != curwp->w_dotp) {
+ ++sline;
+ lp = lforw(lp);
+ }
+
+ /* and return the value */
+ return(sline);
+}
+
+cknewwindow()
+{
+ execute(META|SPEC|'X', FALSE, 1);
+}
+
diff --git a/word.c b/word.c
new file mode 100644
index 0000000..e87f6cf
--- /dev/null
+++ b/word.c
@@ -0,0 +1,717 @@
+/* WORD.C
+ *
+ * The routines in this file implement commands that work word or a
+ * paragraph at a time. There are all sorts of word mode commands. If I
+ * do any sentence mode commands, they are likely to be put in this file.
+ *
+ * modified by Petri Kutvonen
+ */
+
+#include <stdio.h>
+#include "estruct.h"
+#include "edef.h"
+
+/* Word wrap on n-spaces. Back-over whatever precedes the point on the current
+ * line and stop on the first word-break or the beginning of the line. If we
+ * reach the beginning of the line, jump back to the end of the word and start
+ * a new line. Otherwise, break the line at the word-break, eat it, and jump
+ * back to the end of the word.
+ * Returns TRUE on success, FALSE on errors.
+ */
+wrapword(f, n)
+
+int f; /* default flag */
+int n; /* numeric argument */
+
+{
+ register int cnt; /* size of word wrapped to next line */
+ register int c; /* charector temporary */
+
+ /* backup from the <NL> 1 char */
+ if (!backchar(0, 1))
+ return(FALSE);
+
+ /* back up until we aren't in a word,
+ make sure there is a break in the line */
+ cnt = 0;
+ while (((c = lgetc(curwp->w_dotp, curwp->w_doto)) != ' ')
+ && (c != '\t')) {
+ cnt++;
+ if (!backchar(0, 1))
+ return(FALSE);
+ /* if we make it to the beginning, start a new line */
+ if (curwp->w_doto == 0) {
+ gotoeol(FALSE, 0);
+ return(lnewline());
+ }
+ }
+
+ /* delete the forward white space */
+ if (!forwdel(0, 1))
+ return(FALSE);
+
+ /* put in a end of line */
+ if (!lnewline())
+ return(FALSE);
+
+ /* and past the first word */
+ while (cnt-- > 0) {
+ if (forwchar(FALSE, 1) == FALSE)
+ return(FALSE);
+ }
+ return(TRUE);
+}
+
+/*
+ * Move the cursor backward by "n" words. All of the details of motion are
+ * performed by the "backchar" and "forwchar" routines. Error if you try to
+ * move beyond the buffers.
+ */
+backword(f, n)
+{
+ if (n < 0)
+ return (forwword(f, -n));
+ if (backchar(FALSE, 1) == FALSE)
+ return (FALSE);
+ while (n--) {
+ while (inword() == FALSE) {
+ if (backchar(FALSE, 1) == FALSE)
+ return (FALSE);
+ }
+ while (inword() != FALSE) {
+ if (backchar(FALSE, 1) == FALSE)
+ return (FALSE);
+ }
+ }
+ return (forwchar(FALSE, 1));
+}
+
+/*
+ * Move the cursor forward by the specified number of words. All of the motion
+ * is done by "forwchar". Error if you try and move beyond the buffer's end.
+ */
+forwword(f, n)
+{
+ if (n < 0)
+ return (backword(f, -n));
+ while (n--) {
+ while (inword() == TRUE) {
+ if (forwchar(FALSE, 1) == FALSE)
+ return (FALSE);
+ }
+
+ while (inword() == FALSE) {
+ if (forwchar(FALSE, 1) == FALSE)
+ return (FALSE);
+ }
+ }
+ return(TRUE);
+}
+
+/*
+ * Move the cursor forward by the specified number of words. As you move,
+ * convert any characters to upper case. Error if you try and move beyond the
+ * end of the buffer. Bound to "M-U".
+ */
+upperword(f, n)
+{
+ register int c;
+
+ if (curbp->b_mode&MDVIEW) /* don't allow this command if */
+ return(rdonly()); /* we are in read only mode */
+ if (n < 0)
+ return (FALSE);
+ while (n--) {
+ while (inword() == FALSE) {
+ if (forwchar(FALSE, 1) == FALSE)
+ return (FALSE);
+ }
+ while (inword() != FALSE) {
+ c = lgetc(curwp->w_dotp, curwp->w_doto);
+#if PKCODE
+ if (islower(c)) {
+#else
+ if (c>='a' && c<='z') {
+#endif
+ c -= 'a'-'A';
+ lputc(curwp->w_dotp, curwp->w_doto, c);
+ lchange(WFHARD);
+ }
+ if (forwchar(FALSE, 1) == FALSE)
+ return (FALSE);
+ }
+ }
+ return (TRUE);
+}
+
+/*
+ * Move the cursor forward by the specified number of words. As you move
+ * convert characters to lower case. Error if you try and move over the end of
+ * the buffer. Bound to "M-L".
+ */
+lowerword(f, n)
+{
+ register int c;
+
+ if (curbp->b_mode&MDVIEW) /* don't allow this command if */
+ return(rdonly()); /* we are in read only mode */
+ if (n < 0)
+ return (FALSE);
+ while (n--) {
+ while (inword() == FALSE) {
+ if (forwchar(FALSE, 1) == FALSE)
+ return (FALSE);
+ }
+ while (inword() != FALSE) {
+ c = lgetc(curwp->w_dotp, curwp->w_doto);
+#if PKCODE
+ if (isupper(c)) {
+#else
+ if (c>='A' && c<='Z') {
+#endif
+ c += 'a'-'A';
+ lputc(curwp->w_dotp, curwp->w_doto, c);
+ lchange(WFHARD);
+ }
+ if (forwchar(FALSE, 1) == FALSE)
+ return (FALSE);
+ }
+ }
+ return (TRUE);
+}
+
+/*
+ * Move the cursor forward by the specified number of words. As you move
+ * convert the first character of the word to upper case, and subsequent
+ * characters to lower case. Error if you try and move past the end of the
+ * buffer. Bound to "M-C".
+ */
+capword(f, n)
+{
+ register int c;
+
+ if (curbp->b_mode&MDVIEW) /* don't allow this command if */
+ return(rdonly()); /* we are in read only mode */
+ if (n < 0)
+ return (FALSE);
+ while (n--) {
+ while (inword() == FALSE) {
+ if (forwchar(FALSE, 1) == FALSE)
+ return (FALSE);
+ }
+ if (inword() != FALSE) {
+ c = lgetc(curwp->w_dotp, curwp->w_doto);
+#if PKCODE
+ if (islower(c)) {
+#else
+ if (c>='a' && c<='z') {
+#endif
+ c -= 'a'-'A';
+ lputc(curwp->w_dotp, curwp->w_doto, c);
+ lchange(WFHARD);
+ }
+ if (forwchar(FALSE, 1) == FALSE)
+ return (FALSE);
+ while (inword() != FALSE) {
+ c = lgetc(curwp->w_dotp, curwp->w_doto);
+#if PKCODE
+ if (isupper(c)) {
+#else
+ if (c>='A' && c<='Z') {
+#endif
+ c += 'a'-'A';
+ lputc(curwp->w_dotp, curwp->w_doto, c);
+ lchange(WFHARD);
+ }
+ if (forwchar(FALSE, 1) == FALSE)
+ return (FALSE);
+ }
+ }
+ }
+ return (TRUE);
+}
+
+/*
+ * Kill forward by "n" words. Remember the location of dot. Move forward by
+ * the right number of words. Put dot back where it was and issue the kill
+ * command for the right number of characters. With a zero argument, just
+ * kill one word and no whitespace. Bound to "M-D".
+ */
+delfword(f, n)
+{
+ register LINE *dotp; /* original cursor line */
+ register int doto; /* and row */
+ register int c; /* temp char */
+ long size; /* # of chars to delete */
+
+ /* don't allow this command if we are in read only mode */
+ if (curbp->b_mode&MDVIEW)
+ return(rdonly());
+
+ /* ignore the command if there is a negative argument */
+ if (n < 0)
+ return (FALSE);
+
+ /* Clear the kill buffer if last command wasn't a kill */
+ if ((lastflag&CFKILL) == 0)
+ kdelete();
+ thisflag |= CFKILL; /* this command is a kill */
+
+ /* save the current cursor position */
+ dotp = curwp->w_dotp;
+ doto = curwp->w_doto;
+
+ /* figure out how many characters to give the axe */
+ size = 0;
+
+ /* get us into a word.... */
+ while (inword() == FALSE) {
+ if (forwchar(FALSE, 1) == FALSE)
+ return(FALSE);
+ ++size;
+ }
+
+ if (n == 0) {
+ /* skip one word, no whitespace! */
+ while (inword() == TRUE) {
+ if (forwchar(FALSE, 1) == FALSE)
+ return(FALSE);
+ ++size;
+ }
+ } else {
+ /* skip n words.... */
+ while (n--) {
+
+ /* if we are at EOL; skip to the beginning of the next */
+ while (curwp->w_doto == llength(curwp->w_dotp)) {
+ if (forwchar(FALSE, 1) == FALSE)
+ return(FALSE);
+ ++size;
+ }
+
+ /* move forward till we are at the end of the word */
+ while (inword() == TRUE) {
+ if (forwchar(FALSE, 1) == FALSE)
+ return(FALSE);
+ ++size;
+ }
+
+ /* if there are more words, skip the interword stuff */
+ if (n != 0)
+ while (inword() == FALSE) {
+ if (forwchar(FALSE, 1) == FALSE)
+ return(FALSE);
+ ++size;
+ }
+ }
+
+ /* skip whitespace and newlines */
+ while ((curwp->w_doto == llength(curwp->w_dotp)) ||
+ ((c = lgetc(curwp->w_dotp, curwp->w_doto)) == ' ') ||
+ (c == '\t')) {
+ if (forwchar(FALSE, 1) == FALSE)
+ break;
+ ++size;
+ }
+ }
+
+ /* restore the original position and delete the words */
+ curwp->w_dotp = dotp;
+ curwp->w_doto = doto;
+ return (ldelete(size, TRUE));
+}
+
+/*
+ * Kill backwards by "n" words. Move backwards by the desired number of words,
+ * counting the characters. When dot is finally moved to its resting place,
+ * fire off the kill command. Bound to "M-Rubout" and to "M-Backspace".
+ */
+delbword(f, n)
+{
+ long size;
+
+ /* don't allow this command if we are in read only mode */
+ if (curbp->b_mode&MDVIEW)
+ return(rdonly());
+
+ /* ignore the command if there is a nonpositive argument */
+ if (n <= 0)
+ return (FALSE);
+
+ /* Clear the kill buffer if last command wasn't a kill */
+ if ((lastflag&CFKILL) == 0)
+ kdelete();
+ thisflag |= CFKILL; /* this command is a kill */
+
+ if (backchar(FALSE, 1) == FALSE)
+ return (FALSE);
+ size = 0;
+ while (n--) {
+ while (inword() == FALSE) {
+ if (backchar(FALSE, 1) == FALSE)
+ return (FALSE);
+ ++size;
+ }
+ while (inword() != FALSE) {
+ ++size;
+ if (backchar(FALSE, 1) == FALSE)
+ goto bckdel;
+ }
+ }
+ if (forwchar(FALSE, 1) == FALSE)
+ return (FALSE);
+bckdel: return (ldelete(size, TRUE));
+}
+
+/*
+ * 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()
+{
+ register int c;
+
+ if (curwp->w_doto == llength(curwp->w_dotp))
+ return (FALSE);
+ c = lgetc(curwp->w_dotp, curwp->w_doto);
+#if PKCODE
+ if (isletter(c))
+#else
+ if (c>='a' && c<='z')
+ return (TRUE);
+ if (c>='A' && c<='Z')
+#endif
+ return (TRUE);
+ if (c>='0' && c<='9')
+ return (TRUE);
+ return (FALSE);
+}
+
+#if WORDPRO
+fillpara(f, n) /* Fill the current paragraph according to the current
+ fill column */
+
+int f, n; /* deFault flag and Numeric argument */
+
+{
+ register int c; /* current char durring scan */
+ register int wordlen; /* length of current word */
+ register int clength; /* position on line during fill */
+ register int i; /* index during word copy */
+ register int newlength; /* tentative new line length */
+ register int eopflag; /* Are we at the End-Of-Paragraph? */
+ register int firstflag; /* first word? (needs no space) */
+ register LINE *eopline; /* pointer to line just past EOP */
+ register int dotflag; /* was the last char a period? */
+ char wbuf[NSTRING]; /* buffer for current word */
+
+ if (curbp->b_mode&MDVIEW) /* don't allow this command if */
+ return(rdonly()); /* we are in read only mode */
+ if (fillcol == 0) { /* no fill column set */
+ mlwrite("No fill column set");
+ return(FALSE);
+ }
+#if PKCODE
+ justflag = FALSE;
+#endif
+
+ /* record the pointer to the line just past the EOP */
+ gotoeop(FALSE, 1);
+ eopline = lforw(curwp->w_dotp);
+
+ /* and back top the beginning of the paragraph */
+ gotobop(FALSE, 1);
+
+ /* initialize various info */
+ clength = curwp->w_doto;
+ if (clength && curwp->w_dotp->l_text[0] == TAB)
+ clength = 8;
+ wordlen = 0;
+ dotflag = FALSE;
+
+ /* scan through lines, filling words */
+ firstflag = TRUE;
+ eopflag = FALSE;
+ while (!eopflag) {
+ /* get the next character in the paragraph */
+ if (curwp->w_doto == llength(curwp->w_dotp)) {
+ c = ' ';
+ if (lforw(curwp->w_dotp) == eopline)
+ eopflag = TRUE;
+ } else
+ c = lgetc(curwp->w_dotp, curwp->w_doto);
+
+ /* and then delete it */
+ ldelete(1L, FALSE);
+
+ /* if not a separator, just add it in */
+ if (c != ' ' && c != '\t') {
+ dotflag = (c == '.'); /* was it a dot */
+ if (wordlen < NSTRING - 1)
+ wbuf[wordlen++] = c;
+ } else if (wordlen) {
+ /* at a word break with a word waiting */
+ /* calculate tentitive new length with word added */
+ newlength = clength + 1 + wordlen;
+ if (newlength <= fillcol) {
+ /* add word to current line */
+ if (!firstflag) {
+ linsert(1, ' '); /* the space */
+ ++clength;
+ }
+ firstflag = FALSE;
+ } else {
+ /* start a new line */
+ lnewline();
+ clength = 0;
+ }
+
+ /* and add the word in in either case */
+ for (i=0; i<wordlen; i++) {
+ linsert(1, wbuf[i]);
+ ++clength;
+ }
+ if (dotflag) {
+ linsert(1, ' ');
+ ++clength;
+ }
+ wordlen = 0;
+ }
+ }
+ /* and add a last newline for the end of our new paragraph */
+ lnewline();
+ return(TRUE);
+}
+
+#if PKCODE
+justpara(f, n) /* Fill the current paragraph according to the current
+ fill column and cursor position */
+
+int f, n; /* deFault flag and Numeric argument */
+
+{
+ register int c; /* current char durring scan */
+ register int wordlen; /* length of current word */
+ register int clength; /* position on line during fill */
+ register int i; /* index during word copy */
+ register int newlength; /* tentative new line length */
+ register int eopflag; /* Are we at the End-Of-Paragraph? */
+ register int firstflag; /* first word? (needs no space) */
+ register LINE *eopline; /* pointer to line just past EOP */
+ char wbuf[NSTRING]; /* buffer for current word */
+ int leftmarg; /* left marginal */
+
+ if (curbp->b_mode&MDVIEW) /* don't allow this command if */
+ return(rdonly()); /* we are in read only mode */
+ if (fillcol == 0) { /* no fill column set */
+ mlwrite("No fill column set");
+ return(FALSE);
+ }
+ justflag = TRUE;
+ leftmarg = curwp->w_doto;
+ if (leftmarg+10 > fillcol) {
+ leftmarg = 0;
+ mlwrite("Column too narrow");
+ return(FALSE);
+ }
+
+ /* record the pointer to the line just past the EOP */
+ gotoeop(FALSE, 1);
+ eopline = lforw(curwp->w_dotp);
+
+ /* and back top the beginning of the paragraph */
+ gotobop(FALSE, 1);
+
+ /* initialize various info */
+ if (leftmarg < llength(curwp->w_dotp))
+ curwp->w_doto = leftmarg;
+
+ clength = curwp->w_doto;
+ if (clength && curwp->w_dotp->l_text[0] == TAB)
+ clength = 8;
+
+ wordlen = 0;
+
+ /* scan through lines, filling words */
+ firstflag = TRUE;
+ eopflag = FALSE;
+ while (!eopflag) {
+ /* get the next character in the paragraph */
+ if (curwp->w_doto == llength(curwp->w_dotp)) {
+ c = ' ';
+ if (lforw(curwp->w_dotp) == eopline)
+ eopflag = TRUE;
+ } else
+ c = lgetc(curwp->w_dotp, curwp->w_doto);
+
+ /* and then delete it */
+ ldelete(1L, FALSE);
+
+ /* if not a separator, just add it in */
+ if (c != ' ' && c != '\t') {
+ if (wordlen < NSTRING - 1)
+ wbuf[wordlen++] = c;
+ } else if (wordlen) {
+ /* at a word break with a word waiting */
+ /* calculate tentitive new length with word added */
+ newlength = clength + 1 + wordlen;
+ if (newlength <= fillcol) {
+ /* add word to current line */
+ if (!firstflag) {
+ linsert(1, ' '); /* the space */
+ ++clength;
+ }
+ firstflag = FALSE;
+ } else {
+ /* start a new line */
+ lnewline();
+ for (i=0; i<leftmarg; i++)
+ linsert(1, ' ');
+ clength = leftmarg;
+ }
+
+ /* and add the word in in either case */
+ for (i=0; i<wordlen; i++) {
+ linsert(1, wbuf[i]);
+ ++clength;
+ }
+ wordlen = 0;
+ }
+ }
+ /* and add a last newline for the end of our new paragraph */
+ lnewline();
+
+ forwword(FALSE, 1);
+ if (llength(curwp->w_dotp) > leftmarg)
+ curwp->w_doto = leftmarg;
+ else
+ curwp->w_doto = llength(curwp->w_dotp);
+
+ justflag = FALSE;
+ return(TRUE);
+}
+#endif
+
+killpara(f, n) /* delete n paragraphs starting with the current one */
+
+int f; /* default flag */
+int n; /* # of paras to delete */
+
+{
+ register int status; /* returned status of functions */
+
+ while (n--) { /* for each paragraph to delete */
+
+ /* mark out the end and beginning of the para to delete */
+ gotoeop(FALSE, 1);
+
+ /* set the mark here */
+ curwp->w_markp = curwp->w_dotp;
+ curwp->w_marko = curwp->w_doto;
+
+ /* go to the beginning of the paragraph */
+ gotobop(FALSE, 1);
+ curwp->w_doto = 0; /* force us to the beginning of line */
+
+ /* and delete it */
+ if ((status = killregion(FALSE, 1)) != TRUE)
+ return(status);
+
+ /* and clean up the 2 extra lines */
+ ldelete(2L, TRUE);
+ }
+ return(TRUE);
+}
+
+
+/* wordcount: count the # of words in the marked region,
+ along with average word sizes, # of chars, etc,
+ and report on them. */
+
+wordcount(f, n)
+
+int f, n; /* ignored numeric arguments */
+
+{
+ register LINE *lp; /* current line to scan */
+ register int offset; /* current char to scan */
+ long size; /* size of region left to count */
+ register int ch; /* current character to scan */
+ register int wordflag; /* are we in a word now? */
+ register int lastword; /* were we just in a word? */
+ long nwords; /* total # of words */
+ long nchars; /* total number of chars */
+ int nlines; /* total number of lines in region */
+ int avgch; /* average number of chars/word */
+ int status; /* status return code */
+ REGION region; /* region to look at */
+
+#if PKCODE
+ struct {
+ long pk_1;
+ long pk_2;
+ int pk_3;
+ int pk_4;
+ } pk_mlrec;
+#endif
+
+ /* make sure we have a region to count */
+ if ((status = getregion(&region)) != TRUE)
+ return(status);
+ lp = region.r_linep;
+ offset = region.r_offset;
+ size = region.r_size;
+
+ /* count up things */
+ lastword = FALSE;
+ nchars = 0L;
+ nwords = 0L;
+ nlines = 0;
+ while (size--) {
+
+ /* get the current character */
+ if (offset == llength(lp)) { /* end of line */
+ ch = '\n';
+ lp = lforw(lp);
+ offset = 0;
+ ++nlines;
+ } else {
+ ch = lgetc(lp, offset);
+ ++offset;
+ }
+
+ /* and tabulate it */
+ wordflag = (
+#if PKCODE
+ (isletter(ch)) ||
+#else
+ (ch >= 'a' && ch <= 'z') ||
+ (ch >= 'A' && ch <= 'Z') ||
+#endif
+ (ch >= '0' && ch <= '9'));
+ if (wordflag == TRUE && lastword == FALSE)
+ ++nwords;
+ lastword = wordflag;
+ ++nchars;
+ }
+
+ /* and report on the info */
+ if (nwords > 0L)
+ avgch = (int)((100L * nchars) / nwords);
+ else
+ avgch = 0;
+
+#if PKCODE
+ pk_mlrec.pk_1 = nwords;
+ pk_mlrec.pk_2 = nchars;
+ pk_mlrec.pk_3 = nlines + 1;
+ pk_mlrec.pk_4 = avgch;
+ mlwrite("%*Words %D Chars %D Lines %d Avg chars/word %f",
+ &pk_mlrec);
+#else
+ mlwrite("Words %D Chars %D Lines %d Avg chars/word %f",
+ nwords, nchars, nlines + 1, avgch);
+#endif
+ return(TRUE);
+}
+#endif