static char rcsid[] = "$Id: regexp.c,v 1.1 1992/09/05 01:13:32 mike Exp $"; /* $Log: regexp.c,v $ * Revision 1.1 1992/09/05 01:13:32 mike * Initial revision * */ /* * REGEXP.C regular expression search and replace */ /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! * Since the RE routines expect null terminated lines and ME lines don't * have nulls, I copy the line, add a null and then call the RE routine. * This stinks. What I should do is rewrite the RE routines to take a * pointer and length, or pad the line and tack on a null. * But remember, the RE routines maintain backpointers into the line (for * substitutions like query-replace) so if the line changes (ie is edited) * the pointers could be messed up. * Also, since I have to restrict the line length (since the hidden line is * fixed length), I might get false matches or misses. Blech. * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ /* Copyright 1990, 1991, 1992 Craig Durland * Distributed under the terms of the GNU General Public License. * Distributed "as is", without warranties of any kind, but comments, * suggestions and bug reports are welcome. */ #include #include "me2.h" extern char *eopat[], *bopat[], *re_comp(); /* in regex.c */ static int relookfor(); /* Hidden storage for relookfor(), (get-matched) & (looking-at) * needs to stick around because re_subs() has ptrs into it. */ #define HMAX FLINE static char hline[HMAX + 1]; re_search_forward(pattern) char *pattern; { char *ptr; if (ptr = re_comp(pattern)) { mlwrite("%s: %s",ptr,pattern); return ABORT; } return relookfor(); } re_search_reverse(pattern) char *pattern; { char *ptr; register Line *clp; register int cbo; int j, s; if (ptr = re_comp(pattern)) { mlwrite("%s: %s",ptr,pattern); return ABORT; } clp = the_dot->line; cbo = the_dot->offset; while (TRUE) { if (cbo == 0) /* at start of line, goto end of previous line */ { clp = lback(clp); if (clp == BUFFER_LAST_LINE(curbp)) return FALSE; } j = imin(llength(clp),HMAX); blkmov(hline,clp->l_text,j); hline[j] = '\0'; if (cbo) j = cbo; for (j--; j >= 0; j--) { if ((s = re_exec(&hline[j], j == 0, FALSE)) == ABORT) return ABORT; if (s == TRUE) /* match */ { the_dot->line = clp; the_dot->offset = j; dot_moved(); /*if (--n<=0)*/ return TRUE; } } cbo = 0; } /* never gets here */ } /* Search/Replace with regular expressions. * Almost the same as search_replace() but just different enough to make * packing the code into one routine not worth it. * Returns: * TRUE : Did at least one replace. * FALSE: No replacements * ABORT: Something bad happened. */ re_search_replace(search_pattern,replace_pattern) char *search_pattern, *replace_pattern; { char *ptr, line[260]; int s, got_a_match; if (ptr = re_comp(search_pattern)) { mlwrite("%s: %s",ptr,search_pattern); return ABORT; } set_mark(THE_MARK); /* save excursion */ got_a_match = FALSE; while (TRUE) { if ((s = relookfor()) == ABORT) return ABORT; if (s == FALSE) break; /* no more matches */ /* got a match, replace it */ got_a_match = TRUE; if (!re_subs(replace_pattern,line)) { mlwrite("Invalid replace string"); return ABORT; } if (!replace_occ(eopat[0]-bopat[0],line)) /* something bad happened */ return ABORT; } /* while */ /* restore excursion & set mark at end of replace */ swap_marks(THE_DOT,THE_MARK); return got_a_match; } /* * Returns: * TRUE if found * FALSE if not found * ABORT if something bad happens like bad search pattern. */ static int relookfor() /* search_pattern has already been compiled */ { register Line *clp; int cbo, s; clp = the_dot->line; cbo = the_dot->offset; /* start at cursor */ if (clp == BUFFER_LAST_LINE(curbp)) return FALSE; /* ??? needed? */ while (TRUE) { s = imin(llength(clp),HMAX); blkmov(hline,clp->l_text,s); hline[s] = '\0'; if ((s = re_exec(&hline[cbo], cbo == 0, TRUE)) == ABORT) return ABORT; if (s == TRUE) /* match */ { the_dot->line = clp; the_dot->offset = eopat[0] -(char *)hline; dot_moved(); return TRUE; } if ((clp = lforw(clp)) == BUFFER_LAST_LINE(curbp)) return FALSE; cbo = 0; } /* never gets here */ } /* * re_fail: internal error handler for re_exec. */ void re_fail(s,c) char *s, c; { extern re_errorcode; mlputs(s); re_errorcode = ABORT; } /* Apply RE to current line in current buffer. * Notes: * I do the strango code to try and minimize the amount of text * copied. I don't think it gains anything. * If the dot is not at the start of the line, I have to pass at least * one character before the dot to re_exec() because it might look * at it. */ looking_at(pattern) char *pattern; { char *ptr; int cbo, len, i, f; Line *clp; if (ptr = re_comp(pattern)) { mlwrite("%s: %s",ptr,pattern); return ABORT; } clp = the_dot->line; cbo = the_dot->offset; /* start at cursor */ f = (cbo != 0); /* 0 if cbo == 0, else 1 */ i = cbo - f; len = imin(llength(clp) -i, HMAX); blkmov(hline, &clp->l_text[i], len); hline[len] = '\0'; return re_exec(hline + f, !f, FALSE); } /* apply RE to string */ REstring(pattern,str) char *pattern, *str; { char *ptr; if (ptr = re_comp(pattern)) { mlwrite("%s: %s",ptr,pattern); return ABORT; } strcpy(hline,str); return re_exec(hline,TRUE,FALSE); }