BSD 4_3 development
[unix-history] / usr / contrib / jove / re1.c
/*************************************************************************
* This program is copyright (C) 1985, 1986 by Jonathan Payne. It is *
* provided to you without charge for use only on a licensed Unix *
* system. You may copy JOVE provided that this notice is included with *
* the copy. You may not sell copies of this program or versions *
* modified for use on microcomputer systems, unless the copies are *
* included with a Unix system distribution and the source is provided. *
*************************************************************************/
#include "jove.h"
#include "io.h"
#include "re.h"
static
substitute(query, l1, char1, l2, char2)
Line *l1,
*l2;
{
Line *lp;
int numdone = 0,
offset = curchar,
stop = 0;
disk_line UNDO_da = 0;
Line *UNDO_lp = 0;
lsave();
REdirection = FORWARD;
lp = l1;
for (lp = l1; (lp != l2->l_next) && !stop; lp = lp->l_next) {
offset = (lp == l1) ? char1 : 0;
while (!stop && re_lindex(lp, offset, compbuf, alternates, 0)) {
if (lp == l2 && REeom > char2) /* nope, leave this alone */
break;
DotTo(lp, REeom);
offset = curchar;
if (query) {
message("Replace (Type '?' for help)? ");
reswitch: redisplay();
switch (Upper(getchar())) {
case '.':
stop++;
/* Fall into ... */
case ' ':
case 'Y':
break;
case BS:
case RUBOUT:
case 'N':
if (linebuf[offset++] == '\0')
goto nxtline;
continue;
case CTL(W):
re_dosub(linebuf, YES);
numdone++;
offset = curchar = REbom;
makedirty(curline);
/* Fall into ... */
case CTL(R):
case 'R':
RErecur();
offset = curchar;
lp = curline;
continue;
case CTL(U):
case 'U':
if (UNDO_lp == 0)
continue;
lp = UNDO_lp;
lp->l_dline = UNDO_da | DIRTY;
offset = 0;
numdone--;
continue;
case 'P':
case '!':
query = 0;
break;
case CR:
case LF:
case 'Q':
goto done;
case CTL(L):
RedrawDisplay();
goto reswitch;
default:
rbell();
message("Space or Y, Period, Rubout or N, C-R or R, C-W, C-U or U, P or !, Return.");
goto reswitch;
}
}
re_dosub(linebuf, NO);
numdone++;
modify();
offset = curchar = REeom;
makedirty(curline);
if (query) {
message(mesgbuf); /* No blinking. */
redisplay(); /* Show the change. */
}
UNDO_da = curline->l_dline;
UNDO_lp = curline;
if (linebuf[offset] == 0)
nxtline: break;
}
}
SetMark();
done: s_mess("%d substitution%n.", numdone, numdone);
}
/* Prompt for search and replacement strings and do the substitution. The
point is restored when we're done. */
static
replace(query, inreg)
{
Mark *save = MakeMark(curline, curchar, FLOATER),
*m;
char *rep_ptr;
Line *l1 = curline,
*l2 = curbuf->b_last;
int char1 = curchar,
char2 = length(curbuf->b_last);
if (inreg) {
m = CurMark();
l2 = m->m_line;
char2 = m->m_char;
(void) fixorder(&l1, &char1, &l2, &char2);
}
/* Get search string. */
strcpy(rep_search, ask(rep_search[0] ? rep_search : (char *) 0, ProcFmt));
REcompile(rep_search, UseRE, compbuf, alternates);
/* Now the replacement string. Do_ask() so the user can play with
the default (previous) replacement string by typing C-R in ask(),
OR, he can just hit Return to replace with nothing. */
rep_ptr = do_ask("\r\n", (int (*)()) 0, rep_str, ": %f %s with ", rep_search);
if (rep_ptr == 0)
rep_ptr = NullStr;
strcpy(rep_str, rep_ptr);
substitute(query, l1, char1, l2, char2);
ToMark(save);
DelMark(save);
}
RegReplace()
{
replace(0, YES);
}
QRepSearch()
{
replace(1, NO);
}
RepSearch()
{
replace(0, NO);
}
/* C tags package. */
static
lookup(searchbuf, filebuf, tag, file)
char *searchbuf,
*filebuf,
*tag,
*file;
{
register int taglen = strlen(tag);
char line[128],
pattern[100];
File *fp;
fp = open_file(file, iobuff, F_READ, !COMPLAIN, QUIET);
if (fp == NIL)
return 0;
sprintf(pattern, "^%s[^\t]*\t\\([^\t]*\\)\t[?/]\\(.*\\)[?/]$", tag);
while (f_gets(fp, line, sizeof line) != EOF) {
if (line[0] != *tag || strncmp(tag, line, taglen) != 0)
continue;
if (!LookingAt(pattern, line, 0)) {
complain("I thought I saw it!");
break;
} else {
putmatch(2, searchbuf, 100);
putmatch(1, filebuf, 100);
close_file(fp);
return 1;
}
}
f_close(fp);
s_mess("Can't find tag \"%s\".", tag);
return 0;
}
char TagFile[128] = "./tags";
find_tag(tag, localp)
char *tag;
{
char filebuf[FILESIZE],
sstr[100];
register Bufpos *bp;
register Buffer *b;
char *tagfname;
if (!localp)
tagfname = ask(TagFile, "With tag file (%s default): ", TagFile);
else
tagfname = TagFile;
if (lookup(sstr, filebuf, tag, tagfname) == 0)
return;
SetMark();
b = do_find(curwind, filebuf, 0);
if (curbuf != b)
SetABuf(curbuf);
SetBuf(b);
if ((bp = dosearch(sstr, BACKWARD, 0)) == 0 &&
(WrapScan || ((bp = dosearch(sstr, FORWARD, 0)) == 0)))
message("Well, I found the file, but the tag is missing.");
else
SetDot(bp);
}
FindTag()
{
int localp = !exp_p;
char tag[128];
strcpy(tag, ask((char *) 0, ProcFmt));
find_tag(tag, localp);
}
/* Find Tag at Dot. */
FDotTag()
{
int c1 = curchar,
c2 = c1;
char tagname[50];
if (!ismword(linebuf[curchar]))
complain("Not a tag!");
while (c1 > 0 && ismword(linebuf[c1 - 1]))
c1--;
while (ismword(linebuf[c2]))
c2++;
null_ncpy(tagname, linebuf + c1, c2 - c1);
find_tag(tagname, !exp_p);
}
/* I-search returns a code saying what to do:
STOP: We found the match, so unwind the stack and leave
where it is.
DELETE: Rubout the last command.
BACKUP: Back up to where the isearch was last NOT failing.
When a character is typed it is appended to the search string, and
then, isearch is called recursively. When C-S or C-R is typed, isearch
is again called recursively. */
#define STOP 1
#define DELETE 2
#define BACKUP 3
#define TOSTART 4
static char ISbuf[128],
*incp = 0;
int SExitChar = CR;
#define cmp_char(a, b) ((a) == (b) || (CaseIgnore && (Upper(a) == Upper(b))))
static Bufpos *
doisearch(dir, c, failing)
register int c,
dir,
failing;
{
static Bufpos buf;
Bufpos *bp;
if (c == CTL(S) || c == CTL(R))
goto dosrch;
if (failing)
return 0;
DOTsave(&buf);
if (dir == FORWARD) {
if (cmp_char(linebuf[curchar], c)) {
buf.p_char = curchar + 1;
return &buf;
}
} else {
if (look_at(ISbuf))
return &buf;
}
dosrch: if ((bp = dosearch(ISbuf, dir, 0)) == 0)
rbell(); /* ring the first time there's no match */
return bp;
}
IncFSearch()
{
IncSearch(FORWARD);
}
IncRSearch()
{
IncSearch(BACKWARD);
}
static
IncSearch(dir)
{
Bufpos save_env;
DOTsave(&save_env);
ISbuf[0] = 0;
incp = ISbuf;
if (isearch(dir, &save_env) == TOSTART)
SetDot(&save_env);
else {
if (LineDist(curline, save_env.p_line) >= MarkThresh)
DoSetMark(save_env.p_line, save_env.p_char);
}
setsearch(ISbuf);
message(ISbuf);
}
/* Nicely recursive. */
static
isearch(dir, bp)
Bufpos *bp;
{
Bufpos pushbp;
int c,
ndir,
failing;
char *orig_incp;
if (bp != 0) { /* Move to the new position. */
pushbp.p_line = bp->p_line;
pushbp.p_char = bp->p_char;
SetDot(bp);
failing = 0;
} else {
DOTsave(&pushbp);
failing = 1;
}
orig_incp = incp;
ndir = dir; /* Same direction as when we got here, unless
we change it with C-S or C-R. */
for (;;) {
SetDot(&pushbp);
message(NullStr);
if (failing)
add_mess("Failing ");
if (dir == BACKWARD)
add_mess("reverse-");
add_mess("I-search: %s", ISbuf);
DrawMesg(NO);
add_mess(NullStr); /* tell me this is disgusting ... */
c = getch();
if (c == SExitChar)
return STOP;
switch (c) {
case RUBOUT:
case BS:
return DELETE;
case CTL(G):
/* If we're failing, we backup until we're no longer
failing or we've reached the beginning; else, we
just about the search and go back to the start. */
if (failing)
return BACKUP;
return TOSTART;
case CTL(\\):
c = CTL(S);
case CTL(S):
case CTL(R):
/* If this is the first time through and we have a
search string left over from last time, use that
one now. */
if (incp == ISbuf) {
strcpy(ISbuf, getsearch());
incp = &ISbuf[strlen(ISbuf)];
}
ndir = (c == CTL(S)) ? FORWARD : BACKWARD;
/* If we're failing and we're not changing our
direction, don't recur since there's no way
the search can work. */
if (failing && ndir == dir) {
rbell();
continue;
}
break;
case '\\':
if (incp > &ISbuf[(sizeof ISbuf) - 1]) {
rbell();
continue;
}
*incp++ = '\\';
add_mess("\\");
/* Fall into ... */
case CTL(Q):
case CTL(^):
add_mess("");
c = getch() | 0400;
/* Fall into ... */
default:
if (c & 0400)
c &= 0177;
else {
if (c > RUBOUT || (c < ' ' && c != '\t')) {
Ungetc(c);
return STOP;
}
}
if (incp > &ISbuf[(sizeof ISbuf) - 1]) {
rbell();
continue;
}
*incp++ = c;
*incp = 0;
break;
}
add_mess("%s", orig_incp);
add_mess(" ..."); /* so we know what's going on */
DrawMesg(NO); /* do it now */
switch (isearch(ndir, doisearch(ndir, c, failing))) {
case TOSTART:
return TOSTART;
case STOP:
return STOP;
case BACKUP:
/* If we're not failing, we just continue to to the
for loop; otherwise we keep returning to the
previous levels until we find one that isn't
failing OR we reach the beginning. */
if (failing)
return BACKUP;
/* Fall into ... */
case DELETE:
incp = orig_incp;
*incp = 0;
continue;
}
}
}