Path: seismo!harvard!husc6!panda!sources-request From: sources-request@panda.UUCP Newsgroups: mod.sources Subject: MicroEMACS 3.6 (Part 7 of 8) Message-ID: <1827@panda.UUCP> Date: 8 May 86 10:55:13 GMT Sender: jpn@panda.UUCP Lines: 1778 Approved: jpn@panda.UUCP Mod.sources: Volume 4, Issue 104 Submitted by: ihnp4!itivax!duncan!lawrence echo x - random.c sed 's/^X//' >random.c <<'*-*-END-of-random.c-*-*' X/* X * This file contains the command processing functions for a number of random X * commands. There is no functional grouping here, for sure. X */ X X#include X#include "estruct.h" X#include "edef.h" X Xint tabsize; /* Tab size (0: use real tabs) */ X X/* X * Set fill column to n. X */ Xsetfillcol(f, n) X{ X fillcol = n; X mlwrite("[Fill column is %d]",n); X return(TRUE); X} X X/* X * Display the current position of the cursor, in origin 1 X-Y coordinates, X * the character that is under the cursor (in octal), and the fraction of the X * text that is before the cursor. The displayed column is not the current X * column, but the column that would be used on an infinite width display. X * Normally this is bound to "C-X =". X */ Xshowcpos(f, n) X{ X register LINE *clp; X register long nch; X register int cbo; X register long nbc; X register int cac; X register int ratio; X register int col; X X clp = lforw(curbp->b_linep); /* Grovel the data. */ X cbo = 0; X nch = 0; X for (;;) { X if (clp==curwp->w_dotp && cbo==curwp->w_doto) { X nbc = nch; X if (cbo == llength(clp)) X cac = '\n'; X else X cac = lgetc(clp, cbo); X } X if (cbo == llength(clp)) { X if (clp == curbp->b_linep) X break; X clp = lforw(clp); X cbo = 0; X } else X ++cbo; X ++nch; X } X col = getccol(FALSE); /* Get real column. */ X ratio = 0; /* Ratio before dot. */ X if (nch != 0) X ratio = (100L*nbc) / nch; X mlwrite("X=%d Y=%d CH=0x%x .=%D (%d%% of %D)", X col+1, currow+1, cac, nbc, ratio, nch); X return (TRUE); X} X X/* X * Return current column. Stop at first non-blank given TRUE argument. X */ Xgetccol(bflg) Xint bflg; X{ X register int c, i, col; X col = 0; X for (i=0; iw_doto; ++i) { X c = lgetc(curwp->w_dotp, i); X if (c!=' ' && c!='\t' && bflg) X break; X if (c == '\t') X col |= 0x07; X else if (c<0x20 || c==0x7F) X ++col; X ++col; X } X return(col); X} X X/* X * Twiddle the two characters on either side of dot. If dot is at the end of X * the line twiddle the two characters before it. Return with an error if dot X * is at the beginning of line; it seems to be a bit pointless to make this X * work. This fixes up a very common typo with a single stroke. Normally bound X * to "C-T". This always works within a line, so "WFEDIT" is good enough. X */ Xtwiddle(f, n) X{ X register LINE *dotp; X register int doto; X register int cl; X register int cr; X X if (curbp->b_mode&MDVIEW) /* don't allow this command if */ X return(rdonly()); /* we are in read only mode */ X dotp = curwp->w_dotp; X doto = curwp->w_doto; X if (doto==llength(dotp) && --doto<0) X return (FALSE); X cr = lgetc(dotp, doto); X if (--doto < 0) X return (FALSE); X cl = lgetc(dotp, doto); X lputc(dotp, doto+0, cr); X lputc(dotp, doto+1, cl); X lchange(WFEDIT); X return (TRUE); X} X X/* X * Quote the next character, and insert it into the buffer. All the characters X * are taken literally, with the exception of the newline, which always has X * its line splitting meaning. The character is always read, even if it is X * inserted 0 times, for regularity. Bound to "C-Q" X */ Xquote(f, n) X{ X register int s; X register int c; X X if (curbp->b_mode&MDVIEW) /* don't allow this command if */ X return(rdonly()); /* we are in read only mode */ X c = (*term.t_getchar)(); X if (n < 0) X return (FALSE); X if (n == 0) X return (TRUE); X if (c == '\n') { X do { X s = lnewline(); X } while (s==TRUE && --n); X return (s); X } X return (linsert(n, c)); X} X X/* X * Set tab size if given non-default argument (n <> 1). Otherwise, insert a X * tab into file. If given argument, n, of zero, change to true tabs. X * If n > 1, simulate tab stop every n-characters using spaces. This has to be X * done in this slightly funny way because the tab (in ASCII) has been turned X * into "C-I" (in 10 bit code) already. Bound to "C-I". X */ Xtab(f, n) X{ X if (n < 0) X return (FALSE); X if (n == 0 || n > 1) { X tabsize = n; X return(TRUE); X } X if (! tabsize) X return(linsert(1, '\t')); X return(linsert(tabsize - (getccol(FALSE) % tabsize), ' ')); X} X X/* X * Open up some blank space. The basic plan is to insert a bunch of newlines, X * and then back up over them. Everything is done by the subcommand X * procerssors. They even handle the looping. Normally this is bound to "C-O". X */ Xopenline(f, n) X{ X register int i; X register int s; X X if (curbp->b_mode&MDVIEW) /* don't allow this command if */ X return(rdonly()); /* we are in read only mode */ X if (n < 0) X return (FALSE); X if (n == 0) X return (TRUE); X i = n; /* Insert newlines. */ X do { X s = lnewline(); X } while (s==TRUE && --i); X if (s == TRUE) /* Then back up overtop */ X s = backchar(f, n); /* of them all. */ X return (s); X} X X/* X * Insert a newline. Bound to "C-M". If we are in CMODE, do automatic X * indentation as specified. X */ Xnewline(f, n) X{ X register int s; X X if (curbp->b_mode&MDVIEW) /* don't allow this command if */ X return(rdonly()); /* we are in read only mode */ X if (n < 0) X return (FALSE); X X /* if we are in C mode and this is a default */ X if (n == 1 && (curbp->b_mode & MDCMOD) && X curwp->w_dotp != curbp->b_linep) X return(cinsert()); X X /* insert some lines */ X while (n--) { X if ((s=lnewline()) != TRUE) X return (s); X } X return (TRUE); X} X Xcinsert() /* insert a newline and indentation for C */ X X{ X register char *cptr; /* string pointer into text to copy */ X register int tptr; /* index to scan into line */ X register int bracef; /* was there a brace at the end of line? */ X register int i; X char ichar[NSTRING]; /* buffer to hold indent of last line */ X X /* grab a pointer to text to copy indentation from */ X cptr = &curwp->w_dotp->l_text[0]; X X /* check for a brace */ X tptr = curwp->w_doto - 1; X bracef = (cptr[tptr] == '{'); X X /* save the indent of the previous line */ X i = 0; X while ((i < tptr) && (cptr[i] == ' ' || cptr[i] == '\t') X && (i < NSTRING - 1)) { X ichar[i] = cptr[i]; X ++i; X } X ichar[i] = 0; /* terminate it */ X X /* put in the newline */ X if (lnewline() == FALSE) X return(FALSE); X X /* and the saved indentation */ X i = 0; X while (ichar[i]) X linsert(1, ichar[i++]); X X /* and one more tab for a brace */ X if (bracef) X tab(FALSE, 1); X X return(TRUE); X} X Xinsbrace(n, c) /* insert a brace into the text here...we are in CMODE */ X Xint n; /* repeat count */ Xint c; /* brace to insert (always { for now) */ X X{ X register int ch; /* last character before input */ X register int i; X register int target; /* column brace should go after */ X X /* if we are at the begining of the line, no go */ X if (curwp->w_doto == 0) X return(linsert(n,c)); X X /* scan to see if all space before this is white space */ X for (i = curwp->w_doto - 1; i >= 0; --i) { X ch = lgetc(curwp->w_dotp, i); X if (ch != ' ' && ch != '\t') X return(linsert(n, c)); X } X X /* delete back first */ X target = getccol(FALSE); /* calc where we will delete to */ X target -= 1; X target -= target % (tabsize == 0 ? 8 : tabsize); X while (getccol(FALSE) > target) X backdel(FALSE, 1); X X /* and insert the required brace(s) */ X return(linsert(n, c)); X} X Xinspound() /* insert a # into the text here...we are in CMODE */ X X{ X register int ch; /* last character before input */ X register int i; X X /* if we are at the begining of the line, no go */ X if (curwp->w_doto == 0) X return(linsert(1,'#')); X X /* scan to see if all space before this is white space */ X for (i = curwp->w_doto - 1; i >= 0; --i) { X ch = lgetc(curwp->w_dotp, i); X if (ch != ' ' && ch != '\t') X return(linsert(1, '#')); X } X X /* delete back first */ X while (getccol(FALSE) > 1) X backdel(FALSE, 1); X X /* and insert the required pound */ X return(linsert(1, '#')); X} X X/* X * Delete blank lines around dot. What this command does depends if dot is X * sitting on a blank line. If dot is sitting on a blank line, this command X * deletes all the blank lines above and below the current line. If it is X * sitting on a non blank line then it deletes all of the blank lines after X * the line. Normally this command is bound to "C-X C-O". Any argument is X * ignored. X */ Xdeblank(f, n) X{ X register LINE *lp1; X register LINE *lp2; X register int nld; X X if (curbp->b_mode&MDVIEW) /* don't allow this command if */ X return(rdonly()); /* we are in read only mode */ X lp1 = curwp->w_dotp; X while (llength(lp1)==0 && (lp2=lback(lp1))!=curbp->b_linep) X lp1 = lp2; X lp2 = lp1; X nld = 0; X while ((lp2=lforw(lp2))!=curbp->b_linep && llength(lp2)==0) X ++nld; X if (nld == 0) X return (TRUE); X curwp->w_dotp = lforw(lp1); X curwp->w_doto = 0; X return (ldelete(nld)); X} X X/* X * Insert a newline, then enough tabs and spaces to duplicate the indentation X * of the previous line. Assumes tabs are every eight characters. Quite simple. X * Figure out the indentation of the current line. Insert a newline by calling X * the standard routine. Insert the indentation by inserting the right number X * of tabs and spaces. Return TRUE if all ok. Return FALSE if one of the X * subcomands failed. Normally bound to "C-J". X */ Xindent(f, n) X{ X register int nicol; X register int c; X register int i; X X if (curbp->b_mode&MDVIEW) /* don't allow this command if */ X return(rdonly()); /* we are in read only mode */ X if (n < 0) X return (FALSE); X while (n--) { X nicol = 0; X for (i=0; iw_dotp); ++i) { X c = lgetc(curwp->w_dotp, i); X if (c!=' ' && c!='\t') X break; X if (c == '\t') X nicol |= 0x07; X ++nicol; X } X if (lnewline() == FALSE X || ((i=nicol/8)!=0 && linsert(i, '\t')==FALSE) X || ((i=nicol%8)!=0 && linsert(i, ' ')==FALSE)) X return (FALSE); X } X return (TRUE); X} X X/* X * Delete forward. This is real easy, because the basic delete routine does X * all of the work. Watches for negative arguments, and does the right thing. X * If any argument is present, it kills rather than deletes, to prevent loss X * of text if typed with a big argument. Normally bound to "C-D". X */ Xforwdel(f, n) X{ X if (curbp->b_mode&MDVIEW) /* don't allow this command if */ X return(rdonly()); /* we are in read only mode */ X if (n < 0) X return (backdel(f, -n)); X if (f != FALSE) { /* Really a kill. */ X if ((lastflag&CFKILL) == 0) X kdelete(); X thisflag |= CFKILL; X } X return (ldelete(n, f)); X} X X/* X * Delete backwards. This is quite easy too, because it's all done with other X * functions. Just move the cursor back, and delete forwards. Like delete X * forward, this actually does a kill if presented with an argument. Bound to X * both "RUBOUT" and "C-H". X */ Xbackdel(f, n) X{ X register int s; X X if (curbp->b_mode&MDVIEW) /* don't allow this command if */ X return(rdonly()); /* we are in read only mode */ X if (n < 0) X return (forwdel(f, -n)); X if (f != FALSE) { /* Really a kill. */ X if ((lastflag&CFKILL) == 0) X kdelete(); X thisflag |= CFKILL; X } X if ((s=backchar(f, n)) == TRUE) X s = ldelete(n, f); X return (s); X} X X/* X * Kill text. If called without an argument, it kills from dot to the end of X * the line, unless it is at the end of the line, when it kills the newline. X * If called with an argument of 0, it kills from the start of the line to dot. X * If called with a positive argument, it kills from dot forward over that X * number of newlines. If called with a negative argument it kills backwards X * that number of newlines. Normally bound to "C-K". X */ Xkilltext(f, n) X{ X register int chunk; X register LINE *nextp; X X if (curbp->b_mode&MDVIEW) /* don't allow this command if */ X return(rdonly()); /* we are in read only mode */ X if ((lastflag&CFKILL) == 0) /* Clear kill buffer if */ X kdelete(); /* last wasn't a kill. */ X thisflag |= CFKILL; X if (f == FALSE) { X chunk = llength(curwp->w_dotp)-curwp->w_doto; X if (chunk == 0) X chunk = 1; X } else if (n == 0) { X chunk = curwp->w_doto; X curwp->w_doto = 0; X } else if (n > 0) { X chunk = llength(curwp->w_dotp)-curwp->w_doto+1; X nextp = lforw(curwp->w_dotp); X while (--n) { X if (nextp == curbp->b_linep) X return (FALSE); X chunk += llength(nextp)+1; X nextp = lforw(nextp); X } X } else { X mlwrite("neg kill"); X return (FALSE); X } X return (ldelete(chunk, TRUE)); X} X X/* X * Yank text back from the kill buffer. This is really easy. All of the work X * is done by the standard insert routines. All you do is run the loop, and X * check for errors. Bound to "C-Y". X */ Xyank(f, n) X{ X register int c; X register int i; X extern int kused; X X if (curbp->b_mode&MDVIEW) /* don't allow this command if */ X return(rdonly()); /* we are in read only mode */ X if (n < 0) X return (FALSE); X while (n--) { X i = 0; X while ((c=kremove(i)) >= 0) { X if (c == '\n') { X if (lnewline(FALSE, 1) == FALSE) X return (FALSE); X } else { X if (linsert(1, c) == FALSE) X return (FALSE); X } X ++i; X } X } X return (TRUE); X} X Xsetmode(f, n) /* prompt and set an editor mode */ X Xint f, n; /* default and argument */ X X{ X adjustmode(TRUE, FALSE); X} X Xdelmode(f, n) /* prompt and delete an editor mode */ X Xint f, n; /* default and argument */ X X{ X adjustmode(FALSE, FALSE); X} X Xsetgmode(f, n) /* prompt and set a global editor mode */ X Xint f, n; /* default and argument */ X X{ X adjustmode(TRUE, TRUE); X} X Xdelgmode(f, n) /* prompt and delete a global editor mode */ X Xint f, n; /* default and argument */ X X{ X adjustmode(FALSE, TRUE); X} X Xadjustmode(kind, global) /* change the editor mode status */ X Xint kind; /* true = set, false = delete */ Xint global; /* true = global flag, false = current buffer flag */ X{ X register char prompt[50]; /* string to prompt user with */ X register char *scan; /* scanning pointer to convert prompt */ X register int i; /* loop index */ X char cbuf[NPAT]; /* buffer to recieve mode name into */ X X /* build the proper prompt string */ X if (global) X strcpy(prompt,"Global mode to "); X else X strcpy(prompt,"Mode to "); X X if (kind == TRUE) X strcat(prompt, "add: "); X else X strcat(prompt, "delete: "); X X /* prompt the user and get an answer */ X X mlreply(prompt, cbuf, NPAT - 1); X X /* make it uppercase */ X X scan = cbuf; X while (*scan != 0) { X if (*scan >= 'a' && *scan <= 'z') X *scan = *scan - 32; X scan++; X } X X /* test it against the modes we know */ X X for (i=0; i < NUMMODES; i++) { X if (strcmp(cbuf, modename[i]) == 0) { X /* finding a match, we process it */ X if (kind == TRUE) X if (global) X gmode |= (1 << i); X else X curwp->w_bufp->b_mode |= (1 << i); X else X if (global) X gmode &= ~(1 << i); X else X curwp->w_bufp->b_mode &= ~(1 << i); X /* display new mode line */ X if (global == 0) X upmode(); X mlerase(); /* erase the junk */ X return(TRUE); X } X } X X mlwrite("No such mode!"); X return(FALSE); X} *-*-END-of-random.c-*-* echo x - region.c sed 's/^X//' >region.c <<'*-*-END-of-region.c-*-*' X/* X * The routines in this file X * deal with the region, that magic space X * between "." and mark. Some functions are X * commands. Some functions are just for X * internal use. X */ X#include X#include "estruct.h" X#include "edef.h" X X/* X * Kill the region. Ask "getregion" X * to figure out the bounds of the region. X * Move "." to the start, and kill the characters. X * Bound to "C-W". X */ Xkillregion(f, n) X{ X register int s; X REGION region; X X if (curbp->b_mode&MDVIEW) /* don't allow this command if */ X return(rdonly()); /* we are in read only mode */ X if ((s=getregion(®ion)) != TRUE) X return (s); X if ((lastflag&CFKILL) == 0) /* This is a kill type */ X kdelete(); /* command, so do magic */ X thisflag |= CFKILL; /* kill buffer stuff. */ X curwp->w_dotp = region.r_linep; X curwp->w_doto = region.r_offset; X return (ldelete(region.r_size, TRUE)); X} X X/* X * Copy all of the characters in the X * region to the kill buffer. Don't move dot X * at all. This is a bit like a kill region followed X * by a yank. Bound to "M-W". X */ Xcopyregion(f, n) X{ X register LINE *linep; X register int loffs; X register int s; X REGION region; X X if ((s=getregion(®ion)) != TRUE) X return (s); X if ((lastflag&CFKILL) == 0) /* Kill type command. */ X kdelete(); X thisflag |= CFKILL; X linep = region.r_linep; /* Current line. */ X loffs = region.r_offset; /* Current offset. */ X while (region.r_size--) { X if (loffs == llength(linep)) { /* End of line. */ X if ((s=kinsert('\n')) != TRUE) X return (s); X linep = lforw(linep); X loffs = 0; X } else { /* Middle of line. */ X if ((s=kinsert(lgetc(linep, loffs))) != TRUE) X return (s); X ++loffs; X } X } X return (TRUE); X} X X/* X * Lower case region. Zap all of the upper X * case characters in the region to lower case. Use X * the region code to set the limits. Scan the buffer, X * doing the changes. Call "lchange" to ensure that X * redisplay is done in all buffers. Bound to X * "C-X C-L". X */ Xlowerregion(f, n) X{ X register LINE *linep; X register int loffs; X register int c; X register int s; X REGION region; X X if (curbp->b_mode&MDVIEW) /* don't allow this command if */ X return(rdonly()); /* we are in read only mode */ X if ((s=getregion(®ion)) != TRUE) X return (s); X lchange(WFHARD); X linep = region.r_linep; X loffs = region.r_offset; X while (region.r_size--) { X if (loffs == llength(linep)) { X linep = lforw(linep); X loffs = 0; X } else { X c = lgetc(linep, loffs); X if (c>='A' && c<='Z') X lputc(linep, loffs, c+'a'-'A'); X ++loffs; X } X } X return (TRUE); X} X X/* X * Upper case region. Zap all of the lower X * case characters in the region to upper case. Use X * the region code to set the limits. Scan the buffer, X * doing the changes. Call "lchange" to ensure that X * redisplay is done in all buffers. Bound to X * "C-X C-L". X */ Xupperregion(f, n) X{ X register LINE *linep; X register int loffs; X register int c; X register int s; X REGION region; X X if (curbp->b_mode&MDVIEW) /* don't allow this command if */ X return(rdonly()); /* we are in read only mode */ X if ((s=getregion(®ion)) != TRUE) X return (s); X lchange(WFHARD); X linep = region.r_linep; X loffs = region.r_offset; X while (region.r_size--) { X if (loffs == llength(linep)) { X linep = lforw(linep); X loffs = 0; X } else { X c = lgetc(linep, loffs); X if (c>='a' && c<='z') X lputc(linep, loffs, c-'a'+'A'); X ++loffs; X } X } X return (TRUE); X} X X/* X * This routine figures out the X * bounds of the region in the current window, and X * fills in the fields of the "REGION" structure pointed X * to by "rp". Because the dot and mark are usually very X * close together, we scan outward from dot looking for X * mark. This should save time. Return a standard code. X * Callers of this routine should be prepared to get X * an "ABORT" status; we might make this have the X * conform thing later. X */ Xgetregion(rp) Xregister REGION *rp; X{ X register LINE *flp; X register LINE *blp; X int fsize; X register int bsize; X X if (curwp->w_markp == NULL) { X mlwrite("No mark set in this window"); X return (FALSE); X } X if (curwp->w_dotp == curwp->w_markp) { X rp->r_linep = curwp->w_dotp; X if (curwp->w_doto < curwp->w_marko) { X rp->r_offset = curwp->w_doto; X rp->r_size = curwp->w_marko-curwp->w_doto; X } else { X rp->r_offset = curwp->w_marko; X rp->r_size = curwp->w_doto-curwp->w_marko; X } X return (TRUE); X } X blp = curwp->w_dotp; X bsize = curwp->w_doto; X flp = curwp->w_dotp; X fsize = llength(flp)-curwp->w_doto+1; X while (flp!=curbp->b_linep || lback(blp)!=curbp->b_linep) { X if (flp != curbp->b_linep) { X flp = lforw(flp); X if (flp == curwp->w_markp) { X rp->r_linep = curwp->w_dotp; X rp->r_offset = curwp->w_doto; X rp->r_size = fsize+curwp->w_marko; X return (TRUE); X } X fsize += llength(flp)+1; X } X if (lback(blp) != curbp->b_linep) { X blp = lback(blp); X bsize += llength(blp)+1; X if (blp == curwp->w_markp) { X rp->r_linep = blp; X rp->r_offset = curwp->w_marko; X rp->r_size = bsize - curwp->w_marko; X return (TRUE); X } X } X } X mlwrite("Bug: lost mark"); X return (FALSE); X} *-*-END-of-region.c-*-* echo x - search.c sed 's/^X//' >search.c <<'*-*-END-of-search.c-*-*' X/* X * The functions in this file implement commands that search in the forward X * and backward directions. There are no special characters in the search X * strings. Probably should have a regular expression search, or something X * like that. X * X */ X X#include X#include "estruct.h" X#include "edef.h" X X/* X * Search forward. Get a search string from the user, and search, beginning at X * ".", for the string. If found, reset the "." to be just after the match X * string, and [perhaps] repaint the display. Bound to "C-S". X */ X X/* string search input parameters */ X X#define PTBEG 1 /* leave the point at the begining on search */ X#define PTEND 2 /* leave the point at the end on search */ X Xforwsearch(f, n) X X{ X register int status; X X /* resolve the repeat count */ X if (n == 0) X n = 1; X if (n < 1) /* search backwards */ X return(backsearch(f, -n)); X X /* ask the user for the text of a pattern */ X if ((status = readpattern("Search")) != TRUE) X return(status); X X /* search for the pattern */ X while (n-- > 0) { X if ((status = forscan(&pat[0],PTEND)) == FALSE) X break; X } X X /* and complain if not there */ X if (status == FALSE) X mlwrite("Not found"); X return(status); X} X Xforwhunt(f, n) X X{ X register int status; X X /* resolve the repeat count */ X if (n == 0) X n = 1; X if (n < 1) /* search backwards */ X return(backhunt(f, -n)); X X /* Make sure a pattern exists */ X if (pat[0] == 0) { X mlwrite("No pattern set"); X return(FALSE); X } X X /* search for the pattern */ X while (n-- > 0) { X if ((status = forscan(&pat[0],PTEND)) == FALSE) X break; X } X X /* and complain if not there */ X if (status == FALSE) X mlwrite("Not found"); X return(status); X} X X/* X * Reverse search. Get a search string from the user, and search, starting at X * "." and proceeding toward the front of the buffer. If found "." is left X * pointing at the first character of the pattern [the last character that was X * matched]. Bound to "C-R". X */ Xbacksearch(f, n) X X{ X register int s; X X /* resolve null and negative arguments */ X if (n == 0) X n = 1; X if (n < 1) X return(forwsearch(f, -n)); X X /* get a pattern to search */ X if ((s = readpattern("Reverse search")) != TRUE) X return(s); X X /* and go search for it */ X bsearch(f,n); X} X Xbackhunt(f, n) /* hunt backward for the last search string entered */ X X{ X /* resolve null and negative arguments */ X if (n == 0) X n = 1; X if (n < 1) X return(forwhunt(f, -n)); X X /* Make sure a pattern exists */ X if (pat[0] == 0) { X mlwrite("No pattern set"); X return(FALSE); X } X X /* and go search for it */ X bsearch(f,n); X} X Xbsearch(f, n) X X{ X register LINE *clp; X register int cbo; X register LINE *tlp; X register int tbo; X register int c; X register char *epp; X register char *pp; X X /* find a pointer to the end of the pattern */ X for (epp = &pat[0]; epp[1] != 0; ++epp) X ; X X /* make local copies of the starting location */ X clp = curwp->w_dotp; X cbo = curwp->w_doto; X X while (n-- > 0) { X for (;;) { X /* if we are at the begining of the line, wrap back around */ X if (cbo == 0) { X clp = lback(clp); X X if (clp == curbp->b_linep) { X mlwrite("Not found"); X return(FALSE); X } X X cbo = llength(clp)+1; X } X X /* fake the at the end of a line */ X if (--cbo == llength(clp)) X c = '\n'; X else X c = lgetc(clp, cbo); X X /* check for a match against the end of the pattern */ X if (eq(c, *epp) != FALSE) { X tlp = clp; X tbo = cbo; X pp = epp; X X /* scanning backwards through the rest of the X pattern looking for a match */ X while (pp != &pat[0]) { X /* wrap across a line break */ X if (tbo == 0) { X tlp = lback(tlp); X if (tlp == curbp->b_linep) X goto fail; X X tbo = llength(tlp)+1; X } X X /* fake the */ X if (--tbo == llength(tlp)) X c = '\n'; X else X c = lgetc(tlp, tbo); X X if (eq(c, *--pp) == FALSE) X goto fail; X } X X /* A Match! reset the current cursor */ X curwp->w_dotp = tlp; X curwp->w_doto = tbo; X curwp->w_flag |= WFMOVE; X goto next; X } Xfail:; X } Xnext:; X } X return(TRUE); X} X X/* X * Compare two characters. The "bc" comes from the buffer. It has it's case X * folded out. The "pc" is from the pattern. X */ Xeq(bc, pc) X int bc; X int pc; X X{ X if ((curwp->w_bufp->b_mode & MDEXACT) == 0) { X if (bc>='a' && bc<='z') X bc -= 0x20; X X if (pc>='a' && pc<='z') X pc -= 0x20; X } X X if (bc == pc) X return(TRUE); X X return(FALSE); X} X X/* X * Read a pattern. Stash it in the external variable "pat". The "pat" is not X * updated if the user types in an empty line. If the user typed an empty line, X * and there is no old pattern, it is an error. Display the old pattern, in the X * style of Jeff Lomicka. There is some do-it-yourself control expansion. X * change to using to delemit the end-of-pattern to allow s in X * the search string. X */ Xreadpattern(prompt) X Xchar *prompt; X X{ X register int s; X char tpat[NPAT+20]; X X strcpy(tpat, prompt); /* copy prompt to output string */ X strcat(tpat, " ["); /* build new prompt string */ X expandp(&pat[0], &tpat[strlen(tpat)], NPAT/2); /* add old pattern */ X strcat(tpat, "]: "); X X s = mlreplyt(tpat, tpat, NPAT, 27); /* Read pattern */ X X if (s == TRUE) /* Specified */ X strcpy(pat, tpat); X else if (s == FALSE && pat[0] != 0) /* CR, but old one */ X s = TRUE; X X return(s); X} X Xsreplace(f, n) /* Search and replace (ESC-R) */ X Xint f; /* default flag */ Xint n; /* # of repetitions wanted */ X X{ X return(replaces(FALSE, f, n)); X} X Xqreplace(f, n) /* search and replace with query (ESC-CTRL-R) */ X Xint f; /* default flag */ Xint n; /* # of repetitions wanted */ X X{ X return(replaces(TRUE, f, n)); X} X X/* replaces: search for a string and replace it with another X string. query might be enabled (according to X kind). */ Xreplaces(kind, f, n) X Xint kind; /* Query enabled flag */ Xint f; /* default flag */ Xint n; /* # of repetitions wanted */ X X{ X register int i; /* loop index */ X register int s; /* success flag on pattern inputs */ X register int slength, X rlength; /* length of search and replace strings */ X register int numsub; /* number of substitutions */ X register int nummatch; /* number of found matches */ X int nlflag; /* last char of search string a ? */ X int nlrepl; /* was a replace done on the last line? */ X char tmpc; /* temporary character */ X char c; /* input char for query */ X char tpat[NPAT]; /* temporary to hold search pattern */ X LINE *origline; /* original "." position */ X int origoff; /* and offset (for . query option) */ X X if (curbp->b_mode&MDVIEW) /* don't allow this command if */ X return(rdonly()); /* we are in read only mode */ X X /* check for negative repititions */ X if (f && n < 0) X return(FALSE); X X /* ask the user for the text of a pattern */ X if ((s = readpattern( X (kind == FALSE ? "Replace" : "Query replace"))) != TRUE) X return(s); X strcpy(&tpat[0], &pat[0]); /* salt it away */ X X /* ask for the replacement string */ X strcpy(&pat[0], &rpat[0]); /* set up default string */ X if ((s = readpattern("with")) == ABORT) X return(s); X X /* move everything to the right place and length them */ X strcpy(&rpat[0], &pat[0]); X strcpy(&pat[0], &tpat[0]); X slength = strlen(&pat[0]); X rlength = strlen(&rpat[0]); X X /* set up flags so we can make sure not to do a recursive X replace on the last line */ X nlflag = (pat[slength - 1] == '\n'); X nlrepl = FALSE; X X /* build query replace question string */ X strcpy(tpat, "Replace '"); X expandp(&pat[0], &tpat[strlen(tpat)], NPAT/3); X strcat(tpat, "' with '"); X expandp(&rpat[0], &tpat[strlen(tpat)], NPAT/3); X strcat(tpat, "'? "); X X /* save original . position */ X origline = curwp->w_dotp; X origoff = curwp->w_doto; X X /* scan through the file */ X numsub = 0; X nummatch = 0; X while ((f == FALSE || n > nummatch) && X (nlflag == FALSE || nlrepl == FALSE)) { X X /* search for the pattern */ X if (forscan(&pat[0],PTBEG) != TRUE) X break; /* all done */ X ++nummatch; /* increment # of matches */ X X /* check if we are on the last line */ X nlrepl = (lforw(curwp->w_dotp) == curwp->w_bufp->b_linep); X X /* check for query */ X if (kind) { X /* get the query */ X mlwrite(&tpat[0], &pat[0], &rpat[0]); Xqprompt: X update(); /* show the proposed place to change */ X c = (*term.t_getchar)(); /* and input */ X mlwrite(""); /* and clear it */ X X /* and respond appropriately */ X switch (c) { X case 'y': /* yes, substitute */ X case ' ': X break; X X case 'n': /* no, onword */ X forwchar(FALSE, 1); X continue; X X case '!': /* yes/stop asking */ X kind = FALSE; X break; X X case '.': /* abort! and return */ X /* restore old position */ X curwp->w_dotp = origline; X curwp->w_doto = origoff; X curwp->w_flag |= WFMOVE; X X case BELL: /* abort! and stay */ X mlwrite("Aborted!"); X return(FALSE); X X default: /* bitch and beep */ X (*term.t_beep)(); X X case '?': /* help me */ Xmlwrite("(Y)es, (N)o, (!)Do the rest, (^G)Abort, (.)Abort back, (?)Help: "); X goto qprompt; X X } X } X X /* delete the sucker */ X if (ldelete(slength, FALSE) != TRUE) { X /* error while deleting */ X mlwrite("ERROR while deleteing"); X return(FALSE); X } X X /* and insert its replacement */ X for (i=0; i */ X Xchar *patrn; /* string to scan for */ Xint leavep; /* place to leave point X PTBEG = begining of match X PTEND = at end of match */ X X{ X register LINE *curline; /* current line during scan */ X register int curoff; /* position within current line */ X register LINE *lastline; /* last line position during scan */ X register int lastoff; /* position within last line */ X register int c; /* character at current position */ X register LINE *matchline; /* current line during matching */ X register int matchoff; /* position in matching line */ X register char *patptr; /* pointer into pattern */ X X /* setup local scan pointers to global "." */ X X curline = curwp->w_dotp; X curoff = curwp->w_doto; X X /* scan each character until we hit the head link record */ X X while (curline != curbp->b_linep) { X X /* save the current position in case we need to X restore it on a match */ X X lastline = curline; X lastoff = curoff; X X /* get the current character resolving EOLs */ X X if (curoff == llength(curline)) { /* if at EOL */ X curline = lforw(curline); /* skip to next line */ X curoff = 0; X c = '\n'; /* and return a */ X } else X c = lgetc(curline, curoff++); /* get the char */ X X /* test it against first char in pattern */ X if (eq(c, patrn[0]) != FALSE) { /* if we find it..*/ X /* setup match pointers */ X matchline = curline; X matchoff = curoff; X patptr = &patrn[0]; X X /* scan through patrn for a match */ X while (*++patptr != 0) { X /* advance all the pointers */ X if (matchoff == llength(matchline)) { X /* advance past EOL */ X matchline = lforw(matchline); X matchoff = 0; X c = '\n'; X } else X c = lgetc(matchline, matchoff++); X X /* and test it against the pattern */ X if (eq(*patptr, c) == FALSE) X goto fail; X } X X /* A SUCCESSFULL MATCH!!! */ X /* reset the global "." pointers */ X if (leavep == PTEND) { /* at end of string */ X curwp->w_dotp = matchline; X curwp->w_doto = matchoff; X } else { /* at begining of string */ X curwp->w_dotp = lastline; X curwp->w_doto = lastoff; X } X curwp->w_flag |= WFMOVE; /* flag that we have moved */ X return(TRUE); X X } Xfail:; /* continue to search */ X } X X /* we could not find a match */ X X return(FALSE); X} X X/* expandp: expand control key sequences for output */ X Xexpandp(srcstr, deststr, maxlength) X Xchar *srcstr; /* string to expand */ Xchar *deststr; /* destination of expanded string */ Xint maxlength; /* maximum chars in destination */ X X{ X char c; /* current char to translate */ X X /* scan through the string */ X while ((c = *srcstr++) != 0) { X if (c == '\n') { /* its an EOL */ X *deststr++ = '<'; X *deststr++ = 'N'; X *deststr++ = 'L'; X *deststr++ = '>'; X maxlength -= 4; X } else if (c < 0x20 || c == 0x7f) { /* control character */ X *deststr++ = '^'; X *deststr++ = c ^ 0x40; X maxlength -= 2; X } else if (c == '%') { X *deststr++ = '%'; X *deststr++ = '%'; X maxlength -= 2; X X } else { /* any other character */ X *deststr++ = c; X maxlength--; X } X X /* check for maxlength */ X if (maxlength < 4) { X *deststr++ = '$'; X *deststr = '\0'; X return(FALSE); X } X } X *deststr = '\0'; X return(TRUE); X} *-*-END-of-search.c-*-* echo x - spawn.c sed 's/^X//' >spawn.c <<'*-*-END-of-spawn.c-*-*' X/* X * The routines in this file are called to create a subjob running a command X * interpreter. This code is a big fat nothing on CP/M-86. You lose. X */ X#include X#include "estruct.h" X#include "edef.h" X X#if AMIGA X#define NEW 1006 X#endif X X#if VMS X#define EFN 0 /* Event flag. */ X X#include /* Random headers. */ X#include X#include X#include X Xextern int oldmode[]; /* In "termio.c" */ Xextern int newmode[]; /* In "termio.c" */ Xextern short iochan; /* In "termio.c" */ X#endif X X#if MSDOS & LATTICE X#include X#undef CPM X#endif X X#if V7 X#include Xextern int vttidy(); X#endif X X/* X * Create a subjob with a copy of the command intrepreter in it. When the X * command interpreter exits, mark the screen as garbage so that you do a full X * repaint. Bound to "^X C". The message at the start in VMS puts out a newline. X * Under some (unknown) condition, you don't get one free when DCL starts up. X */ Xspawncli(f, n) X{ X#if AMIGA X long newcli; X X newcli = Open("CON:1/1/639/199/MicroEmacs Subprocess", NEW); X mlwrite("[Starting new CLI]"); X sgarbf = TRUE; X Execute("", newcli, 0); X Close(newcli); X return(TRUE); X#endif X X#if V7 X register char *cp; X char *getenv(); X#endif X#if VMS X movecursor(term.t_nrow, 0); /* In last line. */ X mlputs("[Starting DCL]\r\n"); X (*term.t_flush)(); /* Ignore "ttcol". */ X sgarbf = TRUE; X return (sys(NULL)); /* NULL => DCL. */ X#endif X#if CPM X mlwrite("Not in CP/M-86"); X#endif X#if MSDOS & AZTEC X movecursor(term.t_nrow, 0); /* Seek to last line. */ X (*term.t_flush)(); X system("command.com"); X sgarbf = TRUE; X return(TRUE); X#endif X#if MSDOS & LATTICE X movecursor(term.t_nrow, 0); /* Seek to last line. */ X (*term.t_flush)(); X sys("\\command.com", ""); /* Run CLI. */ X sgarbf = TRUE; X return(TRUE); X#endif X#if V7 X movecursor(term.t_nrow, 0); /* Seek to last line. */ X (*term.t_flush)(); X ttclose(); /* stty to old settings */ X if ((cp = getenv("SHELL")) != NULL && *cp != '\0') X system(cp); X else X#if BSD X system("exec /bin/csh"); X#else X system("exec /bin/sh"); X#endif X sgarbf = TRUE; X sleep(2); X ttopen(); X return(TRUE); X#endif X} X X#if V7 & BSD X Xbktoshell() /* suspend MicroEMACS and wait to wake up */ X{ X int pid; X X vttidy(); X pid = getpid(); X kill(pid,SIGTSTP); X} X Xrtfrmshell() X{ X ttopen(); X curwp->w_flag = WFHARD; X refresh(); X} X#endif X X/* X * Run a one-liner in a subjob. When the command returns, wait for a single X * character to be typed, then mark the screen as garbage so a full repaint is X * done. Bound to "C-X !". X */ Xspawn(f, n) X{ X register int s; X char line[NLINE]; X#if AMIGA X long newcli; X X newcli = Open("CON:1/1/639/199/MicroEmacs Subprocess", NEW); X if ((s=mlreply("CLI command: ", line, NLINE)) != TRUE) X return (s); X Execute(line,0,newcli); X Close(newcli); X (*term.t_getchar)(); /* Pause. */ X sgarbf = TRUE; X return(TRUE); X#endif X#if VMS X if ((s=mlreply("DCL command: ", line, NLINE)) != TRUE) X return (s); X (*term.t_putchar)('\n'); /* Already have '\r' */ X (*term.t_flush)(); X s = sys(line); /* Run the command. */ X mlputs("\r\n\n[End]"); /* Pause. */ X (*term.t_flush)(); X (*term.t_getchar)(); X sgarbf = TRUE; X return (s); X#endif X#if CPM X mlwrite("Not in CP/M-86"); X return (FALSE); X#endif X#if MSDOS X if ((s=mlreply("MS-DOS command: ", line, NLINE)) != TRUE) X return (s); X system(line); X mlputs("\r\n\n[End]"); /* Pause. */ X (*term.t_getchar)(); /* Pause. */ X sgarbf = TRUE; X return (TRUE); X#endif X#if V7 X if ((s=mlreply("! ", line, NLINE)) != TRUE) X return (s); X (*term.t_putchar)('\n'); /* Already have '\r' */ X (*term.t_flush)(); X ttclose(); /* stty to old modes */ X system(line); X sleep(2); X ttopen(); X mlputs("[End]"); /* Pause. */ X (*term.t_flush)(); X while ((s = (*term.t_getchar)()) != '\r' && s != ' ') X ; X sgarbf = TRUE; X return (TRUE); X#endif X} X X#if VMS X/* X * Run a command. The "cmd" is a pointer to a command string, or NULL if you X * want to run a copy of DCL in the subjob (this is how the standard routine X * LIB$SPAWN works. You have to do wierd stuff with the terminal on the way in X * and the way out, because DCL does not want the channel to be in raw mode. X */ Xsys(cmd) Xregister char *cmd; X{ X struct dsc$descriptor cdsc; X struct dsc$descriptor *cdscp; X long status; X long substatus; X long iosb[2]; X X status = SYS$QIOW(EFN, iochan, IO$_SETMODE, iosb, 0, 0, X oldmode, sizeof(oldmode), 0, 0, 0, 0); X if (status!=SS$_NORMAL || (iosb[0]&0xFFFF)!=SS$_NORMAL) X return (FALSE); X cdscp = NULL; /* Assume DCL. */ X if (cmd != NULL) { /* Build descriptor. */ X cdsc.dsc$a_pointer = cmd; X cdsc.dsc$w_length = strlen(cmd); X cdsc.dsc$b_dtype = DSC$K_DTYPE_T; X cdsc.dsc$b_class = DSC$K_CLASS_S; X cdscp = &cdsc; X } X status = LIB$SPAWN(cdscp, 0, 0, 0, 0, 0, &substatus, 0, 0, 0); X if (status != SS$_NORMAL) X substatus = status; X status = SYS$QIOW(EFN, iochan, IO$_SETMODE, iosb, 0, 0, X newmode, sizeof(newmode), 0, 0, 0, 0); X if (status!=SS$_NORMAL || (iosb[0]&0xFFFF)!=SS$_NORMAL) X return (FALSE); X if ((substatus&STS$M_SUCCESS) == 0) /* Command failed. */ X return (FALSE); X return (TRUE); X} X#endif X X#if ~AZTEC & MSDOS X X/* X * This routine, once again by Bob McNamara, is a C translation of the "system" X * routine in the MWC-86 run time library. It differs from the "system" routine X * in that it does not unconditionally append the string ".exe" to the end of X * the command name. We needed to do this because we want to be able to spawn X * off "command.com". We really do not understand what it does, but if you don't X * do it exactly "malloc" starts doing very very strange things. X */ Xsys(cmd, tail) Xchar *cmd; Xchar *tail; X{ X#if MWC_86 X register unsigned n; X extern char *__end; X X n = __end + 15; X n >>= 4; X n = ((n + dsreg() + 16) & 0xFFF0) + 16; X return(execall(cmd, tail, n)); X#endif X X#if LATTICE X return forklp(cmd, tail, NULL); X#endif X} X#endif *-*-END-of-spawn.c-*-* echo x - tcap.c sed 's/^X//' >tcap.c <<'*-*-END-of-tcap.c-*-*' X/* tcap: Unix V5, V7 and BS4.2 Termcap video driver X for MicroEMACS X*/ X X#define termdef 1 /* don't define "term" external */ X X#include X#include "estruct.h" X#include "edef.h" X X#if TERMCAP X X#define NROW 24 X#define NCOL 80 X#define MARGIN 8 X#define SCRSIZ 64 X#define BEL 0x07 X#define ESC 0x1B X Xextern int ttopen(); Xextern int ttgetc(); Xextern int ttputc(); Xextern int ttflush(); Xextern int ttclose(); Xextern int tcapmove(); Xextern int tcapeeol(); Xextern int tcapeeop(); Xextern int tcapbeep(); Xextern int tcaprev(); Xextern int tcapopen(); Xextern int tput(); Xextern char *tgoto(); X X#define TCAPSLEN 315 Xchar tcapbuf[TCAPSLEN]; Xchar *UP, PC, *CM, *CE, *CL, *SO, *SE; X XTERM term = { X NROW-1, X NCOL, X MARGIN, X SCRSIZ, X tcapopen, X ttclose, X ttgetc, X ttputc, X ttflush, X tcapmove, X tcapeeol, X tcapeeop, X tcapbeep, X tcaprev X}; X Xtcapopen() X X{ X char *getenv(); X char *t, *p, *tgetstr(); X char tcbuf[1024]; X char *tv_stype; X char err_str[72]; X X if ((tv_stype = getenv("TERM")) == NULL) X { X puts("Environment variable TERM not defined!"); X exit(1); X } X X if((tgetent(tcbuf, tv_stype)) != 1) X { X sprintf(err_str, "Unknown terminal type %s!", tv_stype); X puts(err_str); X exit(1); X } X X p = tcapbuf; X t = tgetstr("pc", &p); X if(t) X PC = *t; X X CL = tgetstr("cl", &p); X CM = tgetstr("cm", &p); X CE = tgetstr("ce", &p); X UP = tgetstr("up", &p); X SE = tgetstr("se", &p); X SO = tgetstr("so", &p); X if (SO != NULL) X revexist = TRUE; X X if(CL == NULL || CM == NULL || UP == NULL) X { X puts("Incomplete termcap entry\n"); X exit(1); X } X X if (CE == NULL) /* will we be able to use clear to EOL? */ X eolexist = FALSE; X X if (p >= &tcapbuf[TCAPSLEN]) X { X puts("Terminal description too big!\n"); X exit(1); X } X ttopen(); X} X Xtcapmove(row, col) Xregister int row, col; X{ X putpad(tgoto(CM, col, row)); X} X Xtcapeeol() X{ X putpad(CE); X} X Xtcapeeop() X{ X putpad(CL); X} X Xtcaprev(state) /* change reverse video status */ X Xint state; /* FALSE = normal video, TRUE = reverse video */ X X{ X if (state) { X if (SO != NULL) X putpad(SO); X } else { X if (SE != NULL) X putpad(SE); X } X} X Xtcapbeep() X{ X ttputc(BEL); X} X Xputpad(str) Xchar *str; X{ X tputs(str, 1, ttputc); X} X Xputnpad(str, n) Xchar *str; X{ X tputs(str, n, ttputc); X} X X#else X Xhello() X{ X} X X#endif TERMCAP *-*-END-of-tcap.c-*-* exit