/* * The functions in this file implement commands that search in the forward * and backward directions. There are no special characters in the search * strings. Probably should have a regular expression search, or something * like that. * */ #include #include "estruct.h" #include "edef.h" /* * Search forward. Get a search string from the user, and search, beginning at * ".", for the string. If found, reset the "." to be just after the match * string, and [perhaps] repaint the display. Bound to "C-S". */ /* string search input parameters */ #define PTBEG 1 /* leave the point at the begining on search */ #define PTEND 2 /* leave the point at the end on search */ forwsearch(f, n) { register int status; /* resolve the repeat count */ if (n == 0) n = 1; if (n < 1) /* search backwards */ return(backsearch(f, -n)); /* ask the user for the text of a pattern */ if ((status = readpattern("Search")) != TRUE) return(status); /* search for the pattern */ while (n-- > 0) { if ((status = forscan(&pat[0],PTEND)) == FALSE) break; } /* and complain if not there */ if (status == FALSE) mlwrite("Not found"); return(status); } forwhunt(f, n) { register int status; /* resolve the repeat count */ if (n == 0) n = 1; if (n < 1) /* search backwards */ return(backhunt(f, -n)); /* Make sure a pattern exists */ if (pat[0] == 0) { mlwrite("No pattern set"); return(FALSE); } /* search for the pattern */ while (n-- > 0) { if ((status = forscan(&pat[0],PTEND)) == FALSE) break; } /* and complain if not there */ if (status == FALSE) mlwrite("Not found"); return(status); } /* * 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]. Bound to "C-R". */ backsearch(f, n) { register int s; /* resolve null and negative arguments */ if (n == 0) n = 1; if (n < 1) return(forwsearch(f, -n)); /* get a pattern to search */ if ((s = readpattern("Reverse search")) != TRUE) return(s); /* and go search for it */ bsearch(f,n); } backhunt(f, n) /* hunt backward for the last search string entered */ { /* resolve null and negative arguments */ if (n == 0) n = 1; if (n < 1) return(forwhunt(f, -n)); /* Make sure a pattern exists */ if (pat[0] == 0) { mlwrite("No pattern set"); return(FALSE); } /* and go search for it */ bsearch(f,n); } bsearch(f, n) { register LINE *clp; register int cbo; register LINE *tlp; register int tbo; register int c; register char *epp; register char *pp; /* find a pointer to the end of the pattern */ for (epp = &pat[0]; epp[1] != 0; ++epp) ; /* make local copies of the starting location */ clp = curwp->w_dotp; cbo = curwp->w_doto; while (n-- > 0) { for (;;) { /* if we are at the begining of the line, wrap back around */ if (cbo == 0) { clp = lback(clp); if (clp == curbp->b_linep) { mlwrite("Not found"); return(FALSE); } cbo = llength(clp)+1; } /* fake the at the end of a line */ if (--cbo == llength(clp)) c = '\n'; else c = lgetc(clp, cbo); /* check for a match against the end of the pattern */ if (eq(c, *epp) != FALSE) { tlp = clp; tbo = cbo; pp = epp; /* scanning backwards through the rest of the pattern looking for a match */ while (pp != &pat[0]) { /* wrap across a line break */ if (tbo == 0) { tlp = lback(tlp); if (tlp == curbp->b_linep) goto fail; tbo = llength(tlp)+1; } /* fake the */ if (--tbo == llength(tlp)) c = '\n'; else c = lgetc(tlp, tbo); if (eq(c, *--pp) == FALSE) goto fail; } /* A Match! reset the current cursor */ curwp->w_dotp = tlp; curwp->w_doto = tbo; curwp->w_flag |= WFMOVE; goto next; } fail:; } next:; } return(TRUE); } /* * Compare two characters. The "bc" comes from the buffer. It has it's case * folded out. The "pc" is from the pattern. */ eq(bc, pc) int bc; int pc; { if ((curwp->w_bufp->b_mode & MDEXACT) == 0) { if (bc>='a' && bc<='z') bc -= 0x20; if (pc>='a' && pc<='z') pc -= 0x20; } if (bc == pc) 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. * change to using to delemit the end-of-pattern to allow s in * the search string. */ readpattern(prompt) char *prompt; { register int s; char tpat[NPAT+20]; strcpy(tpat, prompt); /* copy prompt to output string */ strcat(tpat, " ["); /* build new prompt string */ expandp(&pat[0], &tpat[strlen(tpat)], NPAT/2); /* add old pattern */ strcat(tpat, "]: "); s = mlreplyt(tpat, tpat, NPAT, 27); /* Read pattern */ if (s == TRUE) /* Specified */ strcpy(pat, tpat); else if (s == FALSE && pat[0] != 0) /* CR, but old one */ s = TRUE; return(s); } sreplace(f, n) /* Search and replace (ESC-R) */ int f; /* default flag */ int n; /* # of repetitions wanted */ { return(replaces(FALSE, f, n)); } qreplace(f, n) /* search and replace with query (ESC-CTRL-R) */ int f; /* default flag */ int n; /* # of repetitions wanted */ { return(replaces(TRUE, f, n)); } /* replaces: search for a string and replace it with another string. query might be enabled (according to kind). */ replaces(kind, f, n) int kind; /* Query enabled flag */ int f; /* default flag */ int n; /* # of repetitions wanted */ { register int i; /* loop index */ register int s; /* success flag on pattern inputs */ register int slength, rlength; /* length of search and replace strings */ register int numsub; /* number of substitutions */ register int nummatch; /* number of found matches */ int nlflag; /* last char of search string a ? */ int nlrepl; /* was a replace done on the last line? */ char tmpc; /* temporary character */ char c; /* input char for query */ char tpat[NPAT]; /* temporary to hold search pattern */ LINE *origline; /* original "." position */ int origoff; /* and offset (for . query option) */ if (curbp->b_mode&MDVIEW) /* don't allow this command if */ return(rdonly()); /* we are in read only mode */ /* check for negative repititions */ if (f && n < 0) return(FALSE); /* ask the user for the text of a pattern */ if ((s = readpattern( (kind == FALSE ? "Replace" : "Query replace"))) != TRUE) return(s); strcpy(&tpat[0], &pat[0]); /* salt it away */ /* ask for the replacement string */ strcpy(&pat[0], &rpat[0]); /* set up default string */ if ((s = readpattern("with")) == ABORT) return(s); /* move everything to the right place and length them */ strcpy(&rpat[0], &pat[0]); strcpy(&pat[0], &tpat[0]); slength = strlen(&pat[0]); rlength = strlen(&rpat[0]); /* set up flags so we can make sure not to do a recursive replace on the last line */ nlflag = (pat[slength - 1] == '\n'); nlrepl = FALSE; /* build query replace question string */ strcpy(tpat, "Replace '"); expandp(&pat[0], &tpat[strlen(tpat)], NPAT/3); strcat(tpat, "' with '"); expandp(&rpat[0], &tpat[strlen(tpat)], NPAT/3); strcat(tpat, "'? "); /* save original . position */ origline = curwp->w_dotp; origoff = curwp->w_doto; /* scan through the file */ numsub = 0; nummatch = 0; while ((f == FALSE || n > nummatch) && (nlflag == FALSE || nlrepl == FALSE)) { /* search for the pattern */ if (forscan(&pat[0],PTBEG) != TRUE) break; /* all done */ ++nummatch; /* increment # of matches */ /* check if we are on the last line */ nlrepl = (lforw(curwp->w_dotp) == curwp->w_bufp->b_linep); /* check for query */ if (kind) { /* get the query */ mlwrite(&tpat[0], &pat[0], &rpat[0]); qprompt: update(); /* show the proposed place to change */ c = (*term.t_getchar)(); /* and input */ mlwrite(""); /* and clear it */ /* and respond appropriately */ switch (c) { case 'y': /* yes, substitute */ case ' ': break; case 'n': /* no, onword */ forwchar(FALSE, 1); continue; case '!': /* yes/stop asking */ kind = FALSE; break; case '.': /* abort! and return */ /* restore old position */ curwp->w_dotp = origline; curwp->w_doto = origoff; curwp->w_flag |= WFMOVE; case BELL: /* abort! and stay */ mlwrite("Aborted!"); return(FALSE); default: /* bitch and beep */ (*term.t_beep)(); case '?': /* help me */ mlwrite("(Y)es, (N)o, (!)Do the rest, (^G)Abort, (.)Abort back, (?)Help: "); goto qprompt; } } /* delete the sucker */ if (ldelete(slength, FALSE) != TRUE) { /* error while deleting */ mlwrite("ERROR while deleteing"); return(FALSE); } /* and insert its replacement */ for (i=0; i */ char *patrn; /* string to scan for */ int leavep; /* place to leave point PTBEG = begining of match PTEND = at end of match */ { register LINE *curline; /* current line during scan */ register int curoff; /* position within current line */ register LINE *lastline; /* last line position during scan */ register int lastoff; /* position within last line */ register int c; /* character at current position */ register LINE *matchline; /* current line during matching */ register int matchoff; /* position in matching line */ register char *patptr; /* pointer into pattern */ /* setup local scan pointers to global "." */ curline = curwp->w_dotp; curoff = curwp->w_doto; /* scan each character until we hit the head link record */ while (curline != curbp->b_linep) { /* save the current position in case we need to restore it on a match */ lastline = curline; lastoff = curoff; /* get the current character resolving EOLs */ if (curoff == llength(curline)) { /* if at EOL */ curline = lforw(curline); /* skip to next line */ curoff = 0; c = '\n'; /* and return a */ } else c = lgetc(curline, curoff++); /* get the char */ /* test it against first char in pattern */ if (eq(c, patrn[0]) != FALSE) { /* if we find it..*/ /* setup match pointers */ matchline = curline; matchoff = curoff; patptr = &patrn[0]; /* scan through patrn for a match */ while (*++patptr != 0) { /* advance all the pointers */ if (matchoff == llength(matchline)) { /* advance past EOL */ matchline = lforw(matchline); matchoff = 0; c = '\n'; } else c = lgetc(matchline, matchoff++); /* and test it against the pattern */ if (eq(*patptr, c) == FALSE) goto fail; } /* A SUCCESSFULL MATCH!!! */ /* reset the global "." pointers */ if (leavep == PTEND) { /* at end of string */ curwp->w_dotp = matchline; curwp->w_doto = matchoff; } else { /* at begining of string */ curwp->w_dotp = lastline; curwp->w_doto = lastoff; } curwp->w_flag |= WFMOVE; /* flag that we have moved */ return(TRUE); } fail:; /* continue to search */ } /* we could not find a match */ return(FALSE); } /* expandp: expand control key sequences for output */ expandp(srcstr, deststr, maxlength) char *srcstr; /* string to expand */ char *deststr; /* destination of expanded string */ int maxlength; /* maximum chars in destination */ { char c; /* current char to translate */ /* scan through the string */ while ((c = *srcstr++) != 0) { if (c == '\n') { /* its an EOL */ *deststr++ = '<'; *deststr++ = 'N'; *deststr++ = 'L'; *deststr++ = '>'; maxlength -= 4; } else if (c < 0x20 || c == 0x7f) { /* control character */ *deststr++ = '^'; *deststr++ = c ^ 0x40; maxlength -= 2; } else if (c == '%') { *deststr++ = '%'; *deststr++ = '%'; maxlength -= 2; } else { /* any other character */ *deststr++ = c; maxlength--; } /* check for maxlength */ if (maxlength < 4) { *deststr++ = '$'; *deststr = '\0'; return(FALSE); } } *deststr = '\0'; return(TRUE); }