diff options
author | Linus Torvalds <torvalds@g5.osdl.org> | 2005-05-31 08:50:56 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-05-31 08:50:56 -0700 |
commit | d7148b21fe4fff228acf5b7006cf9323bd750df7 (patch) | |
tree | e49f3fc3013767b4209489e0ced5c3e48618d91d | |
download | uemacs-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.c | 264 | ||||
-rw-r--r-- | basic.c | 462 | ||||
-rw-r--r-- | bind.c | 708 | ||||
-rw-r--r-- | buffer.c | 544 | ||||
-rw-r--r-- | crypt.c | 221 | ||||
-rw-r--r-- | display.c | 1570 | ||||
-rw-r--r-- | dosmake.bat | 2 | ||||
-rw-r--r-- | ebind.h | 249 | ||||
-rw-r--r-- | edef.h | 323 | ||||
-rw-r--r-- | efunc.h | 431 | ||||
-rw-r--r-- | emacs.hlp | 172 | ||||
-rw-r--r-- | emacs.lnk | 29 | ||||
-rw-r--r-- | emacs.prj | 27 | ||||
-rw-r--r-- | emacs.ps | 3667 | ||||
-rw-r--r-- | emacs.rc | 285 | ||||
-rw-r--r-- | emacs.wri | bin | 0 -> 88320 bytes | |||
-rw-r--r-- | epath.h | 53 | ||||
-rw-r--r-- | estruct.h | 731 | ||||
-rw-r--r-- | eval.c | 879 | ||||
-rw-r--r-- | evar.h | 212 | ||||
-rw-r--r-- | exec.c | 1148 | ||||
-rw-r--r-- | file.c | 635 | ||||
-rw-r--r-- | fileio.c | 228 | ||||
-rw-r--r-- | ibmpc.c | 517 | ||||
-rw-r--r-- | input.c | 713 | ||||
-rw-r--r-- | isearch.c | 521 | ||||
-rw-r--r-- | line.c | 655 | ||||
-rw-r--r-- | lock.c | 166 | ||||
-rw-r--r-- | main.c | 895 | ||||
-rw-r--r-- | makefile | 124 | ||||
-rw-r--r-- | makefile.dos | 22 | ||||
-rw-r--r-- | makefile.unx | 121 | ||||
-rw-r--r-- | makefilepatch | 61 | ||||
-rw-r--r-- | pklock.c | 125 | ||||
-rw-r--r-- | posix.c | 159 | ||||
-rw-r--r-- | random.c | 1221 | ||||
-rw-r--r-- | readme | 182 | ||||
-rw-r--r-- | readme.39e | 331 | ||||
-rw-r--r-- | region.c | 212 | ||||
-rw-r--r-- | search.c | 1585 | ||||
-rw-r--r-- | shell.cmd | 57 | ||||
-rw-r--r-- | spawn.c | 628 | ||||
-rw-r--r-- | tcap.c | 386 | ||||
-rw-r--r-- | termio.c | 451 | ||||
-rw-r--r-- | vmslink.com | 29 | ||||
-rw-r--r-- | vmsmake.com | 28 | ||||
-rw-r--r-- | vmsvt.c | 519 | ||||
-rw-r--r-- | vt52.c | 190 | ||||
-rw-r--r-- | window.c | 733 | ||||
-rw-r--r-- | word.c | 717 |
50 files changed, 24188 insertions, 0 deletions
@@ -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 @@ -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); +} @@ -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); +} @@ -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 @@ -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} +}; + + @@ -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 + + @@ -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 +¬, &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 (>k) 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 (¬) 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 ¬ &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 ¬ &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 Binary files differnew file mode 100644 index 0000000..16ffbc9 --- /dev/null +++ b/emacs.wri @@ -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 + @@ -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); +} @@ -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 @@ -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); +} @@ -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); +} @@ -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 + @@ -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 @@ -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); +} @@ -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 @@ -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 @@ -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); +} + @@ -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(®ion)) != TRUE) + return (s); + if ((lastflag&CFKILL) == 0) /* This is a kill type */ + kdelete(); /* command, so do magic */ + thisflag |= CFKILL; /* kill buffer stuff. */ + curwp->w_dotp = region.r_linep; + curwp->w_doto = region.r_offset; + return (ldelete(region.r_size, 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(®ion)) != 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(®ion)) != 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(®ion)) != 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 ¬ &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 @@ -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(®s, ®s); + 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(®s, ®s, &segreg); + if (regs.x.cflag == 0) { + regs.h.ah = 0x4d; /* get child process return code */ + intdos(®s, ®s); /* 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 @@ -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 @@ -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 @@ -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); +} + @@ -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(®ion)) != 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 |