#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 <stdio.h>
#include <stdlib.h>
#include <ctype.h>
       #include <termios.h>
       #include <unistd.h>
#include "editor.h"
#include "main.h"
#include "system.h"
#include "screen.h"
#include "inout.h"
#include "screenpart.h"
#include "config.h"
extern int wantsignal;
extern void omnihandler(int signum) ;
extern void closefilehandle(FILEHANDLE file);
int tmpbuffer(char *name) {return !strncmp(name,"Document",8);}
int Editor::askmenufile(void) {
		char buf[MAXPATHLEN]="*";
		const char *file;
			while(1) {
				if((file=getfile("Open file",buf))) {
					errno=0;
					if(!newfile(file)){
						if(errno)
							message("Can't open %s: %s",file,strerror(errno));
						else 
							message("Can't open %s: zero size file",file);
						wrefresh(editscreen);
						strcpyn(buf,file,MAXPATHLEN);
						continue;
						}
					else
						return 0;
					}
				else {
					editup();
					return -1;
					}
				}
			}
/*
int Editor::askfile(void) {
		char ant[MAXANT];
		getinput("Name of file to visit: ",ant);
		if(!newfile(ant)) {
			const char *file;
			if((file=getfile("Open file",ant))) {
				if(!newfile(file)){
						rewritescreen=1;
						message("Error opening %s",file);
						return -1;
						}
					}
			else {
					editup();
				return -1;
				}
			return 0;
			}
		return ASKFILE;
		};
*/
char *Editor::getfilename(char *buf) {
	if(buf) {
		strcpyn(buf,mem.filename,MAXPATHLEN);
		return buf;
		}
	else
		return mem.filename;
	}

extern OFFTYPE setfilepos(FILEHANDLE file,OFFTYPE offset) ;
extern  FILEHANDLE opencreate(const char *filename);
FILEHANDLE Editor::tmpopenfile(const char *ant) {
	STATTYPE st;
	FILEHANDLE handle;
	int fileexists=0;
	if(!access(ant,0)) {
		if(STAT(ant,&st))
			memset(&st,'\0',sizeof(st));
		fileexists=1;
		}

	if(fileexists) {
		for(int i=0;i<nredit;i++)
			if((st.st_ino==edits[i]->mem.statdata.st_ino)) {
				message("User error: %s is open. Use save or close first",edits[i]->mem.filename);
				wrefresh(editscreen);
		return MY_INVALID_HANDLE_VALUE;
				}
		message("%s exists, overwrite? (y/n)",ant);
		wrefresh(editscreen);
		switch(getch()) {
			case 'y':;
			case 'Y': 
				  break;
			case 'n':;
			case 'N':;
			default:message("Not saved");wrefresh(editscreen); return MY_INVALID_HANDLE_VALUE;

			};
		}

	if((handle=opencreate(ant))==MY_INVALID_HANDLE_VALUE) {
		message("Can't open %s",ant);
		wrefresh(editscreen);
		return MY_INVALID_HANDLE_VALUE;
		}
	  char ch=0;
	  if(writetofile(handle,&ch,1)!=1) {
		  message("write to %s failed",ant);
			closefilehandle(handle);
			return MY_INVALID_HANDLE_VALUE;
			  };
	return handle;
		}
int Editor::openfile(const char *ant) {
	STATTYPE st;
	int handle;
	if((handle=LOPEN(ant,O_WRONLY|O_CREAT BINARY_FLAG,0666))<0) {
		message("Can't open %s: %s",ant,strerror(errno));
		wrefresh(editscreen);
		return -1;
		}
	if(FSTAT(handle,&st)==-1) {
		output("fstat failed, file not saved");
		wrefresh(editscreen);
		return -1;
		}
	if(st.st_size!=0) {
		for(int i=0;i<nredit;i++)
			if((st.st_ino==edits[i]->mem.statdata.st_ino)) {
				message("User error: %s is open. Use save or close first",edits[i]->mem.filename);
				wrefresh(editscreen);
				LCLOSE(handle);
				return -1;
				}
		message("Nonzero %s exists, overwrite? (y/n)",ant);
		wrefresh(editscreen);
		switch(getch()) {
			case 'y':;
			case 'Y': if(FTRUNCATE(handle,0)<0) {
					message("Can't truncate %s: %s",ant,strerror(errno));
					wrefresh(editscreen);
					return -1;
					}
				break;
			case 'n':;
			case 'N':;
			default:message("Not saved");wrefresh(editscreen);LCLOSE(handle);return -1;
			};
		}
	return handle;
		}

int Editor::endedit(void) {
	if(nredit<2) {
		if(!argfile())
			return exitall();
		}

	if(closefile()<0)
		return( -1);
	return ::endedit(this);
	}	
extern Editor **deathcells;
extern int maxdeath,gossip;
extern Editor *selectioneditor;
int Editor::closethis(void) {
	if(endedit()<0)
		return -1;
	else {
		INCDEST();
		if(gossip>=maxdeath) {
			Editor **tmp=deathcells;
			maxdeath*=2;
			deathcells=myallocarpr(Editor **,Editor *,maxdeath);
			memmove(deathcells,tmp,gossip*sizeof(Editor*));
			}
		if(selectioneditor==this)
			selectioneditor=NULL;
		deathcells[gossip++]=this;
		DECDEST();
		}
	return 0;
	}
int Editor::quit(void) {
	return exitall();
	}
int Editor::closefile(void) {
	int i;
	memorize();
	if(!modified) {
		return 0;
		}
	startnonactive=minnum(startnonactive,nredit);
	for(i=startactive;i<startnonactive;i++) 
		if(this==edits[i])
			break;
	if(i==startnonactive) {
		startactive=editfocus;
		startnonactive=startactive+1;
		place(0);
		}
	wrefresh(editscreen);
	while(1) {
		message("Save changes %s before leaving? (y/n/c)",mem.filename);
		switch(getch()) {
			case 'y':;
			case 'Y': if(save())
					return -1;
					else
						return 0;
			case 'n':;
			case 'N': return 0;
			case 'c':;
			case 'C':
				clearmessage();
					return -1;
#define firstescape 27
#define secondescape 254
			case firstescape: 
				if(getch()==secondescape) {
					clearmessage();
					wrefresh(editscreen);
					return -1;
					};
				flushinp();
				wrefresh(editscreen);
			default: beep();
			};
		}; 
	return 0;
	}

int Editor::saveaser(const char *ant) {
	if(!ant) {
		return 1;
		}
	else {
	if(tmpbuffer(mem.filename)) {
		FILEHANDLE oldhandle,handle;
		memorize();
		if((	handle=tmpopenfile(ant))== MY_INVALID_HANDLE_VALUE)		{
			beep();
			return -1;
			}
		INCDEST();
		char filebuf[MAXPATHLEN];
		oldhandle=mem.filehandle;
		char *oldfilename=mem.filename;
		mem.filehandle=handle;
		arealpath(ant,filebuf);
		int len=strlen(filebuf)+1;
		mem.filename=myallocar( char,len);
		memcpy(mem.filename,filebuf,len);
		if(mem.saveall()) {
			myfree(mem.filename);
			mem.filename=oldfilename;
			mem.filehandle=oldhandle;	
			closefilehandle(handle);
		message("Error writing to %s",filebuf);
	DECDEST();
			return -1;
			}
		message("Saved all to %s",mem.filename);
		modified=0;
		closefilehandle(oldhandle);
	DECDEST();
		return 0;
		}
	else {
		int handle;
		if((	handle=openfile(ant))<0)		{
			beep();
			return -1;
			}
	INCDEST();
	errno=0;
			if(mem.saveto(handle)!=0) {
					LCLOSE(handle);
					message("Problems writing to %s: %s",ant,strerror(errno));
					beep();
					wrefresh(editscreen);
	DECDEST();
					return -1;

					}
	DECDEST();
			LCLOSE(handle);
			message("Saved all to %s",ant);
			return 0;
			}
		return -1;
		}
	}
int Editor::saveas(void) {
	char buf[MAXPATHLEN];
	const char *ant="*";
	memorize();
	do {
		strcpyn(buf,ant,MAXPATHLEN);
		ant=getfile("Save as",buf) ;
		editup();
		if(!ant)
			return -1;
		} while( saveaser(ant)<0);
	return 0;
	}

int Editor::dosave(void) {
	if(tmpbuffer(mem.filename))
		return saveas();
	memorize();
	if(!modified) {
		output("Nothing to save");
		return 1;
		}

	while(1) {
		if((mem.touched())) 
			message("Error:: %s changed by other proces. Add modified screens (%d boundaries)????? (n/y)",mem.filename,mem.BLOCKSIZE);
		else
			output("You really want to save changes? (y/n)");
		switch(getch()) {
			case 'y':;
			case 'Y': {
					return save();
					};break;
			case 'n':;
			case 'N': 
				flushinp();
				message("Not saved");
				return 0;
			default: flushinp();beep();
			};
		}; 
	return 1;
	}
int Editor::save(void) {
	int ret;
	memorize();
	if(tmpbuffer(mem.filename)) {
		return saveas();
		}
	INCDEST();
	if((ret=mem.saveall())) {
//		message("Couldn't save file %s: %s",mem.filename, (ret< sys_nerr)?strerror(ret):"?");
		message("Couldn't save file %s: %s",mem.filename, strerror(ret));
		ret=1;
		}
	else {
	  message("Saved %s",mem.filename);
		modified=0;
		ret=0;
		}
	DECDEST();
	return ret;
	}

int Editor::checkchanged(void) {
	int ret;
	memorize();
	INCDEST();
	if(mem.touched()) {
		if(modified)
			message("File changed by other process. Save(as) will mess up old and new"  );
		else {
			rewrite();
			toscreen();
			message("File changed by other process.");
			}
		ret= 2;
		}
	else {
		if(mem.changed() ) { 
			message("Modified: Alt-f,s to save, Alt-e,u to undo changes");
			ret= 1;
			}
		else {
			message("Unmodified");
			modified=0;
			ret= 0;
			}
		}
	DECDEST();
	return ret;
	}

int Editor::saveinode(void) {
	place(0);
	message("Save dangling file, previously called %s? (Y/n)",mem.filename);
	switch(getch()) {
		case 'n':;
		case 'N':;break;
		case 'y':;
		case 'Y': ;
		default:
			while(saveas()<0) {
				beep();
				};
			break;
		}
	return 0;
	}

#undef ERR
#include <signal.h>
#undef ERR
#ifdef GETOTHERTERM
extern int piddenlen;
extern pid_t *pidden;
#endif
#include "cursesinit.h"
char * file2buf(char *name,int *len) {
	char *buf;
	int end;
	int fd=open(name,O_RDONLY BINARY_FLAG);
	if(fd<0)
		return NULL;
	end=lseek(fd,0,SEEK_END);
	buf= (char *)malloc(end);	
	lseek(fd,0,SEEK_SET);
	if(read(fd,buf,end)<end) {
		free(buf);
		return NULL;
		}
	close(fd);
	*len=end;
	return buf;
	}
int readbuf(char *name,char *buf,int max) {
	int fd=open(name,O_RDONLY BINARY_FLAG);
	if(fd<0)
		return -1;
	int end=read(fd,buf,max);
	close(fd);
	return end;
	}
#include "shell.h"

#ifndef HAS_GETUSERSHELL
char **openshells(int *nr) {
	int len;
	char *shells= file2buf("/etc/shells",&len);
	char *shelp;
	int i;
	char *endshell=shells+len;
	for(i=0,shelp=shells;shelp<endshell;i++) {
	       if(!(shelp=(char*)memchr(shelp, '\n', endshell-shelp))) {
			i++;
			break;
			}
		do {
			shelp++;
			} while((shelp[0]=='\n'));
		}
	char **shellen=(char **)malloc(i*sizeof(char *));
	int j;
	for(j=0,shelp=shells;j<i;j++) {
		shellen[j]=shelp;
	       if(!(shelp=(char*)memchr(shelp, '\n', endshell-shelp)))
			break;
		*shelp++='\0';
		 while((shelp[0]=='\n'))
			shelp++;
		}
	*nr=i;
	return shellen;
	}
#endif

#if defined(NOSTOPANDTHREADS) && defined(USETHREADS)
#define DONTSUSPEND 1
#endif
#if defined(PROCEXEFILENAMEFORMAT) && ! defined(DONTSUSPEND)
#define TRY_SUSPEND 1
#else
#undef TRY_SUSPEND 
#endif
#ifdef TRY_SUSPEND
int isashell(pid_t pid) {
#ifndef HAS_GETUSERSHELL
	static int shellnr;
	static char **shells= openshells(&shellnr);
#endif
	char cmdexe[256];
	snprintf(cmdexe,256,PROCEXEFILENAMEFORMAT,pid);
	char name[256];
	int len=readlink(cmdexe,name,256);
	name[len]='\0';
#ifndef HAS_GETUSERSHELL
	for(int i=0;i<shellnr;i++) {
		if(!strcmp(shells[i],name))
			return 1;
		}
#else
	char *ashell=NULL;
	setusershell();
	while((ashell=getusershell())) {
		if(!strcmp(ashell,name)) {
			endusershell();
			return 1;
			}
		}
	endusershell();
#endif
	return 0;	
	}
#endif
char endmenustring[]={0,27,'[','?','1','0','l'};
char showmenustring[]={0,27,'[','?','1','0','h'};

extern const int endmenulen;
extern const int showmenulen;
const int endmenulen=sizeof(endmenustring);
const int showmenulen=sizeof(showmenustring);
extern int ismenu;
int startterminal=1;
extern void resetsize(void);
extern int	resizeconsole(int,int);
struct termios  starttermios; 
int aget=tcgetattr (STDIN_FILENO,&starttermios );
extern int suspender(void) ;
int Editor::suspend(void) {
	return suspender() ;
	}
#ifdef _WIN32
char *changeslash(char *in) {
	if(in) {
		int len=strlen(in);
		for(int i=0;i<len;i++)
			if(in[i]=='\\')
				in[i]='/';
		}
	return in;
	}
#endif
int suspender(void) {
#ifdef TRY_SUSPEND
	pid_t par=getppid();
#define EXESH
#ifndef EXESH

	char cmdpar[256];
	snprintf(cmdpar,256,"/proc/%d/cmdline",par);
	char cmdparline[256];
	int parlen=readbuf(cmdpar,cmdparline,256);

	char cmd[256];
	snprintf(cmd,256,"/proc/%d/cmdline",pid);
	char cmdline[256];
	int len=readbuf(cmd,cmdline,256);
	if(memmem(cmdparline,parlen,cmdline,len)) {
#else
	 pid_t sid=getsid(pid);
	if(!startterminal||(!isashell(par)&&!isashell(sid))) {
//	if((!isashell(par)&&!isashell(sid))) {
#endif
#else
	{
#endif

#ifndef NOENDWIN
//#if defined(PDC_BUILD)&&PDC_BUILD>=2400
if(!isendwin())
	endwin();

if(!startterminal) 
	tcsetattr(STDIN_FILENO, TCSANOW ,&starttermios );


#else
wattrset(stdscr,0);
move(LINES-1,0);
addstr("\n");
refresh();
#endif
SHOWCURSOR;
#ifdef __CYGWIN__
static char *SHELL=changeslash(getenv("SHELL"));
#else
static char *SHELL=getenv("SHELL");
#endif
static const char *OLDPS1=(OLDPS1=getenv("PS1"))?OLDPS1:"\\w# ";
static char PS1[100]="exit to return to bed\n";
static int ps1len=(ps1len=strlen(PS1),
snprintf(PS1+ps1len,100-ps1len,"%s",OLDPS1), setenv("PS1",PS1,1), ps1len);

#ifdef USE_WITH_XBED
		char *oldenv=NULL;
		if(ismenu>=0) {
			oldenv=getenv("FROMXBED");
			unsetenv("FROMXBED");
			if(ismenu==1)
				write(STDOUT_FILENO,endmenustring,sizeof(endmenustring));
			}
#endif
if(SHELL) 
{
		process(SHELL,NULL);	
#ifndef _WIN32
}
else
		process("/bin/sh",NULL);	
#endif

#ifdef USE_WITH_XBED
		if(ismenu>=0) {
			setenv("FROMXBED",oldenv,1);
			if(ismenu==1)
				write(STDOUT_FILENO,showmenustring,sizeof(showmenustring));
			}
#endif
#ifdef _WIN32
}
else {
static const char *prompt=(prompt=getenv("PROMPT"))?prompt:"$N$g";
static char newprompt[100]="exit to return to bed$_";
static int newpromptlen=(newpromptlen=strlen(newprompt),
snprintf(newprompt+newpromptlen,100-newpromptlen,"%s",prompt), setenv("PROMPT",newprompt,1), newpromptlen);
static char *comspec= changeslash( getenv("COMSPEC"));
		if(comspec)
			process(comspec,NULL);	
//			process(comspec,"/K","prompt","exit","to","return","to","bed$_%PROMPT%");	
		else
			system("command.com");
//setenv("PROMPT",prompt,1);
}
#endif
//setenv("PS1",OLDPS1,1);
	 	HIDECURSOR;
#ifndef NOENDWIN
if(isendwin())
	refresh();
#else
//rewrite();
#endif
		resizeflag=1;
		return 0;


		}
#ifdef TRY_SUSPEND
#if GETOTHERTERM
	if(piddenlen) {
		move(thelines-2,0);
		clrtoeol();
		printw("kill -18 %d to return to bed",pid);
		move(thelines-1,0);
		clrtoeol();
		touchline(stdscr,thelines-2,2);
		refresh();
		for(int i=(piddenlen-1);i>=0;--i)
			if(pidden[i]!=pid)
				kill(pidden[i],18);
		for(int i=(piddenlen-1);i>=0;--i)
			if(pidden[i]!=pid)
				kill(pidden[i],28);
		}
#endif
if(!isendwin())
	endwin();

	return kill( getpgrp(),SIGSTOP);
#else
		return 0;
#endif
	}


/*
int Editor::testsearch(void) {
	short len;
	unsigned char ant[512];
	OFFTYPE pos;
	inputget((char *)ant,"Search: ") ;
	len=strlen(ant);
	if((pos=formsearch(filepos+editpos,(char *)ant,len))!=OFFTYPEINVALID)
		return topos(pos);
	return -1;
	}
*/
OFFTYPE Editor::formsearch(ScreenPart *datashown,OFFTYPE from,char *ant,short len) {
//	len=parts[mode]->fromascii(ant,ascii, len) ;
	if(len<=0)
		return OFFTYPEINVALID;
INCDEST();
	if(mem.setsearchgegs(from,(char *)ant,len)<0 ) {
		message("failure");
		DECDEST();
		return OFFTYPEINVALID;
		}

	DECDEST();

	searchbytes=parts[mode]->bytes;
	searchgrens=(filepos+indatatype)%searchbytes;
	OFFTYPE pos=nextregexshown(datashown);

	return pos;
	}

#define getblockformat(off,formbuf) ( takelen=minnum(blocklen+bytes,maxnum(sizef-off,0)),(binlen[bl&1]=(takelen<=0?0:(getmem(off,(char *)binbuf,takelen)))))
/*
		if(onboundary)  {
			if((pos=re_search_2(mem.searchexpr, binbuf[(bl-1)&1], count0, binbuf[bl&1], count, 0, count0,mem.searchregs,count0))!=-1)  {
				mem.searchpos=(((first/ellen)*bytes))+off-blocklen+bytes; 
				return (mem.searchpos-bytes);
				}
			}
		else {
*/

//int onboundary=0;

#define onboundary ((mem.lastforward&8)?1:0)
#define block(bl) (binbuf+((bl&1)*blocksize))
#define form(n) (formbuf+n*formsize)
OFFTYPE		 containboundarysearch(OFFTYPE bytestart,ScreenPart *datashown) {
#ifdef DEBUGFLAG
	const int binerbij=0,formerbij=0;
#else
	const int binerbij=4,formerbij=4;
#endif
	Editor *ed=datashown->editor;
	Memory *me=&(ed->mem);
	int bytes= datashown->getbytes();
	 unsigned char bin[bytes+binerbij];
	int maxres=datashown->maxres;
	char form[maxres+datashown->apart+formerbij];
	OFFTYPE end=ed->filesize()-bytes+1;
	int sbytes=ed->searchbytes;
	for(OFFTYPE off=bytestart;off<end;off+=sbytes) {
		ed->getmem(off,(char *)bin,bytes);
		datashown->bin2search(bin,form,bytes);
		if(re_search(me->searchexpr,form,maxres,0, maxres-1,me->searchregs)>=0) {
//		if(re_match(me->searchexpr,form,maxres,0, me->searchregs)>=0) {
			me->searchpos=off;
			return (me->searchpos+=ed->searchbytes,me->searchpos-ed->searchbytes);
			}
		}
	return OFFTYPEINVALID;
	}
OFFTYPE Editor::nextregexshown(ScreenPart *datashown) {
	if(onboundary&&datashown->bytes!=searchbytes) {
		OFFTYPE	bytestart=(mem.searchpos/searchbytes)*searchbytes+searchgrens;
			return containboundarysearch(bytestart,datashown);
		}
	OFFTYPE bl,sizef=filesize(),off;;
	int bytes=datashown->bytes;
	long items=(mem.BLOCKSIZE/bytes);
	long blocklen=items*bytes;
	SIZE_T count,count0=blocklen,pos;
	long takelen;

	if(blocklen<bytes)
		blocklen=bytes;
	int ellen=datashown->maxres+datashown->apart;
//        unsigned char buf[3][(items)*ellen];
	int blocksize=blocklen+bytes;
         char binbuf[3*blocksize];
	int formsize=(items*ellen);
         char formbuf[2*(formsize)];
	
        int binlen[3];
	short boundaries;
	OFFTYPE bytestart;
	if(onboundary) {
		bytestart=(mem.searchpos/searchbytes)*searchbytes+searchgrens;
		boundaries=1;
		}
	else {
		bytestart= mem.searchpos;
		boundaries=bytes;
		}
	OFFTYPE first;
	bl=0;
	off=bytestart;
		takelen=minnum(blocklen+boundaries,maxnum(sizef-off,0));
		binlen[bl&1]=(takelen<=0?0:(getmem(off,block(bl),takelen)));
	regoff_t	*regsstart=NULL;
	regoff_t	*regsend=NULL;
        for(;	off<sizef;) {

		off+=blocklen;
		bl++;

		takelen=minnum(blocklen+boundaries,maxnum(sizef-off,0));

		binlen[bl&1]=(takelen<=0?0:(getmem(off,block(bl),takelen)));

		first=OFFTYPEINVALID;
		for(int i=0;i<boundaries;i++) {
			if(binlen[(bl)&1]>i) {
				count0=datashown->fromascii((unsigned char *)form(0),(unsigned char *)block(bl-1)+i,blocklen);
				count=datashown->fromascii((unsigned char *)form(1),(unsigned char *)block(bl)+i,minnum(blocklen,((binlen[(bl)&1]-i)/bytes)*bytes));
				pos=re_search_2(mem.searchexpr,form(0) , count0, form(1), count, 0, count0-1,mem.searchregs,count0+count);
				}
			else {
				count0=datashown->fromascii((unsigned char *) form(0),(unsigned char *)block(bl-1)+i,minnum(blocklen,bytes*((binlen[(bl-1)&1]-i)/bytes)));
				count=0;
				pos=re_search(mem.searchexpr,form(0) , count0,  0, count0-1,mem.searchregs);
				}
				if(pos!=-1) {

				OFFTYPE oppos=(((pos/ellen)*bytes)+off-blocklen+i);
				if(oppos<first) {
					if(regsstart)
						myfree(regsstart);
					if(regsend)
						myfree(regsend);
					regsstart=mem.searchregs->start;
					regsend=mem.searchregs->end;
					mem.searchregs->start=myallocarp(regoff_t *,regoff_t,mem.searchregs->num_regs);
					mem.searchregs->end=myallocarp(regoff_t *,regoff_t,mem.searchregs->num_regs);
					first=oppos;

					}
				}
			}
		if(wantsignal) {
			if(regsstart)
				myfree(regsstart);
			if(regsend)
				myfree(regsend);
			int olddont=GETDEST();
			NODEST();
			int wassig=wantsignal;
			wantsignal=0;
			kill(pid,wassig);	
			SETDEST(olddont);
			}
		if(first<OFFTYPEINVALID) {
			myfree (mem.searchregs->start);
			myfree (mem.searchregs->end);
			mem.searchregs->start= regsstart;
			mem.searchregs->end= regsend;
			mem.searchpos=first;
			if(onboundary) {
				return (mem.searchpos+=searchbytes,mem.searchpos-searchbytes);
				}
			else
				return mem.searchpos++;
			}
		}
	
	if(regsstart)
		myfree(regsstart);
	if(regsend)
		myfree(regsend);
	return OFFTYPEINVALID;
	}
#undef ADDNEWLINE

#define ADDNEWLINE  flen+=addnltoar(formbuf+flen);
/*
#undef ADDNEWLINE

#define ADDNEWLINE formbuf[flen++]=0x0D; formbuf[flen++]=0x0A;
*/
int Editor::saveshownname(const char *ant) {
	if(other== OFFTYPEINVALID) {
		return -1;
		}
	int handle;
	memorize();
	if((handle=openfile(ant))<0) {
		return -2;
		}
INCDEST();
	ScreenPart *datashown=parts[mode];
	int showelsize=datashown->maxres+datashown->apart;
	int bytes=datashown->bytes;
	long items=cols()/bytes;
	if(items<1)
		items=1;
	long blocklen=items*bytes;
	OFFTYPE posf=filepos+(editpos/bytes)*bytes,first,last;
	if(other>posf) {
		first=posf;
		last=other+bytes;
		if(last>filesize())
			last-=bytes;
		lensel=last-first;
		if(lensel%bytes) {
			first-=(bytes	-lensel%bytes);
			if(first<0)
				first+=bytes;
			}
		}
	else {
		first=other;
		last=posf;
		lensel=last-first;
		last+=(bytes-lensel%bytes);
		if(last>filesize())
			last-=bytes;
		}
	lensel=last-first;
	if(lensel<=0) {
		message("No full item in selection");
		DECDEST();
		return -1;
		}
	message("Writing to file %s",ant);
	wrefresh(editscreen);
	OFFTYPE blocknr=	lensel/blocklen;
	int rest=lensel%blocklen;
	OFFTYPE endpos=blocknr*blocklen+first;
	unsigned char binbuf[blocklen];
	unsigned char formbuf[items*showelsize+1];
	OFFTYPE off=first;

	for(off=first;off<endpos;off+=blocklen) {
		if(wantsignal) {
			int olddont=GETDEST();
			NODEST();
			int wassig=wantsignal;
			wantsignal=0;
			kill(pid,wassig);	
			SETDEST(olddont);
			}
		getmem(off,(char *)binbuf,blocklen);
		int flen=datashown->fromascii(formbuf,binbuf,blocklen);
ADDNEWLINE
		write(handle,formbuf,flen);
		}
	if(rest>0) {	
		getmem(off,(char *)binbuf,rest);
		int flen=datashown->fromascii(formbuf,binbuf,rest);
ADDNEWLINE
		write(handle,formbuf,flen);
		}
	long total=lseek(handle,0L,SEEK_END);
	if(total<0)
		message("lseek failed");
	if(close(handle)<0){
		message("close(handle) fails: %s",strerror(errno));
		DECDEST();
		return -1;
		}
	message("Selection saved in %s",ant);
	DECDEST();
	return total;
	}

#undef ADDNEWLINE
/*
als regels niet uitkomen op een eenheid na verweideren newline
en het wel uitkomt wanneer newline in een spatie word veranderd
wordt dit gedaan
*/
#define endmmap {if(nommap) myfree(gegs);else  munmap(gegs, endf+1); close(handle);}
int Editor::insertshown(char *gegs, off_t endf) {
	memorize();
	ScreenPart *datashown=parts[mode];
//	int showelsize=datashown->maxres+datashown->apart;
INCDEST();
	int bytes=datashown->bytes;
	int apart=datashown->apart;
	int maxres=datashown->maxres;
	OFFTYPE posf=filepos+(editpos/bytes)*bytes,end,newbeg,fbeg=0;
	do {
		char *ptr=(char *)memchr (gegs+fbeg, '\n',endf-fbeg );
		if(!ptr) {
			end=endf;
			newbeg=end+1;
			end-=fbeg;
			}
		else {
			end=ptr-gegs;
			newbeg=end+1;
			while(gegs[end-1]==0xd)
				end--;
			end-=fbeg;
			}
		{
		unsigned char bin[bytes];
		OFFTYPE left=filesize()-posf;
		if(left<=0)
			break;
		char *formal=gegs+fbeg;
		int b=0,took;
		for(int f=0;f<end&&b<left;b+=bytes) {
			if(wantsignal) {
				modified++;
				updated=0;
				fromfile();
				DECDEST();
				message("Insert Shown Interrupted");
				return -1;
				}
			mem.getpart(posf+b,bytes,(char *)bin);
			if((took=datashown->filterformat2bin(formal+f, bin, minnum(maxres,end-f)))<=0)
				break;
			appendtoundo(posf+b, bytes);
			mem.putpart(posf+b,bytes,(char *)bin);
			f+=(took+apart);
			}
		posf+=b;
		}
		fbeg=newbeg;
		} while(fbeg<endf&&posf<filesize());

	modified++;
	updated=0;
	topos(posf-1);
	fromfile();
DECDEST();
return 0;
}
int Editor::readshownname(const char *ant) {
	int handle,ret=0;
	memorize();
	if((handle=open(ant,O_RDONLY BINARY_FLAG))<0) {
		message("Can't open %s",ant);
		return -1;
		}

	ScreenPart *datashown=parts[mode];
	int showelsize=datashown->maxres+datashown->apart;
       off_t endf;
	endf=lseek(handle, 0L, SEEK_END);
       char *gegs= (char *)mmap(NULL, endf+showelsize,  PROT_READ ,  MAP_SHARED, handle,0);
	int nommap=0;
 	if(gegs==MAP_FAILED) {
		nommap=1;	
		gegs=myallocar(char,endf+showelsize);
		lseek(handle, 0L, SEEK_SET);
		read(handle,gegs,endf);
		}
	ret=insertshown(gegs, endf); 
	endmmap;
	if(wantsignal) {
		int olddont=GETDEST();
		NODEST();
		int wassig=wantsignal;
		wantsignal=0;
		kill(pid,wassig);	
		SETDEST(olddont);
		}
	return ret;
	}

#ifdef OLDREADSHOWN
int Editor::readshownname(const char *ant) {
	int handle,ret=0;
	memorize();
	if((handle=open(ant,O_RDONLY BINARY_FLAG))<0) {
		message("Can't open %s",ant);
		return -1;
		}

	ScreenPart *datashown=parts[mode];
	int showelsize=datashown->maxres+datashown->apart;
       off_t endf;
	endf=lseek(handle, 0L, SEEK_END);
       char *gegs= (char *)mmap(NULL, endf+showelsize,  PROT_READ ,  MAP_SHARED, handle,0);
	int nommap=0;
 	if(gegs==MAP_FAILED) {
		nommap=1;	
		gegs=myallocar(char,endf+showelsize);
		lseek(handle, 0L, SEEK_SET);
		read(handle,gegs,endf);
		}
//	gegs[endf]='\0';
INCDEST();
	int bytes=datashown->bytes;
	int apart=datashown->apart;
	int maxres=datashown->maxres;
	OFFTYPE posf=filepos+(editpos/bytes)*bytes,end,newbeg,fbeg=0;
	do {
		char *ptr=(char *)memchr (gegs+fbeg, '\n',endf-fbeg );
		if(!ptr) {
			end=endf;
			newbeg=end+1;
			end-=fbeg;
			}
		else {
			end=ptr-gegs;
			newbeg=end+1;
			while(gegs[end-1]==0xd)
				end--;
			end-=fbeg;
			}
		{
		unsigned char bin[bytes];
		OFFTYPE left=filesize()-posf;
		if(left<=0)
			break;
		char *formal=gegs+fbeg;
		int b=0,took;
		for(int f=0;f<end&&b<left;b+=bytes) {
			if(wantsignal) {
				modified++;
				updated=0;
				endmmap;
				fromfile();
				int olddont=GETDEST();
				NODEST();
				int wassig=wantsignal;
				wantsignal=0;
				kill(pid,wassig);	
				SETDEST(olddont);
				message("Insert Shown Interrupted");
				return -1;
				}
			mem.getpart(posf+b,bytes,(char *)bin);
			if((took=datashown->filterformat2bin(formal+f, bin, minnum(maxres,end-f)))<=0)
				break;
			appendtoundo(posf+b, bytes);
			mem.putpart(posf+b,bytes,(char *)bin);
			f+=(took+apart);
			}
		posf+=b;
		}
		fbeg=newbeg;
		} while(fbeg<endf&&posf<filesize());

	endmmap;
	modified++;
	updated=0;
	fromfile();
DECDEST();
	return ret;
	}
#endif

int Editor::readshown(void) {
	char buf[MAXPATHLEN];
	const char *ant="*";
	strcpyn(buf,ant,MAXPATHLEN);
	memorize();
	do {
		ant=getfile("Read datatype from file",buf) ;
		editup();
		if(!ant) 
			return -1;
		} while( readshownname(ant)<0);
	return 0;
	}


int Editor::saveshown(void) {
	if(other!=OFFTYPEINVALID) {
		const char *ant;
		SIZE_T ret;
		char buf[MAXPATHLEN]="*";
	do {
		again:
		ant=getfile("Save selection in datatype ?",buf) ;
		editup();
		if(!ant)
			return -1;
		if((ret=saveshownname(ant))==-2) {
			strcpyn(buf,ant,MAXPATHLEN);
			goto again;
			}
		} while(ret==-2);
	return ret;
	}
	message("No selection");
	beep();
	return -1;
	}
