Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!watmath!clyde!burl!ulysses!allegra!mit-eddie!think!harvard!seismo!lll-crg!lll-lcc!qantel!hplabs!tektronix!orca!pogo!jutz From: jutz@pogo.UUCP (Curt Jutzi) Newsgroups: net.sources Subject: MicroEmacs (4 of 7) Message-ID: <2413@pogo.UUCP> Date: Thu, 20-Mar-86 12:14:58 EST Article-I.D.: pogo.2413 Posted: Thu Mar 20 12:14:58 1986 Date-Received: Sat, 22-Mar-86 22:30:40 EST Distribution: net Organization: Tektronix, Beaverton OR Lines: 1002 *** 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 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 #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; iw_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 #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; iw_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;