#include "defines.h"
/*     Bed a menu-driven multi dataformat binary editor for Linux            */
/*     Copyright (C) 1998 Jaap Korthals Altes <jkaltes@hetnet.nl>       */
/*                                                                           */
/*     This program is free software; you can redistribute it and/or modify  */
/*     it under the terms of the GNU General Public License as published by  */
/*     the Free Software Foundation; either version 2 of the License, or     */
/*     (at your option) any later version.                                   */
/*                                                                           */
/*     This program is distributed in the hope that it will be useful,       */
/*     but WITHOUT ANY WARRANTY; without even the implied warranty of        */
/*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         */
/*     GNU General Public License for more details.                          */
/*                                                                           */
/*     You should have received a copy of the GNU General Public License     */
/*     along with this program; if not, write to the Free Software           */
/*     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.             */
/* Fri Dec  8 22:14:27 2000                                                  */
#include "desturbe.h"
#include <alloca.h>
#include "editor.h"
#include "convert.h"
#include "datatypes.h"
#include "getfile.h"
#include "screen.h"
#include "myalloc.h"
#include "main.h"
#include "contain.h"
#include "repeat.h"
#include <stdlib.h>
#define maxbytes 20
#define maxbase 20
#define MAXSEARCHSTR 512
#define isasciimode(x) (instance(x,Ascii)&&(x->lastfilter==x->firstfilter))
//#define standardascii(x) (instance(x,Ascii)&&(x->getbytes()==1)&&(x->lastfilter==x->firstfilter))
//#define standardascii(x) (instance(x,Ascii)&&(x->getbytes()==1)&&(x->lastfilter==x->firstfilter))
int standardascii(ScreenPart *x) {
	return (instance(x,Ascii)&&(x->getbytes()==1)&&(x->lastfilter==x->firstfilter));
	}

#define isdigitmode(x) (instance(x,Digit)&&(x->lastfilter==x->firstfilter))
//#define predefinedmode(x) (isasciimode((x))||(isdigitmode((x))&&((x)->type==2||(x)->type==8||(x)->type==16||(x)->type==10)))
int Editor::searchtype(int newtype) {
	int oldtype=mem.lastforward;
	if(newtype>=0)
		mem.lastforward=newtype;
	return oldtype;
	}
#define onboundary (mem.lastforward&8)?1:0
#define dataname(x) ((x)->getname())
#define namedata dataname(parts[mode])
/*unsigned char tempformatsearch[512];
#define strsearchingfor() ((regsearch(&mem))?formatsearch:(parts[mode]->fromascii((unsigned char *)mem.searchstr,tempformatsearch,mem.searchlen),tempformatsearch))
*/
#define strsearchingfor() formatsearch
#define makesearchdataname() 
//#define makesearchdataname() (((searchdataname==NULL)?(searchdataname= myallocar(char, 20)):NULL), snprintf(searchdataname,20,"%s%s %d",parts[mode]->getname(), modename(parts[mode]->type),parts[mode]->bytes))
#define searchdataname() ((regsearch(&mem)?makesearchdataname():1),searchdataname)
//#define searchdataname() searchdataname
/*#define searchingfor() message("%s: Searching for %.50s",searchdataname(),strsearchingfor())
#define nexsearchingfor() message("%s: Next search for %.50s",searchdataname(),strsearchingfor())
#define notfoundsearchingfor() message("%s: Not found %.50s",searchdataname(),strsearchingfor())
#define alreadysearchingfor() message("%s: Already searching for %.40s",searchdataname(),strsearchingfor())
#define foundsearchingfor() message("%s: Found %.50s",searchdataname(),strsearchingfor())
*/
#define searchingfor()    message("Searching for %.*s",thecols-14,strsearchingfor())
#define nexsearchingfor()      message("Next search for %.*s",thecols-16,strsearchingfor())
#define notfoundsearchingfor() message("Not found %.*s",thecols-10,strsearchingfor())
#define alreadysearchingfor()  message("Already searching for %.*s",thecols-22,strsearchingfor())
#define foundsearchingfor() message("Found %.*s",thecols-6,strsearchingfor())

extern const char *regexerrorstring;
//extern int onboundary;
#ifdef ATOIBUG
extern long strtoint(char *str) ;
extern long mystrtol(char *bytes,char **endp,int base) ;
#else
#define    strtoint(x) atoi(x)
#define mystrtol strtol
#endif

OFFTYPE Editor::memsearch(ScreenPart *part,OFFTYPE pos,char *str,int len) {
	if(searchpart)
		delete searchpart;
	searchpart=part->newone();
	if((regsearch(&mem))&&!standardascii(part)) {
		OFFTYPE ret;
		INCDEST();
		ret= formsearch(part,pos,formatsearch,strlen(formatsearch)) ;
		DECDEST();
		return ret;
		}
	else {
		if(onboundary) {
			searchbytes=parts[mode]->bytes;
			OFFTYPE res;
			searchgrens=(filepos+indatatype)%searchbytes;
			 res=mem.search(pos,str,len);
			while(res!=OFFTYPEINVALID&& (res%searchbytes)!=searchgrens)
				res= mem.nextsearch();
				
			return res;
			}
		else
			return mem.search(pos,str,len);
		}
	return OFFTYPEINVALID;
	}

OFFTYPE Editor::memnextsearch(void) {
	if(regsearch(&mem)&&!standardascii(searchpart)) {
		INCDEST();
		OFFTYPE	ret= nextregexshown(searchpart) ;
		DECDEST();
		return ret;
		}
	else	{
		if(onboundary) {
			if(!searchbytes) {
				searchbytes=searchpart->bytes;
				searchgrens=(filepos+indatatype)%searchbytes;
				}

			OFFTYPE pos;
			while((pos=mem.nextsearch())!=OFFTYPEINVALID&&(pos%searchbytes)!=searchgrens) 
				;
			return pos;
			}
		else
			return mem.nextsearch();
			
		}
	}
#ifdef SEARCHTIME
#include <sys/time.h>
#endif
#ifdef USETHREADS
#undef ERR
#include <signal.h>
#undef ERR

void Editor::stopthread(void) {
	if(threadrunning) {
		sem_wait(&sema);
		myfree( gegsthread.ant);
		 pthread_cancel(threadsearch);
		 threadrunning=0;
		sem_post(&sema);
		}
};
void * listthread(void *arg) {
	sigset_t sigs;
	struct threadgegs *geg=(struct threadgegs*)arg;
	sigemptyset(&sigs);
	sigaddset(&sigs,SIGINT);
#ifdef DONTINTCURSES
	sigaddset(&sigs, SIGUSR1) 
#endif
	sigaddset(&sigs,SIGWINCH);
	sigaddset(&sigs,SIGHUP);
	sigaddset(&sigs,SIGCONT);
	sigaddset(&sigs,SIGSTOP);
	sigaddset(&sigs,SIGTSTP);
	sigaddset(&sigs,SIGTERM);
	sigaddset(&sigs,SIGQUIT);
	sigaddset(&sigs,SIGALRM);
	 pthread_sigmask(SIG_BLOCK,&sigs,NULL);
	 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL);
	geg->ed->searchlister(geg->part,geg->ant,geg->len,geg->pos);
	myfree( geg->ant);
	delete geg->part;
	return arg;
	}
int Editor::searchlist(ScreenPart *part,char *ant, int len) {

	if(threadrunning) {
		alreadysearchingfor();
		return -1;
		}
	memorize();
	message("Thread started, the results will be added to marklist (alt-k,l)");
	wrefresh(editscreen);
	gegsthread.ed= this;
	gegsthread.part= part;
	gegsthread.ant=myallocar( char,len);
	memcpy(gegsthread.ant,ant,len);
	gegsthread.len=len;
	gegsthread.pos=(mem.lastforward&1)?(edge?0:filepos+editpos+1): (edge?(mem.size()-1):(filepos+editpos-1));
	threadrunning++;
	  pthread_create(&threadsearch, NULL, listthread, &gegsthread);
	return 0;
	}

int Editor::searchlister(ScreenPart *part,char *ant,int len,OFFTYPE pos) {
#else //not USETHREADS

int Editor::searchlist(ScreenPart *part,char *ant, int len) {
	OFFTYPE pos;
	int found;
	memorize();
	pos=(mem.lastforward&1)?(edge?0:filepos+editpos+1): (edge?(mem.size()-1):(filepos+editpos-1));
	if(len)
		searchingfor();
	else
		nexsearchingfor();
	wrefresh(editscreen);
#endif
	if(len) {
		pos=memsearch(part,pos,ant,len);
		if(pos== OFFTYPEINVALID) {
			#ifdef USETHREADS
				threadrunning--;
			#endif
			return -1;
			}
		#ifdef USETHREADS
				sem_wait(&sema);
		#endif
				setmark( (unsigned char[]){27,27,27} ,3,pos);
		#ifdef USETHREADS
			sem_post(&sema);
		#endif
		found=1;
		}
	else {
		if(!mem.searchstr) {
			#ifdef USETHREADS
				threadrunning--;
			#endif
			return -1;
			}
		if(onboundary) {
			searchbytes=searchpart->bytes;
			searchgrens=(filepos+indatatype)%searchbytes;
			}
		found=0;
		}
	pos= memnextsearch();
	while(pos!=OFFTYPEINVALID) {
		found++;	
#ifdef USETHREADS
		sem_wait(&sema);
#endif
		setmark( (unsigned char[]){27,27,27} ,3,pos);
#ifdef USETHREADS
	sem_post(&sema);
#endif
		pos= memnextsearch();
		}
#ifdef USETHREADS
	threadrunning--;
#endif
	return found;
	}

/* returns offset of string or SEARCHFAILURE when not found */
OFFTYPE Editor::dosearch(OFFTYPE pos, char *ant,int len) {
#ifdef USETHREADS
	if(threadrunning) {
		alreadysearchingfor();
		return  SEARCHFAILURE ;
		}
#endif
	if(formatsearch)
		myfree( formatsearch);
	formatsearch=myallocar( char,len+1);
	memmove(formatsearch,ant,len);
	formatsearch[len]='\0';
	return dosearcher(parts[mode],pos, ant, len);
	}
OFFTYPE Editor::dosearch(char *ant,int len) {
	OFFTYPE start=(mem.lastforward&1)?(edge?0:filepos+editpos+1): (edge?(mem.size()-1):(filepos+editpos-1));
	return dosearch(start,ant,len);
	}


OFFTYPE Editor::dosearcher(char *ant,int len) {
	OFFTYPE start=(mem.lastforward&1)?(edge?0:filepos+editpos+1): (edge?(mem.size()-1):(filepos+editpos-1));
	return dosearcher(parts[mode],start,ant, len) ;
	}

OFFTYPE Editor::dosearcher(ScreenPart *part,OFFTYPE pos, char *ant,int len) {

#ifdef USETHREADS
	if(threadrunning) {
		alreadysearchingfor();
		return  SEARCHFAILURE ;
		}
#endif
	makesearchdataname();
	memorize();
DEBUGGING("Searching (" OFFPRINT ",%d)#%.80s#\n",pos,len,ant);
	if(len) {

		searchingfor();
		wrefresh(editscreen);
		pos=memsearch(part,pos,ant,len);
		}
	else {
		if(mem.searchstr) {
			nexsearchingfor();
			wrefresh(editscreen);
			pos= memnextsearch();
			}
		else {
			return SEARCHFAILURE;
			}

		}
	return  pos;
	}
int Editor::nextsearch(void) {
	

#ifdef USETHREADS
	if(threadrunning) {
		alreadysearchingfor();
		return -1;
		}
#endif
	OFFTYPE pos,blockpos;
	memorize();
		if(mem.searchstr) {
			nexsearchingfor();
			wrefresh(editscreen);
			pos= memnextsearch();
			}
		else {
			output("No previous search");
			return -1;
			}

	if(pos==OFFTYPEINVALID) {
			notfoundsearchingfor();
		return -1;
		}
	if(pos>=indatatype)
		blockpos=pos-indatatype;
	else {
		blockpos=0;
		beep();
		}
	pretopos(blockpos);
	toborder( blockpos);
	if(dofromfile) {
		fromfile();
		updated=0;
		}
	else
		cursorpos();
	if(!updated)
		writebuf();
	foundsearchingfor();
	wrefresh(editscreen);
	return pos;
	}



#include "reverse.h"
int reord(ScreenPart *part) {
	int reorder;
	char *lab=part->lastfiltername();
	if(lab&&lab[0]=='r'&&((strspn(lab+1,"0123456789")+1)>=strlen(lab))) {
		Reverse *rev=(Reverse*)part->getlastfilter();
		reorder=rev->unit;
		}
	else
		reorder=0;
		
	return reorder;
	}

#define changedatatype() \
	switch(dattype) {\
		case 0:if(!isasciimode(copythis)) {\
				if(!ascii) {\
					ascii=new Ascii(this);\
					}\
				part=ascii;\
				}\
			else\
				part=copythis;\
			break;\
		case 1: if(!isdigitmode(copythis)) {\
				if(!digit) {\
					digit=new Digit(this);\
					}\
				part=digit;\
				}\
			else\
				part=copythis;\
			break;\
		case 2: part=copythis;break;\
		case 3: part=subpart;break;\
\
		};\
	if(byt!=part->datbytes()) {\
		part->chbytes(byt); \
		byt=part->datbytes();\
		sprintf(bytes,"%d",byt);	\
		}\
	if(tmode!=part->type) {\
		part->chbase(tmode) ;\
		tmode=part->type;\
		sprintf(basestr,"%d",tmode);	\
		}\
	if(oldorder!=reorder) {\
		part->reverse();\
		}

/* ask information
Input: startstring, searchinfo
Output: search,searchlen, searchinfo, datatype
	mem.lastforward=forward|(cas<<1)|(reg<<2)|(boundary<<3);
*/

int Editor::search(void) {
	return searcher(0);
	}
extern int getindatatype(ScreenPart *thesub) ;
#define FOREVER 
#define ENDFOREVER(x) x:
#define LEAVE(x) goto x;
#define findgetmode(foundmode)\
	indatatype=0;\
FOREVER\
	if(part->equal(parts[mode])) {\
		LEAVE(foundmode)\
		}\
	if(iscontain(parts[mode])) {\
		if(part->equal(thesub)) {\
\
			indatatype=getindatatype(thesub); \
			LEAVE(foundmode)\
			}\
		Contains *con=(Contains*)parts[mode];\
		int byt=0;\
		for(int i=0;i<con->nrsubparts;i++) {\
				if(part->equal(con->subparts[i])) {\
					indatatype=byt;\
					LEAVE(foundmode)\
					}\
				byt+=con->subparts[i]->bytes;\
			}\
		}\
	for(int i=0;i<nrparts;i++)\
		if(i!=mode&&part->equal(parts[i])) {\
			tomodenr(i);\
			LEAVE(foundmode)\
			}\
	installpart(part->newone(),0);\
ENDFOREVER(foundmode)
int Editor::searcher(int askrepl) {

#ifdef USETHREADS
	if(threadrunning) {
		if(getkeyinput("Searching for %s press (s)top/(c)ontinue: ",formatsearch)=='s') {
			stopthread();
			clearmessage();
			return 0;
			}
		clearmessage();
		return -1;
		}
#endif
	ScreenPart *copythis=parts[mode]->newone(),*part,*digit=NULL,*ascii=NULL;
	int fors,bins;
	ScreenPart *thesub=parts[mode]->getsubpart(fors,bins, parts[mode]->half),*subpart;
	if(thesub&&thesub!=parts[mode]) {
			if(isasciimode(thesub)) {
				part=ascii=thesub->newone();
				subpart=NULL;
				}
			else {
				if(isdigitmode(thesub)) {
					part=digit=thesub->newone();
					subpart=NULL;
					}
				else
					part=subpart=thesub->newone();
				}
		}
	else {
		subpart=NULL;
		part=copythis;
		}
	char ant[MAXSEARCHSTR];
	char ascant[MAXSEARCHSTR];
	char bytes[maxbytes];
	char basestr[maxbase];
	int flen,len,reg=0,cas=1,forward, res=1,list=0,byt=1,dattype;
	int oldbytes,oldorder;
	int reorder=0;
	int wlin=15,wcol=60;
	int maxactive=30;
	char active[maxactive+5];
	char	subactive[maxactive+5];
	forward=mem.lastforward&1;
	cas=(mem.lastforward>>1)&1;
	reg=(mem.lastforward>>2)&1;
	if(mem.searchstr ) {
		if(!reg||standardascii(part)) 
			 flen=frombytes(part,(unsigned char*)ant,(unsigned char*)mem.searchstr,mem.searchlen,MAXSEARCHSTR);
		else {
			memmove(ant,mem.searchstr,mem.searchlen);
			flen=mem.searchlen;
			}
		}
	else {
		ant[0]='\0';
		flen=0;
		}
	int rlen;
	char *rep;
	char *rtmp;
	if(askrepl) {
		wlin+=askrepl;
		rep=(char *)alloca(MAXSEARCHSTR);
		rtmp=(char *) alloca(MAXSEARCHSTR);
		if(replacestrlen) {
			if(!reg||standardascii(part)) 
				 rlen=frombytes(part,(unsigned char*)rep,(unsigned char*)replacestr,replacestrlen,MAXSEARCHSTR);
			else {
				memmove(rep,replacestr,replacestrlen);
				rlen=replacestrlen;
				}
			}
		else {
			rep[0]='\0';
			rlen=0;
			}
		}
	int oldtm=(int)part->type,tmode=oldtm;
	byt=part->datbytes();
	reorder=reord(part)==1;
	int boundary=onboundary;
	sprintf(basestr,"%d",tmode);	
	sprintf(bytes,"%d",byt);	
	if(isasciimode(part))
		dattype=0;
	else {
		if(isdigitmode(part))
			dattype=1;
		else {
			if(subpart)
				dattype=3;
			else
				dattype=2;
			}
		}
	strcpyn(active,copythis->getname(),maxactive-1);
	active[maxactive-1]='\0';
	if(subpart) {
		int len=minnum((int)strlen(subpart->getname()),(maxactive-3));
		memmove(subactive,subpart->getname(),len);
		subactive[len]='~';
		subactive[len+1]='.';
		subactive[len+2]='\0';
		}
	while(1) {
	int afterdata;
	oldorder=reorder;
	oldbytes=byt;
#define placeascii 11
#define startdia 1
	initdialog(20);
		checker("~Regular expression ",1+startdia,3,reg);
		checker( "Case ~sensitive",2+startdia,3,cas); 
		checker( "Bo~undaries",2+startdia,28,boundary);
		checker( "For~ward",1+startdia,44,forward); 
		checker( "~Edge file",2+startdia,44,edge); 
		if(askrepl) {
			linerlennrmax("~Find:",flen,ant,5+startdia,6,43,MAXSEARCHSTR);
			linerlennrmax("Re~place:",rlen,rep,7+startdia,3,43,MAXSEARCHSTR);
			}
		else {
			linerlennrmax("~Find: ",flen,ant,5+startdia,3,45,MAXSEARCHSTR);
			checker( "L~ist",8,3,list);
			}
		oke(10+askrepl,3);
		act("Cance~l", 12+askrepl,3);
		saveact("Se~t", 10+askrepl,12);
		saveact("~Convert", 12+askrepl,12);
	if(subpart) {
		options(dattype,dattype,
			opt("~Ascii",9+askrepl,23,0),
			opt("~Digit",10+askrepl,23,1),
			opt(active,11+askrepl,23,2),
			opt(subactive,12+askrepl,23,3));
			afterdata=4;
			}
		else {
		options(dattype,dattype,
			opt("~Ascii",9+askrepl,23,0),
			opt("~Digit",10+askrepl,23,1),
			opt(active,11+askrepl,23,2));
			afterdata=3;
		  	}
		linernrmax("~Base ",basestr,9+askrepl,43,3,maxbase);
		linernrmax("B~ytes: ",bytes,10+askrepl,43,3,maxbytes);
		checker( "Re~verse",12+askrepl,43,reorder);
	dodialog(res,wlin,wcol,5);
		if(!res||res==(placeascii-2))	 { 
			if(ascii)
				delete ascii;
			if(digit)
				delete digit;
			if(copythis)
				delete copythis;
			if(subpart)
				delete subpart;
			editup(); 
			return -1; 
			}
		else {

			if(res==LONG_MAX)  {
				menuresized();
				wrefresh(editscreen);
				continue;
				}
			char *endp;
			byt=mystrtol(bytes,&endp,10);
			if(bytes==endp)
				byt=oldbytes;
			tmode=mystrtol(basestr,&endp,10);
			if(basestr==endp)
				tmode=oldtm;
			res-=(placeascii+1);
			if(res>=-1&&res<20) {
				if(res==(afterdata+2))
					reorder=!oldorder;
				if(res>=0&&res<afterdata)
					dattype=res;
				len=makebytes(part,(unsigned char*)ascant,MAXSEARCHSTR, (unsigned char*)ant, flen);
				if(askrepl)
					rlen= makebytes(part,(unsigned char *)rtmp,MAXSEARCHSTR,(unsigned char*)rep, rlen) ;
				changedatatype();
				flen=frombytes(part,(unsigned char*)ant,(unsigned char*)ascant,len,MAXSEARCHSTR);
				if(askrepl)
					rlen=frombytes(part,(unsigned char*)rep,(unsigned char*)rtmp,rlen,MAXSEARCHSTR);
				 continue;
				}
			else {
				if(res==-2) {
					changedatatype();
					continue;
					}
				}
			}
	if(askrepl) {
		if(rep[0]=='\0') {
			output("Use space to clear");
			beep();
			erefresh();
			continue;
			}
		if(replacestr)
			myfree( replacestr);
		replacestr=myallocar( char,(rlen+1)*byt);
		}
	if((!reg)||standardascii(part))  {
		changedatatype();
		len= makebytes(part,(unsigned char *)ascant,MAXSEARCHSTR,(unsigned char *)ant, flen) ;
		if(!len&&ant[0]) {
			output("Conversion failed");
			erefresh();
			continue;
			}
		if(askrepl)  {
			replacestrlen=makebytes(part,(unsigned char*)replacestr,MAXSEARCHSTR,(unsigned char*)rep, rlen);
			if(!replacestrlen) {
				message("User error: %.*s is no %s",thecols-20,rep,modename(part->type));
				beep();
				erefresh();
				continue;
				}
			}
		}

	else {
		if(!forward&&reg) {
			beep();
			message("Backward regex search is only supported in ascii");
			erefresh();
			continue;
			}
		memmove(ascant,ant,flen);
		len=flen;
		if(askrepl) {
			memmove(replacestr,rep,rlen);
			replacestrlen=rlen;
			}
		}

		break;
		} /*END WHILE */
	if(formatsearch)
		myfree( formatsearch);
	formatsearch=myallocar( char,flen+1);
	memmove(formatsearch,ant,flen);
	formatsearch[flen]='\0';
	ascant[len]='\0';
	makesearchdataname();
	mem.lastforward=forward|(cas<<1)|(reg<<2)|(boundary<<3);

	editup();
	if(ascii&&ascii!=part)
		delete ascii;
	if(digit&&digit!=part)
		delete digit;
	if(copythis&&copythis!=part)
		delete copythis;
	if(subpart&&subpart!=part)
		delete subpart;



	if(list) {

#ifdef USETHREADS
		message("Locations will be added to marklist (Alt-k,l)");
		return searchlist(part,ascant,len) ;
#else
		if( searchlist(part,ascant,len)>0) {
			message("Locations added to marklist (Alt-k,l)");
			erefresh();
			if(showmarks()==0) {
				findgetmode(listsearchfound)
				delete part;
				return 0;
				}
			else  {
				delete part;
				return -1;
				}
			
			}
		else {
				delete part;
			notfoundsearchingfor();
			return -1;
			}
#endif
		}
	OFFTYPE pos;	
#ifdef SEARCHTIME
	struct timeval  tvstart,tvend,ver;
	gettimeofday(&tvstart,NULL);
	OFFTYPE startfrom=(mem.lastforward&1)?(edge?0:filepos+editpos+1): (edge?(mem.size()-1):(filepos+editpos-1));
#endif
	int oldmode=mode;
	int oldnrparts=nrparts;
	

 findgetmode(foundmodenormaal)
	OFFTYPE start=(mem.lastforward&1)?(edge?0:filepos+editpos+!askrepl): (edge?(mem.size()-1):(filepos+editpos-1));
	if((pos=dosearcher(part,start,ascant,len))==SEARCHFAILURE) {
		if(oldnrparts!=nrparts) {
			removemode();
			shouldreinit=0;
			}
		tomodenr(oldmode);
		if(regexerrorstring) {
			output(regexerrorstring);
			regexerrorstring=NULL;
			}
		else {
#ifdef SEARCHTIME
	gettimeofday(&tvend,NULL);
	timersub(&tvend,&tvstart,&ver);
	long double speed=(filesize()-startfrom)/((ver.tv_sec*1000)+(long double)ver.tv_usec/1000);
	message("Not Found %.80s %d:%d:%d (s:mil:mic) %Lg",formatsearch,ver.tv_sec,ver.tv_usec/1000,ver.tv_usec%1000,speed);
#else
			notfoundsearchingfor();
#endif
			}
				delete part;
		return -1;
		}
#ifdef SEARCHTIME

	gettimeofday(&tvend,NULL);
	timersub(&tvend,&tvstart,&ver);
#endif
	OFFTYPE blockpos;
	if(pos<indatatype) {
		blockpos=pos;	
		indatatype=0;
		installpart(part->newone(),0);
		}
	else
		blockpos=pos-indatatype;
	pretopos(blockpos);
	toborder( blockpos);
	cursorpos();
	toscreen();
	if(askrepl) {
		delete part;
		return replacer(rep,pos);
		}
#ifdef SEARCHTIME
	long double speed=(pos-startfrom)/((ver.tv_sec*1000)+(long double)ver.tv_usec/1000);
	message("Found %.40s %d:%d:%d (s:mil:mic) %Lg",formatsearch,ver.tv_sec,ver.tv_usec/1000,ver.tv_usec%1000,speed);
#else
	foundsearchingfor();
#endif
		delete part;
	return len;
	}


#define tobinlen(len) (((len+maxunit-1)/(maxunit))*bytes)
#define toforlen(len) ((((long long )len+bytes-1)/bytes)*maxunit)
#define binlarger(len) 2*len+80
int Editor::replacehere(OFFTYPE pos, char *str,int len  ) {
	if((mem.lastforward>>2)&1) {
		ScreenPart *part=searchpart;
		int offset,i,ret;
		struct re_registers *searchregs=mem.searchregs;
		int matchlen=searchregs->end[0]-searchregs->start[0];
		int maxout=2*mem.BLOCKSIZE;
		char *whole=myallocar(char,matchlen+2*(part->maxres+part->apart+1));	
		char *to;
		int bytes=part->bytes;
		int apart=part->apart;
		int maxres=part->maxres;
		int maxunit=maxres+apart;
		int binnen=(searchregs->start[0])%(maxres+apart);
		to=myallocar( char,maxout);	
		int flen=matchlen;
		if(!standardascii(part)) {
			int binlen=tobinlen(matchlen);
			char *bin=myallocar( char,binlarger(binlen));
			getpart(pos,binlen,bin);
			flen=part->fromascii((unsigned char*)whole,(unsigned char *)bin,binlen) ;
			myfree( bin);
			memcpy(to,whole,flen);
			to+=binnen;
			whole+=binnen;
			}
		else {
			getpart(pos,matchlen,whole);
			}
		for(offset=0,i=0;i<len;) {
			if(str[i]=='&'&&(!i||str[i-1]!='\\')) {
				memmove(to+offset,whole,matchlen);
				offset+=matchlen;
				i++;
				}
			else {
				if(str[i]=='\\'&&(str[i+1]>'0'&&str[i+1]<='9')&&searchregs->start[str[i+1]-'0']!=-1) {
					int gr=str[++i]-'0';
					int grlen=searchregs->end[gr]-searchregs->start[gr];
					memmove(to+offset,whole+searchregs->start[gr]-searchregs->start[0],grlen);
					offset+=grlen;
					i++;
					}
				else {
					to[offset++]=str[i++];
					}
			      }
			}
		if(!standardascii(part)) {
			offset+=binnen;
			to-=binnen;
			whole-=binnen;
			int rest=offset%maxunit;
			int in=offset/maxunit;
			int binlen=tobinlen(offset);
			char *bin=myallocar( char,binlarger(binlen));
			getpart(pos,binlen,bin);
			if(rest) {
				char *tmp=bin+(in*bytes);
				char *form=myallocar( char,maxunit+1);	
				int l;
				l=part->fromascii((unsigned char *)form,(unsigned char *)tmp,bytes) ;
				memcpy(to+offset,form+rest,l-rest) ;
				offset+=(l-rest);
				myfree( form);
				}

			offset=part->search2bin((char *)to,(unsigned char*)bin,offset);
			myfree( to);
			to=bin;
			}
		myfree( whole);
		ret= posputbuf(pos,to,offset); 
		myfree( to);
		return ret;
		}
	else
		return posputbuf(pos,str,len); 

	}

int Editor::replacer(char *rep,OFFTYPE foundpos) {
	char forward=mem.lastforward&1;
	OFFTYPE lastpos=mem.size()-1,pos;
	while(1) {
		if((!updated||(other!=OFFTYPEINVALID))) {
			writebuf();
			wrefresh(editscreen);
			}

		while(1) {
				if((foundpos)>lastpos) {
						message("User error: Replace over end of file");
						return -1;
						}
				switch(getkeyinput("%s: Replace with %s (y)es/(n)o/(s)top/(a)all)",namedata,rep)) {
					case 'n':;
					case 'N': break; 
					case 'a':;
					case 'A': 
						output("Replace all ...");
						wrefresh(editscreen);
						mem.searchpos+=((replacehere(foundpos,replacestr,replacestrlen)-parts[mode]->bytes)*(2*forward-1));
						while((pos=memnextsearch())!=SEARCHFAILURE) {
							if(pos>lastpos) {
								topos(pos);
								if(!updated)
									writebuf();
								message("User error: Replace over end of file");
								return -1;
								}
							mem.searchpos+=((replacehere(pos,replacestr,replacestrlen)-parts[mode]->bytes)*(2*forward-1));
							}
						fromfile();
						updated=0;
						output("Done");
						return 0;
					case 'y':;
					case 'Y': 
							 
						mem.searchpos+=((replacehere(foundpos,replacestr,replacestrlen)-parts[mode]->bytes)*(2*forward-1));
							fromfile();
							writebuf();
							wrefresh(editscreen);break;
					case 27:
					case 's':
					case 'c':
					case 'S': clearmessage();return -1;
					default: continue;
					}

			  break;
			  }

		if((foundpos=nextsearch())<0)
			return -1;
		}
	}
	
int Editor::replace(void) {	
	return searcher(1);
	}
#define searchoption(option,bit) int Editor::search##option(short yes) { int old= mem.lastforward&bit; if(yes) mem.lastforward|=bit; else mem.lastforward&=(0xffff-bit); return old; }

searchoption(onboundary,8)
searchoption(regex,4)
searchoption(forward,1)
searchoption(case,2)
int Editor::searchedge(short yes) {
	int oldedge=edge;
	edge=yes;
	return oldedge;
	}
/*
int searchonboundary(short yes) ;
	int old= mem.lastforward&8;
	if(yes)
		mem.lastforward|=8;
	else
		mem.lastforward&=0xfff7;
	return old;
	}
int Editor::searchregex(short yes) {
	if(yes)
		mem.lastforward|=4;
	else
		mem.lastforward&=0xfffb;
	return mem.lastforward;
	}
int Editor::searchforward(short yes) {
	if(yes)
		mem.lastforward|=1;
	else
		mem.lastforward&=0xfffe;
	return mem.lastforward;
	}
int Editor::searchcase(short yes) {
	if(yes)
		mem.lastforward|=2;
	else
		mem.lastforward&=0xfffd;
	return mem.lastforward;
	}
*/

int Editor::gotolastsearchpos(void) {
	return topos(mem.searchpos);
	}
