MicroEmacs (4 of 7)
Curt Jutzi
jutz at pogo.UUCP
Fri Mar 21 03:14:58 AEST 1986
*** REPLACE THIS LINE WITH YOUR MESSAGE ***
while (cp3[-1] == cp4[-1])
{
--cp3;
--cp4;
if (cp3[0] != ' ') /* Note if any nonblank */
nbflag = TRUE; /* in right match. */
}
cp5 = cp3;
if (nbflag == FALSE) /* Erase to EOL ? */
{
while (cp5!=cp1 && cp5[-1]==' ')
--cp5;
if (cp3-cp5 <= 3) /* Use only if erase is */
cp5 = cp3; /* fewer characters. */
}
movecursor(row, cp1-&vline[0]); /* Go to start of line. */
while (cp1 != cp5) /* Ordinary. */
{
(*term.t_putchar)(*cp1);
++ttcol;
*cp2++ = *cp1++;
}
if (cp5 != cp3) /* Erase. */
{
(*term.t_eeol)();
while (cp1 != cp3)
*cp2++ = *cp1++;
}
#endif
}
/*
* Redisplay the mode line for the window pointed to by the "wp". This is the
* only routine that has any idea of how the modeline is formatted. You can
* change the modeline format by hacking at this routine. Called by "update"
* any time there is a dirty window.
*/
modeline(wp)
WINDOW *wp;
{
register char *cp;
register int c;
register int n;
register BUFFER *bp;
n = wp->w_toprow+wp->w_ntrows; /* Location. */
vscreen[n]->v_flag |= VFCHG; /* Redraw next time. */
vtmove(n, 0); /* Seek to right line. */
#ifdef ANSI
vtputcl('');
vtputcl('[');
vtputcl('1');
vtputcl(';');
vtputcl('4');
vtputcl('1');
vtputcl('m');
#endif
vtputc('-');
bp = wp->w_bufp;
if ((bp->b_flag&BFCHG) != 0) /* "*" if changed. */
vtputc('*');
else
vtputc('-');
n = 2;
cp = " MicroEMACS -- "; /* Buffer name. */
while ((c = *cp++) != 0)
{
vtputc(c);
++n;
}
cp = &bp->b_bname[0];
while ((c = *cp++) != 0)
{
vtputc(c);
++n;
}
vtputc(' ');
++n;
if (bp->b_fname[0] != 0) /* File name. */
{
cp = "-- File: ";
while ((c = *cp++) != 0)
{
vtputc(c);
++n;
}
cp = &bp->b_fname[0];
while ((c = *cp++) != 0)
{
vtputc(c);
++n;
}
vtputc(' ');
++n;
}
#if WFDEBUG
vtputc('-');
vtputc((wp->w_flag&WFMODE)!=0 ? 'M' : '-');
vtputc((wp->w_flag&WFHARD)!=0 ? 'H' : '-');
vtputc((wp->w_flag&WFEDIT)!=0 ? 'E' : '-');
vtputc((wp->w_flag&WFMOVE)!=0 ? 'V' : '-');
vtputc((wp->w_flag&WFFORCE)!=0 ? 'F' : '-');
n += 6;
#endif
#ifndef ANSI
while (n < term.t_ncol) /* Pad to full width. */
{
vtputc('-');
++n;
}
#endif
#ifdef ANSI
while (n < term.t_ncol-11) /* Pad to full width. */
{
vtputc('-');
++n;
}
vtputcl('');
vtputcl('[');
vtputcl('0');
vtputcl('m');
#endif
}
/*
* Send a command to the terminal to move the hardware cursor to row "row"
* and column "col". The row and column arguments are origin 0. Optimize out
* random calls. Update "ttrow" and "ttcol".
*/
movecursor(row, col)
{
if (row!=ttrow || col!=ttcol)
{
ttrow = row;
ttcol = col;
(*term.t_move)(row, col);
}
}
/*
* Erase the message line. This is a special routine because the message line
* is not considered to be part of the virtual screen. It always works
* immediately; the terminal buffer is flushed via a call to the flusher.
*/
mlerase()
{
movecursor(term.t_nrow, 0);
(*term.t_eeol)();
(*term.t_flush)();
mpresf = FALSE;
}
/*
* 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;
{
register int s;
char buf[64];
for (;;)
{
strcpy(buf, prompt);
strcat(buf, " [y/n]? ");
s = mlreply(buf, buf, sizeof(buf));
if (s == ABORT)
return (ABORT);
if (s != FALSE)
{
if (buf[0]=='y' || buf[0]=='Y')
return (TRUE);
if (buf[0]=='n' || buf[0]=='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;
{
register int cpos;
register int i;
register int c;
cpos = 0;
if (kbdmop != NULL)
{
while ((c = *kbdmop++) != '\0')
buf[cpos++] = c;
buf[cpos] = 0;
if (buf[0] == 0)
return (FALSE);
return (TRUE);
}
mlwrite(prompt);
for (;;)
{
c = (*term.t_getchar)();
switch (c)
{
case 0x0D: /* Return, end of line */
buf[cpos++] = 0;
if (kbdmip != NULL)
{
if (kbdmip+cpos > &kbdm[NKBDM-3])
{
ctrlg(FALSE, 0);
(*term.t_flush)();
return (ABORT);
}
for (i=0; i<cpos; ++i)
*kbdmip++ = buf[i];
}
(*term.t_putchar)('\r');
ttcol = 0;
(*term.t_flush)();
if (buf[0] == 0)
return (FALSE);
return (TRUE);
case 0x07: /* Bell, abort */
(*term.t_putchar)('^');
(*term.t_putchar)('G');
ttcol += 2;
ctrlg(FALSE, 0);
(*term.t_flush)();
return (ABORT);
case 0x7F: /* Rubout, erase */
case 0x08: /* Backspace, erase */
if (cpos != 0)
{
(*term.t_putchar)('\b');
(*term.t_putchar)(' ');
(*term.t_putchar)('\b');
--ttcol;
if (buf[--cpos] < 0x20)
{
(*term.t_putchar)('\b');
(*term.t_putchar)(' ');
(*term.t_putchar)('\b');
--ttcol;
}
(*term.t_flush)();
}
break;
case 0x15: /* C-U, kill */
while (cpos != 0)
{
(*term.t_putchar)('\b');
(*term.t_putchar)(' ');
(*term.t_putchar)('\b');
--ttcol;
if (buf[--cpos] < 0x20)
{
(*term.t_putchar)('\b');
(*term.t_putchar)(' ');
(*term.t_putchar)('\b');
--ttcol;
}
}
(*term.t_flush)();
break;
default:
if (cpos < nbuf-1)
{
buf[cpos++] = c;
if (c < ' ')
{
(*term.t_putchar)('^');
++ttcol;
c ^= 0x40;
}
(*term.t_putchar)(c);
++ttcol;
(*term.t_flush)();
}
}
}
}
/*
* Write a message into the message line. Keep track of the physical cursor
* position. A small class of printf like format items is handled. Assumes the
* stack grows down; this assumption is made by the "++" in the argument scan
* loop. Set the "message line" flag TRUE.
*/
mlwrite(fmt, arg)
char *fmt;
{
register int c;
register char *ap;
movecursor(term.t_nrow, 0);
ap = (char *) &arg;
while ((c = *fmt++) != 0) {
if (c != '%') {
(*term.t_putchar)(c);
++ttcol;
}
else
{
c = *fmt++;
switch (c) {
case 'd':
mlputi(*(int *)ap, 10);
ap += sizeof(int);
break;
case 'o':
mlputi(*(int *)ap, 8);
ap += sizeof(int);
break;
case 'x':
mlputi(*(int *)ap, 16);
ap += sizeof(int);
break;
case 'D':
mlputli(*(long *)ap, 10);
ap += sizeof(long);
break;
case 's':
mlputs(*(char **)ap);
ap += sizeof(char *);
break;
default:
(*term.t_putchar)(c);
++ttcol;
}
}
}
(*term.t_eeol)();
(*term.t_flush)();
mpresf = TRUE;
}
/*
* Write out a string. Update the physical cursor position. This assumes that
* the characters in the string all have width "1"; if this is not the case
* things will get screwed up a little.
*/
mlputs(s)
char *s;
{
register int c;
while ((c = *s++) != 0)
{
(*term.t_putchar)(c);
++ttcol;
}
}
/*
* Write out an integer, in the specified radix. Update the physical cursor
* position. This will not handle any negative numbers; maybe it should.
*/
mlputi(i, r)
{
register int q;
static char hexdigits[] = "0123456789ABCDEF";
if (i < 0)
{
i = -i;
(*term.t_putchar)('-');
}
q = i/r;
if (q != 0)
mlputi(q, r);
(*term.t_putchar)(hexdigits[i%r]);
++ttcol;
}
/*
* do the same except as a long integer.
*/
mlputli(l, r)
long l;
{
register long q;
if (l < 0)
{
l = -l;
(*term.t_putchar)('-');
}
q = l/r;
if (q != 0)
mlputli(q, r);
(*term.t_putchar)((int)(l%r)+'0');
++ttcol;
}
#if RAINBOW
putline(row, col, buf)
int row, col;
char buf[];
{
int n;
n = strlen(buf);
if (col + n - 1 > term.t_ncol)
n = term.t_ncol - col + 1;
Put_Data(row, col, n, buf);
}
#endif
/*
*
* FILE.C MODULE
*
*/
/*
* The routines in this file
* handle the reading and writing of
* disk files. All of details about the
* reading and writing of the disk are
* in "fileio.c".
*/
#include <stdio.h>
#include "ed.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 ((s=mlreply("Read file: ", fname, NFILEN)) != TRUE)
return (s);
return (readin(fname));
}
/*
* 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-V.
*/
filevisit(f, n)
{
register BUFFER *bp;
register WINDOW *wp;
register LINE *lp;
register int i;
register int s;
char bname[NBUFN];
char fname[NFILEN];
if ((s=mlreply("Visit file: ", fname, NFILEN)) != TRUE)
return (s);
for (bp=bheadp; bp!=NULL; bp=bp->b_bufp) {
if ((bp->b_flag&BFTEMP)==0 && strcmp(bp->b_fname, fname)==0) {
if (--curbp->b_nwnd == 0) {
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;
curwp->w_bufp = bp;
if (bp->b_nwnd++ == 0) {
curwp->w_dotp = bp->b_dotp;
curwp->w_doto = bp->b_doto;
curwp->w_markp = bp->b_markp;
curwp->w_marko = bp->b_marko;
} else {
wp = wheadp;
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;
}
}
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;
mlwrite("[Old buffer]");
return (TRUE);
}
}
makename(bname, fname); /* New buffer name. */
while ((bp=bfind(bname, FALSE, 0)) != NULL) {
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);
}
/* added by Curt Jutzi */
if (nextwind(NULL,NULL)==FALSE) /* if two windows open go to other */
splitwind(NULL,NULL); /* and display new buffer their else */
/* split window and display in other */
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++;
return (readin(fname)); /* Read it in. */
}
/*
* Read file "fname" into the current
* buffer, blowing away any text found there. Called
* by both the read and visit 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.
*/
readin(fname)
char fname[];
{
register LINE *lp1;
register LINE *lp2;
register int i;
register WINDOW *wp;
register BUFFER *bp;
register int s;
register int nbytes;
register int nline;
char line[NLINE];
bp = curbp; /* Cheap. */
if ((s=bclear(bp)) != TRUE) /* Might be old. */
return (s);
bp->b_flag &= ~(BFTEMP|BFCHG);
strcpy(bp->b_fname, fname);
if ((s=ffropen(fname)) == FIOERR) /* Hard file open. */
goto out;
if (s == FIOFNF) { /* File not found. */
mlwrite("[New file]");
goto out;
}
mlwrite("[Reading file]");
nline = 0;
while ((s=ffgetline(line, NLINE)) == FIOSUC) {
nbytes = strlen(line);
if ((lp1=lalloc(nbytes)) == NULL) {
s = FIOERR; /* Keep message on the */
break; /* display. */
}
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, line[i]);
++nline;
}
ffclose(); /* Ignore errors. */
if (s == FIOEOF) { /* Don't zap message! */
if (nline == 1)
mlwrite("[Read 1 line]");
else
mlwrite("[Read %d lines]", nline);
}
out:
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) /* False if error. */
return (FALSE);
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 AMIGA
while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!='/')
--cp1;
#endif
#if VMS
while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!=']')
--cp1;
#endif
#if CPM
while (cp1!=&fname[0] && cp1[-1]!=':')
--cp1;
#endif
#if MSDOS
while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!='\\')
--cp1;
#endif
#if V7
while (cp1!=&fname[0] && cp1[-1]!='/')
--cp1;
#endif
cp2 = &bname[0];
while (cp2!=&bname[NBUFN-1] && *cp1!=0 && *cp1!=';')
*cp2++ = *cp1++;
*cp2 = 0;
}
/*
* 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 ((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_flag&BFCHG) == 0) /* Return, no changes. */
return (TRUE);
if (curbp->b_fname[0] == 0) { /* Must have a name. */
mlwrite("No file name");
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 ((s=ffwopen(fn)) != FIOSUC) /* Open writes message. */
return (FALSE);
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. */
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 ((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;
}
return (TRUE);
}
/*
*
* RANDOM.C MODULE
*
*/
/*
* This file contains the command processing functions for a number of random
* commands. There is no functional grouping here, for sure.
*/
#include <stdio.h>
#include "ed.h"
int tabsize; /* Tab size (0: use real tabs) */
/*
* Set fill column to n.
*/
setfillcol(f, n)
{
fillcol = n;
return(TRUE);
}
/*
* Display the current position of the cursor, in origin 1 X-Y coordinates,
* the character that is under the cursor (in octal), and the fraction of the
* text that is before the cursor. The displayed column is not the current
* column, but the column that would be used on an infinite width display.
* Normally this is bound to "C-X =".
*/
showcpos(f, n)
{
register LINE *clp;
register long nch;
register int cbo;
register long nbc;
register int cac;
register int ratio;
register int col;
register int i;
register int c;
clp = lforw(curbp->b_linep); /* Grovel the data. */
cbo = 0;
nch = 0;
for (;;) {
if (clp==curwp->w_dotp && cbo==curwp->w_doto) {
nbc = nch;
if (cbo == llength(clp))
cac = '\n';
else
cac = lgetc(clp, cbo);
}
if (cbo == llength(clp)) {
if (clp == curbp->b_linep)
break;
clp = lforw(clp);
cbo = 0;
} else
++cbo;
++nch;
}
col = getccol(FALSE); /* Get real column. */
ratio = 0; /* Ratio before dot. */
if (nch != 0)
ratio = (100L*nbc) / nch;
mlwrite("X=%d Y=%d CH=0x%x .=%D (%d%% of %D)",
col+1, currow+1, cac, nbc, ratio, nch);
return (TRUE);
}
/*
* Return current column. Stop at first non-blank given TRUE argument.
*/
getccol(bflg)
int bflg;
{
register int c, i, col;
col = 0;
for (i=0; i<curwp->w_doto; ++i) {
c = lgetc(curwp->w_dotp, i);
if (c!=' ' && c!='\t' && bflg)
break;
if (c == '\t')
col |= 0x07;
else if (c<0x20 || c==0x7F)
++col;
++col;
}
return(col);
}
/*
* Twiddle the two characters on either side of dot. If dot is at the end of
* the line twiddle the two characters before it. Return with an error if dot
* is at the beginning of line; it seems to be a bit pointless to make this
* work. This fixes up a very common typo with a single stroke. Normally bound
* to "C-T". This always works within a line, so "WFEDIT" is good enough.
*/
twiddle(f, n)
{
register LINE *dotp;
register int doto;
register int cl;
register int cr;
dotp = curwp->w_dotp;
doto = curwp->w_doto;
if (doto==llength(dotp) && --doto<0)
return (FALSE);
cr = lgetc(dotp, doto);
if (--doto < 0)
return (FALSE);
cl = lgetc(dotp, doto);
lputc(dotp, doto+0, cr);
lputc(dotp, doto+1, cl);
lchange(WFEDIT);
return (TRUE);
}
/*
* Quote the next character, and insert it into the buffer. All the characters
* are taken literally, with the exception of the newline, which always has
* its line splitting meaning. The character is always read, even if it is
* inserted 0 times, for regularity. Bound to "M-Q" (for me) and "C-Q" (for
* Rich, and only on terminals that don't need XON-XOFF).
*/
quote(f, n)
{
register int s;
register int c;
c = (*term.t_getchar)();
if (n < 0)
return (FALSE);
if (n == 0)
return (TRUE);
if (c == '\n') {
do {
s = lnewline();
} while (s==TRUE && --n);
return (s);
}
return (linsert(n, c));
}
/*
* Set tab size if given non-default argument (n <> 1). Otherwise, insert a
* tab into file. If given argument, n, of zero, change to true tabs.
* If n > 1, simulate tab stop every n-characters using spaces. This has to be
* done in this slightly funny way because the tab (in ASCII) has been turned
* into "C-I" (in 10 bit code) already. Bound to "C-I".
*/
tab(f, n)
{
if (n < 0)
return (FALSE);
if (n == 0 || n > 1) {
tabsize = n;
More information about the Comp.sources.unix
mailing list