v03i029: mg 2a part 5 of 15
Bob Larson
BLARSON at ECLA.USC.EDU
Thu May 26 14:55:37 AEST 1988
comp.sources.misc: Volume 3, Issue 29
Submitted-By: "Bob Larson" <BLARSON at ECLA.USC.EDU>
Archive-Name: mg2a/Part5
# This is a shell archive.
# Remove everything above and including the cut line.
# Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar: Shell Archiver
# Run the following text with /bin/sh to create:
# basic.c
# modes.c
# paragraph.c
# region.c
# search.c
# version.c
# window.c
# word.c
# This archive created: Tue May 17 18:06:31 1988
# By: blarson
cat << \SHAR_EOF > basic.c
/*
* Basic cursor motion commands.
*
* The routines in this file are the basic
* command functions for moving the cursor around on
* the screen, setting mark, and swapping dot with
* mark. Only moves between lines, which might make the
* current buffer framing bad, are hard.
*/
#include "def.h"
VOID setgoal();
/*
* Go to beginning of line.
*/
/*ARGSUSED*/
gotobol(f, n)
{
curwp->w_doto = 0;
return (TRUE);
}
/*
* Move cursor backwards. Do the
* right thing if the count is less than
* 0. Error if you try to move back from
* the beginning of the buffer.
*/
/*ARGSUSED*/
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) {
if (!(f & FFRAND))
ewprintf("Beginning of buffer");
return (FALSE);
}
curwp->w_dotp = lp;
curwp->w_doto = llength(lp);
curwp->w_flag |= WFMOVE;
} else
curwp->w_doto--;
}
return TRUE;
}
/*
* Go to end of line.
*/
/*ARGSUSED*/
gotoeol(f, n)
{
curwp->w_doto = llength(curwp->w_dotp);
return (TRUE);
}
/*
* Move cursor forwards. Do the
* right thing if the count is less than
* 0. Error if you try to move forward
* from the end of the buffer.
*/
/*ARGSUSED*/
forwchar(f, n)
register int n;
{
if (n < 0) return backchar(f, -n);
while (n--) {
if (curwp->w_doto == llength(curwp->w_dotp)) {
curwp->w_dotp = lforw(curwp->w_dotp);
if (curwp->w_dotp == curbp->b_linep) {
curwp->w_dotp = lback(curwp->w_dotp);
if (!(f & FFRAND))
ewprintf("End of buffer");
return FALSE;
}
curwp->w_doto = 0;
curwp->w_flag |= WFMOVE;
} else
curwp->w_doto++;
}
return TRUE;
}
/*
* Go to the beginning of the
* buffer. Setting WFHARD is conservative,
* but almost always the case.
*/
gotobob(f, n)
{
(VOID) setmark(f, n) ;
curwp->w_dotp = lforw(curbp->b_linep);
curwp->w_doto = 0;
curwp->w_flag |= WFHARD;
return TRUE;
}
/*
* Go to the end of the buffer.
* Setting WFHARD is conservative, but
* almost always the case.
*/
gotoeob(f, n)
{
(VOID) setmark(f, n) ;
curwp->w_dotp = lback(curbp->b_linep);
curwp->w_doto = llength(curwp->w_dotp);
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.
*/
/*ARGSUSED*/
forwline(f, n)
{
register LINE *dlp;
if (n < 0)
return backline(f|FFRAND, -n);
if ((lastflag&CFCPCN) == 0) /* Fix goal. */
setgoal();
thisflag |= CFCPCN;
if (n == 0) return TRUE;
dlp = curwp->w_dotp;
while (dlp!=curbp->b_linep && n--)
dlp = lforw(dlp);
curwp->w_flag |= WFMOVE;
if(dlp==curbp->b_linep) { /* ^N at end of buffer creates lines (like gnu) */
if(!(curbp->b_flag&BFCHG)) { /* first change */
curbp->b_flag |= BFCHG;
curwp->w_flag |= WFMODE;
}
curwp->w_doto = 0;
while(n-- >= 0) {
if((dlp = lallocx(0)) == NULL) return FALSE;
dlp->l_fp = curbp->b_linep;
dlp->l_bp = lback(dlp->l_fp);
dlp->l_bp->l_fp = dlp->l_fp->l_bp = dlp;
}
curwp->w_dotp = lback(curbp->b_linep);
} else {
curwp->w_dotp = dlp;
curwp->w_doto = getgoal(dlp);
}
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.
*/
/*ARGSUSED*/
backline(f, n)
{
register LINE *dlp;
if (n < 0) return forwline(f|FFRAND, -n);
if ((lastflag&CFCPCN) == 0) /* Fix goal. */
setgoal();
thisflag |= CFCPCN;
dlp = curwp->w_dotp;
while (n-- && lback(dlp)!=curbp->b_linep)
dlp = lback(dlp);
curwp->w_dotp = dlp;
curwp->w_doto = getgoal(dlp);
curwp->w_flag |= WFMOVE;
return TRUE;
}
/*
* Set the current goal column,
* which is saved in the external variable "curgoal",
* to the current cursor column. The column is never off
* the edge of the screen; it's more like display then
* show position.
*/
VOID
setgoal() {
curgoal = getcolpos() - 1; /* Get the position. */
/* we can now display past end of display, don't chop! */
}
/*
* This routine looks at a line (pointed
* to by the LINE pointer "dlp") and the current
* vertical motion goal column (set by the "setgoal"
* routine above) and returns the best offset to use
* when a vertical motion is made into the line.
*/
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'
#ifdef NOTAB
&& !(curbp->b_flag & BFNOTAB)
#endif
)
newcol |= 0x07;
else if (ISCTRL(c) != FALSE)
++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.
* The "2" is the window overlap (this is the default
* value from ITS EMACS). Because the top line in
* the window is zapped, we have to do a hard
* update and get it back.
*/
/*ARGSUSED*/
forwpage(f, n)
register int n;
{
register LINE *lp;
if (!(f & FFARG)) {
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|FFRAND, -n);
#ifdef CVMVAS
else /* Convert from pages */
n *= curwp->w_ntrows; /* to lines. */
#endif
lp = curwp->w_linep;
while (n-- && lforw(lp)!=curbp->b_linep)
lp = lforw(lp);
curwp->w_linep = lp;
curwp->w_flag |= WFHARD;
/* if in current window, don't move dot */
for(n = curwp->w_ntrows; n-- && lp!=curbp->b_linep; lp = lforw(lp))
if(lp==curwp->w_dotp) return TRUE;
curwp->w_dotp = curwp->w_linep;
curwp->w_doto = 0;
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. The
* hard update is done because the top line in
* the window is zapped.
*/
/*ARGSUSED*/
backpage(f, n)
register int n;
{
register LINE *lp;
if (!(f & FFARG)) {
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|FFRAND, -n);
#ifdef 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_flag |= WFHARD;
/* if in current window, don't move dot */
for(n = curwp->w_ntrows; n-- && lp!=curbp->b_linep; lp = lforw(lp))
if(lp==curwp->w_dotp) return TRUE;
curwp->w_dotp = curwp->w_linep;
curwp->w_doto = 0;
return TRUE;
}
/* These functions are provided for compatibility with Gosling's Emacs.
* They are used to scroll the display up (or down) one line at a time.
*/
#ifdef GOSMACS
forw1page(f, n)
int f, n;
{
if (!(f & FFARG)) {
n = 1;
f = FFUNIV;
}
forwpage(f|FFRAND, n);
}
back1page(f, n)
int f, n;
{
if (!(f & FFARG)) {
n = 1;
f = FFUNIV;
}
backpage(f|FFRAND, n);
}
#endif
/*
* Page the other window. Check to make sure it exists, then
* nextwind, forwpage and restore window pointers.
*/
pagenext(f, n)
{
register WINDOW *wp;
if (wheadp->w_wndp == NULL) {
ewprintf("No other window");
return FALSE;
}
wp = curwp;
(VOID) nextwind(f, n);
(VOID) forwpage(f, n);
curwp = wp;
curbp = wp->w_bufp;
return TRUE;
}
/*
* Internal set mark routine, used by other functions (daveb).
*/
VOID
isetmark()
{
curwp->w_markp = curwp->w_dotp;
curwp->w_marko = curwp->w_doto;
}
/*
* Set the mark in the current window
* to the value of dot. A message is written to
* the echo line. (ewprintf knows about macros)
*/
/*ARGSUSED*/
setmark(f, n)
{
isetmark();
ewprintf("Mark set");
return TRUE;
}
/*
* Swap the values of "dot" and "mark" in
* the current window. This is pretty easy, because
* all of the hard work gets done by the standard routine
* that moves the mark about. The only possible
* error is "no mark".
*/
/*ARGSUSED*/
swapmark(f, n)
{
register LINE *odotp;
register int odoto;
if (curwp->w_markp == NULL) {
ewprintf("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;
}
/*
* Go to a specific line, mostly for
* looking up errors in C programs, which give the
* error a line number. If an argument is present, then
* it is the line number, else prompt for a line number
* to use.
*/
/*ARGSUSED*/
gotoline(f, n)
register int n;
{
register LINE *clp;
register int s;
char buf[32];
if (!(f & FFARG)) {
if ((s=ereply("Goto line: ", buf, sizeof(buf))) != TRUE)
return s;
n = atoi(buf);
}
if (n > 0) {
clp = lforw(curbp->b_linep); /* "clp" is first line */
while (--n > 0) {
if (lforw(clp) == curbp->b_linep) break;
clp = lforw(clp);
}
} else {
clp = lback(curbp->b_linep); /* clp is last line */
while (n < 0) {
if (lback(clp) == curbp->b_linep) break;
clp = lback(clp);
n++;
}
}
curwp->w_dotp = clp;
curwp->w_doto = 0;
curwp->w_flag |= WFMOVE;
return TRUE;
}
SHAR_EOF
cat << \SHAR_EOF > modes.c
/*
* Commands to toggle modes. Without an argument, toggle mode.
* Negitive or zero argument, mode off. Positive argument, mode on.
*/
#include "def.h"
#include "kbd.h"
int defb_nmodes = 0;
MAPS *defb_modes[PBMODES] = {&map_table[0]};
int defb_flag = 0;
static int changemode(f, n, mode)
int f, n;
char *mode;
{
register int i;
MAPS *m;
VOID upmodes();
if((m = name_mode(mode)) == NULL) {
ewprintf("Can't find mode %s", mode);
return FALSE;
}
if(!(f & FFARG)) {
for(i=0; i <= curbp->b_nmodes; i++)
if(curbp->b_modes[i] == m) {
n = 0; /* mode already set */
break;
}
}
if(n > 0) {
for(i=0; i <= curbp->b_nmodes; i++)
if(curbp->b_modes[i] == m) return TRUE; /* mode already set */
if(curbp->b_nmodes >= PBMODES-1) {
ewprintf("Too many modes");
return FALSE;
}
curbp->b_modes[++(curbp->b_nmodes)] = m;
} else {
/* fundamental is b_modes[0] and can't be unset */
for(i=1; i <= curbp->b_nmodes && m != curbp->b_modes[i]; i++) {}
if(i > curbp->b_nmodes) return TRUE; /* mode wasn't set */
for(; i < curbp->b_nmodes; i++)
curbp->b_modes[i] = curbp->b_modes[i+1];
curbp->b_nmodes--;
}
upmodes(curbp);
return TRUE;
}
indentmode(f, n)
{
return changemode(f, n, "indent");
}
fillmode(f, n)
{
return changemode(f, n, "fill");
}
/*
* Fake the GNU "blink-matching-paren" variable.
*/
blinkparen(f, n)
{
return changemode(f, n, "blink");
}
#ifdef NOTAB
notabmode(f, n)
{
if(changemode(f, n, "notab") == FALSE) return FALSE;
if(f & FFARG) {
if(n <= 0) curbp->b_flag &= ~BFNOTAB;
else curbp->b_flag |= BFNOTAB;
} else curbp->b_flag ^= BFNOTAB;
return TRUE;
}
#endif
overwrite(f, n)
int f, n;
{
if(changemode(f, n, "overwrite") == FALSE) return FALSE;
if(f & FFARG) {
if(n <= 0) curbp->b_flag &= ~BFOVERWRITE;
else curbp->b_flag |= BFOVERWRITE;
} else curbp->b_flag ^= BFOVERWRITE;
return TRUE;
}
set_default_mode(f, n)
int f, n;
{
register int i;
register MAPS *m;
char mode[32];
if(eread("Set Default Mode: ", mode, 32, EFNEW) != TRUE)
return ABORT;
if((m = name_mode(mode)) == NULL) {
ewprintf("can't find mode %s", mode);
return FALSE;
}
if(!(f & FFARG)) {
for(i=0; i <= defb_nmodes; i++)
if(defb_modes[i] == m) {
n = 0; /* mode already set */
break;
}
}
if(n > 0) {
for(i=0; i <= defb_nmodes; i++)
if(defb_modes[i] == m) return TRUE; /* mode already set */
if(defb_nmodes >= PBMODES-1) {
ewprintf("Too many modes");
return FALSE;
}
defb_modes[++defb_nmodes] = m;
} else {
/* fundamental is defb_modes[0] and can't be unset */
for(i=1; i <= defb_nmodes && m != defb_modes[i]; i++) {}
if(i > defb_nmodes) return TRUE; /* mode wasn't set */
for(; i < defb_nmodes; i++)
defb_modes[i] = defb_modes[i+1];
defb_nmodes--;
}
if(strcmp(mode, "overwrite")==0)
if(n<=0) defb_flag &= ~BFOVERWRITE;
else defb_flag |= BFOVERWRITE;
#ifdef NOTAB
if(strcmp(mode, "notab")==0)
if(n<=0) defb_flag &= ~BFNOTAB;
else defb_flag |= BFNOTAB;
#endif
return TRUE;
}
SHAR_EOF
cat << \SHAR_EOF > paragraph.c
/*
* Code for dealing with paragraphs and filling. Adapted from MicroEMACS 3.6
* and GNU-ified by mwm at ucbvax. Several bug fixes by blarson at usc-oberon.
*/
#include "def.h"
static int fillcol = 70 ;
#define MAXWORD 256
/*
* go back to the begining of the current paragraph
* here we look for a <NL><NL> or <NL><TAB> or <NL><SPACE>
* combination to delimit the begining of a paragraph
*/
/*ARGSUSED*/
gotobop(f, n)
{
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 */
while (backchar(FFRAND, 1) && !inword()) {}
curwp->w_doto = 0; /* and go to the B-O-Line */
/* and scan back until we hit a <NL><SP> <NL><TAB> or <NL><NL> */
while (lback(curwp->w_dotp) != curbp->b_linep)
if (llength(lback(curwp->w_dotp))
&& lgetc(curwp->w_dotp,0) != ' '
&& lgetc(curwp->w_dotp,0) != '\t')
curwp->w_dotp = lback(curwp->w_dotp);
else
break;
}
curwp->w_flag |= WFMOVE; /* force screen update */
return TRUE;
}
/*
* 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 begining of a paragraph
*/
/*ARGSUSED*/
gotoeop(f, n)
{
if (n < 0) /* the other way...*/
return gotobop(f, -n);
while (n-- > 0) { /* for each one asked for */
/* Find the first word on/after the current line */
curwp->w_doto = 0;
while(forwchar(FFRAND, 1) && !inword()) {}
curwp->w_doto = 0;
curwp->w_dotp = lforw(curwp->w_dotp);
/* and scan forword until we hit a <NL><SP> or ... */
while (curwp->w_dotp != curbp->b_linep) {
if (llength(curwp->w_dotp)
&& lgetc(curwp->w_dotp,0) != ' '
&& lgetc(curwp->w_dotp,0) != '\t')
curwp->w_dotp = lforw(curwp->w_dotp);
else
break;
}
if(curwp->w_dotp == curbp->b_linep) {
/* beond end of buffer, cleanup time */
curwp->w_dotp = lback(curwp->w_dotp);
curwp->w_doto = llength(curwp->w_dotp);
break;
}
}
curwp->w_flag |= WFMOVE; /* force screen update */
return TRUE;
}
/*
* Fill the current paragraph according to the current
* fill column
*/
/*ARGSUSED*/
fillpara(f, n)
{
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 eopflag; /* Are we at the End-Of-Paragraph? */
int firstflag; /* first word? (needs no space) */
int newlength; /* tentative new line length */
int eolflag; /* was at end of line */
LINE *eopline; /* pointer to line just past EOP */
char wbuf[MAXWORD]; /* buffer for current word */
/* record the pointer to the line just past the EOP */
(VOID) gotoeop(FFRAND, 1);
if(curwp->w_doto != 0) {
/* paragraph ends at end of buffer */
(VOID) lnewline();
eopline = lforw(curwp->w_dotp);
} else eopline = curwp->w_dotp;
/* and back top the begining of the paragraph */
(VOID) gotobop(FFRAND, 1);
/* initialize various info */
while (!inword() && forwchar(FFRAND, 1)) {}
clength = curwp->w_doto;
wordlen = 0;
/* scan through lines, filling words */
firstflag = TRUE;
eopflag = FALSE;
while (!eopflag) {
/* get the next character in the paragraph */
if (eolflag=(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 */
if (ldelete((RSIZE) 1, KNONE) == FALSE && !eopflag)
return FALSE;
/* if not a separator, just add it in */
if (c != ' ' && c != '\t') {
if (wordlen < MAXWORD - 1)
wbuf[wordlen++] = c;
else {
/* You loose chars beyond MAXWORD if the word
* is to long. I'm to lazy to fix it now; it
* just silently truncated the word before, so
* I get to feel smug.
*/
ewprintf("Word too long!");
}
} else if (wordlen) {
/* calculate tenatitive new length with word added */
newlength = clength + 1 + wordlen;
/* if at end of line or at doublespace and previous
* character was one of '.','?','!' doublespace here.
*/
if((eolflag || curwp->w_doto==llength(curwp->w_dotp)
|| (c=lgetc(curwp->w_dotp,curwp->w_doto))==' '
|| c=='\t')
&& ISEOSP(wbuf[wordlen-1])
&& wordlen<MAXWORD-1)
wbuf[wordlen++] = ' ';
/* at a word break with a word waiting */
if (newlength <= fillcol) {
/* add word to current line */
if (!firstflag) {
(VOID) linsert(1, ' ');
++clength;
}
firstflag = FALSE;
} else {
if(curwp->w_doto > 0 &&
lgetc(curwp->w_dotp,curwp->w_doto-1)==' ') {
curwp->w_doto -= 1;
(VOID) ldelete((RSIZE) 1, KNONE);
}
/* start a new line */
(VOID) lnewline();
clength = 0;
}
/* and add the word in in either case */
for (i=0; i<wordlen; i++) {
(VOID) linsert(1, wbuf[i]);
++clength;
}
wordlen = 0;
}
}
/* and add a last newline for the end of our new paragraph */
(VOID) lnewline();
/* we realy should wind up where we started, (which is hard to keep
* track of) but I think the end of the last line is better than the
* begining of the blank line. */
(VOID) backchar(FFRAND, 1);
return TRUE;
}
/* delete n paragraphs starting with the current one */
/*ARGSUSED*/
killpara(f, n)
{
register int status; /* returned status of functions */
while (n--) { /* for each paragraph to delete */
/* mark out the end and begining of the para to delete */
(VOID) gotoeop(FFRAND, 1);
/* set the mark here */
curwp->w_markp = curwp->w_dotp;
curwp->w_marko = curwp->w_doto;
/* go to the begining of the paragraph */
(VOID) gotobop(FFRAND, 1);
curwp->w_doto = 0; /* force us to the begining of line */
/* and delete it */
if ((status = killregion(FFRAND, 1)) != TRUE)
return status;
/* and clean up the 2 extra lines */
(VOID) ldelete((RSIZE) 1, KFORW);
}
return TRUE;
}
/*
* check to see if we're past fillcol, and if so,
* justify this line. As a last step, justify the line.
*/
/*ARGSUSED*/
fillword(f, n)
{
register char c;
register int col, i, nce;
for (i = col = 0; col <= fillcol; ++i, ++col) {
if (i == curwp->w_doto) return selfinsert(f, n) ;
c = lgetc(curwp->w_dotp, i);
if (c == '\t'
#ifdef NOTAB
&& !(curbp->b_flag & BFNOTAB)
#endif
) col |= 0x07;
else if (ISCTRL(c) != FALSE) ++col;
}
if (curwp->w_doto != llength(curwp->w_dotp)) {
(VOID) selfinsert(f, n);
nce = llength(curwp->w_dotp) - curwp->w_doto;
} else nce = 0;
curwp->w_doto = i;
if ((c = lgetc(curwp->w_dotp, curwp->w_doto)) != ' ' && c != '\t')
do {
(VOID) backchar(FFRAND, 1);
} while ((c = lgetc(curwp->w_dotp, curwp->w_doto)) != ' '
&& c != '\t' && curwp->w_doto > 0);
if (curwp->w_doto == 0)
do {
(VOID) forwchar(FFRAND, 1);
} while ((c = lgetc(curwp->w_dotp, curwp->w_doto)) != ' '
&& c != '\t' && curwp->w_doto < llength(curwp->w_dotp));
(VOID) delwhite(FFRAND, 1);
(VOID) lnewline();
i = llength(curwp->w_dotp) - nce;
curwp->w_doto = i>0 ? i : 0;
curwp->w_flag |= WFMOVE;
if (nce == 0 && curwp->w_doto != 0) return fillword(f, n);
return TRUE;
}
/* Set fill column to n. */
setfillcol(f, n) {
extern int getcolpos() ;
fillcol = ((f & FFARG) ? n : getcolpos());
ewprintf("Fill column set to %d", fillcol);
return TRUE;
}
SHAR_EOF
cat << \SHAR_EOF > region.c
/*
* Region based commands.
* The routines in this file
* deal with the region, that magic space
* between "." and mark. Some functions are
* commands. Some functions are just for
* internal use.
*/
#include "def.h"
/*
* Kill the region. Ask "getregion"
* to figure out the bounds of the region.
* Move "." to the start, and kill the characters.
*/
/*ARGSUSED*/
killregion(f, n)
{
register int s;
REGION region;
if ((s=getregion(®ion)) != TRUE)
return (s);
if ((lastflag&CFKILL) == 0) /* This is a kill type */
kdelete(); /* command, so do magic */
thisflag |= CFKILL; /* kill buffer stuff. */
curwp->w_dotp = region.r_linep;
curwp->w_doto = region.r_offset;
return (ldelete(region.r_size, KFORW));
}
/*
* 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.
*/
/*ARGSUSED*/
copyregion(f, n)
{
register LINE *linep;
register int loffs;
register int s;
REGION region;
VOID kdelete();
if ((s=getregion(®ion)) != TRUE)
return s;
if ((lastflag&CFKILL) == 0) /* Kill type command. */
kdelete();
thisflag |= CFKILL;
linep = region.r_linep; /* Current line. */
loffs = region.r_offset; /* Current offset. */
while (region.r_size--) {
if (loffs == llength(linep)) { /* End of line. */
if ((s=kinsert('\n', KFORW)) != TRUE)
return (s);
linep = lforw(linep);
loffs = 0;
} else { /* Middle of line. */
if ((s=kinsert(lgetc(linep, loffs), KFORW)) != TRUE)
return s;
++loffs;
}
}
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.
*/
/*ARGSUSED*/
lowerregion(f, n)
{
register LINE *linep;
register int loffs;
register int c;
register int s;
REGION region;
if ((s=getregion(®ion)) != TRUE)
return s;
lchange(WFHARD);
linep = region.r_linep;
loffs = region.r_offset;
while (region.r_size--) {
if (loffs == llength(linep)) {
linep = lforw(linep);
loffs = 0;
} else {
c = lgetc(linep, loffs);
if (ISUPPER(c) != FALSE)
lputc(linep, loffs, TOLOWER(c));
++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.
*/
/*ARGSUSED*/
upperregion(f, n)
{
register LINE *linep;
register int loffs;
register int c;
register int s;
REGION region;
VOID lchange();
if ((s=getregion(®ion)) != TRUE)
return s;
lchange(WFHARD);
linep = region.r_linep;
loffs = region.r_offset;
while (region.r_size--) {
if (loffs == llength(linep)) {
linep = lforw(linep);
loffs = 0;
} else {
c = lgetc(linep, loffs);
if (ISLOWER(c) != FALSE)
lputc(linep, loffs, TOUPPER(c));
++loffs;
}
}
return TRUE;
}
/*
* This routine figures out the bound of the region
* in the current window, and stores the results into the fields
* of the REGION structure. Dot and mark are usually close together,
* but I don't know the order, so I scan outward from dot, in both
* directions, looking for mark. The size is kept in a long. At the
* end, after the size is figured out, it is assigned to the size
* field of the region structure. If this assignment loses any bits,
* then we print an error. This is "type independent" overflow
* checking. All of the callers of this routine should be ready to
* get an ABORT status, because I might add a "if regions is big,
* ask before clobberring" flag.
*/
getregion(rp) register REGION *rp; {
register LINE *flp;
register LINE *blp;
register long fsize; /* Long now. */
register long bsize;
if (curwp->w_markp == NULL) {
ewprintf("No mark set in this window");
return (FALSE);
}
if (curwp->w_dotp == curwp->w_markp) { /* "r_size" always ok. */
rp->r_linep = curwp->w_dotp;
if (curwp->w_doto < curwp->w_marko) {
rp->r_offset = curwp->w_doto;
rp->r_size = (RSIZE) (curwp->w_marko-curwp->w_doto);
} else {
rp->r_offset = curwp->w_marko;
rp->r_size = (RSIZE) (curwp->w_doto-curwp->w_marko);
}
return TRUE;
}
flp = blp = curwp->w_dotp; /* Get region size. */
bsize = curwp->w_doto;
fsize = llength(flp)-curwp->w_doto+1;
while (lforw(flp)!=curbp->b_linep || lback(blp)!=curbp->b_linep) {
if (lforw(flp) != curbp->b_linep) {
flp = lforw(flp);
if (flp == curwp->w_markp) {
rp->r_linep = curwp->w_dotp;
rp->r_offset = curwp->w_doto;
return (setsize(rp,
(RSIZE) (fsize+curwp->w_marko)));
}
fsize += llength(flp)+1;
}
if (lback(blp) != curbp->b_linep) {
blp = lback(blp);
bsize += llength(blp)+1;
if (blp == curwp->w_markp) {
rp->r_linep = blp;
rp->r_offset = curwp->w_marko;
return (setsize(rp,
(RSIZE) (bsize-curwp->w_marko)));
}
}
}
ewprintf("Bug: lost mark"); /* Gak! */
return FALSE;
}
/*
* Set size, and check for overflow.
*/
setsize(rp, size) register REGION *rp; register RSIZE size; {
rp->r_size = size;
if (rp->r_size != size) {
ewprintf("Region is too large");
return FALSE;
}
return TRUE;
}
#ifdef PREFIXREGION
/*
* Implements one of my favorite keyboard macros; put a string at the
* beginning of a number of lines in a buffer. The quote string is
* settable by using set-prefix-string. Great for quoting mail, which
* is the real reason I wrote it, but also has uses for creating bar
* comments (like the one you're reading) in C code.
*/
#define PREFIXLENGTH 40
static char prefix_string[PREFIXLENGTH] = { '>', '\0' };
/*
* Prefix the region with whatever is in prefix_string.
* Leaves dot at the beginning of the line after the end
* of the region. If an argument is given, prompts for the
* line prefix string.
*/
/*ARGSUSED*/
prefixregion(f, n)
{
register int s;
register LINE *first, *last;
register int nline;
REGION region;
char *prefix = prefix_string;
if ((f == TRUE) && ((s = setprefix(FFRAND, 1)) != TRUE))
return s;
/* get # of lines to affect */
if ((s = getregion(®ion)) != TRUE)
return (s);
first = region.r_linep;
last = (first == curwp->w_dotp) ? curwp->w_markp : curwp->w_dotp;
for (nline = 1; first != last; nline++)
first = lforw(first);
/*move to beginning of region */
curwp->w_dotp = region.r_linep;
curwp->w_doto = region.r_offset;
/* for each line, go to beginning and insert the prefix string */
while (nline--) {
(VOID) gotobol(FFRAND, 1);
for (prefix = prefix_string; *prefix; prefix++)
(VOID) linsert(1, *prefix);
(VOID) forwline(FFRAND, 1);
}
(VOID) gotobol(FFRAND, 1);
return TRUE;
}
/*
* Set prefix string.
*/
/*ARGSUSED*/
setprefix(f, n)
{
char buf[PREFIXLENGTH];
register int s;
if (prefix_string[0] == '\0')
s = ereply("Prefix string: ",buf,sizeof buf);
else
s = ereply("Prefix string (default %s): ",
buf,sizeof buf,prefix_string);
if (s == TRUE)
(VOID) strcpy(prefix_string, buf);
if ((s == FALSE) && (prefix_string[0] != '\0')) /* CR -- use old one */
s = TRUE;
return s;
}
#endif
SHAR_EOF
cat << \SHAR_EOF > search.c
/*
* Search commands.
* The functions in this file implement the
* search commands (both plain and incremental searches
* are supported) and the query-replace command.
*
* The plain old search code is part of the original
* MicroEMACS "distribution". The incremental search code,
* and the query-replace code, is by Rich Ellison.
*/
#include "def.h"
#ifndef NO_MACRO
#include "macro.h"
#endif
#define SRCH_BEGIN (0) /* Search sub-codes. */
#define SRCH_FORW (-1)
#define SRCH_BACK (-2)
#define SRCH_NOPR (-3)
#define SRCH_ACCM (-4)
#define SRCH_MARK (-5)
typedef struct {
int s_code;
LINE *s_dotp;
int s_doto;
} SRCHCOM;
static SRCHCOM cmds[NSRCH];
static int cip;
int srch_lastdir = SRCH_NOPR; /* Last search flags. */
static VOID is_cpush();
static VOID is_lpush();
static VOID is_pop();
static int is_peek();
static VOID is_undo();
static int is_find();
static VOID is_prompt();
static VOID is_dspl();
static int eq();
/*
* Search forward.
* Get a search string from the user, and search for it,
* starting at ".". If found, "." gets moved to just after the
* matched characters, and display does all the hard stuff.
* If not found, it just prints a message.
*/
/*ARGSUSED*/
forwsearch(f, n)
{
register int s;
if ((s=readpattern("Search")) != TRUE)
return s;
if (forwsrch() == FALSE) {
ewprintf("Search failed: \"%s\"", pat);
return FALSE;
}
srch_lastdir = SRCH_FORW;
return TRUE;
}
/*
* Reverse search.
* Get a search string from the user, and search, starting at "."
* and proceeding toward the front of the buffer. If found "." is left
* pointing at the first character of the pattern [the last character that
* was matched].
*/
/*ARGSUSED*/
backsearch(f, n)
{
register int s;
if ((s=readpattern("Search backward")) != TRUE)
return (s);
if (backsrch() == FALSE) {
ewprintf("Search failed: \"%s\"", pat);
return FALSE;
}
srch_lastdir = SRCH_BACK;
return TRUE;
}
/*
* Search again, using the same search string
* and direction as the last search command. The direction
* has been saved in "srch_lastdir", so you know which way
* to go.
*/
/*ARGSUSED*/
searchagain(f, n)
{
if (srch_lastdir == SRCH_FORW) {
if (forwsrch() == FALSE) {
ewprintf("Search failed: \"%s\"", pat);
return FALSE;
}
return TRUE;
}
if (srch_lastdir == SRCH_BACK) {
if (backsrch() == FALSE) {
ewprintf("Search failed: \"%s\"", pat);
return FALSE;
}
return TRUE;
}
ewprintf("No last search");
return FALSE;
}
/*
* Use incremental searching, initially in the forward direction.
* isearch ignores any explicit arguments.
*/
/*ARGSUSED*/
forwisearch(f, n)
{
return isearch(SRCH_FORW);
}
/*
* Use incremental searching, initially in the reverse direction.
* isearch ignores any explicit arguments.
*/
/*ARGSUSED*/
backisearch(f, n)
{
return isearch(SRCH_BACK);
}
/*
* Incremental Search.
* dir is used as the initial direction to search.
* ^S switch direction to forward
* ^R switch direction to reverse
* ^Q quote next character (allows searching for ^N etc.)
* <ESC> exit from Isearch
* <DEL> undoes last character typed. (tricky job to do this correctly).
* other ^ exit search, don't set mark
* else accumulate into search string
*/
isearch(dir) {
register int c;
register LINE *clp;
register int cbo;
register int success;
int pptr;
char opat[NPAT];
VOID ungetkey();
#ifndef NO_MACRO
if(macrodef) {
ewprintf("Can't isearch in macro");
return FALSE;
}
#endif
for (cip=0; cip<NSRCH; cip++)
cmds[cip].s_code = SRCH_NOPR;
(VOID) strcpy(opat, pat);
cip = 0;
pptr = -1;
clp = curwp->w_dotp;
cbo = curwp->w_doto;
is_lpush();
is_cpush(SRCH_BEGIN);
success = TRUE;
is_prompt(dir, TRUE, success);
for (;;) {
update();
switch (c = getkey(FALSE)) {
case CCHR('['):
srch_lastdir = dir;
curwp->w_markp = clp;
curwp->w_marko = cbo;
ewprintf("Mark set");
return (TRUE);
case CCHR('G'):
if (success != TRUE) {
while (is_peek() == SRCH_ACCM)
is_undo(&pptr, &dir);
success = TRUE;
is_prompt(dir, pptr < 0, success);
break;
}
curwp->w_dotp = clp;
curwp->w_doto = cbo;
curwp->w_flag |= WFMOVE;
srch_lastdir = dir;
(VOID) ctrlg(FFRAND, 0);
(VOID) strcpy(pat, opat);
return ABORT;
case CCHR(']'):
case CCHR('S'):
if (dir == SRCH_BACK) {
dir = SRCH_FORW;
is_lpush();
is_cpush(SRCH_FORW);
success = TRUE;
}
if (success==FALSE && dir==SRCH_FORW)
break;
is_lpush();
pptr = strlen(pat);
(VOID) forwchar(FFRAND, 1);
if (is_find(SRCH_FORW) != FALSE) is_cpush(SRCH_MARK);
else {
(VOID) backchar(FFRAND, 1);
ttbeep();
success = FALSE;
}
is_prompt(dir, pptr < 0, success);
break;
case CCHR('R'):
if (dir == SRCH_FORW) {
dir = SRCH_BACK;
is_lpush();
is_cpush(SRCH_BACK);
success = TRUE;
}
if (success==FALSE && dir==SRCH_BACK)
break;
is_lpush();
pptr = strlen(pat);
(VOID) backchar(FFRAND, 1);
if (is_find(SRCH_BACK) != FALSE) is_cpush(SRCH_MARK);
else {
(VOID) forwchar(FFRAND, 1);
ttbeep();
success = FALSE;
}
is_prompt(dir, pptr < 0, success);
break;
case CCHR('H'):
case CCHR('?'):
is_undo(&pptr, &dir);
if (is_peek() != SRCH_ACCM) success = TRUE;
is_prompt(dir, pptr < 0, success);
break;
case CCHR('\\'):
case CCHR('Q'):
c = (char) getkey(FALSE);
goto addchar;
case CCHR('M'):
c = CCHR('J');
goto addchar;
default:
if (ISCTRL(c)) {
ungetkey(c);
curwp->w_markp = clp;
curwp->w_marko = cbo;
ewprintf("Mark set");
curwp->w_flag |= WFMOVE;
return TRUE;
} /* and continue */
case CCHR('I'):
case CCHR('J'):
addchar:
if (pptr == -1)
pptr = 0;
if (pptr == 0)
success = TRUE;
pat[pptr++] = c;
if (pptr == NPAT) {
ewprintf("Pattern too long");
return FALSE;
}
pat[pptr] = '\0';
is_lpush();
if (success != FALSE) {
if (is_find(dir) != FALSE)
is_cpush(c);
else {
success = FALSE;
ttbeep();
is_cpush(SRCH_ACCM);
}
} else
is_cpush(SRCH_ACCM);
is_prompt(dir, FALSE, success);
}
}
/*NOTREACHED*/
}
static VOID
is_cpush(cmd) register int cmd; {
if (++cip >= NSRCH)
cip = 0;
cmds[cip].s_code = cmd;
}
static VOID
is_lpush() {
register int ctp;
ctp = cip+1;
if (ctp >= NSRCH)
ctp = 0;
cmds[ctp].s_code = SRCH_NOPR;
cmds[ctp].s_doto = curwp->w_doto;
cmds[ctp].s_dotp = curwp->w_dotp;
}
static VOID
is_pop() {
if (cmds[cip].s_code != SRCH_NOPR) {
curwp->w_doto = cmds[cip].s_doto;
curwp->w_dotp = cmds[cip].s_dotp;
curwp->w_flag |= WFMOVE;
cmds[cip].s_code = SRCH_NOPR;
}
if (--cip <= 0)
cip = NSRCH-1;
}
static int
is_peek() {
return cmds[cip].s_code;
}
/* this used to always return TRUE (the return value was checked) */
static VOID
is_undo(pptr, dir) register int *pptr; register int *dir; {
register int redo = FALSE ;
switch (cmds[cip].s_code) {
case SRCH_BEGIN:
case SRCH_NOPR:
*pptr = -1;
case SRCH_MARK:
break;
case SRCH_FORW:
*dir = SRCH_BACK;
redo = TRUE;
break;
case SRCH_BACK:
*dir = SRCH_FORW;
redo = TRUE;
break;
case SRCH_ACCM:
default:
*pptr -= 1;
if (*pptr < 0)
*pptr = 0;
pat[*pptr] = '\0';
break;
}
is_pop();
if (redo) is_undo(pptr, dir);
}
static int
is_find(dir) register int dir; {
register int plen, odoto;
register LINE *odotp ;
odoto = curwp->w_doto;
odotp = curwp->w_dotp;
plen = strlen(pat);
if (plen != 0) {
if (dir==SRCH_FORW) {
(VOID) backchar(FFARG | FFRAND, plen);
if (forwsrch() == FALSE) {
curwp->w_doto = odoto;
curwp->w_dotp = odotp;
return FALSE;
}
return TRUE;
}
if (dir==SRCH_BACK) {
(VOID) forwchar(FFARG | FFRAND, plen);
if (backsrch() == FALSE) {
curwp->w_doto = odoto;
curwp->w_dotp = odotp;
return FALSE;
}
return TRUE;
}
ewprintf("bad call to is_find");
return FALSE;
}
return FALSE;
}
/*
* If called with "dir" not one of SRCH_FORW
* or SRCH_BACK, this routine used to print an error
* message. It also used to return TRUE or FALSE,
* depending on if it liked the "dir". However, none
* of the callers looked at the status, so I just
* made the checking vanish.
*/
static VOID
is_prompt(dir, flag, success) {
if (dir == SRCH_FORW) {
if (success != FALSE)
is_dspl("I-search", flag);
else
is_dspl("Failing I-search", flag);
} else if (dir == SRCH_BACK) {
if (success != FALSE)
is_dspl("I-search backward", flag);
else
is_dspl("Failing I-search backward", flag);
} else ewprintf("Broken call to is_prompt");
}
/*
* Prompt writing routine for the incremental search.
* The "prompt" is just a string. The "flag" determines
* whether pat should be printed.
*/
static VOID
is_dspl(prompt, flag) char *prompt; {
if (flag != FALSE)
ewprintf("%s: ", prompt);
else
ewprintf("%s: %s", prompt, pat);
}
/*
* Query Replace.
* Replace strings selectively. Does a search and replace operation.
*/
/*ARGSUSED*/
queryrepl(f, n)
{
register int s;
register int rcnt = 0; /* Replacements made so far */
register int plen; /* length of found string */
char news[NPAT]; /* replacement string */
#ifndef NO_MACRO
if(macrodef) {
ewprintf("Can't query replace in macro");
return FALSE;
}
#endif
if ((s=readpattern("Query replace")) != TRUE)
return (s);
if ((s=ereply("Query replace %s with: ",news, NPAT, pat)) == ABORT)
return (s);
if (s == FALSE)
news[0] = '\0';
ewprintf("Query replacing %s with %s:", pat, news);
plen = strlen(pat);
/*
* Search forward repeatedly, checking each time whether to insert
* or not. The "!" case makes the check always true, so it gets put
* into a tighter loop for efficiency.
*/
while (forwsrch() == TRUE) {
retry:
update();
switch (getkey(FALSE)) {
case ' ':
if (lreplace((RSIZE) plen, news, f) == FALSE)
return (FALSE);
rcnt++;
break;
case '.':
if (lreplace((RSIZE) plen, news, f) == FALSE)
return (FALSE);
rcnt++;
goto stopsearch;
case CCHR('G'): /* ^G or ESC */
(VOID) ctrlg(FFRAND, 0);
case CCHR('['):
goto stopsearch;
case '!':
do {
if (lreplace((RSIZE) plen, news, f) == FALSE)
return (FALSE);
rcnt++;
} while (forwsrch() == TRUE);
goto stopsearch;
case CCHR('H'):
case CCHR('?'): /* To not replace */
break;
default:
ewprintf("<SP> replace, [.] rep-end, <DEL> don't, [!] repl rest <ESC> quit");
goto retry;
}
}
stopsearch:
curwp->w_flag |= WFHARD;
update();
if (rcnt == 0)
ewprintf("(No replacements done)");
else if (rcnt == 1)
ewprintf("(1 replacement done)");
else
ewprintf("(%d replacements done)", rcnt);
return TRUE;
}
/*
* This routine does the real work of a
* forward search. The pattern is sitting in the external
* variable "pat". If found, dot is updated, the window system
* is notified of the change, and TRUE is returned. If the
* string isn't found, FALSE is returned.
*/
forwsrch() {
register LINE *clp;
register int cbo;
register LINE *tlp;
register int tbo;
char *pp;
register int c;
clp = curwp->w_dotp;
cbo = curwp->w_doto;
for(;;) {
if (cbo == llength(clp)) {
if((clp = lforw(clp)) == curbp->b_linep) break;
cbo = 0;
c = CCHR('J');
} else
c = lgetc(clp, cbo++);
if (eq(c, pat[0]) != FALSE) {
tlp = clp;
tbo = cbo;
pp = &pat[1];
while (*pp != 0) {
if (tbo == llength(tlp)) {
tlp = lforw(tlp);
if (tlp == curbp->b_linep)
goto fail;
tbo = 0;
c = CCHR('J');
} else
c = lgetc(tlp, tbo++);
if (eq(c, *pp++) == FALSE)
goto fail;
}
curwp->w_dotp = tlp;
curwp->w_doto = tbo;
curwp->w_flag |= WFMOVE;
return TRUE;
}
fail: ;
}
return FALSE;
}
/*
* This routine does the real work of a
* backward search. The pattern is sitting in the external
* variable "pat". If found, dot is updated, the window system
* is notified of the change, and TRUE is returned. If the
* string isn't found, FALSE is returned.
*/
backsrch() {
register LINE *clp;
register int cbo;
register LINE *tlp;
register int tbo;
register int c;
register char *epp;
register char *pp;
for (epp = &pat[0]; epp[1] != 0; ++epp)
;
clp = curwp->w_dotp;
cbo = curwp->w_doto;
for (;;) {
if (cbo == 0) {
clp = lback(clp);
if (clp == curbp->b_linep)
return FALSE;
cbo = llength(clp)+1;
}
if (--cbo == llength(clp))
c = CCHR('J');
else
c = lgetc(clp,cbo);
if (eq(c, *epp) != FALSE) {
tlp = clp;
tbo = cbo;
pp = epp;
while (pp != &pat[0]) {
if (tbo == 0) {
tlp = lback(tlp);
if (tlp == curbp->b_linep)
goto fail;
tbo = llength(tlp)+1;
}
if (--tbo == llength(tlp))
c = CCHR('J');
else
c = lgetc(tlp,tbo);
if (eq(c, *--pp) == FALSE)
goto fail;
}
curwp->w_dotp = tlp;
curwp->w_doto = tbo;
curwp->w_flag |= WFMOVE;
return TRUE;
}
fail: ;
}
/*NOTREACHED*/
}
/*
* Compare two characters.
* The "bc" comes from the buffer.
* It has its case folded out. The
* "pc" is from the pattern.
*/
static int
eq(bc, pc)
register int bc, pc;
{
bc = CHARMASK(bc);
pc = CHARMASK(pc);
if (bc == pc) return TRUE;
if (ISUPPER(bc)) return TOLOWER(bc) == pc;
if (ISUPPER(pc)) return bc == TOLOWER(pc);
return FALSE;
}
/*
* Read a pattern.
* Stash it in the external variable "pat". The "pat" is
* not updated if the user types in an empty line. If the user typed
* an empty line, and there is no old pattern, it is an error.
* Display the old pattern, in the style of Jeff Lomicka. There is
* some do-it-yourself control expansion.
*/
readpattern(prompt) char *prompt; {
register int s;
char tpat[NPAT];
if (tpat[0] == '\0') s = ereply("%s: ", tpat, NPAT, prompt);
else s = ereply("%s: (default %s) ", tpat, NPAT, prompt, pat);
if (s == TRUE) /* Specified */
(VOID) strcpy(pat, tpat);
else if (s==FALSE && pat[0]!=0) /* CR, but old one */
s = TRUE;
return s;
}
SHAR_EOF
cat << \SHAR_EOF > version.c
/*
* This file contains the string that get written
* out by the emacs-version command.
*/
#define TRUE 1 /* include "def.h" when things get more complicated */
char version[] = "Mg 2a (formerly MicroGnuEmacs)";
/*
* Display the version. All this does
* is copy the version string onto the echo line.
*/
/*ARGSUSED*/
showversion(f, n)
int f, n;
{
ewprintf(version);
return TRUE;
}
SHAR_EOF
cat << \SHAR_EOF > window.c
/*
* Window handling.
*/
#include "def.h"
/*
* Reposition dot in the current
* window to line "n". If the argument is
* positive, it is that line. If it is negative it
* is that line from the bottom. If it is 0 the window
* is centered (this is what the standard redisplay code
* does). If GOSREC is undefined, default is 0, so it acts like GNU.
* If GOSREC is defined, with no argument it defaults to 1
* and works like in Gosling.
*/
/*ARGSUSED*/
reposition(f, n)
{
#ifndef GOSREC
curwp->w_force = (f & FFARG) ? (n>=0 ? n+1 : n) : 0;
#else
curwp->w_force = n;
#endif
curwp->w_flag |= WFFORCE;
sgarbf = TRUE;
return TRUE;
}
/*
* Refresh the display. A call is made to the
* "ttresize" entry in the terminal handler, which tries
* to reset "nrow" and "ncol". They will, however, never
* be set outside of the NROW or NCOL range. If the display
* changed size, arrange that everything is redone, then
* call "update" to fix the display. We do this so the
* new size can be displayed. In the normal case the
* call to "update" in "main.c" refreshes the screen,
* and all of the windows need not be recomputed.
* Note that when you get to the "display unusable"
* message, the screen will be messed up. If you make
* the window bigger again, and send another command,
* everything will get fixed!
*/
/*ARGSUSED*/
refresh(f, n)
{
register WINDOW *wp;
register int oldnrow;
register int oldncol;
oldnrow = nrow;
oldncol = ncol;
ttresize();
if (nrow!=oldnrow || ncol!=oldncol) {
wp = wheadp; /* Find last. */
while (wp->w_wndp != NULL)
wp = wp->w_wndp;
if (nrow < wp->w_toprow+3) { /* Check if too small. */
ewprintf("Display unusable");
return (FALSE);
}
wp->w_ntrows = nrow-wp->w_toprow-2;
sgarbf = TRUE;
update();
ewprintf("New size %d by %d", nrow, ncol);
} else
sgarbf = TRUE;
return TRUE;
}
/*
* The command to 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.
*/
/*ARGSUSED*/
nextwind(f, n)
{
register WINDOW *wp;
if ((wp=curwp->w_wndp) == NULL)
wp = wheadp;
curwp = wp;
curbp = wp->w_bufp;
return TRUE;
}
#ifdef GOSMACS
/* not in Gnu Emacs */
/*
* 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.
*/
/*ARGSUSED*/
prevwind(f, n)
{
register WINDOW *wp1;
register WINDOW *wp2;
wp1 = wheadp;
wp2 = curwp;
if (wp1 == wp2)
wp2 = NULL;
while (wp1->w_wndp != wp2)
wp1 = wp1->w_wndp;
curwp = wp1;
curbp = wp1->w_bufp;
return TRUE;
}
#endif
/*
* This command makes the current
* window the only window on the screen.
* 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.
*/
/*ARGSUSED*/
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 = nrow-2; /* 2 = mode, echo. */
curwp->w_linep = lp;
curwp->w_flag |= WFMODE|WFHARD;
return TRUE;
}
/*
* Split the current window. A window
* smaller than 3 lines cannot be split.
* The only other error that is possible is
* a "malloc" failure allocating the structure
* for the new window.
*/
/*ARGSUSED*/
splitwind(f, n)
{
register WINDOW *wp;
register LINE *lp;
register int ntru;
register int ntrd;
int ntrl;
WINDOW *wp1, *wp2;
if (curwp->w_ntrows < 3) {
ewprintf("Cannot split a %d line window", curwp->w_ntrows);
return (FALSE);
}
if ((wp = (WINDOW *)malloc(sizeof(WINDOW))) == NULL) {
ewprintf("Can't get %d", sizeof(WINDOW));
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;
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 (ntrd <= ntru) { /* 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.
*/
/*ARGSUSED*/
enlargewind(f, n)
{
register WINDOW *adjwp;
register LINE *lp;
register int i;
if (n < 0)
return shrinkwind(f, -n);
if (wheadp->w_wndp == NULL) {
ewprintf("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) {
ewprintf("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;
curwp->w_flag |= WFMODE|WFHARD;
adjwp->w_flag |= WFMODE|WFHARD;
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.
*/
shrinkwind(f, n)
{
register WINDOW *adjwp;
register LINE *lp;
register int i;
if (n < 0)
return enlargewind(f, -n);
if (wheadp->w_wndp == NULL) {
ewprintf("Only one window");
return FALSE;
}
/*
* Bit of flakiness - KRANDOM means it was an internal call, and
* to be trusted implicitly about sizes.
*/
if ( !(f & FFRAND) && curwp->w_ntrows <= n) {
ewprintf("Impossible change");
return (FALSE);
}
if ((adjwp=curwp->w_wndp) == NULL) {
adjwp = wheadp;
while (adjwp->w_wndp != curwp)
adjwp = adjwp->w_wndp;
}
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;
curwp->w_flag |= WFMODE|WFHARD;
adjwp->w_flag |= WFMODE|WFHARD;
return (TRUE);
}
/*
* Delete current window. Call shrink-window to do the screen
* updating, then throw away the window.
*/
/*ARGSUSED*/
delwind(f, n)
{
register WINDOW *wp, *nwp;
wp = curwp; /* Cheap... */
/* shrinkwind returning false means only one window... */
if (shrinkwind(FFRAND, wp->w_ntrows + 1) == FALSE)
return FALSE;
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;
}
/* since shrinkwind did't crap out, we know we have a second window */
if (wp == wheadp) wheadp = curwp = wp->w_wndp;
else if ((curwp = wp->w_wndp) == NULL) curwp = wheadp;
curbp = curwp->w_bufp;
for (nwp = wheadp; nwp != NULL; nwp = nwp->w_wndp)
if (nwp->w_wndp == wp) {
nwp->w_wndp = wp->w_wndp;
break ;
}
free((char *) wp);
return TRUE;
}
/*
* 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
&& splitwind(FFRAND, 0) == FALSE)
return NULL;
wp = wheadp; /* Find window to use */
while (wp!=NULL && wp==curwp)
wp = wp->w_wndp;
return wp;
}
SHAR_EOF
cat << \SHAR_EOF > word.c
/*
* Word mode commands.
* The routines in this file
* implement commands that work word at
* a time. There are all sorts of word mode
* commands.
*/
#include "def.h"
/*
* Move the cursor backward by
* "n" words. All of the details of motion
* are performed by the "backchar" and "forwchar"
* routines.
*/
/*ARGSUSED*/
backword(f, n)
{
if (n < 0) return forwword(f | FFRAND, -n);
if (backchar(FFRAND, 1) == FALSE)
return FALSE;
while (n--) {
while (inword() == FALSE) {
if (backchar(FFRAND, 1) == FALSE)
return TRUE;
}
while (inword() != FALSE) {
if (backchar(FFRAND, 1) == FALSE)
return TRUE;
}
}
return forwchar(FFRAND, 1);
}
/*
* Move the cursor forward by
* the specified number of words. All of the
* motion is done by "forwchar".
*/
/*ARGSUSED*/
forwword(f, n)
{
if (n < 0)
return backword(f | FFRAND, -n);
while (n--) {
while (inword() == FALSE) {
if (forwchar(FFRAND, 1) == FALSE)
return TRUE;
}
while (inword() != FALSE) {
if (forwchar(FFRAND, 1) == FALSE)
return TRUE;
}
}
return TRUE;
}
/*
* Move the cursor forward by
* the specified number of words. As you move,
* convert any characters to upper case.
*/
/*ARGSUSED*/
upperword(f, n)
{
register int c;
if (n < 0) return FALSE;
while (n--) {
while (inword() == FALSE) {
if (forwchar(FFRAND, 1) == FALSE)
return TRUE;
}
while (inword() != FALSE) {
c = lgetc(curwp->w_dotp, curwp->w_doto);
if (ISLOWER(c) != FALSE) {
c = TOUPPER(c);
lputc(curwp->w_dotp, curwp->w_doto, c);
lchange(WFHARD);
}
if (forwchar(FFRAND, 1) == FALSE)
return TRUE;
}
}
return TRUE;
}
/*
* Move the cursor forward by
* the specified number of words. As you move
* convert characters to lower case.
*/
/*ARGSUSED*/
lowerword(f, n)
{
register int c;
if (n < 0) return FALSE;
while (n--) {
while (inword() == FALSE) {
if (forwchar(FFRAND, 1) == FALSE)
return TRUE;
}
while (inword() != FALSE) {
c = lgetc(curwp->w_dotp, curwp->w_doto);
if (ISUPPER(c) != FALSE) {
c = TOLOWER(c);
lputc(curwp->w_dotp, curwp->w_doto, c);
lchange(WFHARD);
}
if (forwchar(FFRAND, 1) == FALSE)
return TRUE;
}
}
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.
*/
/*ARGSUSED*/
capword(f, n)
{
register int c;
VOID lchange();
if (n < 0) return FALSE;
while (n--) {
while (inword() == FALSE) {
if (forwchar(FFRAND, 1) == FALSE)
return TRUE;
}
if (inword() != FALSE) {
c = lgetc(curwp->w_dotp, curwp->w_doto);
if (ISLOWER(c) != FALSE) {
c = TOUPPER(c);
lputc(curwp->w_dotp, curwp->w_doto, c);
lchange(WFHARD);
}
if (forwchar(FFRAND, 1) == FALSE)
return TRUE;
while (inword() != FALSE) {
c = lgetc(curwp->w_dotp, curwp->w_doto);
if (ISUPPER(c) != FALSE) {
c = TOLOWER(c);
lputc(curwp->w_dotp, curwp->w_doto, c);
lchange(WFHARD);
}
if (forwchar(FFRAND, 1) == FALSE)
return TRUE;
}
}
}
return TRUE;
}
/*
* Kill forward by "n" words.
*/
/*ARGSUSED*/
delfword(f, n)
{
register RSIZE size;
register LINE *dotp;
register int doto;
if (n < 0)
return FALSE;
if ((lastflag&CFKILL) == 0) /* Purge kill buffer. */
kdelete();
thisflag |= CFKILL;
dotp = curwp->w_dotp;
doto = curwp->w_doto;
size = 0;
while (n--) {
while (inword() == FALSE) {
if (forwchar(FFRAND, 1) == FALSE)
goto out; /* Hit end of buffer. */
++size;
}
while (inword() != FALSE) {
if (forwchar(FFRAND, 1) == FALSE)
goto out; /* Hit end of buffer. */
++size;
}
}
out:
curwp->w_dotp = dotp;
curwp->w_doto = doto;
return (ldelete(size, KFORW));
}
/*
* Kill backwards by "n" words. The rules
* for success and failure are now different, to prevent
* strange behavior at the start of the buffer. The command
* only fails if something goes wrong with the actual delete
* of the characters. It is successful even if no characters
* are deleted, or if you say delete 5 words, and there are
* only 4 words left. I considered making the first call
* to "backchar" special, but decided that that would just
* be wierd. Normally this is bound to "M-Rubout" and
* to "M-Backspace".
*/
/*ARGSUSED*/
delbword(f, n)
{
register RSIZE size;
VOID kdelete();
if (n < 0) return FALSE;
if ((lastflag&CFKILL) == 0) /* Purge kill buffer. */
kdelete();
thisflag |= CFKILL;
if (backchar(FFRAND, 1) == FALSE)
return (TRUE); /* Hit buffer start. */
size = 1; /* One deleted. */
while (n--) {
while (inword() == FALSE) {
if (backchar(FFRAND, 1) == FALSE)
goto out; /* Hit buffer start. */
++size;
}
while (inword() != FALSE) {
if (backchar(FFRAND, 1) == FALSE)
goto out; /* Hit buffer start. */
++size;
}
}
if (forwchar(FFRAND, 1) == FALSE)
return FALSE;
--size; /* Undo assumed delete. */
out:
return ldelete(size, KBACK);
}
/*
* Return TRUE if the character at dot
* is a character that is considered to be
* part of a word. The word character list is hard
* coded. Should be setable.
*/
inword() {
/* can't use lgetc in ISWORD due to bug in OSK cpp */
return curwp->w_doto != llength(curwp->w_dotp) &&
ISWORD(curwp->w_dotp->l_text[curwp->w_doto]);
}
SHAR_EOF
# End of shell archive
exit 0
-------
More information about the Comp.sources.misc
mailing list