This is usearch.c in view mode; [Download] [Up]
/* Search & Replace system */
#include "pw.h"
#include "qw.h"
#include "vs.h"
#include "regex.h"
#include "ublock.h"
#include "uedit.h"
#include "main.h"
#include "undo.h"
#include "usearch.h"
int smode=0; /* Decremented to zero by execmd */
int csmode=0; /* Set for continued search mode */
B *findhist=0; /* Search string history */
B *replhist=0; /* Replacement string history */
SRCH *globalsrch=0; /* Most recent completed search data */
SRCHREC fsr={{&fsr,&fsr}};
/* Search forward.
bw, pattern and ignore must be set
The first possible string we can find is the one beginning under p
Returns p if we found a string:
The found string is placed in entire/pieces
p is placed right after the found string
Return 0 if we did not find the string:
p is left in its orignal spot
*/
P *searchf(srch,p)
SRCH *srch;
P *p;
{
char *pattern=srch->pattern;
P *start=pdup(p);
P *end=pdup(p);
int x;
for(x=0;x!=sLEN(pattern) && pattern[x]!='\\';++x)
if(srch->ignore) pattern[x]=toup(pattern[x]);
while(srch->ignore?pifind(start,pattern,x):pfind(start,pattern,x))
{
pset(end,start);
pfwrd(end,(long)x);
if(pmatch(srch->pieces,pattern+x,sLEN(pattern)-x,end,0,srch->ignore))
{
srch->entire=vstrunc(srch->entire,(int)(end->byte-start->byte));
brmem(start,srch->entire,(int)(end->byte-start->byte));
pset(p,end);
prm(start); prm(end);
return p;
}
if(pgetc(start)== MAXINT) break;
}
prm(start); prm(end);
return 0;
}
/* Search backwards.
bw, pattern and ignore must be set
The first possible string we can find is the one beginning one position
to the left of p.
Returns 1 if we found a string:
The found string is placed in entire
p is placed at the beginning of the string
Return 0 if we did not find the string:
p is left in its orignal spot
*/
P *searchb(srch,p)
SRCH *srch;
P *p;
{
char *pattern=srch->pattern;
P *start=pdup(p);
P *end=pdup(p);
int x;
for(x=0;x!=sLEN(pattern) && pattern[x]!='\\';++x)
if(srch->ignore) pattern[x]=toup(pattern[x]);
while(pbkwd(start,1L) && (srch->ignore?prifind(start,pattern,x):prfind(start,pattern,x)))
{
pset(end,start);
pfwrd(end,(long)x);
if(pmatch(srch->pieces,pattern+x,sLEN(pattern)-x,end,0,srch->ignore))
{
srch->entire=vstrunc(srch->entire,(int)(end->byte-start->byte));
brmem(start,srch->entire,(int)(end->byte-start->byte));
pset(p,start);
prm(start); prm(end);
return p;
}
}
prm(start); prm(end);
return 0;
}
/* Make a search stucture */
SRCH *setmark(srch)
SRCH *srch;
{
if(markv(1)) srch->valid=1;
srch->markb=markb;
if(srch->markb) srch->markb->owner= &srch->markb;
markb=0;
srch->markk=markk;
if(srch->markk) srch->markk->owner= &srch->markk;
markk=0;
return srch;
}
SRCH *mksrch(pattern,replacement,ignore,backwards,repeat,replace,rest)
char *pattern, *replacement;
{
SRCH *srch=(SRCH *)malloc(sizeof(SRCH));
int x;
srch->pattern=pattern;
srch->replacement=replacement;
srch->ignore=ignore;
srch->backwards=backwards;
srch->repeat=repeat;
srch->replace=replace;
srch->rest=rest;
srch->entire=0;
srch->flg=0;
srch->addr= -1;
srch->markb=0;
srch->markk=0;
srch->valid=0;
srch->restrict=0;
izque(SRCHREC,link,&srch->recs);
for(x=0;x!=26;++x) srch->pieces[x]=0;
return srch;
}
/* Eliminate a search structure */
void rmsrch(srch)
SRCH *srch;
{
int x;
prm(markb); prm(markk);
if(srch->markb)
{
markb=srch->markb;
markb->owner= &markb;
markb->xcol=piscol(markb);
}
if(srch->markk)
{
markk=srch->markk;
markk->owner= &markk;
markk->xcol=piscol(markk);
}
for(x=0;x!=26;++x) vsrm(srch->pieces[x]);
frchn(&fsr,&srch->recs);
vsrm(srch->pattern);
vsrm(srch->replacement);
vsrm(srch->entire);
free(srch);
updall();
}
/* Insert a replacement string
* p is advanced past the inserted text
*/
P *insert(srch,p,s,len)
SRCH *srch;
P *p;
char *s;
{
int x;
while(len)
{
for(x=0;x!=len && s[x]!='\\';++x);
if(x)
{
binsm(p,s,x);
pfwrd(p,(long)x);
len-=x;
s+=x;
}
else if(len>=2)
{
if(s[1]=='\\') binsc(p,'\\'), pgetc(p);
else if(s[1]=='n') binsc(p,'\n'), pgetc(p);
else if((s[1]>='a' && s[1]<='z' ||
s[1]>='A' && s[1]<='Z') && srch->pieces[(s[1]&0x1f)-1])
{
binsm(p,sv(srch->pieces[(s[1]&0x1f)-1]));
pfwrd(p,(long)sLEN(srch->pieces[(s[1]&0x1f)-1]));
}
else if(s[1]>='0' && s[1]<='9' && srch->pieces[s[1]-'0'])
{
binsm(p,sv(srch->pieces[s[1]-'0']));
pfwrd(p,(long)sLEN(srch->pieces[s[1]-'0']));
}
else if(s[1]=='&' && srch->entire)
{
binsm(p,sv(srch->entire));
pfwrd(p,(long)sLEN(srch->entire));
}
s+=2; len-=2;
}
else len=0;
}
return p;
}
/* Search system user interface */
/* Query for search string, search options, possible replacement string,
* and execute first search */
char srchstr[]="Search"; /* Context sensitive help identifier */
static int pfabort(bw,srch)
BW *bw;
SRCH *srch;
{
if(srch) rmsrch(srch);
return -1;
}
static int pfsave(bw,srch)
BW *bw;
SRCH *srch;
{
if(srch)
{
if(globalsrch) rmsrch(globalsrch);
globalsrch=srch;
srch->rest=0;
srch->repeat= -1;
srch->flg=0;
prm(markb); prm(markk);
if(srch->markb)
{
markb=srch->markb;
markb->owner= &markb;
markb->xcol=piscol(markb);
}
if(srch->markk)
{
markk=srch->markk;
markk->owner= &markk;
markk->xcol=piscol(markk);
}
srch->markb=0; srch->markk=0;
updall();
}
return -1;
}
static int set_replace(bw,s,srch,notify)
BW *bw;
char *s;
SRCH *srch;
int *notify;
{
srch->replacement=s;
return dopfnext(bw,srch,notify);
}
static int set_options(bw,s,srch,notify)
BW *bw;
char *s;
SRCH *srch;
int *notify;
{
int x;
for(x=0;s[x];++x)
switch(s[x])
{
case 'r': case 'R': srch->replace=1; break;
case 'b': case 'B': srch->backwards=1; break;
case 'i': case 'I': srch->ignore=1; break;
case 'k': case 'K': srch->restrict=1; break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
if(srch->repeat== -1) srch->repeat=0;
srch->repeat=srch->repeat*10+s[x]-'0';
break;
}
vsrm(s);
if(srch->replace)
{
if(wmkpw(bw,
"Replace with (^C to abort): ",&replhist,set_replace,srchstr,pfabort,utypebw,srch,notify))
return 0;
else return -1;
}
else return dopfnext(bw,srch,notify);
}
static int set_pattern(bw,s,srch,notify)
BW *bw;
char *s;
SRCH *srch;
int *notify;
{
BW *pbw;
vsrm(srch->pattern); srch->pattern=s;
if(pbw=wmkpw(bw,
"(I)gnore (R)eplace (B)ackwards Bloc(K) NNN (^C to abort): ",
NULL,set_options,srchstr,pfabort,utypebw,srch,notify))
{
char buf[10];
if(srch->ignore) binsc(pbw->cursor,'i');
if(srch->replace) binsc(pbw->cursor,'r');
if(srch->backwards) binsc(pbw->cursor,'b');
if(srch->repeat>=0) sprintf(buf,"%d",srch->repeat), binss(pbw->cursor,buf);
pset(pbw->cursor,pbw->b->eof);
pbw->cursor->xcol=piscol(pbw->cursor);
srch->ignore=0;
srch->replace=0;
srch->backwards=0;
srch->repeat= -1;
return 0;
}
else
{
rmsrch(srch);
return -1;
}
}
static int dofirst(bw,back,repl)
BW *bw;
{
SRCH *srch;
if(smode && globalsrch)
{
globalsrch->backwards=back;
globalsrch->replace=repl;
return pfnext(bw);
}
if(bw->parent->huh==srchstr)
{
long byte;
peol(bw->cursor);
byte=bw->cursor->byte;
pbol(bw->cursor);
if(byte==bw->cursor->byte) prgetc(bw->cursor);
return urtn(bw,MAXINT);
}
srch=setmark(mksrch(NULL,NULL,0,back,-1,repl,0));
srch->addr=bw->cursor->byte;
if(wmkpw(bw,"Find (^C to abort): ",&findhist,set_pattern,srchstr,pfabort,utypebw,srch,NULL))
return 0;
else
{
rmsrch(srch);
return -1;
}
}
int pffirst(bw)
BW *bw;
{
return dofirst(bw,0,0);
}
int prfirst(bw)
BW *bw;
{
return dofirst(bw,1,0);
}
int pqrepl(bw)
BW *bw;
{
return dofirst(bw,0,1);
}
/* Execute next search */
static int doreplace(bw,srch)
BW *bw;
SRCH *srch;
{
P *q;
if(bw->b->rdonly) { msgnw(bw,"Read only"); return -1; }
if(markk) markk->end=1;
if(srch->markk) srch->markk->end=1;
q=pdup(bw->cursor);
if(srch->backwards)
{
q=pfwrd(q,(long)sLEN(srch->entire));
bdel(bw->cursor,q);
prm(q);
}
else
{
q=pbkwd(q,(long)sLEN(srch->entire));
bdel(q,bw->cursor);
prm(q);
}
insert(srch,bw->cursor,sv(srch->replacement));
srch->addr=bw->cursor->byte;
if(markk) markk->end=0;
if(srch->markk) srch->markk->end=0;
return 0;
}
static void visit(srch,bw,yn)
SRCH *srch;
BW *bw;
{
SRCHREC *r=(SRCHREC *)alitem(&fsr,sizeof(SRCHREC));
r->addr=bw->cursor->byte;
r->yn=yn;
enqueb(SRCHREC,link,&srch->recs,r);
}
static void goback(srch,bw)
SRCH *srch;
BW *bw;
{
SRCHREC *r=srch->recs.link.prev;
if(r!=&srch->recs)
{
if(r->yn) uundo(bw);
if(bw->cursor->byte!=r->addr) pgoto(bw->cursor,r->addr);
demote(SRCHREC,link,&fsr,r);
}
}
static int dopfrepl(bw,c,srch,notify)
BW *bw;
SRCH *srch;
int *notify;
{
srch->addr=bw->cursor->byte;
if(c=='N' || c=='n')
return dopfnext(bw,srch,notify);
else if(c=='Y' || c=='y' || c==' ')
{
srch->recs.link.prev->yn=1;
if(doreplace(bw,srch))
{
pfsave(bw,srch);
return -1;
}
else return dopfnext(bw,srch,notify);
}
else if(c=='R' || c=='r')
{ if(doreplace(bw,srch)) return -1; srch->rest=1; return dopfnext(bw,srch,notify); }
else if(c==8 || c==127 || c=='b' || c=='B')
{ goback(srch,bw); goback(srch,bw); return dopfnext(bw,srch,notify); }
else if(c!=MAXINT)
{
if(notify) *notify=1;
pfsave(bw,srch);
nungetc(c);
return 0;
}
if(mkqwnsr(bw,sc("Replace (Y)es (N)o (R)est (B)ackup (^C to abort)?"),dopfrepl,pfsave,srch,notify))
return 0;
else return pfsave(bw,srch);
}
/* Test if found text is within region
* return 0 if it is,
* -1 if we should keep searching
* 1 if we're done
*/
int restrict(bw,srch)
BW *bw;
SRCH *srch;
{
if(!srch->valid || !srch->restrict) return 0;
bw->cursor->xcol=piscol(bw->cursor);
if(srch->backwards)
if(!square)
{
if(bw->cursor->byte<srch->markb->byte) return 1;
else if(bw->cursor->byte+sLEN(srch->entire)>srch->markk->byte) return -1;
}
else
{
if(bw->cursor->line<srch->markb->line) return 1;
else if(bw->cursor->line>srch->markk->line) return -1;
else if(piscol(bw->cursor)+sLEN(srch->entire)>srch->markk->xcol ||
piscol(bw->cursor)<srch->markb->xcol) return -1;
}
else
if(!square)
{
if(bw->cursor->byte>srch->markk->byte) return 1;
else if(bw->cursor->byte-sLEN(srch->entire)<srch->markb->byte) return -1;
}
else
{
if(bw->cursor->line>srch->markk->line) return 1;
if(bw->cursor->line<srch->markb->line) return -1;
if(piscol(bw->cursor)>srch->markk->xcol ||
piscol(bw->cursor)-sLEN(srch->entire)<srch->markb->xcol) return -1;
}
return 0;
}
/* Possible results:
* 0) Search or search & replace is finished.
* 1) Search string was not found.
* 2) Search string was found.
*/
static int fnext(bw,srch)
BW *bw;
SRCH *srch;
{
P *sta;
next:
if(srch->repeat!= -1)
if(!srch->repeat) return 0;
else --srch->repeat;
again: if(srch->backwards) sta=searchb(srch,bw->cursor);
else sta=searchf(srch,bw->cursor);
if(!sta)
{
srch->repeat= -1;
return 1;
}
else
if(srch->rest || srch->repeat!= -1 && srch->replace)
{
if(srch->valid)
switch(restrict(bw,srch))
{
case -1: goto again;
case 1: if(srch->addr>=0) pgoto(bw->cursor,srch->addr); return !srch->rest;
}
if(doreplace(bw,srch)) return 0;
goto next;
}
else if(srch->repeat!= -1)
{
if(srch->valid)
switch(restrict(bw,srch))
{
case -1: goto again;
case 1: if(srch->addr>=0) pgoto(bw->cursor,srch->addr); return 1;
}
srch->addr=bw->cursor->byte;
goto next;
}
else return 2;
}
int dopfnext(bw,srch,notify)
BW *bw;
SRCH *srch;
int *notify;
{
int orgmid=mid; /* Original mid status */
int ret=0;
mid=1; /* Screen recenters mode during search */
if(csmode) smode=2; /* We have started a search mode */
if(srch->replace) visit(srch,bw,0);
again: switch(fnext(bw,srch))
{
case 0:
break;
case 1:
bye: if(!srch->flg && !srch->rest)
{
if(srch->valid && srch->restrict)
msgnw(bw,"Not found (search restricted to marked block)");
else msgnw(bw,"Not found");
ret= -1;
}
break;
case 2:
if(srch->valid)
switch(restrict(bw,srch))
{
case -1: goto again;
case 1: if(srch->addr>=0) pgoto(bw->cursor,srch->addr); goto bye;
}
srch->addr=bw->cursor->byte;
if(srch->replace)
{
if(square) bw->cursor->xcol=piscol(bw->cursor);
if(srch->backwards)
{
pdupown(bw->cursor,&markb); markb->xcol=piscol(markb);
pdupown(markb,&markk);
pfwrd(markk,(long)sLEN(srch->entire));
markk->xcol=piscol(markk);
}
else
{
pdupown(bw->cursor,&markk); markk->xcol=piscol(markk);
pdupown(bw->cursor,&markb);
pbkwd(markb,(long)sLEN(srch->entire));
markb->xcol=piscol(markb);
}
srch->flg=1;
if(dopfrepl(bw,MAXINT,srch,notify)) ret= -1;
notify=0;
srch=0;
}
break;
}
bw->cursor->xcol=piscol(bw->cursor);
dofollows();
mid=orgmid;
if(notify) *notify=1;
if(srch) pfsave(bw,srch);
else updall();
return ret;
}
int pfnext(bw)
BW *bw;
{
if(!globalsrch) /* Query for search string if there isn't any */
return pffirst(bw);
else
{
SRCH *srch=globalsrch;
globalsrch=0;
srch->addr=bw->cursor->byte;
return dopfnext(bw,setmark(srch),NULL);
}
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.