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