Path: seismo!harvard!talcott!panda!genrad!decvax!minow (Martin Minow) From: sources-request@panda.UUCP Newsgroups: mod.sources Subject: MicroEmacs (Part 3 of 6) Message-ID: <1658@panda.UUCP> Date: 14 Apr 86 03:03:28 GMT Sender: jpn@panda.UUCP Lines: 2510 Approved: jpn@panda.UUCP Mod.sources: Volume 4, Issue 70 Submitted by: decvax!minow (Martin Minow) #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # random.c # region.c # search.c # symbol.c # version.c # window.c # word.c # This archive created: Sun Apr 13 11:16:33 1986 export PATH; PATH=/bin:$PATH echo shar: extracting "'random.c'" '(10957 characters)' if test -f 'random.c' then echo shar: will not over-write existing file "'random.c'" else cat << \SHAR_EOF > 'random.c' /* * Name: MicroEMACS * Assorted commands. * Version: 29 * Last edit: 10-Feb-86 * By: rex::conroy * decvax!decwrl!dec-rhea!dec-rex!conroy * * The file contains the command * processors for a large assortment of unrelated * commands. The only thing they have in common is * that they are all command processors. */ #include "def.h" /* * Display a bunch of useful information about * the current location of dot. The character under the * cursor (in octal), the current line, row, and column, and * approximate position of the cursor in the file (as a percentage) * is displayed. The column position assumes an infinite position * display; it does not truncate just because the screen does. * This is normally bound to "C-X =". */ showcpos(f, n, k) { register LINE *clp; register int cbo; register int nchar; register int cchar; register int nline; register int cline; register int cbyte; register int ratio; register int row; register int col; register int i; register int c; clp = lforw(curbp->b_linep); /* Collect the data. */ cbo = 0; nchar = 0; nline = 1; /* Origin 1. */ for (;;) { if (clp == curwp->w_dotp) { cline = nline; if (cbo == curwp->w_doto) { cchar = nchar; if (cbo == llength(clp)) cbyte = '\n'; else cbyte = lgetc(clp, cbo); } } if (cbo == llength(clp)) { if (clp == curbp->b_linep) break; clp = lforw(clp); cbo = 0; ++nline; /* Count a line. */ } else ++cbo; ++nchar; /* Count a character. */ } row = curwp->w_toprow; /* Determine row. */ clp = curwp->w_linep; while (clp!=curbp->b_linep && clp!=curwp->w_dotp) { ++row; clp = lforw(clp); } ++row; /* Convert to origin 1. */ col = 0; /* Determine column. */ for (i=0; iw_doto; ++i) { c = lgetc(curwp->w_dotp, i); if (c == '\t') col |= 0x07; else if (ISCTRL(c) != FALSE) ++col; ++col; } ++col; /* Convert to origin 1. */ ratio = 0; /* Ratio before dot. */ if (nchar != 0) { ratio = (100L*cchar) / nchar; if (ratio==0 && cchar!=0) /* Allow 0% only at the */ ratio = 1; /* start of the file. */ } eprintf("[CH:0%o Line:%d Row:%d Col:%d %d%% of %d]", cbyte, cline, row, col, ratio, nchar); return (TRUE); } /* * 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, k) { 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. */ quote(f, n, k) { register int s; register int c; if (kbdmop != NULL) c = *kbdmop++; else { c = ttgetc(); if (kbdmip != NULL) { if (kbdmip > &kbdm[NKBDM-4]) { ctrlg(FALSE, 0, KRANDOM); return (ABORT); } *kbdmip++ = c; } } 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)); } /* * Ordinary text characters are bound to this function, * which inserts them into the buffer. Characters marked as control * characters (using the CTRL flag) may be remapped to their ASCII * equivalent. This makes TAB (C-I) work right, and also makes the * world look reasonable if a control character is bound to this * this routine by hand. Any META or CTLX flags on the character * are discarded. This is the only routine that actually looks * the the "k" argument. */ selfinsert(f, n, k) { register int c; if (n < 0) return (FALSE); if (n == 0) return (TRUE); c = k & KCHAR; if ((k&KCTRL)!=0 && c>='@' && c<='_') /* ASCII-ify. */ c -= '@'; return (linsert(n, c)); } /* * Open up some blank space. The basic plan * is to insert a bunch of newlines, and then back * up over them. Everything is done by the subcommand * procerssors. They even handle the looping. Normally * this is bound to "C-O". */ openline(f, n, k) { register int i; register int s; if (n < 0) return (FALSE); if (n == 0) return (TRUE); i = n; /* Insert newlines. */ do { s = lnewline(); } while (s==TRUE && --i); if (s == TRUE) /* Then back up overtop */ s = backchar(f, n, KRANDOM); /* of them all. */ return (s); } /* * Insert a newline. * If you are at the end of the line and the * next line is a blank line, just move into the * blank line. This makes "C-O" and "C-X C-O" work * nicely, and reduces the ammount of screen * update that has to be done. This would not be * as critical if screen update were a lot * more efficient. */ newline(f, n, k) { register LINE *lp; register int s; if (n < 0) return (FALSE); while (n--) { lp = curwp->w_dotp; if (llength(lp) == curwp->w_doto && lp != curbp->b_linep && llength(lforw(lp)) == 0) { if ((s=forwchar(FALSE, 1, KRANDOM)) != TRUE) return (s); } else if ((s=lnewline()) != TRUE) return (s); } return (TRUE); } /* * Delete blank lines around dot. * What this command does depends if dot is * sitting on a blank line. If dot is sitting on a * blank line, this command deletes all the blank lines * above and below the current line. If it is sitting * on a non blank line then it deletes all of the * blank lines after the line. Normally this command * is bound to "C-X C-O". Any argument is ignored. */ deblank(f, n, k) { register LINE *lp1; register LINE *lp2; register int nld; lp1 = curwp->w_dotp; while (llength(lp1)==0 && (lp2=lback(lp1))!=curbp->b_linep) lp1 = lp2; lp2 = lp1; nld = 0; while ((lp2=lforw(lp2))!=curbp->b_linep && llength(lp2)==0) ++nld; if (nld == 0) return (TRUE); curwp->w_dotp = lforw(lp1); curwp->w_doto = 0; return (ldelete(nld, FALSE)); } /* * Insert a newline, then enough * tabs and spaces to duplicate the indentation * of the previous line. Assumes tabs are every eight * characters. Quite simple. Figure out the indentation * of the current line. Insert a newline by calling * the standard routine. Insert the indentation by * inserting the right number of tabs and spaces. * Return TRUE if all ok. Return FALSE if one * of the subcomands failed. Normally bound * to "C-J". */ indent(f, n, k) { register int nicol; register int c; register int i; if (n < 0) return (FALSE); while (n--) { nicol = 0; for (i=0; iw_dotp); ++i) { c = lgetc(curwp->w_dotp, i); if (c!=' ' && c!='\t') break; if (c == '\t') nicol |= 0x07; ++nicol; } if (lnewline() == FALSE || ((i=nicol/8)!=0 && linsert(i, '\t')==FALSE) || ((i=nicol%8)!=0 && linsert(i, ' ')==FALSE)) return (FALSE); } return (TRUE); } /* * Delete forward. This is real * easy, because the basic delete routine does * all of the work. Watches for negative arguments, * and does the right thing. If any argument is * present, it kills rather than deletes, to prevent * loss of text if typed with a big argument. * Normally bound to "C-D". */ forwdel(f, n, k) { if (n < 0) return (backdel(f, -n, KRANDOM)); if (f != FALSE) { /* Really a kill. */ if ((lastflag&CFKILL) == 0) kdelete(); thisflag |= CFKILL; } return (ldelete(n, f)); } /* * Delete backwards. This is quite easy too, * because it's all done with other functions. Just * move the cursor back, and delete forwards. * Like delete forward, this actually does a kill * if presented with an argument. */ backdel(f, n, k) { register int s; if (n < 0) return (forwdel(f, -n, KRANDOM)); if (f != FALSE) { /* Really a kill. */ if ((lastflag&CFKILL) == 0) kdelete(); thisflag |= CFKILL; } if ((s=backchar(f, n, KRANDOM)) == TRUE) s = ldelete(n, f); return (s); } /* * Kill line. If called without an argument, * it kills from dot to the end of the line, unless it * is at the end of the line, when it kills the newline. * If called with an argument of 0, it kills from the * start of the line to dot. If called with a positive * argument, it kills from dot forward over that number * of newlines. If called with a negative argument it * kills any text before dot on the current line, * then it kills back abs(arg) lines. */ killline(f, n, k) { register int chunk; register LINE *nextp; if ((lastflag&CFKILL) == 0) /* Clear kill buffer if */ kdelete(); /* last wasn't a kill. */ thisflag |= CFKILL; if (f == FALSE) { chunk = llength(curwp->w_dotp)-curwp->w_doto; if (chunk == 0) chunk = 1; } else if (n > 0) { chunk = llength(curwp->w_dotp)-curwp->w_doto+1; nextp = lforw(curwp->w_dotp); while (--n) { if (nextp == curbp->b_linep) return (FALSE); chunk += llength(nextp)+1; nextp = lforw(nextp); } } else { /* n <= 0 */ chunk = curwp->w_doto; curwp->w_doto = 0; while (n++) { if (lback(curwp->w_dotp) == curbp->b_linep) break; curwp->w_dotp = lback(curwp->w_dotp); curwp->w_flag |= WFMOVE; chunk += llength(curwp->w_dotp)+1; } } return (ldelete(chunk, TRUE)); } /* * Yank text back from the kill buffer. This * is really easy. All of the work is done by the * standard insert routines. All you do is run the loop, * and check for errors. The blank * lines are inserted with a call to "newline" * instead of a call to "lnewline" so that the magic * stuff that happens when you type a carriage * return also happens when a carriage return is * yanked back from the kill buffer. * An attempt has been made to fix the cosmetic bug * associated with a yank when dot is on the top line of * the window (nothing moves, because all of the new * text landed off screen). */ yank(f, n, k) { register int c; register int i; register LINE *lp; register int nline; if (n < 0) return (FALSE); nline = 0; /* Newline counting. */ while (n--) { i = 0; while ((c=kremove(i)) >= 0) { if (c == '\n') { if (newline(FALSE, 1, KRANDOM) == FALSE) return (FALSE); ++nline; } else { if (linsert(1, c) == FALSE) return (FALSE); } ++i; } } lp = curwp->w_linep; /* Cosmetic adjustment */ if (curwp->w_dotp == lp) { /* if offscreen insert. */ while (nline-- && lback(lp)!=curbp->b_linep) lp = lback(lp); curwp->w_linep = lp; /* Adjust framing. */ curwp->w_flag |= WFHARD; } return (TRUE); } SHAR_EOF if test 10957 -ne "`wc -c < 'random.c'`" then echo shar: error transmitting "'random.c'" '(should have been 10957 characters)' fi fi echo shar: extracting "'region.c'" '(5340 characters)' if test -f 'region.c' then echo shar: will not over-write existing file "'region.c'" else cat << \SHAR_EOF > 'region.c' /* * Name: MicroEMACS * Region based commands. * Version: 29 * Last edit: 12-Feb-86 * By: rex::conroy * decvax!decwrl!dec-rhea!dec-rex!conroy * What: Region operations. * * 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. */ killregion(f, n, k) { 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, TRUE)); } /* * Copy all of the characters in the * region to the kill buffer. Don't move dot * at all. This is a bit like a kill region followed * by a yank. */ copyregion(f, n, k) { register LINE *linep; register int loffs; register int s; REGION region; 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')) != TRUE) return (s); linep = lforw(linep); loffs = 0; } else { /* Middle of line. */ if ((s=kinsert(lgetc(linep, loffs))) != 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. */ lowerregion(f, n, k) { 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. */ upperregion(f, n, k) { 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 (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) { eprintf("No mark 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 = curwp->w_marko-curwp->w_doto; } else { rp->r_offset = curwp->w_marko; rp->r_size = curwp->w_doto-curwp->w_marko; } return (TRUE); } blp = curwp->w_dotp; /* Get region size. */ flp = curwp->w_dotp; bsize = curwp->w_doto; fsize = llength(flp)-curwp->w_doto+1; while (flp!=curbp->b_linep || lback(blp)!=curbp->b_linep) { if (flp != curbp->b_linep) { flp = lforw(flp); if (flp == curwp->w_markp) { rp->r_linep = curwp->w_dotp; rp->r_offset = curwp->w_doto; return (setsize(rp, 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, bsize-curwp->w_marko)); } } } eprintf("Bug: lost mark"); /* Gak! */ return (FALSE); } /* * Set size, and check for overflow. */ setsize(rp, size) register REGION *rp; register long size; { rp->r_size = size; if (rp->r_size != size) { eprintf("Region is too large"); return (FALSE); } return (TRUE); } SHAR_EOF if test 5340 -ne "`wc -c < 'region.c'`" then echo shar: error transmitting "'region.c'" '(should have been 5340 characters)' fi fi echo shar: extracting "'search.c'" '(14284 characters)' if test -f 'search.c' then echo shar: will not over-write existing file "'search.c'" else cat << \SHAR_EOF > 'search.c' /* * Name: MicroEMACS * Search commands. * Version: 30 * Last edit: 14-Feb-86 * By: rex::conroy, rex::ellison * decvax!decwrl!dec-rhea!dec-rex!conroy * ...!dec-vox!ellison * * 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" #define CCHR(x) ((x)-'@') #define SRCH_BEGIN (0) /* Search sub-codes. */ #define SRCH_FORW (-1) #define SRCH_BACK (-2) #define SRCH_PREV (-3) #define SRCH_NEXT (-4) #define SRCH_NOPR (-5) #define SRCH_ACCM (-6) 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. */ /* * 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. */ forwsearch(f, n, k) { register int s; if ((s=readpattern("Search")) != TRUE) return (s); if (forwsrch() == FALSE) { eprintf("Not found"); 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]. */ backsearch(f, n, k) { register int s; if ((s=readpattern("Reverse search")) != TRUE) return (s); if (backsrch() == FALSE) { eprintf("Not found"); 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. */ searchagain(f, n, k) { if (srch_lastdir == SRCH_FORW) { if (forwsrch() == FALSE) { eprintf("Not found"); return (FALSE); } return (TRUE); } if (srch_lastdir == SRCH_BACK) { if (backsrch() == FALSE) { eprintf("Not found"); return (FALSE); } return (TRUE); } eprintf("No last search"); return (FALSE); } /* * Use incremental searching, initially in the forward direction. * isearch ignores any explicit arguments. */ forwisearch(f, n, k) { return (isearch(SRCH_FORW)); } /* * Use incremental searching, initially in the reverse direction. * isearch ignores any explicit arguments. */ backisearch(f, n, k) { return (isearch(SRCH_BACK)); } /* * Incremental Search. * dir is used as the initial direction to search. * ^N find next occurance (if first thing typed reuse old string). * ^P find prev occurance (if first thing typed reuse old string). * ^S switch direction to forward, find next * ^R switch direction to reverse, find prev * ^Q quote next character (allows searching for ^N etc.) * exit from Isearch. * undoes last character typed. (tricky job to do this correctly). * else accumulate into search string */ isearch(dir) { register int c; register LINE *clp; register int cbo; register int success; int pptr; for (cip=0; cipw_dotp; cbo = curwp->w_doto; is_lpush(); is_cpush(SRCH_BEGIN); success = TRUE; is_prompt(dir, TRUE, success); for (;;) { update(); switch (c = ttgetc()) { case CCHR('M'): case METACH: srch_lastdir = dir; eprintf("[Done]"); return (TRUE); case CCHR('G'): curwp->w_dotp = clp; curwp->w_doto = cbo; curwp->w_flag |= WFMOVE; srch_lastdir = dir; ctrlg(FALSE, 0, KRANDOM); return (FALSE); case CCHR('S'): case CCHR('F'): if (dir == SRCH_BACK) { dir = SRCH_FORW; is_lpush(); is_cpush(SRCH_FORW); success = TRUE; } /* Drop through to find next. */ case CCHR('N'): if (success==FALSE && dir==SRCH_FORW) break; is_lpush(); forwchar(FALSE, 1, KRANDOM); if (is_find(SRCH_NEXT) != FALSE) { is_cpush(SRCH_NEXT); pptr = strlen(pat); } else { backchar(FALSE, 1, KRANDOM); ttbeep(); success = FALSE; } is_prompt(dir, FALSE, success); break; case CCHR('R'): case CCHR('B'): if (dir == SRCH_FORW) { dir = SRCH_BACK; is_lpush(); is_cpush(SRCH_BACK); success = TRUE; } /* Drop through to find previous. */ case CCHR('P'): if (success==FALSE && dir==SRCH_BACK) break; is_lpush(); backchar(FALSE, 1, KRANDOM); if (is_find(SRCH_PREV) != FALSE) { is_cpush(SRCH_PREV); pptr = strlen(pat); } else { forwchar(FALSE, 1, KRANDOM); ttbeep(); success = FALSE; } is_prompt(dir,FALSE,success); break; case 0x7F: if (is_undo(&pptr, &dir) != TRUE) return (ABORT); if (is_peek() != SRCH_ACCM) success = TRUE; is_prompt(dir, FALSE, success); break; case CCHR('^'): case CCHR('Q'): c = ttgetc(); case CCHR('U'): case CCHR('X'): case CCHR('J'): goto addchar; default: if (ISCTRL(c) != FALSE) { c += '@'; c |= KCTRL; success = execute(c, FALSE, 1); curwp->w_flag |= WFMOVE; return (success); } addchar: if (pptr == -1) pptr = 0; if (pptr == 0) success = TRUE; pat[pptr++] = c; if (pptr == NPAT) { eprintf("Pattern too long"); ctrlg(FALSE, 0, KRANDOM); return (ABORT); } 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); } } } is_cpush(cmd) register int cmd; { if (++cip >= NSRCH) cip = 0; cmds[cip].s_code = cmd; } 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; } 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; } is_peek() { if (cip == 0) return (cmds[NSRCH-1].s_code); else return (cmds[cip-1].s_code); } is_undo(pptr, dir) register int *pptr; register int *dir; { switch (cmds[cip].s_code) { case SRCH_NOPR: case SRCH_BEGIN: case SRCH_NEXT: case SRCH_PREV: break; case SRCH_FORW: *dir = SRCH_BACK; break; case SRCH_BACK: *dir = SRCH_FORW; break; case SRCH_ACCM: default: *pptr -= 1; if (*pptr < 0) *pptr = 0; pat[*pptr] = '\0'; break; } is_pop(); return (TRUE); } is_find(dir) register int dir; { register int plen; plen = strlen(pat); if (plen != 0) { if (dir==SRCH_FORW || dir==SRCH_NEXT) { backchar(FALSE, plen, KRANDOM); if (forwsrch() == FALSE) { forwchar(FALSE, plen, KRANDOM); return (FALSE); } return (TRUE); } if (dir==SRCH_BACK || dir==SRCH_PREV) { forwchar(FALSE, plen, KRANDOM); if (backsrch() == FALSE) { backchar(FALSE, plen, KRANDOM); return (FALSE); } return (TRUE); } eprintf("bad call to is_find"); ctrlg(FALSE, 0, KRANDOM); 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. */ is_prompt(dir, flag, success) { if (dir == SRCH_FORW) { if (success != FALSE) is_dspl("i-search forward", flag); else is_dspl("failing i-search forward", flag); } else if (dir == SRCH_BACK) { if (success != FALSE) is_dspl("i-search backward", flag); else is_dspl("failing i-search backward", flag); } } /* * Prompt writing routine for the incremental search. * The "prompt" is just a string. The "flag" determines * if a "[ ]" or ":" embelishment is used. */ is_dspl(prompt, flag) char *prompt; { if (flag != FALSE) eprintf("%s [%s]", prompt, pat); else eprintf("%s: %s", prompt, pat); } /* * Query Replace. * Replace strings selectively. Does a search and replace operation. * A space or a comma replaces the string, a period replaces and quits, * an n doesn't replace, a C-G quits. */ queryrepl(f, n, k) { register int s; char news[NPAT]; /* replacement string */ register int kludge; /* Watch for saved line move */ LINE *clp; /* saved line pointer */ int cbo; /* offset into the saved line */ int rcnt = 0; /* Replacements made so far */ int plen; /* length of found string */ if ((s=readpattern("Old string")) != TRUE) return (s); if ((s=ereply("New string: ",news, NPAT)) == ABORT) return (s); if (s == FALSE) news[0] = '\0'; eprintf("Query Replace: [%s] -> [%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. * * If we change the line that is the remembered value of dot, then * it is possible for the remembered value to move. This causes great * pain when trying to return to the non-existant line. * * possible fixes: * 1) put a single, relocated marker in the WINDOW structure, handled * like mark. The problem now becomes a what if two are needed... * 2) link markers into a list that gets updated (auto structures for * the nodes) * 3) Expand the mark into a stack of marks and add pushmark, popmark. */ clp = curwp->w_dotp; /* save the return location */ cbo = curwp->w_doto; while (forwsrch() == TRUE) { retry: update(); switch (ttgetc()) { case ' ': case ',': kludge = (curwp->w_dotp == clp); if (lreplace(plen, news, f) == FALSE) return (FALSE); rcnt++; if (kludge != FALSE) clp = curwp->w_dotp; break; case '.': kludge = (curwp->w_dotp == clp); if (lreplace(plen, news, f) == FALSE) return (FALSE); rcnt++; if (kludge != FALSE) clp = curwp->w_dotp; goto stopsearch; case CCHR('G'): ctrlg(FALSE, 0, KRANDOM); goto stopsearch; case '!': do { kludge = (curwp->w_dotp == clp); if (lreplace(plen, news, f) == FALSE) return (FALSE); rcnt++; if (kludge != FALSE) clp = curwp->w_dotp; } while (forwsrch() == TRUE); goto stopsearch; case 'n': break; default: eprintf("[,] replace, [.] rep-end, [n] don't, [!] repl rest [C-G] quit"); goto retry; } } stopsearch: curwp->w_dotp = clp; curwp->w_doto = cbo; curwp->w_flag |= WFHARD; update(); if (rcnt == 0) eprintf("[No replacements done]"); else if (rcnt == 1) eprintf("[1 replacement done]"); else eprintf("[%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; register char *pp; register int c; clp = curwp->w_dotp; cbo = curwp->w_doto; while (clp != curbp->b_linep) { if (cbo == llength(clp)) { clp = lforw(clp); cbo = 0; c = '\n'; } else c = lgetc(clp, cbo++); if (eq(c, pat[0]) != FALSE) { tlp = clp; tbo = cbo; pp = &pat[1]; while (*pp != 0) { if (tlp == curbp->b_linep) goto fail; if (tbo == llength(tlp)) { tlp = lforw(tlp); if (tlp == curbp->b_linep) goto fail; tbo = 0; c = '\n'; } 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 = '\n'; 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 = '\n'; 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: ; } } /* * Compare two characters. * The "bc" comes from the buffer. * It has its case folded out. The * "pc" is from the pattern. */ eq(bc, pc) { register int ibc; register int ipc; ibc = bc & 0xFF; ipc = pc & 0xFF; if (ISLOWER(ibc) != FALSE) ibc = TOUPPER(ibc); if (ISLOWER(ipc) != FALSE) ipc = TOUPPER(ipc); if (ibc == ipc) return (TRUE); 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]; s = ereply("%s [%s]: ", tpat, NPAT, prompt, pat); if (s == TRUE) /* Specified */ strcpy(pat, tpat); else if (s==FALSE && pat[0]!=0) /* CR, but old one */ s = TRUE; return (s); } SHAR_EOF if test 14284 -ne "`wc -c < 'search.c'`" then echo shar: error transmitting "'search.c'" '(should have been 14284 characters)' fi fi echo shar: extracting "'symbol.c'" '(10576 characters)' if test -f 'symbol.c' then echo shar: will not over-write existing file "'symbol.c'" else cat << \SHAR_EOF > 'symbol.c' /* * Name: MicroEMACS * Symbol table stuff. * Version: 29 * Last edit: 05-Feb-86 * By: rex::conroy * decvax!decwrl!dec-rhea!dec-rex!conroy * * Symbol tables, and keymap setup. * The terminal specific parts of building the * keymap has been moved to a better place. */ #include "def.h" #define DIRLIST 0 /* Disarmed! */ /* * Defined by "main.c". */ extern int ctrlg(); /* Abort out of things */ extern int quit(); /* Quit */ extern int ctlxlp(); /* Begin macro */ extern int ctlxrp(); /* End macro */ extern int ctlxe(); /* Execute macro */ extern int jeffexit(); /* Jeff Lomicka style exit. */ extern int showversion(); /* Show version numbers, etc. */ /* * Defined by "search.c". */ extern int forwsearch(); /* Search forward */ extern int backsearch(); /* Search backwards */ extern int searchagain(); /* Repeat last search command */ extern int forwisearch(); /* Incremental search forward */ extern int backisearch(); /* Incremental search backwards */ extern int queryrepl(); /* Query replace */ /* * Defined by "basic.c". */ extern int gotobol(); /* Move to start of line */ extern int backchar(); /* Move backward by characters */ extern int gotoeol(); /* Move to end of line */ extern int forwchar(); /* Move forward by characters */ extern int gotobob(); /* Move to start of buffer */ extern int gotoeob(); /* Move to end of buffer */ extern int forwline(); /* Move forward by lines */ extern int backline(); /* Move backward by lines */ extern int forwpage(); /* Move forward by pages */ extern int backpage(); /* Move backward by pages */ extern int setmark(); /* Set mark */ extern int swapmark(); /* Swap "." and mark */ extern int gotoline(); /* Go to a specified line. */ /* * Defined by "buffer.c". */ extern int listbuffers(); /* Display list of buffers */ extern int usebuffer(); /* Switch a window to a buffer */ extern int killbuffer(); /* Make a buffer go away. */ #if DIRLIST /* * Defined by "dirlist.c". */ extern int dirlist(); /* Directory list. */ #endif /* * Defined by "display.c". */ extern int readmsg(); /* Read next line of message. */ /* * Defined by "file.c". */ extern int fileread(); /* Get a file, read only */ extern int filevisit(); /* Get a file, read write */ extern int filewrite(); /* Write a file */ extern int filesave(); /* Save current file */ extern int filename(); /* Adjust file name */ /* * Defined by "random.c". */ extern int selfinsert(); /* Insert character */ extern int showcpos(); /* Show the cursor position */ extern int twiddle(); /* Twiddle characters */ extern int quote(); /* Insert literal */ extern int openline(); /* Open up a blank line */ extern int newline(); /* Insert CR-LF */ extern int deblank(); /* Delete blank lines */ extern int indent(); /* Insert CR-LF, then indent */ extern int forwdel(); /* Forward delete */ extern int backdel(); /* Backward delete */ extern int killline(); /* Kill forward */ extern int yank(); /* Yank back from killbuffer. */ /* * Defined by "region.c". */ extern int killregion(); /* Kill region. */ extern int copyregion(); /* Copy region to kill buffer. */ extern int lowerregion(); /* Lower case region. */ extern int upperregion(); /* Upper case region. */ /* * Defined by "spawn.c". */ extern int spawncli(); /* Run CLI in a subjob. */ /* * Defined by "window.c". */ extern int reposition(); /* Reposition window */ extern int refresh(); /* Refresh the screen */ extern int nextwind(); /* Move to the next window */ extern int prevwind(); /* Move to the previous window */ extern int mvdnwind(); /* Move window down */ extern int mvupwind(); /* Move window up */ extern int onlywind(); /* Make current window only one */ extern int splitwind(); /* Split current window */ extern int enlargewind(); /* Enlarge display window. */ extern int shrinkwind(); /* Shrink window. */ /* * Defined by "word.c". */ extern int backword(); /* Backup by words */ extern int forwword(); /* Advance by words */ extern int upperword(); /* Upper case word. */ extern int lowerword(); /* Lower case word. */ extern int capword(); /* Initial capitalize word. */ extern int delfword(); /* Delete forward word. */ extern int delbword(); /* Delete backward word. */ /* * Defined by "extend.c". */ extern int extend(); /* Extended commands. */ extern int help(); /* Help key. */ extern int bindtokey(); /* Modify key bindings. */ extern int wallchart(); /* Make wall chart. */ typedef struct { short k_key; /* Key to bind. */ int (*k_funcp)(); /* Function. */ char *k_name; /* Function name string. */ } KEY; /* * Default key binding table. This contains * the function names, the symbol table name, and (possibly) * a key binding for the builtin functions. There are no * bindings for C-U or C-X. These are done with special * code, but should be done normally. */ KEY key[] = { KCTRL|'@', setmark, "set-mark", KCTRL|'A', gotobol, "goto-bol", KCTRL|'B', backchar, "back-char", KCTRL|'C', spawncli, "spawn-cli", KCTRL|'D', forwdel, "forw-del-char", KCTRL|'E', gotoeol, "goto-eol", KCTRL|'F', forwchar, "forw-char", KCTRL|'G', ctrlg, "abort", KCTRL|'H', backdel, "back-del-char", KCTRL|'I', selfinsert, "ins-self", KCTRL|'J', indent, "ins-nl-and-indent", KCTRL|'K', killline, "kill-line", KCTRL|'L', refresh, "refresh", KCTRL|'M', newline, "ins-nl", KCTRL|'N', forwline, "forw-line", KCTRL|'O', openline, "ins-nl-and-backup", KCTRL|'P', backline, "back-line", KCTRL|'Q', quote, "quote", KCTRL|'R', backisearch, "back-i-search", KCTRL|'S', forwisearch, "forw-i-search", KCTRL|'T', twiddle, "twiddle", KCTRL|'V', forwpage, "forw-page", KCTRL|'W', killregion, "kill-region", KCTRL|'Y', yank, "yank", KCTRL|'Z', jeffexit, "jeff-exit", KCTLX|KCTRL|'B',listbuffers, "display-buffers", KCTLX|KCTRL|'C',quit, "quit", #if DIRLIST KCTLX|KCTRL|'D',dirlist, "display-directory", #endif KCTLX|KCTRL|'F',filename, "set-file-name", KCTLX|KCTRL|'L',lowerregion, "lower-region", KCTLX|KCTRL|'N',mvdnwind, "down-window", KCTLX|KCTRL|'O',deblank, "del-blank-lines", KCTLX|KCTRL|'P',mvupwind, "up-window", KCTLX|KCTRL|'R',fileread, "file-read", KCTLX|KCTRL|'S',filesave, "file-save", KCTLX|KCTRL|'U',upperregion, "upper-region", KCTLX|KCTRL|'V',filevisit, "file-visit", KCTLX|KCTRL|'W',filewrite, "file-write", KCTLX|KCTRL|'X',swapmark, "swap-dot-and-mark", KCTLX|KCTRL|'Z',shrinkwind, "shrink-window", KCTLX|'=', showcpos, "display-position", KCTLX|'(', ctlxlp, "start-macro", KCTLX|')', ctlxrp, "end-macro", KCTLX|'1', onlywind, "only-window", KCTLX|'2', splitwind, "split-window", KCTLX|'B', usebuffer, "use-buffer", KCTLX|'E', ctlxe, "execute-macro", KCTLX|'G', gotoline, "goto-line", KCTLX|'K', killbuffer, "kill-buffer", KCTLX|'N', nextwind, "forw-window", KCTLX|'P', prevwind, "back-window", KCTLX|'Z', enlargewind, "enlarge-window", KMETA|KCTRL|'H',delbword, "back-del-word", KMETA|KCTRL|'R',readmsg, "display-message", KMETA|KCTRL|'V',showversion, "display-version", KMETA|'!', reposition, "reposition-window", KMETA|'>', gotoeob, "goto-eob", KMETA|'<', gotobob, "goto-bob", KMETA|'%', queryrepl, "query-replace", KMETA|'B', backword, "back-word", KMETA|'C', capword, "cap-word", KMETA|'D', delfword, "forw-del-word", KMETA|'F', forwword, "forw-word", KMETA|'L', lowerword, "lower-word", KMETA|'R', backsearch, "back-search", KMETA|'S', forwsearch, "forw-search", KMETA|'U', upperword, "upper-word", KMETA|'V', backpage, "back-page", KMETA|'W', copyregion, "copy-region", KMETA|'X', extend, "extended-command", -1, searchagain, "search-again", -1, help, "help", -1, wallchart, "display-bindings", -1, bindtokey, "bind-to-key" }; #define NKEY (sizeof(key) / sizeof(key[0])) /* * Symbol table lookup. * Return a pointer to the SYMBOL node, or NULL if * the symbol is not found. */ SYMBOL * symlookup(cp) register char *cp; { register SYMBOL *sp; sp = symbol[symhash(cp)]; while (sp != NULL) { if (strcmp(cp, sp->s_name) == 0) return (sp); sp = sp->s_symp; } return (NULL); } /* * Take a string, and compute the symbol table * bucket number. This is done by adding all of the characters * together, and taking the sum mod NSHASH. The string probably * should not contain any GR characters; if it does the "*cp" * may get a nagative number on some machines, and the "%" * will return a negative number! */ symhash(cp) register char *cp; { register int c; register int n; n = 0; while ((c = *cp++) != 0) n += c; return (n % NSHASH); } /* * Build initial keymap. The funny keys * (commands, odd control characters) are mapped using * a big table and calls to "keyadd". The printing characters * are done with some do-it-yourself handwaving. The terminal * specific keymap initialization code is called at the * very end to finish up. All errors are fatal. */ keymapinit() { register SYMBOL *sp; register KEY *kp; register int i; register int hash; for (i=0; ik_key, kp->k_funcp, kp->k_name); keydup(KCTLX|KCTRL|'G', "abort"); keydup(KMETA|KCTRL|'G', "abort"); keydup(0x7F, "back-del-char"); keydup(KCTLX|'R', "back-i-search"); keydup(KCTLX|'S', "forw-i-search"); keydup(KMETA|'.', "set-mark"); keydup(KMETA|'Q', "quote"); keydup(KMETA|0x7F, "back-del-word"); /* * Should be bound by "tab" already. */ if ((sp=symlookup("ins-self")) == NULL) abort(); for (i=0x20; i<0x7F; ++i) { if (binding[i] != NULL) abort(); binding[i] = sp; ++sp->s_nkey; } ttykeymapinit(); } /* * Create a new builtin function "name" * with function "funcp". If the "new" is a real * key, bind it as a side effect. All errors * are fatal. */ keyadd(new, funcp, name) int (*funcp)(); char *name; { register SYMBOL *sp; register int hash; if ((sp=(SYMBOL *)malloc(sizeof(SYMBOL))) == NULL) abort(); hash = symhash(name); sp->s_symp = symbol[hash]; symbol[hash] = sp; sp->s_nkey = 0; sp->s_name = name; sp->s_funcp = funcp; if (new >= 0) { /* Bind this key. */ if (binding[new] != NULL) abort(); binding[new] = sp; ++sp->s_nkey; } } /* * Bind key "new" to the existing * routine "name". If the name cannot be found, * or the key is already bound, abort. */ keydup(new, name) register int new; char *name; { register SYMBOL *sp; if (binding[new]!=NULL || (sp=symlookup(name))==NULL) abort(); binding[new] = sp; ++sp->s_nkey; } SHAR_EOF if test 10576 -ne "`wc -c < 'symbol.c'`" then echo shar: error transmitting "'symbol.c'" '(should have been 10576 characters)' fi fi echo shar: extracting "'version.c'" '(600 characters)' if test -f 'version.c' then echo shar: will not over-write existing file "'version.c'" else cat << \SHAR_EOF > 'version.c' /* * Name: MicroEMACS * Version stamp. * Version: 30 * Last edit: 14-Feb-86 * By: rex::conroy * decvax!decwrl!dec-rhea!dec-rex!conroy * * This file contains the string(s) * that get written out by the show version command. * Rich had it generated by a command file. I do * it manually, until I can figure out a way to get * the MicroEMACS version number generated in a * reasonable (automatic) manner. Perhaps a program * that reads "things2do.txt". */ #include "def.h" char *version[] = { "MicroEMACS version 30", "Source from REX::USER$A:[CONROY.HACKING.MINIEMACS]", NULL }; SHAR_EOF if test 600 -ne "`wc -c < 'version.c'`" then echo shar: error transmitting "'version.c'" '(should have been 600 characters)' fi fi echo shar: extracting "'window.c'" '(9891 characters)' if test -f 'window.c' then echo shar: will not over-write existing file "'window.c'" else cat << \SHAR_EOF > 'window.c' /* * Name: MicroEMACS * Window handling. * Version: 29 * Last edit: 10-Feb-86 * By: rex::conroy * decvax!decwrl!dec-rhea!dec-rex!conroy */ #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). With no argument it defaults to 1. * Because of the default, it works like in * Gosling. */ reposition(f, n, k) { curwp->w_force = n; curwp->w_flag |= WFFORCE; 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! */ refresh(f, n, k) { 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. */ eprintf("Display unusable"); return (FALSE); } wp->w_ntrows = nrow-wp->w_toprow-2; wp = wheadp; /* Redraw all. */ while (wp != NULL) { wp->w_flag |= WFMODE|WFHARD; wp = wp->w_wndp; } sgarbf = TRUE; update(); eprintf("[New size %d by %d]", nrow, ncol); } else sgarbf = TRUE; return (TRUE); } /* * The command make the next * window (next => down the screen) * the current window. There are no real * errors, although the command does * nothing if there is only 1 window on * the screen. */ nextwind(f, n, k) { register WINDOW *wp; if ((wp=curwp->w_wndp) == NULL) wp = wheadp; curwp = wp; curbp = wp->w_bufp; return (TRUE); } /* * This command makes the previous * window (previous => up the screen) the * current window. There arn't any errors, * although the command does not do a lot * if there is 1 window. */ prevwind(f, n, k) { 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); } /* * This command moves the current * window down by "arg" lines. Recompute * the top line in the window. The move up and * move down code is almost completely the same; * most of the work has to do with reframing the * window, and picking a new dot. We share the * code by having "move down" just be an interface * to "move up". */ mvdnwind(f, n, k) register int n; { return (mvupwind(f, -n, KRANDOM)); } /* * Move the current window up by "arg" * lines. Recompute the new top line of the window. * Look to see if "." is still on the screen. If it is, * you win. If it isn't, then move "." to center it * in the new framing of the window (this command does * not really move "."; it moves the frame). */ mvupwind(f, n, k) register int n; { register LINE *lp; register int i; lp = curwp->w_linep; if (n < 0) { while (n++ && lp!=curbp->b_linep) lp = lforw(lp); } else { while (n-- && lback(lp)!=curbp->b_linep) lp = lback(lp); } curwp->w_linep = lp; curwp->w_flag |= WFHARD; /* Mode line is OK. */ for (i=0; iw_ntrows; ++i) { if (lp == curwp->w_dotp) return (TRUE); if (lp == curbp->b_linep) break; lp = lforw(lp); } lp = curwp->w_linep; i = curwp->w_ntrows/2; while (i-- && lp!=curbp->b_linep) lp = lforw(lp); curwp->w_dotp = lp; curwp->w_doto = 0; return (TRUE); } /* * This command makes the current * window the only window on the screen. * Try to set the framing * so that "." does not have to move on * the display. Some care has to be taken * to keep the values of dot and mark * in the buffer structures right if the * distruction of a window makes a buffer * become undisplayed. */ onlywind(f, n, k) { 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. */ splitwind(f, n, k) { register WINDOW *wp; register LINE *lp; register int ntru; register int ntrl; register int ntrd; register WINDOW *wp1; register WINDOW *wp2; if (curwp->w_ntrows < 3) { eprintf("Cannot split a %d line window", curwp->w_ntrows); return (FALSE); } if ((wp = (WINDOW *) malloc(sizeof(WINDOW))) == NULL) { eprintf("Cannot allocate WINDOW block"); 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. */ enlargewind(f, n, k) { register WINDOW *adjwp; register LINE *lp; register int i; if (n < 0) return (shrinkwind(f, -n, KRANDOM)); if (wheadp->w_wndp == NULL) { eprintf("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) { eprintf("Impossible change"); return (FALSE); } if (curwp->w_wndp == adjwp) { /* Shrink below. */ lp = adjwp->w_linep; for (i=0; iw_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; ib_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, k) { register WINDOW *adjwp; register LINE *lp; register int i; if (n < 0) return (enlargewind(f, -n, KRANDOM)); if (wheadp->w_wndp == NULL) { eprintf("Only one window"); return (FALSE); } if ((adjwp=curwp->w_wndp) == NULL) { adjwp = wheadp; while (adjwp->w_wndp != curwp) adjwp = adjwp->w_wndp; } if (curwp->w_ntrows <= n) { eprintf("Impossible change"); return (FALSE); } if (curwp->w_wndp == adjwp) { /* Grow below. */ lp = adjwp->w_linep; for (i=0; iw_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; ib_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); } /* * 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(FALSE, 0, KRANDOM) == FALSE) return (NULL); wp = wheadp; /* Find window to use */ while (wp!=NULL && wp==curwp) wp = wp->w_wndp; return (wp); } SHAR_EOF if test 9891 -ne "`wc -c < 'window.c'`" then echo shar: error transmitting "'window.c'" '(should have been 9891 characters)' fi fi echo shar: extracting "'word.c'" '(6222 characters)' if test -f 'word.c' then echo shar: will not over-write existing file "'word.c'" else cat << \SHAR_EOF > 'word.c' /* * Name: MicroEMACS * Word mode commands. * Version: 29 * Last edit: 05-Feb-86 * By: rex::conroy * decvax!decwrl!dec-rhea!dec-rex!conroy * * The routines in this file * implement commands that work word at * a time. There are all sorts of word mode * commands. If I do any sentence and/or paragraph * mode commands, they are likely to be put in * this file. */ #include "def.h" /* * Move the cursor backward by * "n" words. All of the details of motion * are performed by the "backchar" and "forwchar" * routines. Error if you try to move beyond * the buffers. */ backword(f, n, k) { if (n < 0) return (forwword(f, -n, KRANDOM)); if (backchar(FALSE, 1, KRANDOM) == FALSE) return (FALSE); while (n--) { while (inword() == FALSE) { if (backchar(FALSE, 1, KRANDOM) == FALSE) return (FALSE); } while (inword() != FALSE) { if (backchar(FALSE, 1, KRANDOM) == FALSE) return (FALSE); } } return (forwchar(FALSE, 1, KRANDOM)); } /* * Move the cursor forward by * the specified number of words. All of the * motion is done by "forwchar". Error if you * try and move beyond the buffer's end. */ forwword(f, n, k) { if (n < 0) return (backword(f, -n, KRANDOM)); while (n--) { while (inword() == FALSE) { if (forwchar(FALSE, 1, KRANDOM) == FALSE) return (FALSE); } while (inword() != FALSE) { if (forwchar(FALSE, 1, KRANDOM) == FALSE) return (FALSE); } } return (TRUE); } /* * Move the cursor forward by * the specified number of words. As you move, * convert any characters to upper case. Error * if you try and move beyond the end of the * buffer. */ upperword(f, n, k) { register int c; if (n < 0) return (FALSE); while (n--) { while (inword() == FALSE) { if (forwchar(FALSE, 1, KRANDOM) == FALSE) return (FALSE); } 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(FALSE, 1, KRANDOM) == FALSE) return (FALSE); } } return (TRUE); } /* * Move the cursor forward by * the specified number of words. As you move * convert characters to lower case. Error if you * try and move over the end of the buffer. */ lowerword(f, n, k) { register int c; if (n < 0) return (FALSE); while (n--) { while (inword() == FALSE) { if (forwchar(FALSE, 1, KRANDOM) == FALSE) return (FALSE); } 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(FALSE, 1, KRANDOM) == FALSE) return (FALSE); } } return (TRUE); } /* * Move the cursor forward by * the specified number of words. As you move * convert the first character of the word to upper * case, and subsequent characters to lower case. Error * if you try and move past the end of the buffer. */ capword(f, n, k) { register int c; if (n < 0) return (FALSE); while (n--) { while (inword() == FALSE) { if (forwchar(FALSE, 1, KRANDOM) == FALSE) return (FALSE); } 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(FALSE, 1, KRANDOM) == FALSE) return (FALSE); 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(FALSE, 1, KRANDOM) == FALSE) return (FALSE); } } } return (TRUE); } /* * Kill forward by "n" words. The rules for final * status are now different. It is not considered an error * to delete fewer words than you asked. This lets you say * "kill lots of words" and have the command stop in a reasonable * way when it hits the end of the buffer. Normally this is */ delfword(f, n, k) { register int 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(FALSE, 1, KRANDOM) == FALSE) goto out; /* Hit end of buffer. */ ++size; } while (inword() != FALSE) { if (forwchar(FALSE, 1, KRANDOM) == FALSE) goto out; /* Hit end of buffer. */ ++size; } } out: curwp->w_dotp = dotp; curwp->w_doto = doto; return (ldelete(size, TRUE)); } /* * 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". */ delbword(f, n, k) { register int size; if (n < 0) return (FALSE); if ((lastflag&CFKILL) == 0) /* Purge kill buffer. */ kdelete(); thisflag |= CFKILL; if (backchar(FALSE, 1, KRANDOM) == FALSE) return (TRUE); /* Hit buffer start. */ size = 1; /* One deleted. */ while (n--) { while (inword() == FALSE) { if (backchar(FALSE, 1, KRANDOM) == FALSE) goto out; /* Hit buffer start. */ ++size; } while (inword() != FALSE) { if (backchar(FALSE, 1, KRANDOM) == FALSE) goto out; /* Hit buffer start. */ ++size; } } if (forwchar(FALSE, 1, KRANDOM) == FALSE) return (FALSE); --size; /* Undo assumed delete. */ out: return (ldelete(size, TRUE)); } /* * Return TRUE if the character at dot * is a character that is considered to be * part of a word. The word character list is hard * coded. Should be setable. */ inword() { if (curwp->w_doto == llength(curwp->w_dotp)) return (FALSE); if (ISWORD(lgetc(curwp->w_dotp, curwp->w_doto)) != FALSE) return (TRUE); return (FALSE); } SHAR_EOF if test 6222 -ne "`wc -c < 'word.c'`" then echo shar: error transmitting "'word.c'" '(should have been 6222 characters)' fi fi exit 0 # End of shell archive