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.
This commit is contained in:
Linus Torvalds 2005-05-31 08:50:56 -07:00
commit d7148b21fe
50 changed files with 24188 additions and 0 deletions

264
ansi.c Normal file
View File

@ -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

462
basic.c Normal file
View File

@ -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);
}

708
bind.c Normal file
View File

@ -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);
}

544
buffer.c Normal file
View File

@ -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);
}

221
crypt.c Normal file
View File

@ -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

1570
display.c Normal file

File diff suppressed because it is too large Load Diff

2
dosmake.bat Normal file
View File

@ -0,0 +1,2 @@
cl -AL -Ot -Gs -c *.c
link @emacs.lnk

249
ebind.h Normal file
View File

@ -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}
};

323
edef.h Normal file
View File

@ -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

431
efunc.h Normal file
View File

@ -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}
};

172
emacs.hlp Normal file
View File

@ -0,0 +1,172 @@
=> uEmacs/PK 4.0 HELP INDEX
.. The very basics
.. Cursor movement
.. File commands
.. Miscellaneous character commands
.. Mode commands
.. Keys and commands
.. Deleting and inserting
.. Formatting
.. Window commands
.. Buffer commands
.. Searching and replacing
.. Accessing the operating system
.. Macro commands
.. Miscellaneous
.. Functions
.. System variables
.. File name completion
-------------------------------------------------------------------------------
=> THE VERY BASICS
Notations: ^X means <Ctrl> and X. The <Meta> key is <Esc> on most systems.
Exiting: ^G aborts almost any operation. ^X ^C will get you out of uEmacs.
A BUFFER is a named area containing a FILE being edited. Many buffers may
be active at once. Many WINDOWS may be active at once on the screen. All
windows may show different parts of the same buffer, or each may display a
different one.
-------------------------------------------------------------------------------
=> CURSOR MOVEMENT
Backward character .... ^B Forward character ..... ^F
Previous word ......... Meta B Next word ............. Meta F
Beginning of line ..... ^A End of line ........... ^E
Previous line ......... ^P Next line ............. ^N
Previous paragraph .... Meta P Next paragraph ........ Meta N
Previous page ......... ^Z Next page ............. ^V
Beginning of file ..... Meta < End of file ........... Meta >
-------------------------------------------------------------------------------
=> FILE COMMANDS
Find file ............. ^X ^F Quick exit ............ Meta Z
View file ............. ^X ^V Exit emacs ............ ^X ^C
Insert file ........... ^X ^I
Change file name ...... ^X N Filter buffer ......... ^X #
Save file ............. ^X ^D
Read file ............. ^X ^R
Write file ............ ^X ^W Execute file .......... not bound
-------------------------------------------------------------------------------
=> MISCELLANEOUS CHARACTER COMMANDS
Newline ............... ^M Transpose characters .. ^T
Newline and indent .... ^J Trim line ............. ^X ^T
Open line ............. ^O
Handle tab ............ ^I Quote character ....... ^X Q
Insert space .......... ^C
Goto line ............. Meta G Abort command ......... ^G
Goto matching fence ... Meta ^F
-------------------------------------------------------------------------------
=> MODE COMMANDS
Add mode .............. ^X M Add global mode ....... Meta M
Delete mode ........... ^X ^M Delete global mode .... Meta ^M
OVER :: Overwrite, don't insert MAGIC :: Match patterns in search
WRAP :: Automatic carriage return ^ $ Beginning and end of line
VIEW :: View only, don't change . Any character \c Character c
CMODE :: C program indenting c* Any number of character c
EXACT :: Match case in search [ ] Character class
-------------------------------------------------------------------------------
=> KEYS AND COMMANDS
Bind to key ........... Meta K Help .................. Meta ?
Unbind key ............ Meta ^K Apropos ............... Meta A
Describe key .......... ^X ? Abort command ......... ^G
Describe bindings ..... not bound
Meta prefix ........... Esc :: Although meta-prefix can be bound to
Cntlx prefix .......... ^X :: some other key, no other command can
Execute named command . Meta X :: be bound to Esc.
-------------------------------------------------------------------------------
=> DELETING AND INSERTING
Delete previous character ^H Delete next character . ^D
Delete previous word .. Meta ^H Delete next word ...... Meta D
Kill to end of line ... ^K Set mark .............. Meta Space
Kill region ........... ^W Yank .................. ^Y
Kill paragraph ........ Meta ^W Exchange point and mark ^X ^X
Delete blank lines .... ^X ^O :: A region is defined as the area between
Copy region ........... Meta W :: the mark and the current position.
-------------------------------------------------------------------------------
=> FORMATTING
Case word upper ....... Meta U Case word lower ....... Meta L
Case region upper ..... ^X ^U Case region lower ..... ^X ^L
Case word capitalize .. Meta C Trim line ............. ^X ^T
Detab line ............ ^X ^A
Set fill column ....... ^X F Entab line ............ ^X ^E
Fill paragraph ........ Meta Q Change screen size .... Meta ^D
Justify paragraph ..... Meta J Change screen width ... Meta ^T
-------------------------------------------------------------------------------
=> WINDOW COMMANDS
Split current window .. ^X 2 Next window ........... ^X O
Delete other windows .. ^X 1 Previous window ....... ^X P
Delete window ......... ^X 0 Scroll next up ........ Meta ^Z
Grow window ........... ^X Z Scroll next down ...... Meta ^V
Shrink window ......... ^X ^Z Resize window ......... ^X W
Move window up ........ ^X ^P Save window ........... not bound
Move window down ...... ^X ^N Restore window ........ not bound
-------------------------------------------------------------------------------
=> BUFFER COMMANDS
Next buffer ........... ^X X Buffer position ....... ^X =
Select buffer ......... ^X B Unmark buffer ......... Meta ~
List buffers .......... ^X ^B
Delete buffer ......... ^X K Write message ......... not bound
Name buffer ........... Meta ^N Clear message line .... not bound
Filter buffer ......... ^X #
Pipe command .......... ^X @ Execute buffer ........ not bound
-------------------------------------------------------------------------------
=> SEARCHING AND REPLACING
Search forward ........ Meta S :: End string with Meta.
Incremental search .... ^X S :: Search next ^X, stop Meta, cancel ^G.
Search reverse ........ ^R
Reverse incremental search Hunt forward .......... Alt-S
....................... ^X R Hunt backward ......... Alt-R
Replace string ........ Meta R
Query replace string .. Meta ^R :: Yes/no Y/N, replace rest !, cancel ^G.
-------------------------------------------------------------------------------
=> ACCESSING THE OPERATING SYSTEM
Quick exit ............ Meta Z :: Write out all changed buffers and exit.
Exit emacs ............ ^X ^C :: Exit without automatic save.
I shell ............... ^X C :: Start a new command processor.
Shell command ......... ^X ! :: Execute one operating system command.
Pipe command .......... ^X @ :: Pipe command results to a new buffer. *
Filter buffer ......... ^X # :: Filter buffer through a program. *
Execute program ....... ^X $ :: * Not under VMS.
-------------------------------------------------------------------------------
=> MACRO COMMANDS
Begin macro ........... ^X (
End macro ............. ^X )
Execute macro ......... ^X E
Store macro ........... not bound
Execute macro nn ...... not bound
Store procedure ....... not bound
Execute procedure ..... Meta ^E
-------------------------------------------------------------------------------
=> MISCELLANEOUS
Universal argument .... ^U Set mark .............. Meta Space
Clear and redraw ...... ^L Exchange point and mark ^X ^X
Redraw display ........ Meta ^L
Execute named command . Meta X Insert string ......... not bound
Execute command line .. not bound Overwrite string ...... not bound
Set encryption key .... Meta E Wrap word ............. not bound
Count words ........... Meta ^C Update screen ......... not bound
-------------------------------------------------------------------------------
=> SYSTEM VARIABLES
Set ................... Meta ^A Current buffer name ... $cbufname
Tabulator (4, 8)....... $tab Current file name ..... $cfname
Screen resolution ..... $sres :: NORMAL, CGA, EGA, VGA
Display commands ...... $discmd :: TRUE, FALSE
Scrolling enabled ..... $scroll :: TRUE, FALSE, can only be reset
Scrolling movement .... $jump :: # lines, default 1, 0 = 1/2 page
Page overlap .......... $overlap :: # lines, default 0, 0 = 1/3 page
-------------------------------------------------------------------------------
=> FUNCTIONS
&neg, &abs, &add, &sub, &tim, &div, &mod ... Arithmetic
&equ, &les, &gre ........................... Arithmetic comparisons
&not, &and, &or ............................ Logical
&lef s len, &rig s pos, &mid s pos len ..... Substring
&cat, &len, &upp, &low, &asc, &chr ......... Other string operations
&seq, &sle, &sgr ........................... String comparisons
&sin ....................................... String index
-------------------------------------------------------------------------------
=> FILE NAME COMPLETION
File name completion can be used with all file commands (find-file,
view-file, ...) but it works only under UNIX and MS-DOS. It is invoked
by a <Space> or <Tab>. If there exist more than one possible completions
they are displayed one by one. If the file name contains wild card
characters, the name is expanded instead of simple completion. Special
characters can be entered verbatim by prefixing them with ^V (or ^Q).
-------------------------------------------------------------------------------

29
emacs.lnk Normal file
View File

@ -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
;

27
emacs.prj Normal file
View File

@ -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)

3667
emacs.ps Normal file

File diff suppressed because it is too large Load Diff

285
emacs.rc Normal file
View File

@ -0,0 +1,285 @@
; EMACS.RC / .emascrc
;
; Startup file for MicroEMACS 3.9 and uEmacs/PK 4.0
; This file is executed every time the editor is entered.
;
; Modified by Petri Kutvonen, last edited September 1991.
set $discmd "FALSE"
; First, try to resolve if we are on a PC ... yes, this is a kludge
!if &seq $sres "NORMAL"
set %system "OTHER"
!else
set %system "PC"
!endif
!if &seq %system "PC"
; PC specific initialization
write-message "(Setting up)"
; Comment out or change this line if you want more than 25 lines,
; other possible $sres values include EGA and VGA
set $sres "CGA"
; Uncomment next line if your old screen "snows"
;set $flicker "TRUE"
; If your screen "snows" you'll not like scrolling
!if &seq $flicker "TRUE"
set $scroll "FALSE"
!endif
; Function keys (unshifted)
; f1 f2 f3 f4 f5 f6 f7 f8 f9 f10
; FN; FN< FN= FN> FN? FN@ FNA FNB FNC FND
bind-to-key help FN;
bind-to-key exit-emacs FND
; Function keys (shifted)
; F1 F2 F3 F4 F5 F6 F7 F8 F9 F10
; FNT FNU FNV FNW FNX FNY FNZ FN[ FN\ FN]
; Other special keys (unshifted)
; Home End Ins Del PgUp PgDn
; FNG FNO FNR FNS FNI FNQ
; Some common Alt-keys
; Alt-X Alt-Z Alt-C Alt-F Alt-O
; FN- FN, FN. FN! FN^X
bind-to-key exit-emacs FN-
bind-to-key quick-exit FN,
bind-to-key i-shell FN.
bind-to-key find-file FN!
bind-to-key view-file FN/
bind-to-key next-window FN^X
; Set screen colors
; You can define a DOS environment variable EMACS_BW (any value)
; if you don't like colors, e.g. if you have a LCD screen
!if &seq &env "EMACS_BW" ""
add-global-mode "blue"
add-global-mode "HIGH"
!endif
!endif
; Help facility
40 store-macro
set $discmd "FALSE"
!if &not &seq $cbufname "emacs.hlp"
write-message "(Loading Help)"
!force help
!force 8 resize-window
!if &seq %system "PC"
!if &seq &env "EMACS_BW" ""
add-mode "red"
!endif
bind-to-key execute-macro-38 FNI
bind-to-key execute-macro-37 FNQ
!else
bind-to-key execute-macro-38 FN5
bind-to-key execute-macro-37 FN6
!endif
beginning-of-line
2 forward-character
1 redraw-display
save-window
!if &seq %system "PC"
set %hlpupdn "<PgUp> / <PgDn>"
set %hlphelp "<F1>"
!else
set %hlpupdn "<Prev Scrn> / <Next Scrn>"
set %hlphelp "<Help>"
!endif
execute-macro-39
!else
set %hlpcode &lef $line 2
!if &seq %hlpcode ".."
set %hlptopic &mid $line 4 99
end-of-line
!force search-forward %hlptopic
beginning-of-line
2 forward-character
1 redraw-display
execute-macro-39
!else
!if &seq %system "PC"
bind-to-key previous-page FNI
bind-to-key next-page FNQ
!else
bind-to-key previous-page FN5
bind-to-key next-page FN6
!endif
!force restore-window
!force delete-window
clear-message-line
!endif
!endif
set $discmd "TRUE"
!endm
bind-to-key execute-macro-40 M-?
!if &seq %system "PC"
bind-to-key execute-macro-40 FN;
!else
bind-to-key execute-macro-40 FNh
!endif
; Help on Help
39 store-macro
!if &seq &rig $line 5 "INDEX"
write-message &cat "Select topic from list and press " %hlphelp
!else
write-message &cat "Use " &cat %hlpupdn &cat " to scan help file -- " &cat %hlphelp " to toggle help window"
!endif
!endm
; Previous help page
38 store-macro
!if &seq $cbufname "emacs.hlp"
beginning-of-line
!force search-reverse "=>"
2 forward-character
1 redraw-display
execute-macro-39
!else
previous-page
!endif
!endm
; Next help page
37 store-macro
!if &seq $cbufname "emacs.hlp"
beginning-of-line
2 forward-character
!force search-forward "=>"
1 redraw-display
execute-macro-39
!else
next-page
!endif
!endm
; Set up auto CMODE
36 store-macro
!if &seq &mid $cfname 1 7 "/tmp/Re"
add-mode "wrap"
!return
!endif
!if &gre &sin $cfname "/.ed" 0
add-mode "wrap"
!return
!endif
!if &gre &sin $cfname "/.let" 0
add-mode "wrap"
!return
!endif
!if &gre &sin $cfname "/.art" 0
add-mode "wrap"
!return
!endif
!if &gre &sin $cfname "/nn." 0
add-mode "wrap"
!return
!endif
set %rctmp &sin $cfname "."
!if &equ %rctmp 0
!return
!endif
set %rctmp &mid $cfname &add %rctmp 1 5
!if &or &seq %rctmp "c" &seq %rctmp "h"
add-mode "cmode"
!endif
!if &or &seq %rctmp "txt" &or &seq %rctmp "doc" &or &seq %rctmp "tmp" &seq %rctmp "tex"
add-mode "wrap"
!endif
!endm
bind-to-key execute-macro-36 M-FNR
; Setup for ASCII {|}[\] to ISO Latin-1 translation
21 store-macro
insert-string "ä"
!endm
22 store-macro
insert-string "ö"
!endm
23 store-macro
insert-string "å"
!endm
24 store-macro
insert-string "Ä"
!endm
25 store-macro
insert-string "Ö"
!endm
26 store-macro
insert-string "Å"
!endm
27 store-macro
bind-to-key execute-macro-21 {
bind-to-key execute-macro-22 |
bind-to-key execute-macro-23 }
bind-to-key execute-macro-24 [
bind-to-key execute-macro-25 \
bind-to-key execute-macro-26 ]
write-message "ISO Latin-1 äöåÄÖÅ"
!endm
28 store-macro
unbind-key {
unbind-key |
unbind-key }
unbind-key [
unbind-key \
unbind-key ]
write-message "ASCII {|}[\]"
!endm
bind-to-key execute-macro-27 ^X[
bind-to-key execute-macro-28 ^X]
; Make cut-paste easier in window systems
bind-to-key newline ^J
; uEmacs/PK specific initialization
!if &seq $progname "uEmacs/PK"
; Don't scroll on a Sun
!if &or &seq $TERM "sun" &seq $TERM "sun-cmd"
set $scroll "FALSE"
!endif
; Execute local initialization files
!if &seq %system "PC"
!force execute-file "EM.RC"
!else
!force execute-file &cat $HOME "/.emrc"
!force execute-file ".emrc"
!endif
!endif
set $discmd "TRUE"

BIN
emacs.wri Normal file

Binary file not shown.

53
epath.h Normal file
View File

@ -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 *))

731
estruct.h Normal file
View File

@ -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

879
eval.c Normal file
View File

@ -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);
}

212
evar.h Normal file
View File

@ -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

1148
exec.c Normal file

File diff suppressed because it is too large Load Diff

635
file.c Normal file
View File

@ -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);
}

228
fileio.c Normal file
View File

@ -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);
}

517
ibmpc.c Normal file
View File

@ -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

713
input.c Normal file
View File

@ -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++);
}

521
isearch.c Normal file
View File

@ -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

655
line.c Normal file
View File

@ -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);
}

166
lock.c Normal file
View File

@ -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

895
main.c Normal file
View File

@ -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

124
makefile Normal file
View File

@ -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

22
makefile.dos Normal file
View File

@ -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)

121
makefile.unx Normal file
View File

@ -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

61
makefilepatch Normal file
View File

@ -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

125
pklock.c Normal file
View File

@ -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

159
posix.c Normal file
View File

@ -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 */

1221
random.c Normal file

File diff suppressed because it is too large Load Diff

182
readme Normal file
View File

@ -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

331
readme.39e Normal file
View File

@ -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.

212
region.c Normal file
View File

@ -0,0 +1,212 @@
/* REGION.C
*
* The routines in this file
* deal with the region, that magic space
* between "." and mark. Some functions are
* commands. Some functions are just for
* internal use.
*
* modified by Petri Kutvonen
*/
#include <stdio.h>
#include "estruct.h"
#include "edef.h"
/*
* Kill the region. Ask "getregion"
* to figure out the bounds of the region.
* Move "." to the start, and kill the characters.
* Bound to "C-W".
*/
killregion(f, n)
{
register int s;
REGION region;
if (curbp->b_mode&MDVIEW) /* don't allow this command if */
return(rdonly()); /* we are in read only mode */
if ((s=getregion(&region)) != TRUE)
return (s);
if ((lastflag&CFKILL) == 0) /* This is a kill type */
kdelete(); /* command, so do magic */
thisflag |= CFKILL; /* kill buffer stuff. */
curwp->w_dotp = region.r_linep;
curwp->w_doto = region.r_offset;
return (ldelete(region.r_size, TRUE));
}
/*
* Copy all of the characters in the
* region to the kill buffer. Don't move dot
* at all. This is a bit like a kill region followed
* by a yank. Bound to "M-W".
*/
copyregion(f, n)
{
register LINE *linep;
register int loffs;
register int s;
REGION region;
if ((s=getregion(&region)) != TRUE)
return (s);
if ((lastflag&CFKILL) == 0) /* Kill type command. */
kdelete();
thisflag |= CFKILL;
linep = region.r_linep; /* Current line. */
loffs = region.r_offset; /* Current offset. */
while (region.r_size--) {
if (loffs == llength(linep)) { /* End of line. */
if ((s=kinsert('\n')) != TRUE)
return (s);
linep = lforw(linep);
loffs = 0;
} else { /* Middle of line. */
if ((s=kinsert(lgetc(linep, loffs))) != TRUE)
return (s);
++loffs;
}
}
mlwrite("(region copied)");
return (TRUE);
}
/*
* Lower case region. Zap all of the upper
* case characters in the region to lower case. Use
* the region code to set the limits. Scan the buffer,
* doing the changes. Call "lchange" to ensure that
* redisplay is done in all buffers. Bound to
* "C-X C-L".
*/
lowerregion(f, n)
{
register LINE *linep;
register int loffs;
register int c;
register int s;
REGION region;
if (curbp->b_mode&MDVIEW) /* don't allow this command if */
return(rdonly()); /* we are in read only mode */
if ((s=getregion(&region)) != TRUE)
return (s);
lchange(WFHARD);
linep = region.r_linep;
loffs = region.r_offset;
while (region.r_size--) {
if (loffs == llength(linep)) {
linep = lforw(linep);
loffs = 0;
} else {
c = lgetc(linep, loffs);
if (c>='A' && c<='Z')
lputc(linep, loffs, c+'a'-'A');
++loffs;
}
}
return (TRUE);
}
/*
* Upper case region. Zap all of the lower
* case characters in the region to upper case. Use
* the region code to set the limits. Scan the buffer,
* doing the changes. Call "lchange" to ensure that
* redisplay is done in all buffers. Bound to
* "C-X C-L".
*/
upperregion(f, n)
{
register LINE *linep;
register int loffs;
register int c;
register int s;
REGION region;
if (curbp->b_mode&MDVIEW) /* don't allow this command if */
return(rdonly()); /* we are in read only mode */
if ((s=getregion(&region)) != TRUE)
return (s);
lchange(WFHARD);
linep = region.r_linep;
loffs = region.r_offset;
while (region.r_size--) {
if (loffs == llength(linep)) {
linep = lforw(linep);
loffs = 0;
} else {
c = lgetc(linep, loffs);
if (c>='a' && c<='z')
lputc(linep, loffs, c-'a'+'A');
++loffs;
}
}
return (TRUE);
}
/*
* This routine figures out the
* bounds of the region in the current window, and
* fills in the fields of the "REGION" structure pointed
* to by "rp". Because the dot and mark are usually very
* close together, we scan outward from dot looking for
* mark. This should save time. Return a standard code.
* Callers of this routine should be prepared to get
* an "ABORT" status; we might make this have the
* conform thing later.
*/
getregion(rp)
register REGION *rp;
{
register LINE *flp;
register LINE *blp;
long fsize;
long bsize;
if (curwp->w_markp == NULL) {
mlwrite("No mark set in this window");
return (FALSE);
}
if (curwp->w_dotp == curwp->w_markp) {
rp->r_linep = curwp->w_dotp;
if (curwp->w_doto < curwp->w_marko) {
rp->r_offset = curwp->w_doto;
rp->r_size = (long)(curwp->w_marko-curwp->w_doto);
} else {
rp->r_offset = curwp->w_marko;
rp->r_size = (long)(curwp->w_doto-curwp->w_marko);
}
return (TRUE);
}
blp = curwp->w_dotp;
bsize = (long)curwp->w_doto;
flp = curwp->w_dotp;
fsize = (long)(llength(flp)-curwp->w_doto+1);
while (flp!=curbp->b_linep || lback(blp)!=curbp->b_linep) {
if (flp != curbp->b_linep) {
flp = lforw(flp);
if (flp == curwp->w_markp) {
rp->r_linep = curwp->w_dotp;
rp->r_offset = curwp->w_doto;
rp->r_size = fsize+curwp->w_marko;
return (TRUE);
}
fsize += llength(flp)+1;
}
if (lback(blp) != curbp->b_linep) {
blp = lback(blp);
bsize += llength(blp)+1;
if (blp == curwp->w_markp) {
rp->r_linep = blp;
rp->r_offset = curwp->w_marko;
rp->r_size = bsize - curwp->w_marko;
return (TRUE);
}
}
}
mlwrite("Bug: lost mark");
return (FALSE);
}

1585
search.c Normal file

File diff suppressed because it is too large Load Diff

57
shell.cmd Normal file
View File

@ -0,0 +1,57 @@
; OS shell interface, MS-DOS and UNIX
store-procedure prompt
set $discmd FALSE
end-of-file
insert-string "shell% "
set-mark
set $discmd TRUE
unmark-buffer
!endm
store-procedure getline
set $discmd FALSE
end-of-file
!force backward-character
exchange-point-and-mark
copy-region
set %shline $kill
end-of-file
set $discmd TRUE
!endm
store-procedure execline
; shell-command "echo command not found > shtmp"
shell-command &cat %shline " > shtmp"
!force insert-file shtmp
!endm
; prompt and execute a command
10 store-macro
run getline
!if &not &seq %shline ""
run execline
!endif
run prompt
!endm
11 store-macro
set $discmd FALSE
!if &seq $cbufname "*Shell*"
bind-to-key execute-macro-10 ^M
run prompt
!else
bind-to-key newline ^M
!endif
set $discmd TRUE
!endm
store-procedure openshell
set $discmd FALSE
bind-to-key execute-macro-11 M-FNX
select-buffer "*Shell*"
set $discmd TRUE
!endm
run openshell

628
spawn.c Normal file
View File

@ -0,0 +1,628 @@
/* SPAWN.C
* various operating system access commands
*
* modified by Petri Kutvonen
*/
#include <stdio.h>
#include "estruct.h"
#include "edef.h"
#if VMS
#define EFN 0 /* Event flag. */
#include <ssdef.h> /* Random headers. */
#include <stsdef.h>
#include <descrip.h>
#include <iodef.h>
extern int oldmode[3]; /* In "termio.c" */
extern int newmode[3]; /* In "termio.c" */
extern short iochan; /* In "termio.c" */
#endif
#if V7 | USG | BSD
#include <signal.h>
extern int vttidy();
#ifdef SIGWINCH
extern int chg_width, chg_height;
extern void sizesignal();
#endif
#endif
#if MSDOS & (MSC | TURBO)
#include <process.h>
#endif
/*
* Create a subjob with a copy of the command intrepreter in it. When the
* command interpreter exits, mark the screen as garbage so that you do a full
* repaint. Bound to "^X C". The message at the start in VMS puts out a newline.
* Under some (unknown) condition, you don't get one free when DCL starts up.
*/
spawncli(f, n)
{
#if V7 | USG | BSD
register char *cp;
char *getenv();
#endif
/* don't allow this command if restricted */
if (restflag)
return(resterr());
#if VMS
movecursor(term.t_nrow, 0); /* In last line. */
mlputs("(Starting DCL)\r\n");
TTflush(); /* Ignore "ttcol". */
sgarbf = TRUE;
sys(NULL);
sleep(1);
mlputs("\r\n(Returning from DCL)\r\n");
TTflush();
sleep(1);
return(TRUE);
#endif
#if MSDOS & (MSC | TURBO)
movecursor(term.t_nrow, 0); /* Seek to last line. */
TTflush();
TTkclose();
shellprog("");
TTkopen();
sgarbf = TRUE;
return(TRUE);
#endif
#if V7 | USG | BSD
movecursor(term.t_nrow, 0); /* Seek to last line. */
TTflush();
TTclose(); /* stty to old settings */
if ((cp = getenv("SHELL")) != NULL && *cp != '\0')
system(cp);
else
#if BSD
system("exec /bin/csh");
#else
system("exec /bin/sh");
#endif
sgarbf = TRUE;
sleep(2);
TTopen();
TTkopen();
#ifdef SIGWINCH
/*
* This fools the update routines to force a full
* redraw with complete window size checking.
* -lbt
*/
chg_width = term.t_ncol;
chg_height = term.t_nrow+1;
term.t_nrow = term.t_ncol = 0;
#endif
return(TRUE);
#endif
}
#if BSD | __hpux | SVR4
bktoshell() /* suspend MicroEMACS and wait to wake up */
{
int pid;
vttidy();
/******************************
pid = getpid();
kill(pid,SIGTSTP);
******************************/
kill(0, SIGTSTP);
}
rtfrmshell()
{
TTopen();
curwp->w_flag = WFHARD;
sgarbf = TRUE;
}
#endif
/*
* Run a one-liner in a subjob. When the command returns, wait for a single
* character to be typed, then mark the screen as garbage so a full repaint is
* done. Bound to "C-X !".
*/
spawn(f, n)
{
register int s;
char line[NLINE];
/* don't allow this command if restricted */
if (restflag)
return(resterr());
#if VMS
if ((s=mlreply("!", line, NLINE)) != TRUE)
return (s);
movecursor(term.t_nrow, 0);
TTflush();
s = sys(line); /* Run the command. */
if (clexec == FALSE) {
mlputs("\r\n\n(End)"); /* Pause. */
TTflush();
tgetc();
}
sgarbf = TRUE;
return (s);
#endif
#if MSDOS
if ((s=mlreply("!", line, NLINE)) != TRUE)
return(s);
movecursor(term.t_nrow, 0);
TTkclose();
shellprog(line);
TTkopen();
/* if we are interactive, pause here */
if (clexec == FALSE) {
mlputs("\r\n(End)");
tgetc();
}
sgarbf = TRUE;
return (TRUE);
#endif
#if V7 | USG | BSD
if ((s=mlreply("!", line, NLINE)) != TRUE)
return (s);
TTflush();
TTclose(); /* stty to old modes */
TTkclose();
system(line);
fflush(stdout); /* to be sure P.K. */
TTopen();
if (clexec == FALSE) {
mlputs("(End)"); /* Pause. */
TTflush();
while ((s = tgetc()) != '\r' && s != ' ')
;
mlputs("\r\n");
}
TTkopen();
sgarbf = TRUE;
return (TRUE);
#endif
}
/*
* Run an external program with arguments. When it returns, wait for a single
* character to be typed, then mark the screen as garbage so a full repaint is
* done. Bound to "C-X $".
*/
execprg(f, n)
{
register int s;
char line[NLINE];
/* don't allow this command if restricted */
if (restflag)
return(resterr());
#if VMS
if ((s=mlreply("!", line, NLINE)) != TRUE)
return (s);
TTflush();
s = sys(line); /* Run the command. */
mlputs("\r\n\n(End)"); /* Pause. */
TTflush();
tgetc();
sgarbf = TRUE;
return (s);
#endif
#if MSDOS
if ((s=mlreply("$", line, NLINE)) != TRUE)
return(s);
movecursor(term.t_nrow, 0);
TTkclose();
execprog(line);
TTkopen();
/* if we are interactive, pause here */
if (clexec == FALSE) {
mlputs("\r\n(End)");
tgetc();
}
sgarbf = TRUE;
return (TRUE);
#endif
#if V7 | USG | BSD
if ((s=mlreply("!", line, NLINE)) != TRUE)
return (s);
TTputc('\n'); /* Already have '\r' */
TTflush();
TTclose(); /* stty to old modes */
system(line);
fflush(stdout); /* to be sure P.K. */
TTopen();
mlputs("(End)"); /* Pause. */
TTflush();
while ((s = tgetc()) != '\r' && s != ' ')
;
sgarbf = TRUE;
return (TRUE);
#endif
}
/*
* Pipe a one line command into a window
* Bound to ^X @
*/
pipecmd(f, n)
{
register int s; /* return status from CLI */
register WINDOW *wp; /* pointer to new window */
register BUFFER *bp; /* pointer to buffer to zot */
char line[NLINE]; /* command line send to shell */
static char bname[] = "command";
static char filnam[NSTRING] = "command";
#if MSDOS
char *tmp;
char *getenv();
FILE *fp;
FILE *fopen();
int len;
#endif
/* don't allow this command if restricted */
if (restflag)
return(resterr());
#if MSDOS
if ((tmp = getenv("TMP")) == NULL && (tmp = getenv("TEMP")) == NULL)
strcpy(filnam, "command");
else {
strcpy(filnam, tmp);
len = strlen(tmp);
if (len <= 0 || filnam[len-1] != '\\' && filnam[len-1] != '/')
strcat(filnam,"\\");
strcat(filnam,"command");
}
#endif
#if VMS
mlwrite("Not available under VMS");
return(FALSE);
#endif
/* get the command to pipe in */
if ((s=mlreply("@", line, NLINE)) != TRUE)
return(s);
/* get rid of the command output buffer if it exists */
if ((bp=bfind(bname, FALSE, 0)) != FALSE) {
/* try to make sure we are off screen */
wp = wheadp;
while (wp != NULL) {
if (wp->w_bufp == bp) {
#if PKCODE
if (wp == curwp)
delwind(FALSE, 1);
else
onlywind(FALSE, 1);
break;
#else
onlywind(FALSE, 1);
break;
#endif
}
wp = wp->w_wndp;
}
if (zotbuf(bp) != TRUE)
return(FALSE);
}
#if MSDOS
strcat(line," >>");
strcat(line,filnam);
movecursor(term.t_nrow, 0);
TTkclose();
shellprog(line);
TTkopen();
sgarbf = TRUE;
if ((fp = fopen(filnam, "r")) == NULL) {
s = FALSE;
} else {
fclose(fp);
s = TRUE;
}
#endif
#if V7 | USG | BSD
TTflush();
TTclose(); /* stty to old modes */
strcat(line,">");
strcat(line,filnam);
system(line);
TTopen();
TTflush();
sgarbf = TRUE;
s = TRUE;
#endif
if (s != TRUE)
return(s);
/* split the current window to make room for the command output */
if (splitwind(FALSE, 1) == FALSE)
return(FALSE);
/* and read the stuff in */
if (getfile(filnam, FALSE) == FALSE)
return(FALSE);
/* make this window in VIEW mode, update all mode lines */
curwp->w_bufp->b_mode |= MDVIEW;
wp = wheadp;
while (wp != NULL) {
wp->w_flag |= WFMODE;
wp = wp->w_wndp;
}
/* and get rid of the temporary file */
unlink(filnam);
return(TRUE);
}
/*
* filter a buffer through an external DOS program
* Bound to ^X #
*/
filter(f, n)
{
register int s; /* return status from CLI */
register BUFFER *bp; /* pointer to buffer to zot */
char line[NLINE]; /* command line send to shell */
char tmpnam[NFILEN]; /* place to store real file name */
static char bname1[] = "fltinp";
static char filnam1[] = "fltinp";
static char filnam2[] = "fltout";
/* don't allow this command if restricted */
if (restflag)
return(resterr());
if (curbp->b_mode&MDVIEW) /* don't allow this command if */
return(rdonly()); /* we are in read only mode */
#if VMS
mlwrite("Not available under VMS");
return(FALSE);
#endif
/* get the filter name and its args */
if ((s=mlreply("#", line, NLINE)) != TRUE)
return(s);
/* setup the proper file names */
bp = curbp;
strcpy(tmpnam, bp->b_fname); /* save the original name */
strcpy(bp->b_fname, bname1); /* set it to our new one */
/* write it out, checking for errors */
if (writeout(filnam1) != TRUE) {
mlwrite("(Cannot write filter file)");
strcpy(bp->b_fname, tmpnam);
return(FALSE);
}
#if MSDOS
strcat(line," <fltinp >fltout");
movecursor(term.t_nrow - 1, 0);
TTkclose();
shellprog(line);
TTkopen();
sgarbf = TRUE;
s = TRUE;
#endif
#if V7 | USG | BSD
TTputc('\n'); /* Already have '\r' */
TTflush();
TTclose(); /* stty to old modes */
strcat(line," <fltinp >fltout");
system(line);
TTopen();
TTflush();
sgarbf = TRUE;
s = TRUE;
#endif
/* on failure, escape gracefully */
if (s != TRUE || (readin(filnam2,FALSE) == FALSE)) {
mlwrite("(Execution failed)");
strcpy(bp->b_fname, tmpnam);
unlink(filnam1);
unlink(filnam2);
return(s);
}
/* reset file name */
strcpy(bp->b_fname, tmpnam); /* restore name */
bp->b_flag |= BFCHG; /* flag it as changed */
/* and get rid of the temporary file */
unlink(filnam1);
unlink(filnam2);
return(TRUE);
}
#if VMS
/*
* Run a command. The "cmd" is a pointer to a command string, or NULL if you
* want to run a copy of DCL in the subjob (this is how the standard routine
* LIB$SPAWN works. You have to do wierd stuff with the terminal on the way in
* and the way out, because DCL does not want the channel to be in raw mode.
*/
sys(cmd)
register char *cmd;
{
struct dsc$descriptor cdsc;
struct dsc$descriptor *cdscp;
long status;
long substatus;
long iosb[2];
status = SYS$QIOW(EFN, iochan, IO$_SETMODE, iosb, 0, 0,
oldmode, sizeof(oldmode), 0, 0, 0, 0);
if (status!=SS$_NORMAL || (iosb[0]&0xFFFF)!=SS$_NORMAL)
return (FALSE);
cdscp = NULL; /* Assume DCL. */
if (cmd != NULL) { /* Build descriptor. */
cdsc.dsc$a_pointer = cmd;
cdsc.dsc$w_length = strlen(cmd);
cdsc.dsc$b_dtype = DSC$K_DTYPE_T;
cdsc.dsc$b_class = DSC$K_CLASS_S;
cdscp = &cdsc;
}
status = LIB$SPAWN(cdscp, 0, 0, 0, 0, 0, &substatus, 0, 0, 0);
if (status != SS$_NORMAL)
substatus = status;
status = SYS$QIOW(EFN, iochan, IO$_SETMODE, iosb, 0, 0,
newmode, sizeof(newmode), 0, 0, 0, 0);
if (status!=SS$_NORMAL || (iosb[0]&0xFFFF)!=SS$_NORMAL)
return (FALSE);
if ((substatus&STS$M_SUCCESS) == 0) /* Command failed. */
return (FALSE);
return (TRUE);
}
#endif
#if MSDOS & (TURBO | MSC)
/* SHELLPROG: Execute a command in a subshell */
shellprog(cmd)
char *cmd; /* Incoming command line to execute */
{
char *shell; /* Name of system command processor */
char *p; /* Temporary pointer */
char swchar; /* switch character to use */
union REGS regs; /* parameters for dos call */
char comline[NSTRING]; /* constructed command line */
char *getenv();
/* detect current switch character and set us up to use it */
regs.h.ah = 0x37; /* get setting data */
regs.h.al = 0x00; /* get switch character */
intdos(&regs, &regs);
swchar = (char)regs.h.dl;
/* get name of system shell */
if ((shell = getenv("COMSPEC")) == NULL) {
return(FALSE); /* No shell located */
}
/* trim leading whitespace off the command */
while (*cmd == ' ' || *cmd == '\t') /* find out if null command */
cmd++;
/** If the command line is not empty, bring up the shell **/
/** and execute the command. Otherwise, bring up the **/
/** shell in interactive mode. **/
if (*cmd) {
strcpy(comline, shell);
strcat(comline, " ");
comline[strlen(comline) + 1] = 0;
comline[strlen(comline)] = swchar;
strcat(comline, "c ");
strcat(comline, cmd);
return(execprog(comline));
} else
return(execprog(shell));
}
/* EXECPROG: A function to execute a named program
with arguments
*/
execprog(cmd)
char *cmd; /* Incoming command line to execute */
{
char *sp; /* temporary string pointer */
char f1[38]; /* FCB1 area (not initialized */
char f2[38]; /* FCB2 area (not initialized */
char prog[NSTRING]; /* program filespec */
char tail[NSTRING]; /* command tail with length byte */
union REGS regs; /* parameters for dos call */
struct SREGS segreg; /* segment registers for dis call */
struct pblock { /* EXEC parameter block */
short envptr; /* 2 byte pointer to environment string */
char *cline; /* 4 byte pointer to command line */
char *fcb1; /* 4 byte pointer to FCB at PSP+5Ch */
char *fcb2; /* 4 byte pointer to FCB at PSP+6Ch */
} pblock;
char *flook();
/* parse the command name from the command line */
sp = prog;
while (*cmd && (*cmd != ' ') && (*cmd != '\t'))
*sp++ = *cmd++;
*sp = 0;
/* and parse out the command tail */
while (*cmd && ((*cmd == ' ') || (*cmd == '\t')))
++cmd;
*tail = (char)(strlen(cmd)); /* record the byte length */
strcpy(&tail[1], cmd);
strcat(&tail[1], "\r");
/* look up the program on the path trying various extentions */
if ((sp = flook(prog, TRUE)) == NULL)
if ((sp = flook(strcat(prog, ".exe"), TRUE)) == NULL) {
strcpy(&prog[strlen(prog)-4], ".com");
if ((sp = flook(prog, TRUE)) == NULL)
return(FALSE);
}
strcpy(prog, sp);
/* get a pointer to this PSPs environment segment number */
segread(&segreg);
/* set up the EXEC parameter block */
pblock.envptr = 0; /* make the child inherit the parents env */
pblock.fcb1 = f1; /* point to a blank FCB */
pblock.fcb2 = f2; /* point to a blank FCB */
pblock.cline = tail; /* parameter line pointer */
/* and make the call */
regs.h.ah = 0x4b; /* EXEC Load or Execute a Program */
regs.h.al = 0x00; /* load end execute function subcode */
segreg.ds = ((unsigned long)(prog) >> 16); /* program name ptr */
regs.x.dx = (unsigned int)(prog);
segreg.es = ((unsigned long)(&pblock) >> 16); /* set up param block ptr */
regs.x.bx = (unsigned int)(&pblock);
#if TURBO | MSC
intdosx(&regs, &regs, &segreg);
if (regs.x.cflag == 0) {
regs.h.ah = 0x4d; /* get child process return code */
intdos(&regs, &regs); /* go do it */
rval = regs.x.ax; /* save child's return code */
} else
#if MSC
rval = -1;
#else
rval = -_doserrno; /* failed child call */
#endif
#endif
return((rval < 0) ? FALSE : TRUE);
}
#endif

386
tcap.c Normal file
View File

@ -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

451
termio.c Normal file
View File

@ -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 */

29
vmslink.com Normal file
View File

@ -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

28
vmsmake.com Normal file
View File

@ -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

519
vmsvt.c Normal file
View File

@ -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

190
vt52.c Normal file
View File

@ -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

733
window.c Normal file
View File

@ -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);
}

717
word.c Normal file
View File

@ -0,0 +1,717 @@
/* WORD.C
*
* The routines in this file implement commands that work word or a
* paragraph at a time. There are all sorts of word mode commands. If I
* do any sentence mode commands, they are likely to be put in this file.
*
* modified by Petri Kutvonen
*/
#include <stdio.h>
#include "estruct.h"
#include "edef.h"
/* Word wrap on n-spaces. Back-over whatever precedes the point on the current
* line and stop on the first word-break or the beginning of the line. If we
* reach the beginning of the line, jump back to the end of the word and start
* a new line. Otherwise, break the line at the word-break, eat it, and jump
* back to the end of the word.
* Returns TRUE on success, FALSE on errors.
*/
wrapword(f, n)
int f; /* default flag */
int n; /* numeric argument */
{
register int cnt; /* size of word wrapped to next line */
register int c; /* charector temporary */
/* backup from the <NL> 1 char */
if (!backchar(0, 1))
return(FALSE);
/* back up until we aren't in a word,
make sure there is a break in the line */
cnt = 0;
while (((c = lgetc(curwp->w_dotp, curwp->w_doto)) != ' ')
&& (c != '\t')) {
cnt++;
if (!backchar(0, 1))
return(FALSE);
/* if we make it to the beginning, start a new line */
if (curwp->w_doto == 0) {
gotoeol(FALSE, 0);
return(lnewline());
}
}
/* delete the forward white space */
if (!forwdel(0, 1))
return(FALSE);
/* put in a end of line */
if (!lnewline())
return(FALSE);
/* and past the first word */
while (cnt-- > 0) {
if (forwchar(FALSE, 1) == FALSE)
return(FALSE);
}
return(TRUE);
}
/*
* Move the cursor backward by "n" words. All of the details of motion are
* performed by the "backchar" and "forwchar" routines. Error if you try to
* move beyond the buffers.
*/
backword(f, n)
{
if (n < 0)
return (forwword(f, -n));
if (backchar(FALSE, 1) == FALSE)
return (FALSE);
while (n--) {
while (inword() == FALSE) {
if (backchar(FALSE, 1) == FALSE)
return (FALSE);
}
while (inword() != FALSE) {
if (backchar(FALSE, 1) == FALSE)
return (FALSE);
}
}
return (forwchar(FALSE, 1));
}
/*
* Move the cursor forward by the specified number of words. All of the motion
* is done by "forwchar". Error if you try and move beyond the buffer's end.
*/
forwword(f, n)
{
if (n < 0)
return (backword(f, -n));
while (n--) {
while (inword() == TRUE) {
if (forwchar(FALSE, 1) == FALSE)
return (FALSE);
}
while (inword() == FALSE) {
if (forwchar(FALSE, 1) == FALSE)
return (FALSE);
}
}
return(TRUE);
}
/*
* Move the cursor forward by the specified number of words. As you move,
* convert any characters to upper case. Error if you try and move beyond the
* end of the buffer. Bound to "M-U".
*/
upperword(f, n)
{
register int c;
if (curbp->b_mode&MDVIEW) /* don't allow this command if */
return(rdonly()); /* we are in read only mode */
if (n < 0)
return (FALSE);
while (n--) {
while (inword() == FALSE) {
if (forwchar(FALSE, 1) == FALSE)
return (FALSE);
}
while (inword() != FALSE) {
c = lgetc(curwp->w_dotp, curwp->w_doto);
#if PKCODE
if (islower(c)) {
#else
if (c>='a' && c<='z') {
#endif
c -= 'a'-'A';
lputc(curwp->w_dotp, curwp->w_doto, c);
lchange(WFHARD);
}
if (forwchar(FALSE, 1) == FALSE)
return (FALSE);
}
}
return (TRUE);
}
/*
* Move the cursor forward by the specified number of words. As you move
* convert characters to lower case. Error if you try and move over the end of
* the buffer. Bound to "M-L".
*/
lowerword(f, n)
{
register int c;
if (curbp->b_mode&MDVIEW) /* don't allow this command if */
return(rdonly()); /* we are in read only mode */
if (n < 0)
return (FALSE);
while (n--) {
while (inword() == FALSE) {
if (forwchar(FALSE, 1) == FALSE)
return (FALSE);
}
while (inword() != FALSE) {
c = lgetc(curwp->w_dotp, curwp->w_doto);
#if PKCODE
if (isupper(c)) {
#else
if (c>='A' && c<='Z') {
#endif
c += 'a'-'A';
lputc(curwp->w_dotp, curwp->w_doto, c);
lchange(WFHARD);
}
if (forwchar(FALSE, 1) == FALSE)
return (FALSE);
}
}
return (TRUE);
}
/*
* Move the cursor forward by the specified number of words. As you move
* convert the first character of the word to upper case, and subsequent
* characters to lower case. Error if you try and move past the end of the
* buffer. Bound to "M-C".
*/
capword(f, n)
{
register int c;
if (curbp->b_mode&MDVIEW) /* don't allow this command if */
return(rdonly()); /* we are in read only mode */
if (n < 0)
return (FALSE);
while (n--) {
while (inword() == FALSE) {
if (forwchar(FALSE, 1) == FALSE)
return (FALSE);
}
if (inword() != FALSE) {
c = lgetc(curwp->w_dotp, curwp->w_doto);
#if PKCODE
if (islower(c)) {
#else
if (c>='a' && c<='z') {
#endif
c -= 'a'-'A';
lputc(curwp->w_dotp, curwp->w_doto, c);
lchange(WFHARD);
}
if (forwchar(FALSE, 1) == FALSE)
return (FALSE);
while (inword() != FALSE) {
c = lgetc(curwp->w_dotp, curwp->w_doto);
#if PKCODE
if (isupper(c)) {
#else
if (c>='A' && c<='Z') {
#endif
c += 'a'-'A';
lputc(curwp->w_dotp, curwp->w_doto, c);
lchange(WFHARD);
}
if (forwchar(FALSE, 1) == FALSE)
return (FALSE);
}
}
}
return (TRUE);
}
/*
* Kill forward by "n" words. Remember the location of dot. Move forward by
* the right number of words. Put dot back where it was and issue the kill
* command for the right number of characters. With a zero argument, just
* kill one word and no whitespace. Bound to "M-D".
*/
delfword(f, n)
{
register LINE *dotp; /* original cursor line */
register int doto; /* and row */
register int c; /* temp char */
long size; /* # of chars to delete */
/* don't allow this command if we are in read only mode */
if (curbp->b_mode&MDVIEW)
return(rdonly());
/* ignore the command if there is a negative argument */
if (n < 0)
return (FALSE);
/* Clear the kill buffer if last command wasn't a kill */
if ((lastflag&CFKILL) == 0)
kdelete();
thisflag |= CFKILL; /* this command is a kill */
/* save the current cursor position */
dotp = curwp->w_dotp;
doto = curwp->w_doto;
/* figure out how many characters to give the axe */
size = 0;
/* get us into a word.... */
while (inword() == FALSE) {
if (forwchar(FALSE, 1) == FALSE)
return(FALSE);
++size;
}
if (n == 0) {
/* skip one word, no whitespace! */
while (inword() == TRUE) {
if (forwchar(FALSE, 1) == FALSE)
return(FALSE);
++size;
}
} else {
/* skip n words.... */
while (n--) {
/* if we are at EOL; skip to the beginning of the next */
while (curwp->w_doto == llength(curwp->w_dotp)) {
if (forwchar(FALSE, 1) == FALSE)
return(FALSE);
++size;
}
/* move forward till we are at the end of the word */
while (inword() == TRUE) {
if (forwchar(FALSE, 1) == FALSE)
return(FALSE);
++size;
}
/* if there are more words, skip the interword stuff */
if (n != 0)
while (inword() == FALSE) {
if (forwchar(FALSE, 1) == FALSE)
return(FALSE);
++size;
}
}
/* skip whitespace and newlines */
while ((curwp->w_doto == llength(curwp->w_dotp)) ||
((c = lgetc(curwp->w_dotp, curwp->w_doto)) == ' ') ||
(c == '\t')) {
if (forwchar(FALSE, 1) == FALSE)
break;
++size;
}
}
/* restore the original position and delete the words */
curwp->w_dotp = dotp;
curwp->w_doto = doto;
return (ldelete(size, TRUE));
}
/*
* Kill backwards by "n" words. Move backwards by the desired number of words,
* counting the characters. When dot is finally moved to its resting place,
* fire off the kill command. Bound to "M-Rubout" and to "M-Backspace".
*/
delbword(f, n)
{
long size;
/* don't allow this command if we are in read only mode */
if (curbp->b_mode&MDVIEW)
return(rdonly());
/* ignore the command if there is a nonpositive argument */
if (n <= 0)
return (FALSE);
/* Clear the kill buffer if last command wasn't a kill */
if ((lastflag&CFKILL) == 0)
kdelete();
thisflag |= CFKILL; /* this command is a kill */
if (backchar(FALSE, 1) == FALSE)
return (FALSE);
size = 0;
while (n--) {
while (inword() == FALSE) {
if (backchar(FALSE, 1) == FALSE)
return (FALSE);
++size;
}
while (inword() != FALSE) {
++size;
if (backchar(FALSE, 1) == FALSE)
goto bckdel;
}
}
if (forwchar(FALSE, 1) == FALSE)
return (FALSE);
bckdel: return (ldelete(size, TRUE));
}
/*
* Return TRUE if the character at dot is a character that is considered to be
* part of a word. The word character list is hard coded. Should be setable.
*/
inword()
{
register int c;
if (curwp->w_doto == llength(curwp->w_dotp))
return (FALSE);
c = lgetc(curwp->w_dotp, curwp->w_doto);
#if PKCODE
if (isletter(c))
#else
if (c>='a' && c<='z')
return (TRUE);
if (c>='A' && c<='Z')
#endif
return (TRUE);
if (c>='0' && c<='9')
return (TRUE);
return (FALSE);
}
#if WORDPRO
fillpara(f, n) /* Fill the current paragraph according to the current
fill column */
int f, n; /* deFault flag and Numeric argument */
{
register int c; /* current char durring scan */
register int wordlen; /* length of current word */
register int clength; /* position on line during fill */
register int i; /* index during word copy */
register int newlength; /* tentative new line length */
register int eopflag; /* Are we at the End-Of-Paragraph? */
register int firstflag; /* first word? (needs no space) */
register LINE *eopline; /* pointer to line just past EOP */
register int dotflag; /* was the last char a period? */
char wbuf[NSTRING]; /* buffer for current word */
if (curbp->b_mode&MDVIEW) /* don't allow this command if */
return(rdonly()); /* we are in read only mode */
if (fillcol == 0) { /* no fill column set */
mlwrite("No fill column set");
return(FALSE);
}
#if PKCODE
justflag = FALSE;
#endif
/* record the pointer to the line just past the EOP */
gotoeop(FALSE, 1);
eopline = lforw(curwp->w_dotp);
/* and back top the beginning of the paragraph */
gotobop(FALSE, 1);
/* initialize various info */
clength = curwp->w_doto;
if (clength && curwp->w_dotp->l_text[0] == TAB)
clength = 8;
wordlen = 0;
dotflag = FALSE;
/* scan through lines, filling words */
firstflag = TRUE;
eopflag = FALSE;
while (!eopflag) {
/* get the next character in the paragraph */
if (curwp->w_doto == llength(curwp->w_dotp)) {
c = ' ';
if (lforw(curwp->w_dotp) == eopline)
eopflag = TRUE;
} else
c = lgetc(curwp->w_dotp, curwp->w_doto);
/* and then delete it */
ldelete(1L, FALSE);
/* if not a separator, just add it in */
if (c != ' ' && c != '\t') {
dotflag = (c == '.'); /* was it a dot */
if (wordlen < NSTRING - 1)
wbuf[wordlen++] = c;
} else if (wordlen) {
/* at a word break with a word waiting */
/* calculate tentitive new length with word added */
newlength = clength + 1 + wordlen;
if (newlength <= fillcol) {
/* add word to current line */
if (!firstflag) {
linsert(1, ' '); /* the space */
++clength;
}
firstflag = FALSE;
} else {
/* start a new line */
lnewline();
clength = 0;
}
/* and add the word in in either case */
for (i=0; i<wordlen; i++) {
linsert(1, wbuf[i]);
++clength;
}
if (dotflag) {
linsert(1, ' ');
++clength;
}
wordlen = 0;
}
}
/* and add a last newline for the end of our new paragraph */
lnewline();
return(TRUE);
}
#if PKCODE
justpara(f, n) /* Fill the current paragraph according to the current
fill column and cursor position */
int f, n; /* deFault flag and Numeric argument */
{
register int c; /* current char durring scan */
register int wordlen; /* length of current word */
register int clength; /* position on line during fill */
register int i; /* index during word copy */
register int newlength; /* tentative new line length */
register int eopflag; /* Are we at the End-Of-Paragraph? */
register int firstflag; /* first word? (needs no space) */
register LINE *eopline; /* pointer to line just past EOP */
char wbuf[NSTRING]; /* buffer for current word */
int leftmarg; /* left marginal */
if (curbp->b_mode&MDVIEW) /* don't allow this command if */
return(rdonly()); /* we are in read only mode */
if (fillcol == 0) { /* no fill column set */
mlwrite("No fill column set");
return(FALSE);
}
justflag = TRUE;
leftmarg = curwp->w_doto;
if (leftmarg+10 > fillcol) {
leftmarg = 0;
mlwrite("Column too narrow");
return(FALSE);
}
/* record the pointer to the line just past the EOP */
gotoeop(FALSE, 1);
eopline = lforw(curwp->w_dotp);
/* and back top the beginning of the paragraph */
gotobop(FALSE, 1);
/* initialize various info */
if (leftmarg < llength(curwp->w_dotp))
curwp->w_doto = leftmarg;
clength = curwp->w_doto;
if (clength && curwp->w_dotp->l_text[0] == TAB)
clength = 8;
wordlen = 0;
/* scan through lines, filling words */
firstflag = TRUE;
eopflag = FALSE;
while (!eopflag) {
/* get the next character in the paragraph */
if (curwp->w_doto == llength(curwp->w_dotp)) {
c = ' ';
if (lforw(curwp->w_dotp) == eopline)
eopflag = TRUE;
} else
c = lgetc(curwp->w_dotp, curwp->w_doto);
/* and then delete it */
ldelete(1L, FALSE);
/* if not a separator, just add it in */
if (c != ' ' && c != '\t') {
if (wordlen < NSTRING - 1)
wbuf[wordlen++] = c;
} else if (wordlen) {
/* at a word break with a word waiting */
/* calculate tentitive new length with word added */
newlength = clength + 1 + wordlen;
if (newlength <= fillcol) {
/* add word to current line */
if (!firstflag) {
linsert(1, ' '); /* the space */
++clength;
}
firstflag = FALSE;
} else {
/* start a new line */
lnewline();
for (i=0; i<leftmarg; i++)
linsert(1, ' ');
clength = leftmarg;
}
/* and add the word in in either case */
for (i=0; i<wordlen; i++) {
linsert(1, wbuf[i]);
++clength;
}
wordlen = 0;
}
}
/* and add a last newline for the end of our new paragraph */
lnewline();
forwword(FALSE, 1);
if (llength(curwp->w_dotp) > leftmarg)
curwp->w_doto = leftmarg;
else
curwp->w_doto = llength(curwp->w_dotp);
justflag = FALSE;
return(TRUE);
}
#endif
killpara(f, n) /* delete n paragraphs starting with the current one */
int f; /* default flag */
int n; /* # of paras to delete */
{
register int status; /* returned status of functions */
while (n--) { /* for each paragraph to delete */
/* mark out the end and beginning of the para to delete */
gotoeop(FALSE, 1);
/* set the mark here */
curwp->w_markp = curwp->w_dotp;
curwp->w_marko = curwp->w_doto;
/* go to the beginning of the paragraph */
gotobop(FALSE, 1);
curwp->w_doto = 0; /* force us to the beginning of line */
/* and delete it */
if ((status = killregion(FALSE, 1)) != TRUE)
return(status);
/* and clean up the 2 extra lines */
ldelete(2L, TRUE);
}
return(TRUE);
}
/* wordcount: count the # of words in the marked region,
along with average word sizes, # of chars, etc,
and report on them. */
wordcount(f, n)
int f, n; /* ignored numeric arguments */
{
register LINE *lp; /* current line to scan */
register int offset; /* current char to scan */
long size; /* size of region left to count */
register int ch; /* current character to scan */
register int wordflag; /* are we in a word now? */
register int lastword; /* were we just in a word? */
long nwords; /* total # of words */
long nchars; /* total number of chars */
int nlines; /* total number of lines in region */
int avgch; /* average number of chars/word */
int status; /* status return code */
REGION region; /* region to look at */
#if PKCODE
struct {
long pk_1;
long pk_2;
int pk_3;
int pk_4;
} pk_mlrec;
#endif
/* make sure we have a region to count */
if ((status = getregion(&region)) != TRUE)
return(status);
lp = region.r_linep;
offset = region.r_offset;
size = region.r_size;
/* count up things */
lastword = FALSE;
nchars = 0L;
nwords = 0L;
nlines = 0;
while (size--) {
/* get the current character */
if (offset == llength(lp)) { /* end of line */
ch = '\n';
lp = lforw(lp);
offset = 0;
++nlines;
} else {
ch = lgetc(lp, offset);
++offset;
}
/* and tabulate it */
wordflag = (
#if PKCODE
(isletter(ch)) ||
#else
(ch >= 'a' && ch <= 'z') ||
(ch >= 'A' && ch <= 'Z') ||
#endif
(ch >= '0' && ch <= '9'));
if (wordflag == TRUE && lastword == FALSE)
++nwords;
lastword = wordflag;
++nchars;
}
/* and report on the info */
if (nwords > 0L)
avgch = (int)((100L * nchars) / nwords);
else
avgch = 0;
#if PKCODE
pk_mlrec.pk_1 = nwords;
pk_mlrec.pk_2 = nchars;
pk_mlrec.pk_3 = nlines + 1;
pk_mlrec.pk_4 = avgch;
mlwrite("%*Words %D Chars %D Lines %d Avg chars/word %f",
&pk_mlrec);
#else
mlwrite("Words %D Chars %D Lines %d Avg chars/word %f",
nwords, nchars, nlines + 1, avgch);
#endif
return(TRUE);
}
#endif