#include "defines.h"
/*     Bed a Binary EDitor for Linux and for Rxvt running under Linux.       */
/*     Copyright (C) 1998  Jaap Korthals Altes <jkaltes@hetnet.nl>      */
/*                                                                           */
/*     Bed 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.                                   */
/*                                                                           */
/*     Bed 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 bed; if not, write to the Free Software                    */
/*     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.             */
/*                                                                           */
/* Sun Dec  6 18:34:27 1998                                                  */

/***
 *  v2  2000.09.20  Jim Blackson	moved definiton of TRUNCATE to offtypes.h;
 *					rename truncate to truncatefile.
 */

#include "desturbe.h"
#include <features.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#ifdef __linux__
#include <linux/fs.h>
#include <linux/cdrom.h>
#endif
#include <sys/ioctl.h>
#include <limits.h>
#include <unistd.h>
#include <ctype.h>
#include "memory.h"
#include "system.h"
#include "myalloc.h"
#include "main.h"
#ifdef USE_WINFILE
#include <windows.h>
#include <WINIOCTL.H>
#endif
#ifdef USE_MMAP
const size_t mmap_page_size = (size_t) sysconf (_SC_PAGESIZE);
#define	FREEMMAP(str, len) {if(nommap){free(str);}else {MUNMAP(str,len);}}
#define BIGGERMMAPBLOCK
#endif
#define EXTRAMMAP 0
#if defined(USE_MMAP)&&!defined(BIGGERMMAPBLOCK)
int STBLOCKSIZE=mmap_page_size;

#else
//const int STBLOCKSIZE=1024;
int STBLOCKSIZE=4096;
#endif

int userblocksize=-1;
#if defined(BIGGERMMAPBLOCK) && defined(USE_MMAP)
#define MMAPBLOCKSIZE (mmap_page_size*4)
#define MMAPBLOCKTYPE BLOCKTYPE
#else
#define MMAPBLOCKSIZE BLOCKSIZE
#define MMAPBLOCKTYPE BLOCKTYPE
#endif /*BIGGERMMAPBLOCK */

inline int isup(int ch) { return (ch>='A'&&ch<='Z');}
inline int islow(int ch) { return (ch>='a'&&ch<='z');}
inline int tolow(int ch) {return ch+(-'A'+'a');}
inline int toup(int ch) {return ch+(-'a'+'A');}
inline int mklow(int ch) { return (isup(ch)?tolow(ch):ch);}
inline int mkup(int ch) { return (islow(ch)?toup(ch):ch);}

OFFTYPE setfilepos(FILEHANDLE file,OFFTYPE offset) ;




inline BOOL Memory::sizehigher(OFFTYPE sizefile) {
	char readtestchar;
	return (readat(&readtestchar,1,(sizefile))>=1);
	}
//#define sizehigher(sizefile) (readat(&readtestchar,1,(sizefile))>=1)

inline BOOL Memory::testsize(OFFTYPE sizetest) {
	return (sizehigher((sizetest))?0:((sizehigher(((sizetest)-1)))?1:0));
	}

#define MAXCDSIZE 1024*1024*1024
char realsize=0;
const char *regexerrorstring=NULL;
#define re_search_2(pat,s1,l1,s2,l2,start,range,regs,stop) ((l2>0)?re_search_2(pat,s1,l1,s2,l2,start,range,regs,stop):re_search(pat,s1,l1,start,range,regs) )


#ifndef NEEDS_BLOCKMODE
OFFTYPE Memory::exploresize(FILEHANDLE file,OFFTYPE begin, OFFTYPE end) {
	OFFTYPE half;
	do {
		half=(OFFTYPE)((LARGERTYPE)(end+begin)/2);
		if(sizehigher((half)))
			begin=half+1;
		else
			end=half;
		} while(end>begin);

	return begin;
	}
#else
OFFTYPE Memory::exploresize(FILEHANDLE file,OFFTYPE begin, OFFTYPE end) {
	OFFTYPE half;
	OFFTYPE beginblock=begin/(LARGERTYPE)blockreadonly;
	OFFTYPE endblock=end/(LARGERTYPE)blockreadonly;
	do {
		half=(OFFTYPE)((LARGERTYPE)(endblock+beginblock)/2);
		if(sizehigher((half*blockreadonly)))
			beginblock=half+1;
		else
			endblock=half;
		} while(endblock>beginblock);

	return beginblock*blockreadonly;
	}
#endif
#define EXPLORESIZE {if((filesize=exploresize(filehandle,begin,end))>=MAXDISCSIZE) { errors=6; return;}}
OFFTYPE sizespecified=0;
#ifdef USE_WINFILE
FILEHANDLE opencreate(const char *filename) {
return CreateFile(
    filename,	// address of name of the file 
    GENERIC_WRITE,	// access (read-write) mode 
    FILE_SHARE_READ|FILE_SHARE_WRITE,	// share mode 
    NULL,	// address of security descriptor 
    CREATE_ALWAYS,	// how to create 
    FILE_ATTRIBUTE_NORMAL,	// file attributes 
    NULL 	// handle of file with attributes to copy  
   );
	}

FILEHANDLE openreadwrite(const char *filename) {
return CreateFile(
    filename,	// address of name of the file 
    GENERIC_READ|GENERIC_WRITE,	// access (read-write) mode 
    FILE_SHARE_READ|FILE_SHARE_WRITE,	// share mode 
    NULL,	// address of security descriptor 
    OPEN_EXISTING,	// how to create 
    FILE_ATTRIBUTE_NORMAL,	// file attributes 
    NULL 	// handle of file with attributes to copy  
   );
	}
FILEHANDLE openreading(const char *filename) {
  return CreateFile(

	  filename,	// address of name of the file 
	  GENERIC_READ,	// access (read-write) mode 
	  FILE_SHARE_READ|FILE_SHARE_WRITE,	// share mode 
	  NULL,	// address of security descriptor 
	  OPEN_EXISTING,	// how to create 
	  FILE_ATTRIBUTE_READONLY,	// file attributes 
	  NULL 	// handle of file with attributes to copy  
	 );
	}
#else 
FILEHANDLE openreading(const char *filename) {
	return LOPEN(filename,O_RDONLY LARGEFILE_FLAG BINARY_FLAG);
	}
FILEHANDLE openreadwrite(const char *filename) {
  return LOPEN(filename,O_RDWR LARGEFILE_FLAG BINARY_FLAG);
	}

FILEHANDLE opencreate(const char *filename) {
  return LOPEN(filename,O_WRONLY|O_CREAT|O_TRUNC		 LARGEFILE_FLAG BINARY_FLAG,0600);
	}
#endif
/*
Returns -1 if no diskdevice, otherwise a bios disk identifier 
*/
int isdiskdevice(char *filename) 
{
int disknum=-1;
char start[]="\\\\.\\";
char disk[]="PHYSICALDRIVE";
//const int disklen=sizeof(disk)-1;
const int disklen=strlen(disk);
if(!strncmp(filename,start,sizeof(start)-1)) 
  {
  char *ptr=filename+sizeof(start)-1;
  if(ptr[2]=='\0'&&ptr[1]==':') {
		if((ptr[0]>='a'&&ptr[0]<='z'))	 {
			disknum=ptr[0]-'a';
			}
  else	{
			if(ptr[0]>='A'&&ptr[0]<='Z') {
				disknum=ptr[0]-'A';
				}
			}

			}
  else {
	  if(!strncasecmp(disk,ptr,disklen)) {
		  char *endp;
		  disknum=strtol(ptr+disklen, &endp,10);
		  if(!endp	||!*endp) {
			  disknum|=0x80;
			  }

		  }
	  }
  }
return disknum;
}
#ifdef BIOSDISK
Diskread diskread=NULL,diskwrite=NULL;
Getfilesize getfilesize=NULL,getblocksize=NULL;
Diskopen diskopener=NULL;
Diskreopen diskreopen=NULL;
Diskclose diskclose=NULL;
Diskpresent diskpresenter=NULL;

#define BIOSDISKDLL "biosdisk32.dll"
HINSTANCE biosdiskhinstance=NULL;
void freebiosdisk(void) {
	if(biosdiskhinstance){
			FreeLibrary(biosdiskhinstance);
			biosdiskhinstance=NULL;
			}
	}
BOOL loadbiosdisk(void) {
	if(biosdiskhinstance)
		return 1;
	if( !(biosdiskhinstance=LoadLibrary(CONFDIR "//" BIOSDISKDLL)))
		if(!(biosdiskhinstance=LoadLibrary(BIOSDISKDLL))) {
			fprintf(stderr,"LoadLibrary(%s) failed\n",BIOSDISKDLL);
			return 0;
			}
	atexit(freebiosdisk);
	if(!(diskopener=(Diskopen)GetProcAddress(biosdiskhinstance,"diskopen"))) {
		fprintf(stderr,"GetProcAddress(%s,diskopen) failed\n",BIOSDISKDLL);
		freebiosdisk();
		return 0;
		}
	if(!(diskread=(Diskread)GetProcAddress(biosdiskhinstance,"diskread"))) {
		fprintf(stderr,"GetProcAddress(%s,diskread) failed\n",BIOSDISKDLL);
		freebiosdisk();
		return 0;
		}
	if(!(diskwrite=(Diskread)GetProcAddress(biosdiskhinstance,"diskwrite"))) {
		fprintf(stderr,"GetProcAddress(%s,diskwrite) failed\n",BIOSDISKDLL);
		freebiosdisk();
		return 0;
		}
	if(!(diskclose=(Diskclose)GetProcAddress(biosdiskhinstance,"diskclose"))) {
		fprintf(stderr,"GetProcAddress(%s,diskclose) failed\n",BIOSDISKDLL);
		freebiosdisk();
		return 0;
		}
	if(!(getblocksize=(Getfilesize)GetProcAddress(biosdiskhinstance,"getblocksize"))) {
		fprintf(stderr,"GetProcAddress(%s,getblocksize) failed %ld\n",BIOSDISKDLL,GetLastError());
		freebiosdisk();
		return 0;
		}
	if(!(diskreopen=(Diskreopen)GetProcAddress(biosdiskhinstance,"diskreopen"))) {
		fprintf(stderr,"GetProcAddress(%s,diskreopen) failed\n",BIOSDISKDLL);
		freebiosdisk();
		return 0;
		}
	if(!(getfilesize=(Getfilesize)GetProcAddress(biosdiskhinstance,"getfilesize"))) {
		fprintf(stderr,"GetProcAddress(%s,getfilesize) failed\n",BIOSDISKDLL);
		freebiosdisk();
		return 0;
		}
	if(!(diskpresenter=(Diskpresent)GetProcAddress(biosdiskhinstance,"diskpresent"))) {
		fprintf(stderr,"GetProcAddress(%s,diskpresenter) failed\n",BIOSDISKDLL);
		freebiosdisk();
		return 0;
		}
	return 1;
	}
BOOL diskpresent(int disknum) {
	if( !loadbiosdisk() ) {
			return FALSE;
			}
		return diskpresenter(disknum);
		}
 
Diskinfo *diskopen(int disknum,int access) {
	if( !loadbiosdisk() ) {
			return NULL;
			}
	return diskopener(disknum,access);
	}
	
struct regdisk {
	DWORD cylinders;
	DWORD heads;
	DWORD sectors;
	LONGLONG disksectors; 
	WORD BytesPerSector;
	LONGLONG disksize;
   }  PACKSTRUCT;
typedef struct regdisk RegDisk;
char registrysubkey[]="SOFTWARE\\Bed\\hardisks";
OFFTYPE Memory::getregistrysize(Diskinfo *infodisk,OFFTYPE &begin,OFFTYPE &end) 
{
	HKEY hkProtocol;
	memset(&statdata,'\0',sizeof(statdata));
	if((blockreadonly=getblocksize(infodisk))<=0)  {
		fprintf(stderr,"Zero Blocksize\n");
		return OFFTYPEINVALID;
		}
	
	filehandle=GetStdHandle(STD_ERROR_HANDLE); /*Don't point to anyone */

	if((infodisk->drive&0x80)) {
		int disknr=infodisk->drive&0x0F;
		char name[10]="disk";
		OFFTYPE cylen= infodisk->heads*infodisk->sectors*infodisk->BytesPerSector;
		filesize=getfilesize(infodisk);
		end=filesize+cylen;
		sprintf(name+4,"%d",disknr);
		DWORD bintype=REG_BINARY,dwType	;
		RegDisk diskgegs;
		if(RegOpenKeyEx( HKEY_LOCAL_MACHINE, registrysubkey,
				0, 
					KEY_ALL_ACCESS	,	// desired security access 
					&hkProtocol	// address of buffer for opened handle  
				 )==ERROR_SUCCESS) 
		{
		DWORD diskgegslen=sizeof(diskgegs);
		if(RegQueryValueEx(
				hkProtocol,	// handle of key to query 
				name,	// address of name of value to query 
				0,
				&dwType,	// address of buffer for value type 
				(BYTE *)&diskgegs,	// address of data buffer 
				&diskgegslen 	// address of data buffer size 
			 )==ERROR_SUCCESS) {
			 if(dwType==bintype&&diskgegslen==sizeof(diskgegs)&&
				!memcmp(&diskgegs,infodisk,((char*)&diskgegs.disksize)-((char *)&diskgegs.cylinders))) {

		;
		 			RegCloseKey(hkProtocol);
					filesize=diskgegs.disksize;
					if(!realsize)
							return begin=end=filesize;

					}
				}
		 RegCloseKey(hkProtocol);
		}
	/*To large end doesn't fail anymore, so try something which works
	with my three harddisks */
    if(sizehigher((end))) 
	  {
	  do {
		  end+=filesize;
		  if(end>=MAXDISCSIZE) {
			  break;
			  }
		  } while(sizehigher((end)));
	  };
		return filesize;
	}
#if 1
else 
	{
		if(realsize)
		{
			filesize=getfilesize(infodisk);
			begin=0;end=2*filesize;
			return filesize;
		}	
		else 
			return filesize=begin=end=getfilesize(infodisk);
	}
#else
else	 { /*Determine floppy size */
		const OFFTYPE highsize=2880*512,doubsize=1440*512;
		end=getfilesize(infodisk);
    if(end>=highsize&&sizehigher((highsize-1))) {
				if(end==highsize||!sizehigher(highsize))
					return filesize=begin=end=highsize;
				else	{
					begin=highsize+1;
					}
				}
		else {
			fprintf(stderr,"end="OFFPRINT " highsize=" OFFPRINT,end,highsize);
				if(sizehigher(doubsize-1)) {
						if(!sizehigher(doubsize))
							return filesize=begin=end=doubsize;
						else	{
							begin=doubsize-1;
							end=highsize-1;
							}

						}
				else {
					end=doubsize-1;
					}
				}

	return 0;
	}
#endif
}
BOOL Memory::setregistrysize(Diskinfo *infodisk,OFFTYPE filesize) 
{
if(!(infodisk->drive&0x80))
	return TRUE;

	HKEY hkProtocol;
	DWORD dispos;
	if(RegCreateKeyEx(
			HKEY_LOCAL_MACHINE,
			registrysubkey,
			0,	// reserved 
			"Geometry",	// address of class string 
			REG_OPTION_VOLATILE,	// special options flag 
			KEY_ALL_ACCESS	,	// desired security access 
			NULL,	// address of key security structure 
			&hkProtocol,	// address of buffer for opened handle  
			&dispos 	// address of disposition value buffer 
				 )==ERROR_SUCCESS) 
	 {
		RegDisk diskgegs;
		int disknr=infodisk->drive&0x0F;
		char name[10]="disk";
		sprintf(name+4,"%d",disknr);
		DWORD bintype=REG_BINARY;
		memcpy(&diskgegs,infodisk,(((char*)&diskgegs.disksize)-((char *)&diskgegs.cylinders)));
		diskgegs.disksize=filesize;
		if(RegSetValueEx(hkProtocol,
				name,	// address of value to set 
				0,
				bintype,	// flag for value type 
				(BYTE *)&diskgegs,	// address of value data 
				sizeof(diskgegs)	// size of value data 
			 )!=ERROR_SUCCESS) 
		{
			fprintf(stderr,"RegSetValueEx failed\n"); 
			return FALSE;
		}
		return TRUE;
	}
return FALSE;
}

#endif
#ifdef USE_WINFILE
#define TOLONGLONG(largeint) (((largeint).LowPart)|(((long long)((largeint).HighPart))<<32))
extern OSVERSIONINFO WindowsVersion;
OFFTYPE Memory::win32diskfilesize(FILEHANDLE filehandle) {
OFFTYPE filesize=0;
if(WindowsVersion.dwOSVersionInfoSize&&WindowsVersion.dwPlatformId!=VER_PLATFORM_WIN32_WINDOWS) {
	DWORD retsize;
  DISK_GEOMETRY diskgeo;
    if(DeviceIoControl(filehandle, IOCTL_DISK_GET_DRIVE_GEOMETRY
		, NULL, 0, &diskgeo, sizeof(diskgeo), &retsize,NULL)) {
		filesize=TOLONGLONG(diskgeo.Cylinders)*diskgeo.TracksPerCylinder*
   diskgeo.SectorsPerTrack*diskgeo.BytesPerSector;
	blockreadonly=diskgeo.BytesPerSector;
	OFFTYPE filsize;
((unsigned long *)&filsize)[0]= GetFileSize(filehandle,((unsigned long *)&filsize)+1 );
if((((unsigned long *)&filsize)[0] == 0xFFFFFFFF && ( GetLastError()) != NO_ERROR )){
		fprintf(stderr,__FILE__ "%d GetFileSize Failed\n",__LINE__); 
      } 
	else {
		if(filsize>filesize) 
			filesize=filsize;
			
		}
	}
	}
return filesize;
}
#endif
int setblocksize(int bsize) {
	int BLOCKSIZE;
	if(userblocksize>0) {
		BLOCKSIZE=userblocksize;
		}
	else {
		if(bsize>0)
			BLOCKSIZE=bsize;
		else
			BLOCKSIZE=STBLOCKSIZE;
		}
	return BLOCKSIZE;	
	}

#ifdef __FreeBSD__
int getblockreadonly(FILEHANDLE filehandle) 
{
	char readtestchar;
	int blockread=1;
	if(LPREAD(filehandle,&readtestchar,1,0)<1) 
	{
		int freebsdblocksize=1024;
		char buf[freebsdblocksize];
		if(LPREAD(filehandle,buf,freebsdblocksize,0)==freebsdblocksize) 
		{
			blockread=freebsdblocksize;
			LSEEK(filehandle,0,SEEK_SET);
		}
	}
	return blockread;
}
#endif
inline BOOL Memory::checkfilesize(OFFTYPE filsize,OFFTYPE &begin,OFFTYPE &end) 
{
	if(sizehigher(filsize)) 
		begin=filsize;
	else 
	{
		if(sizehigher(filsize-1)) 
			return TRUE;
		else
			end=filsize-1;
	}
	return FALSE;
}	
void Memory::openfile(void) 
{
int dontcheck=0;
OFFTYPE begin=0;
OFFTYPE end = MAXDISCSIZE;
filehandle=MY_INVALID_HANDLE_VALUE;
#ifdef BIOSDISK
if(WindowsVersion.dwOSVersionInfoSize&&WindowsVersion.dwPlatformId==VER_PLATFORM_WIN32_WINDOWS) 
{
int disknum;
if((disknum=isdiskdevice(filename))!=-1) 
  {
  if((infodisk=diskopen(disknum,O_RDONLY)))	
	{
	if((filesize=getregistrysize(infodisk,begin,end))==OFFTYPEINVALID) {
			diskclose(infodisk);infodisk=NULL;	
			errors=77;
			return;
			}
	if(begin==end)
		dontcheck=1;
	goto havesize;
   }
  }
}
#endif

#ifdef PROCLOCKSBUG
	if(!strcmp(filename,"/proc/locks")) {
		errors=9;
		return;
		}
#endif
	if(STAT(filename,&statdata)) {
#ifdef NOSTAT
		memset(&statdata,'\0',sizeof(statdata));
#else
		errors=8;	
		return;
#endif
		}
	if( S_ISFIFO(statdata.st_mode)  ) {
		errors=7;
		return;
		}
if((filehandle=openreading(filename))==MY_INVALID_HANDLE_VALUE) {
	  errors=9;
	  return;
	}	
#ifdef USE_WINFILE
filesize=win32diskfilesize(filehandle) ;
#endif
#ifdef BIOSDISK
havesize:
#endif
BLOCKSIZE=setblocksize(statdata.st_blksize);
	errors=0;
#ifdef __FreeBSD__
if(statdata.st_mode&S_IFBLK ) 
	blockreadonly=getblockreadonly(filehandle);
#endif

if(sizespecified) {
	filesize=sizespecified;
	return;
	}
if(dontcheck&&!realsize) 
	return;
if(filesize>0&&checkfilesize(filesize,begin,end))
				return;
#ifndef ALWAYSEXPLORESIZE
if(S_ISREG(statdata.st_mode) ) 
{
			mmapfailed=0;
	#ifdef USE_WINFILE
	((unsigned long *)&filesize)[0]= GetFileSize(filehandle,
														((unsigned long *)&filesize)+1 );
	if((((unsigned long *)&filesize)[0] == 0xFFFFFFFF && 
														(GetLastError()) != NO_ERROR ))
	{
		fprintf(stderr,"%s: GetFileSize Failed\015\012",filename); 
		filesize=statdata.st_size;
	} 
#else
	filesize=statdata.st_size;
#endif
	if(filesize>0&&checkfilesize(filesize,begin,end))
		return;
	goto catchall;
}
else   
{
#ifdef __linux__
		if(S_ISBLK(statdata.st_mode)) {
			int blkgetsize;
			if(ioctl(filehandle,BLKGETSIZE ,&blkgetsize)>=0) { 
				filesize= (OFFTYPE) blkgetsize*512;
				if(sizehigher(filesize)) 
					begin=filesize;
				else {
					if(sizehigher(filesize-1)) 
						return;
					else
						end=filesize-1;
					}
				}
		DEBUG("BLKGETSIZE failed\n");
/*Maybe a cdrom drive */
#ifdef CDROM_DISC_STATUS
		if(ioctl(filehandle,CDROM_DISC_STATUS)<0) {
				 EXPLORESIZE;
			}
		else { /*Cdrom */
				char sbuf[8];
				OFFTYPE lookat=0x8050;
				OFFTYPE newbegin,newend;

				if(readat(sbuf,8,lookat)>=8&&memcmp(sbuf,sbuf+4,4)) {
					for(int i=0;i<4;i++) {
						if(sbuf[i]!=sbuf[7-i]) {
							DEBUG("No opposide");
							goto catchall;
							}
						}
					newbegin=(*((int*)&sbuf)*2048);
					if(sizehigher(newbegin-1)) {

						if(realsize) {
							begin=newbegin;
							newend=MAXCDSIZE;
							if(sizehigher(newend)) 
								begin=newend;
							else {
								end=newend;
									 }
							goto catchall;
							}
						else {
							filesize=newbegin;
							return ;
							}

						}
					else {
						end=newbegin; 
						}
					
					} /*End Read cdromsize */
				goto catchall;
			} /*END cdrom */
#else
				 EXPLORESIZE;
#endif
		} /*END block device */
#endif /*linux */
} /*END not regular */
#endif /*ALWAYSEXPLORESIZE*/
if(S_ISDIR(statdata.st_mode)) 
{
	errors=5;
	return;
}
else 
{
 catchall:
 EXPLORESIZE ;
}
}
void Memory::init(char *name) {
#if 0
	char buf[MAXPATHLEN];
	expandfilename(buf,name);
#else
	#define buf name
#endif
	mmapfailed=1;
	searchpos=0;
	lastforward=3;
	searchexpr=NULL;
	searchregs=NULL;
	searchstr=NULL;
	table=tablebase-SCHAR_MIN;
	int len=strlen(buf)+1;
	filename=myallocar( char,len);
	memcpy(filename,buf,len);
	openfile();
#ifdef BIOSDISK
if(infodisk)
	setregistrysize(infodisk,filesize);
#endif
	diskfilesize=filesize;
#undef buf
	}



Memory::Memory(char *name): 
#ifdef BIOSDISK
	infodisk(NULL),
#endif
#ifdef NEEDS_BLOCKMODE
blockreadonly(1),
#endif
readonly(0),filesize(0)
{
	 INITUSELSEEK;
//	filefp=NULL;
	init(name);
	}
void closefilehandle(FILEHANDLE file) {
  #ifdef USE_WINFILE
	  if(file!=MY_INVALID_HANDLE_VALUE) {
		  if(!CloseHandle(file)) {
			  fprintf(stderr,"Close failed\n");
			  }
		  }
  #else
	  if(file>0)
		  LCLOSE(file);
  #endif
	}
void Memory::endfile(void) {
#ifdef BIOSDISK
	if(infodisk) {
		diskclose(infodisk);
		infodisk=NULL;
		}
	else
#endif
	  closefilehandle(filehandle);
	empty();
	if(filename)
		myfree( filename);
	}
int Memory::reinit(char *name) {
	endfile();
	 init(name);
	 return 0;
	}
int Memory::reinit(void) {
	return reinit(filename);
	}
int Memory::empty(void) {
	for(Treel *iter=tree.treecontrol->roottree;iter!=tree.NIL;iter=tree.next(iter))
		myfree( iter->data.buf);
	tree.empty();
	return 0;
	}

Memory::~Memory() {
	endfile();
	 DESTROYUSELSEEK;
	}


/* Bepaal of file veranderd is na opstarte of laatste keer saven             */
/* Ga alle nodes af en save die nodes.                                       */
/* Nodes delete                                                              */
/*                                                                           */
/* Saven van een node:                                                       */
/* 	- ga naar positie file;                                                  */
/* 	- schrijf gegevens in file                                               */
/* 	- delete gegevens                                                        */
/* Sat Oct  3 00:50:05 1998                                                  */

int Memory::savenode(FILEHANDLE output, Treel *node) {
	DEBUG("Save " BLOCKPRINT "\n",node->data.blocknr);
	OFFTYPE diff=filesize-(node->data.blocknr*BLOCKSIZE);
	if(diff>0) {
		SIZE_T size=(diff<BLOCKSIZE)?diff:BLOCKSIZE;
		if(node->data.size!=size)
			fprintf(stderr,"WARNING: savenode/1: not enough in node " BLOCKPRINT" " SIZE_TPRINT "!=" SIZE_TPRINT "\n",node->data.blocknr,size,node->data.size);
		return writeat(output,node->data.buf,node->data.size,node->data.blocknr*BLOCKSIZE);
		}
	return 0;
	}

int Memory::touched(void) {
	STATTYPE st;
	if(tmpbuffer(filename))
		return 0;
#ifdef BIOSDISK
if(!infodisk) 
#endif
{
	if(STAT(filename,&st)<0)
		return -1;
	if(st.st_mtime!=statdata.st_mtime)
		return 5;
	if(st.st_size!=statdata.st_size)
		return 3;
	if(st.st_ino!=statdata.st_ino)
		return 4;
	}
	return 0;
	}
#ifdef USE_WINFILE
int myftruncate(FILEHANDLE output,OFFTYPE size) {
	if(setfilepos(output,size)!=size) {
		return -1;
		}
	if(!SetEndOfFile(output)) {
		return -1;
		}
	return 0;
	}
#endif
inline OFFTYPE setfilepos(FILEHANDLE file,OFFTYPE offset) {
#ifdef USE_WINFILE
LONG hi=offset>>32;
DWORD lo;
lo=SetFilePointer(file,
	    offset&0xFFFFFFFF,	// number of bytes to move file pointer 
		    &hi,	// address of high-order word of distance to move  
		FILE_BEGIN
				   );
if(lo==0xFFFFFFFF&&GetLastError()) {
	return OFFTYPEINVALID;
	}
return (lo|(((OFFTYPE)hi)<<32));
#else
return LSEEK(file,offset,SEEK_SET);
#endif
}
int Memory::saveall(void) {
#ifdef USE_WINFILE
FILEHANDLE output=GetStdHandle(STD_ERROR_HANDLE); /* So it doesn't point to someone */
#else
FILEHANDLE output=STDERR_FILENO; /* So it doesn't point to someone */
#endif

	if(readonly) {
		return 1;
		}
#ifdef BIOSDISK
if(infodisk) {
	infodisk=diskreopen(infodisk,O_RDWR);
	for(Treel *iter=tree.treecontrol->roottree;iter!=tree.NIL;iter=tree.next(iter)) {
		if(savenode(output,iter)<0) {
			  infodisk=diskreopen(infodisk,O_RDONLY);
				errors=8887;
				return errors;
				}
		myfree( iter->data.buf);
		}
	tree.empty();
	infodisk=diskreopen(infodisk,O_RDONLY);
	return errors;
	}
else
#endif
{
	closefilehandle(filehandle); /*Because file is changed */ 
#ifdef USE_WINFILE
if(((output=openreadwrite(filename))==MY_INVALID_HANDLE_VALUE)||(diskfilesize>filesize&&((setfilepos(output,filesize)!=filesize)||!SetEndOfFile(filehandle)))) {
#else
	if((diskfilesize!=filesize&&(TRUNCATE(filename,filesize)<0))||((output=openreadwrite(filename))==MY_INVALID_HANDLE_VALUE)) {
#endif
		int errors;
		readonly=1;
		if(errno)
			errors=errno;
		else
			errors=7777;
		if((filehandle=openreading(filename))==MY_INVALID_HANDLE_VALUE) {
			if(errno)
				errors=errno;
			else
				errors=7777;
			}
		return errors;
		}
	for(Treel *iter=tree.treecontrol->roottree;iter!=tree.NIL;iter=tree.next(iter)) {
		if(savenode(output,iter)<0) {
				closefilehandle(output);
				if((filehandle=openreading(filename))==MY_INVALID_HANDLE_VALUE) {
					if(errno)
						errors=errno;
					else
						errors=7777;
					}
				errors=8887;
				return errors;
				}
		myfree( iter->data.buf);
		}
	closefilehandle(output);
	tree.empty();
	if((filehandle=openreading(filename))==MY_INVALID_HANDLE_VALUE) {
		if(errno)
			errors=errno;
		else
			errors=7777;
		}
#ifdef USE_WINFILE
	STAT(filename,&statdata);
#else
	FSTAT(filehandle,&statdata);
#endif

	diskfilesize=filesize;
	return errors;
	}
}
/*
	struct stat stats;
		fstat(handle,&stats);
		if(stats.st_ino==statdata.st_ino&&stats.st_dev==statdata.st_dev) {
			LCLOSE(handle);
			return saveall();
		}
		*/
int Memory::changednode(Treel *node) {
	char tmpbuf[BLOCKSIZE];
	OFFTYPE diff=filesize-((OFFTYPE)node->data.blocknr*BLOCKSIZE);
	if(diff>0) {
		SIZE_T size=(diff<BLOCKSIZE)?diff:BLOCKSIZE;
		if(node->data.size!=size)
			fprintf(stderr,"WARNING: changednode/1: not enough in node " BLOCKPRINT" " SIZE_TPRINT "!=" SIZE_TPRINT "\n",node->data.blocknr,size,node->data.size);
		blockreadat(tmpbuf,node->data.size,node->data.blocknr*BLOCKSIZE);
		return memcmp(tmpbuf, node->data.buf, node->data.size);
		}
	return 0;
	}
int Memory::changed(void) {
	OFFTYPE disksize;
	if(!tmpbuffer(filename)) 
		disksize=diskfilesize;
	else
		disksize=(OFFTYPE)1;

//	DEBUG("diskfilesize=" OFFPRINT " realsize=" OFFPRINT " tosavesize=" OFFPRINT "\n",diskfilesize,disksize,filesize);
	if(disksize!=filesize)
		return -1;
	for(Treel *iter=tree.treecontrol->roottree;iter!=tree.NIL;iter=tree.next(iter)) {
		if(changednode(iter))
			return -1;
		}
	for(Treel *iter=tree.treecontrol->roottree;iter!=tree.NIL;iter=tree.next(iter)) 
		myfree( iter->data.buf);
	tree.empty();
	return errors;
	}

int Memory::saveto(int handle) {
		char buf[BLOCKSIZE];
		BLOCKTYPE nr;
		SIZE_T did, ret=0;
		for(nr=0;(did=getblock(nr, buf));nr++) {
				ret=LWRITE(handle,buf,did);
				if(ret!=did) {
					return -1;
					}
				}
		if((maxnum((OFFTYPE)(nr-1)*BLOCKSIZE,0)+ret)!=filesize)
			return -1;
		return 0;
		}
SIZE_T Memory::getblockpiece(OFFTYPE beg,SIZE_T len,char *get) {
	BLOCKTYPE onder=beg/BLOCKSIZE;
	SIZE_T ret;
	SIZE_T in=beg%BLOCKSIZE;
	Treel *el=tree.search(onder);
	if(el!=tree.NIL) {
		ret=minnum(el->data.size,len);
		memmove(get,el->data.buf+in,ret);
		}
	else {
		ret=readat(get,len,beg);
		}
	return ret;
	}

OFFTYPE Memory::getpart(OFFTYPE beg,OFFTYPE len,char *gegs) {
	if(beg>=filesize) {
		if(beg==filesize&&!len)
			return 0;
		else
			return OFFTYPEINVALID;
		}

	BLOCKTYPE start,bl;
	SIZE_T over; 
	OFFTYPE full,end=minnum(beg+len,filesize);
	len=end-beg;
	over=(BLOCKSIZE-(beg%BLOCKSIZE));
	over=minnum(len,over);

	if(getblockpiece(beg,over,gegs)!=over)
		return OFFTYPEINVALID;


	full=len-over;
	if(full>0) {
		char *ptr;
		SIZE_T nog; 
		start=(beg/BLOCKSIZE)+1;
		bl=full/BLOCKSIZE+start;
		nog=full%BLOCKSIZE;
		ptr=gegs+over;
		for(BLOCKTYPE nr=start;nr<bl;nr++,ptr+=BLOCKSIZE) {
			if((BLOCKSIZE!=getblock(nr, ptr)))
				return OFFTYPEINVALID;
			}
		if(getblockpiece(end-nog,nog,ptr)!=nog)
			return OFFTYPEINVALID;
		}
	return len;
	}

OFFTYPE Memory::putpart(OFFTYPE beg,OFFTYPE aanlen,char *gegs) {
	if(beg>=filesize) {
		if(beg==filesize&&!aanlen)
			return 0;
		else
			return OFFTYPEINVALID;
		}
	OFFTYPE len=aanlen;
	BLOCKTYPE start,bl;
	SIZE_T over;
	OFFTYPE end=minnum(beg+len,filesize),full;
	len=end-beg;
	over=(BLOCKSIZE-(beg%BLOCKSIZE));
	over=minnum(len,over);
	if(over)
		if(putblockpiece(beg,over,gegs)!=over)
			return OFFTYPEINVALID;


	full=len-over;
	if(full>0) {
		char *ptr;
		SIZE_T nog;
		start=(beg/BLOCKSIZE)+1;
		bl=full/BLOCKSIZE+start;
		nog=full%BLOCKSIZE;
		ptr=gegs+over;
		for(BLOCKTYPE nr=start;nr<bl;nr++,ptr+=BLOCKSIZE) {
			if((BLOCKSIZE!=putblock(nr, ptr)))
				return OFFTYPEINVALID;
			}
		if(putblockpiece(end-nog,nog,ptr)!=nog)
			return OFFTYPEINVALID;
		}
	return len;
	}
SIZE_T Memory::saveto(int handle,OFFTYPE beg,OFFTYPE len) {
	if(beg>=filesize) {
		if(beg==filesize&&!len)
			return 0;
		else
			return -1;
		}
	OFFTYPE full;
	SIZE_T over;
	char buf[BLOCKSIZE];
	OFFTYPE end=beg+len;
	over=(BLOCKSIZE-(beg%BLOCKSIZE));
	over=minnum(len,over);
	if(over) {
		if(getpart(beg,over,buf)!=over)
			return -1;
		if(LWRITE(handle,buf,over)!=over)
			return -1;
		}


	full=len-over;
	if(full) {
		SIZE_T nog;
		BLOCKTYPE bl,start=(beg/BLOCKSIZE)+1;
		bl=full/BLOCKSIZE+start;
		nog=full%BLOCKSIZE;
		for(BLOCKTYPE nr=start;nr<bl;nr++) {
			if((BLOCKSIZE!=getblock(nr, buf)))
				return -1;
			SIZE_T ret=LWRITE(handle,buf,BLOCKSIZE);
			if(ret!=BLOCKSIZE) {
				return -1;
				}
			}
		if(nog) {
			if(getpart(end-nog,nog,buf)!=nog)
				return -1;
			if(LWRITE(handle,buf,nog)!=nog)
				return -1;
			}
		}
	return 0;
	}
Treel *Memory::gettreel(BLOCKTYPE blockiter) {
		Treel *el=tree.search(blockiter);
		if(el==tree.NIL) {
			char *gegs=myallocar( char,BLOCKSIZE);
			tree.insert((Data){blockiter,gegs,0});
			el=tree.search(blockiter);
			}
		return el;
		}
#ifdef USE_WINFILE
#ifdef USE_PREAD
inline SIZE_T mypread64(FILEHANDLE input,char *buf,SIZE_T nr,OFFTYPE offset) {
DWORD did;
OVERLAPPED overlap;
memset(&overlap,'\0',sizeof(overlap));
overlap.Offset = offset&0xFFFFFFFF;
overlap.OffsetHigh = offset>>32;

if(!ReadFile(
    input,	// handle of file to write to 
    buf,	// address of data to write to file 
    nr,	// number of bytes to write 
    &did,	// address of number of bytes written 
    &overlap 	// addr. of structure needed for overlapped I/O  
   )) {
	if(!GetOverlappedResult(

			input,	// handle of file, pipe, or communications device  
			&overlap,	// address of overlapped structure 
			&did,	// address of actual bytes count 
			TRUE 	// wait flag 
		 ))
		return -1;
	}
return did;
}
static inline SIZE_T mypwrite64(FILEHANDLE outputhandle,char *buf,SIZE_T nr,OFFTYPE offset) {
DWORD did;
OVERLAPPED overlap;
memset(&overlap,'\0',sizeof(overlap));
overlap.Offset = offset&0xFFFFFFFF;
overlap.OffsetHigh = offset>>32;

if(!WriteFile(
    outputhandle,	// handle of file to write to 
    buf,	// address of data to write to file 
    nr,	// number of bytes to write 
    &did,	// address of number of bytes written 
    &overlap 	// addr. of structure needed for overlapped I/O  
   ))
	return -1;
else 
	return did;
}
#endif
#endif
static inline SIZE_T readfromfile(FILEHANDLE input,char *buf,SIZE_T nr) {
#ifdef USE_WINFILE
DWORD did;
if(!ReadFile(

    input,	// handle of file to write to 
    buf,	// address of data to write to file 
    nr,	// number of bytes to write 
    &did,	// address of number of bytes written 
    NULL 	// addr. of structure needed for overlapped I/O  
   ))
	return -1;
else 
	return did;
#else
return LREAD(input,buf,nr);
#endif
}
SIZE_T writetofile(FILEHANDLE output,char *buf,SIZE_T nr) {
#ifdef USE_WINFILE
DWORD did;
if(!WriteFile(

    output,	// handle of file to write to 
    buf,	// address of data to write to file 
    nr,	// number of bytes to write 
    &did,	// address of number of bytes written 
    NULL 	// addr. of structure needed for overlapped I/O  
   ))
	return -1;
else 
	return did;
#else
return LWRITE(output,buf,nr);
#endif
}

#ifdef HAS_PREAD
#define HAS_PWRITE 1
#endif

SIZE_T Memory::writeat(FILEHANDLE output,char *ptr,SIZE_T size,OFFTYPE offset) {
#ifdef BIOSDISK
	if(infodisk)	{
		SIZE_T count=size/blockreadonly;
		if(count<=0) {
		  fprintf(stderr,"Memory::writeat %ld is not a multiple of %d ( disk blocksize)\n",size,blockreadonly);
		return -5;
			}
		if(diskwrite(infodisk, ptr,size/blockreadonly,offset/blockreadonly)) {
			return size;
			}
		return -4;
		}
	else	
#endif
{
#ifdef HAS_PWRITE
	SIZE_T ret;
	ret=LPWRITE(output,ptr,size,offset);
	if(ret!=size) {
		fprintf(stderr,"write failed "SIZE_TPRINT"!=" SIZE_TPRINT "\n",ret,size);
		return -2;
		}
	return ret;
#else
	STARTUSELSEEK;
	OFFTYPE isof=setfilepos(output,offset);
	SIZE_T ret;
	if(isof!=offset) {
		fprintf(stderr,"writeat: lseek failed " OFFPRINT "!=" OFFPRINT "\n",isof,offset);
		STOPUSELSEEK;
		return -1;
		}
	ret=writetofile(output,ptr,size);
	if(ret!=size) {
		fprintf(stderr,"write failed %ld!=" SIZE_TPRINT "\n",ret,size);
		STOPUSELSEEK;
		return -2;
		}
	STOPUSELSEEK;
	return ret;
#endif
 }
	}

SIZE_T Memory::blockreadat(char *ptr,SIZE_T size,OFFTYPE offset) {
		SIZE_T ret;
#ifdef BIOSDISK
	if(infodisk)	{
/*
		if((offset+size)>filesize) {
			if(offset>filesize) {
				return -3;
				}
			if(offset==filesize)
				return 0;
			size=filesize-offset;
			}
*/
		SIZE_T count=size/blockreadonly;
		if(count<=0) {
		  fprintf(stderr,"Memory::blockreadat %ld is not a multiple of %d ( disk blocksize)\n",size,blockreadonly);
		return -5;
			}
		if(diskread(infodisk, ptr,count,offset/blockreadonly)) {
			return size;
			}
		return -4;
		}
	else	
#endif
{
#ifdef HAS_PREAD
		ret=LPREAD(filehandle,ptr,size,offset);
#else
		STARTUSELSEEK;
		OFFTYPE isof=setfilepos(filehandle,offset);
		if(isof!=offset) {
//			fprintf(stderr,"readat: lseek failed " OFFPRINT "!=" OFFPRINT "\n",isof,offset);
			STOPUSELSEEK;
			return -1;
			}
		ret= readfromfile(filehandle,ptr,size);
#endif
		if(ret!=size) {
//			fprintf(stderr,"readat failed "SIZE_TPRINT  "!=" SIZE_TPRINT "\n",ret,size);
			STOPUSELSEEK;
			return -2;
			}
		STOPUSELSEEK;
		return ret;
}
}

#ifdef NEEDS_BLOCKMODE
inline SIZE_T Memory::readat(char *ptr,SIZE_T size,OFFTYPE offset) {
	if(blockreadonly>1) {
		OFFTYPE offunder=(offset/blockreadonly)*blockreadonly;
		SIZE_T extra=offset-offunder;
		SIZE_T blen=(((size+extra)+blockreadonly-1)/blockreadonly)*blockreadonly;
		char buf[blen];
		if(blockreadat(buf,blen,offunder)<(size+extra))
				return -1;
		memcpy(ptr,buf+extra,size);
		return size;		
		}
	else {
		return blockreadat(	ptr,size,offset);
		}
	}
#else
inline SIZE_T Memory::readat(char *ptr,SIZE_T size,OFFTYPE offset) {
		return blockreadat(	ptr,size,offset);
	}
#endif
#ifdef USE_MMAP
/*
Uses a other MMAPBLOCKSIZE larger than the general blocksize.
blocknr is given in terms of MMAPBLOCKSIZE
*/
#ifdef BIGGERMMAPBLOCK
SIZE_T Memory::mmapgetblock(MMAPBLOCKTYPE blocknr,char *buf) {

	SIZE_T takesize,disktakesize;
	OFFTYPE offset=(blocknr*MMAPBLOCKSIZE);
	if(offset>=filesize)
		return 0;
	caddr_t ptr;
	takesize=minnum(MMAPBLOCKSIZE,filesize-offset);
	disktakesize=minnum(MMAPBLOCKSIZE,diskfilesize-offset);
	if(mmapfailed||(disktakesize>0&&((ptr=(caddr_t)MMAP(buf, disktakesize , PROT_READ|PROT_WRITE ,  MAP_PRIVATE|MAP_FIXED , filehandle, offset))== MAP_FAILED ))) {
		mmapfailed=1;
		int len=MMAPBLOCKSIZE/ BLOCKSIZE;
		BLOCKTYPE start=blocknr*len;
		takesize=0;
		for(int iter=0;iter<len;iter++) {
			takesize+=getblock(iter+start, buf+(BLOCKSIZE*iter));
			}
		return takesize;
		}
	else {
		int len=MMAPBLOCKSIZE/ BLOCKSIZE;
		BLOCKTYPE start=blocknr*len;
		for(int iter=0;iter<len;iter++) {
			Treel *el=tree.search(iter+start);
			if(el!=tree.NIL) {
				memcpy(buf+(BLOCKSIZE*iter),el->data.buf,el->data.size);
				}
			}
		return takesize;
		}

	}
#else
SIZE_T Memory::mmapgetblock(BLOCKTYPE blocknr,char *buf) {
	SIZE_T ret;
	OFFTYPE offset=(blocknr*BLOCKSIZE);

	if(offset>=filesize)
		return 0;
	Treel *el=tree.search(blocknr);
	if(el!=tree.NIL) {
		ret=el->data.size;
		memcpy(buf,el->data.buf,ret);
		}
	else {
		caddr_t ptr;
		SIZE_T disktakesize;
		ret=minnum(BLOCKSIZE,filesize-offset);
		disktakesize=minnum(BLOCKSIZE,diskfilesize-offset);
		 if(mmapfailed||(disktakesize>0&&((ptr=(caddr_t)MMAP(buf, ret , PROT_READ|PROT_WRITE ,  MAP_PRIVATE|MAP_FIXED , filehandle, offset))== MAP_FAILED ))) {
			mmapfailed=1;
			ret=blockreadat(buf,disktakesize,offset);
			}
		}
	return minnum(filesize-offset,ret);
	}
#endif
#else
inline SIZE_T Memory::mmapgetblock(BLOCKTYPE blocknr,char *buf) {return getblock(blocknr,buf);}
#endif
SIZE_T Memory::getblock(BLOCKTYPE blocknr,char *buf) {
	SIZE_T ret;
	OFFTYPE offset=(blocknr*BLOCKSIZE);
	if(offset>=filesize)
		return 0;
	Treel *el=tree.search(blocknr);
	if(el!=tree.NIL) {
		memmove(buf,el->data.buf,el->data.size);
		ret=el->data.size;
		}
	else {
		int len=minnum(filesize-offset,BLOCKSIZE);
		ret=blockreadat(buf,len,offset);
		}
	return minnum(filesize-offset,ret);
	}

SIZE_T Memory::putblock(BLOCKTYPE blocknr,char *buf) {
	OFFTYPE offset=(blocknr*BLOCKSIZE);
	if(offset>=filesize)
		return 0;
	SIZE_T thissize=minnum(filesize-offset,BLOCKSIZE);
	Treel *el=gettreel(blocknr);
	memmove(el->data.buf,buf,thissize);
	el->data.size=thissize;
	return thissize;
	}

void	Memory::setborder(OFFTYPE pos) {
	BLOCKTYPE under=pos/BLOCKSIZE;
	Treel *el=tree.search(under);
	if(el==tree.NIL)
		return;
	OFFTYPE offset=under*BLOCKSIZE;
	el->data.size=minnum(filesize-offset,BLOCKSIZE);
	}
void Memory::extend(OFFTYPE newsize) {
	char buf[BLOCKSIZE];
	OFFTYPE oldsize=filesize;
	BLOCKTYPE under=oldsize/BLOCKSIZE;
	Treel *el=tree.search(under);
	if(el==tree.NIL) {
		OFFTYPE begin=under*BLOCKSIZE,sizebuf=filesize-begin;
		getpart(begin,sizebuf,buf) ;
		putpart(begin,sizebuf,buf) ;
		el=tree.search(under);
		}
	filesize=newsize;
	OFFTYPE offset=under*BLOCKSIZE;
	el->data.size=minnum(filesize-offset,BLOCKSIZE);
	return;
	}
void Memory::truncatefile(OFFTYPE pos) {			/* v2 */
	Treel *el=tree.search(filesize);
	if(el!=tree.NIL) {			/**CAUTION old data is not removed. No problem: extending goes always with putpart? (extend, undo, saveall?)**/
		el->data.size=BLOCKSIZE;
		}
	filesize=pos;
	setborder(pos);
	}
SIZE_T Memory::putblockpiece(OFFTYPE  beg,SIZE_T len,char *get) {
	 BLOCKTYPE onder=beg/BLOCKSIZE;
	SIZE_T ret;
	 OFFTYPE bstart=onder*BLOCKSIZE;
	SIZE_T in=beg%BLOCKSIZE;
	Treel *el=tree.search(onder);
	SIZE_T thissize=minnum(filesize-bstart,BLOCKSIZE);
	if(el!=tree.NIL) {
		if(el->data.size<thissize) {
			fprintf(stderr,"putblockpiece " SIZE_TPRINT " (intree)!="SIZE_TPRINT " (should)\n",el->data.size,thissize);
			char *gegs=myallocar( char,BLOCKSIZE);
			char *old; 
			ret=blockreadat(gegs,thissize,bstart);
			if(ret!=thissize) {
				fprintf(stderr,"putblockpiece " SIZE_TPRINT "(read)!=" SIZE_TPRINT "(should)\n",ret,thissize);
				}
			memmove(gegs,el->data.buf,ret);
			old=el->data.buf;
			el->data.buf=gegs;
			myfree( old);
			el->data.size=ret;
			}
		memmove(el->data.buf+in,get,len);
		}
	else {
		char *gegs=myallocar( char,BLOCKSIZE); 
		ret=blockreadat(gegs,thissize,bstart);
		/*
		if(ret!=thissize) {
			fprintf(stderr,"2:putblockpiece %ld(read)!=%ld(should)\n",ret,thissize);
			}*/
		memmove(gegs+in,get,len);
		tree.insert((Data){onder,gegs,thissize});
		}
	return len;
	}

OFFTYPE Memory::search(OFFTYPE beg,char *str,int len) {
#ifdef DONTINTCURSES 
DECDEST();
#endif
	OFFTYPE ret= OFFTYPEINVALID;
		switch(lastforward&0x7) {
								//forward, icase, norm
		case 3: ret= casesearch(beg,str,len);break;
		case 1: ret= icasesearch(beg,str,len);break;
		case 7:ret= regexsearch(beg,str,len);break;
		case 5: ret= icaseregexsearch(beg,str,len);break;



		case 2: ret= backsearch(beg,str,len);break;
		case 0: ret= backicasesearch(beg,str,len);break;
		case 6: ret= backregexsearch(beg,str,len);break;
		case 4: ret= backicaseregexsearch(beg,str,len);break;
		default: ret= OFFTYPEINVALID;break;
		};
#ifdef DONTINTCURSES 
INCDEST();
#endif
	return ret;
	}


OFFTYPE Memory::nextsearch(void) {
	if(!searchstr)
		return OFFTYPEINVALID;

#ifdef DONTINTCURSES 
DECDEST();
#endif
	OFFTYPE ret= OFFTYPEINVALID;
	switch(lastforward&0x7) {
		case 3: ret= nextforwardsearch();break;
		case 1: ret= nextforwardicasesearch();break;
		case 7:
		case 5: ret= nextforwardregexsearch();break;


		case 2: ret= nextbacksearch();break;
		case 0: ret= nextbackicasesearch();break;
		case 6:
		case 4: ret= nextbackregexsearch();break;
		default: ret= OFFTYPEINVALID;break;
		};
#ifdef DONTINTCURSES 
INCDEST();
#endif
	return ret;
	}

#define MYSYNTAX (RE_BK_PLUS_QM              | RE_CHAR_CLASSES                          | RE_HAT_LISTS_NOT_NEWLINE | RE_INTERVALS                             | RE_NEWLINE_ALT)

// RE_HAT_LISTS_NOT_NEWLINE

void Memory::initsearch( void) {
	if(!searchexpr){
		if(!(searchexpr=myallocp(struct re_pattern_buffer*,struct re_pattern_buffer)))
				return;
		if(!(searchregs=myallocp(struct re_registers*,struct re_registers))) {
			myfree(searchexpr);
			return;
			}
		}
	memset(searchexpr,'\0',sizeof(struct re_pattern_buffer));
	 re_set_syntax(MYSYNTAX);
	 return;
	}
OFFTYPE Memory::backicaseregexsearch(OFFTYPE beg,char *str,int len) {
	unsigned char *ta;
	int i;
	initsearch();
	searchpos=beg;
       	if(searchstr)
       		myfree( searchstr);
       	searchstr =myallocarp(char *,char,len+1);
	memmove(searchstr,str,len);
       	searchstr[len]='\0';
	searchlen=len;
	 searchexpr->fastmap=(char *)tablebase;
	 ta=((unsigned char*)tablebase)+256;
	 for(i=0;i<0400;i++)
	 	ta[i]=i;
	 for(i='a';i<='z';i++)
	 	ta[i]=i-040;	
	 searchexpr->translate=( char*)ta;
	if((regexerrorstring=re_compile_pattern(searchstr, searchlen, searchexpr))) {
		return OFFTYPEINVALID;
	 	}
	return nextbackregexsearch(); 
	}

OFFTYPE Memory::backregexsearch(OFFTYPE beg,char *str,int len) {
	initsearch();
	searchpos=beg;
       	if(searchstr)
       		myfree( searchstr);
       	searchstr =myallocarp(char *,char,len+1);
	memmove(searchstr,str,len);
       	searchstr[len]='\0';
	searchlen=len;
	searchexpr->translate=NULL;

	if((regexerrorstring=re_compile_pattern(searchstr, searchlen, searchexpr))) {
		return OFFTYPEINVALID;
	 	}
	 searchexpr->fastmap=(char *)tablebase;
	return nextbackregexsearch(); 
	}

//	SIZE_T Memory::getblock(BLOCKTYPE blocknr,char *buf) ;

OFFTYPE Memory::nextbackregexsearch(void) {
        char buf[3][BLOCKSIZE];
	SIZE_T count,count0;
	BLOCKTYPE bl,endblock;
	SIZE_T pos;
	SIZE_T endpos,last;
	OFFTYPE end;

	end=(searchpos+(BLOCKSIZE/2));
	endblock=end/BLOCKSIZE;
	endpos=end%BLOCKSIZE;

        bl=endblock;

        count0=getblock(bl,buf[bl&1]);
	bl--;
        if(bl>=0) {
		count=getblock(bl,buf[bl&1]);
		last=searchpos-bl*BLOCKSIZE+1;
		}
	else {
		last=searchpos+1;
		count=0;
		}

	if((pos=re_search_2(searchexpr, buf[(bl)&1], count, buf[(bl+1)&1], count0,last-1,-last+1,searchregs,count+last))!=-1) {
			if(bl<0)	
				searchpos=pos;
			else
				searchpos=pos+((bl)*BLOCKSIZE);
			return searchpos--;
			}

        for(; bl>0;) {
		bl--;
		getblock(bl,buf[bl&1]);
		if((pos=re_search_2(searchexpr, buf[(bl)&1], BLOCKSIZE, buf[(bl+1)&1], BLOCKSIZE,BLOCKSIZE-1,-BLOCKSIZE+1,searchregs,2*BLOCKSIZE))!=-1) {
			searchpos=pos+((bl)*BLOCKSIZE);
			return searchpos--;
			}
		}
	return OFFTYPEINVALID;
	}
OFFTYPE Memory::regexsearch(OFFTYPE beg,char *str,int len) {
	initsearch();
	if(!searchexpr)
		return OFFTYPEINVALID;
	searchpos=beg;
       	if(searchstr)
       		myfree( searchstr);
       	searchstr =myallocarp(char *,char,len+1);
	memmove(searchstr,str,len);
       	searchstr[len]='\0';
	searchlen=len;
	searchexpr->translate=NULL;
	searchexpr->fastmap=(char *)tablebase;
	if((regexerrorstring=re_compile_pattern(searchstr, searchlen, searchexpr))) {
		return OFFTYPEINVALID;
	 	}
	return nextforwardregexsearch(); 
	}


OFFTYPE Memory::icaseregexsearch(OFFTYPE beg,char *str,int len) {
	unsigned char *ta;
	int i;
	initsearch();
	searchpos=beg;
       	if(searchstr)
       		myfree( searchstr);
       	searchstr =myallocarp(char *,char,len+1);
	memmove(searchstr,str,len);
       	searchstr[len]='\0';
	searchlen=len;
	 searchexpr->fastmap=(char *)tablebase;
	 ta=((unsigned char*)tablebase)+256;
	 for(i=0;i<0400;i++)
	 	ta[i]=i;
	 for(i='a';i<='z';i++)
	 	ta[i]=i-040;	
	 searchexpr->translate=( char*)ta;

	if((regexerrorstring=re_compile_pattern(searchstr, searchlen, searchexpr))) {
		return OFFTYPEINVALID;
	 	}
	return nextforwardregexsearch(); 
	}











OFFTYPE Memory::nextforwardregexsearch(void) {
        char buf[3][BLOCKSIZE];
	SIZE_T count,count0,pos,begin;
	BLOCKTYPE bl;

	begin=searchpos%BLOCKSIZE;
        for(bl=searchpos/BLOCKSIZE,count=getblock(bl,buf[bl&1]);	count>0;) {
		bl++;
		count0=count-begin;
		count=getblock(bl,buf[bl&1]);
		if((pos=re_search_2(searchexpr, buf[(bl-1)&1]+begin, count0, buf[bl&1], count, 0, count0-1,searchregs,count0+count))!=-1) {
			searchpos=pos+((bl-1)*BLOCKSIZE)+begin;
			return searchpos++;
			}
		begin=0;
		}
	return OFFTYPEINVALID;
	}

OFFTYPE Memory::icasesearch(OFFTYPE beg,char *str,int len) {

	int i;
	memset(tablebase,0,sizeof(tablebase));
       	if(searchstr)
       		myfree( searchstr);
       	searchstr =myallocarp(char *,char,len+1);
       	for(i=0;i<len;i++) {
       		char ch=str[i];
		table[ch]=i+1;
       		if(isup(ch)) {
       			ch=tolow(ch);
			searchstr[i]=ch;
			table[ch]=i+1;
			}
		else {
			searchstr[i]=ch;
			if(islow(ch))
				table[toup(ch)]=i+1;
			}
       		}
       	searchstr[len]='\0';
       	searchlen=len;
	searchpos=beg;
	return nextforwardicasesearch(); 
	}

OFFTYPE Memory::nextforwardicasesearch(void) {
        SIZE_T DBUFSIZE=2*BLOCKSIZE;
        char buf[3][BLOCKSIZE];
        char *start,*endstart;
	BLOCKTYPE bl;
        int i,bij=0;
	OFFTYPE endblock,ending;
	SIZE_T count;


	int endstr=searchlen-1;
        for(bl=searchpos/BLOCKSIZE,count=getblock(bl,buf[bl&1]),endblock=bl*BLOCKSIZE;	count>0;) {
                endblock+=count;
		bl++;

		count=getblock(bl,buf[bl&1]);
		endblock+=minnum(0,(count-endstr));

		ending=endblock-endstr;

                for(start=buf[0]+(searchpos%DBUFSIZE), endstart=start+(ending-searchpos) ;start<endstart;) {
                		if(table[start[endstr]]) {
                			if((bij=table[start[endstr]])==searchlen) {
						if(!strncasecmp(searchstr,start++,searchlen)) {
							searchpos=(ending-(endstart-start+1));
							return searchpos++;
							}
						}
					else
						start+=(searchlen-bij);

					}
				else
					start+=searchlen;
                                }

/*searchpos=(bl-1)*BLOCKSIZE+(start-buf[(bl-1)&1]); */
							
                for(searchpos=(ending-(endstart-start));searchpos<endblock;) {
                		if(table[buf[0][(searchpos+endstr)%(DBUFSIZE)]]) {
					if((bij=table[buf[0][(searchpos+endstr)%(DBUFSIZE)]])==searchlen) {
						for(i=0;searchstr[i]==mklow(buf[0][(searchpos+i)%(DBUFSIZE)]);i++) 
								if(i==endstr) {
									return searchpos++;
									}
						searchpos++;
						}
					else
						searchpos+=(searchlen-bij)	;
					}
				else
					searchpos+=searchlen;
				}
		}
	return OFFTYPEINVALID;
	}

OFFTYPE Memory::casesearch(OFFTYPE beg,char *str,int len) {
	int i;
	memset(tablebase,0,sizeof(tablebase));
       	for(i=0;i<len;i++) 
       		table[str[i]]=i+1;
       	if(searchstr)
       		myfree( searchstr);
       	searchstr =myallocarp(char *,char,len+1);
       	memmove(searchstr,str,len);
       	searchstr[len]='\0';
       	searchlen=len;
	searchpos=beg;
	return nextforwardsearch(); 
	}
/*
endblock: laatste begin positie in block -1
ending: laatste begin positie van search waarvan het eind in dit bloc zit
endstart: laastste start positie waarvn het eind in dit block zit

*/
#ifndef BIGGERMMAPBLOCK
#ifndef USE_MMAP
#undef FREEMMAP
#define FREEMMAP(x,y) myfree(buf)
#undef MMAP
#define MMAP(take,len ,prot  ,flag, file, off) myallocar(char,3*BLOCKSIZE)
#define mmapgetblocker(bl) ( getblock(bl,((buf+(bl&1)*BLOCKSIZE))))
#else
#define mmapgetblocker(bl) ( mmapgetblock(bl,((buf+(bl&1)*BLOCKSIZE))))
#endif
OFFTYPE Memory::nextforwardsearch(void) {
	int nommap=1;
        SIZE_T DBUFSIZE=2*BLOCKSIZE, count;
        char *buf=(char *)MMAP(0, 3*BLOCKSIZE+EXTRAMMAP,PROT_WRITE|PROT_READ  ,MAP_PRIVATE| MAP_ANON, -1, 0);
        char *start,*endstart;
	BLOCKTYPE bl;
        int i,bij=0;
	OFFTYPE endblock,ending;
	if(buf==MAP_FAILED) {
//		puts("Mmap failed");
//		fprintf(stderr,"Mmap failed");
		mmapfailed=1;
		nommap=1;
		buf=(char *)malloc(3*BLOCKSIZE+EXTRAMMAP);
		}


	int endstr=searchlen-1;
        for(bl=searchpos/BLOCKSIZE,count=mmapgetblocker(bl),endblock=bl*BLOCKSIZE;	count>0;) {
                endblock+=count;
		bl++;

		count=mmapgetblocker(bl);
		endblock+=minnum(0,(count-endstr));

		ending=endblock-endstr;

                for(start=buf+(searchpos%DBUFSIZE),endstart=start+(ending-searchpos);start<endstart;) {
                		if(table[start[endstr]]) {
                			if((bij=table[start[endstr]])==searchlen) {
						if(!memcmp(searchstr,start++,searchlen)) {
							searchpos=(ending-(endstart-start+1));
							FREEMMAP(buf, 3*BLOCKSIZE);
							return searchpos++;
							}
						}
					else
						start+=(searchlen-bij);

					}
				else
					start+=searchlen;
                                }

							
                for(searchpos=(ending-(endstart-start));searchpos<endblock;) {
                		if(table[buf[(searchpos+endstr)%(DBUFSIZE)]]) {
					if((bij=table[buf[(searchpos+endstr)%(DBUFSIZE)]])==searchlen) {
						for(i=0;searchstr[i]==buf[(searchpos+i)%(DBUFSIZE)];i++) 
								if(i==endstr) {
									FREEMMAP(buf, 3*BLOCKSIZE);
									return searchpos++;
									}
						searchpos++;
						}
					else
						searchpos+=(searchlen-bij)	;
					}
				else
					searchpos+=searchlen;
				}
		}

	FREEMMAP(buf, 3*BLOCKSIZE);
	return OFFTYPEINVALID;
	}
#else
#ifndef USE_MMAP
#undef FREEMMAP
#define FREEMMAP(x,y) myfree(buf)
#undef MMAP
#define MMAP(take,len ,prot  ,flag, file, off) myallocar(char,3*BLOCKSIZE)
#define mmapgetblocker(bl) ( getblock(bl,((buf+(bl&1)*BLOCKSIZE))))
#else
#define mmapgetblocker(bl) ( mmapgetblock(bl,((buf+(bl&1)*MMAPBLOCKSIZE))))
#endif
#define  TAKEBLOCKS 2
OFFTYPE Memory::nextforwardsearch(void) {
	int nommap=0;
        SIZE_T DBUFSIZE=2*MMAPBLOCKSIZE, count;
        char *start,*endstart;
	BLOCKTYPE bl;
        int i,bij=0;
	OFFTYPE endblock,ending;
        char *buf;
	if(mmapfailed||(buf=(char *)MMAP(0, TAKEBLOCKS*MMAPBLOCKSIZE+EXTRAMMAP,PROT_WRITE|PROT_READ  ,MAP_PRIVATE| MAP_ANON, -1, 0))==MAP_FAILED) {
	//	fprintf(stderr,"\7nextforwaredsearch MMAP failed!!!! Not searched\7");
		mmapfailed=1;
		nommap=1;
		buf=(char *)malloc(TAKEBLOCKS*MMAPBLOCKSIZE+EXTRAMMAP);
		}


	int endstr=searchlen-1;
        for(bl=searchpos/MMAPBLOCKSIZE,count=mmapgetblocker(bl),endblock=bl*MMAPBLOCKSIZE;	count>0;) {
                endblock+=count;
		bl++;

		count=mmapgetblocker(bl);
		endblock+=minnum(0,(count-endstr));

		ending=endblock-endstr;

                for(start=buf+(searchpos%DBUFSIZE),endstart=start+(ending-searchpos);start<endstart;) {
                		if(table[start[endstr]]) {
                			if((bij=table[start[endstr]])==searchlen) {
						if(!memcmp(searchstr,start++,searchlen)) {
							searchpos=(ending-(endstart-start+1));
							FREEMMAP(buf, TAKEBLOCKS*MMAPBLOCKSIZE);
							return searchpos++;
							}
						}
					else
						start+=(searchlen-bij);

					}
				else
					start+=searchlen;
                                }

/*searchpos=(bl-1)*BLOCKSIZE+(start-buf[(bl-1)&1]); */
							
                for(searchpos=(ending-(endstart-start));searchpos<endblock;) {
                		if(table[buf[(searchpos+endstr)%(DBUFSIZE)]]) {
					if((bij=table[buf[(searchpos+endstr)%(DBUFSIZE)]])==searchlen) {
						for(i=0;searchstr[i]==buf[(searchpos+i)%(DBUFSIZE)];i++) 
								if(i==endstr) {
									FREEMMAP(buf, TAKEBLOCKS*MMAPBLOCKSIZE);
									return searchpos++;
									}
						searchpos++;
						}
					else
						searchpos+=(searchlen-bij)	;
					}
				else
					searchpos+=searchlen;
				}
		}

	FREEMMAP(buf, TAKEBLOCKS*MMAPBLOCKSIZE);
	return OFFTYPEINVALID;
	}
#endif
OFFTYPE Memory::backsearch(OFFTYPE beg,char *str,int len) {
	int i;
	for(i=SCHAR_MIN;i<=SCHAR_MAX;i++)
		table[i]=-1;
       	for(i=len-1;i>=0;i--) 
       		table[str[i]]=i;
       	if(searchstr)
       		myfree( searchstr);
       	searchstr =myallocarp(char *,char,len+1);
       	memmove(searchstr,str,len);
       	searchstr[len]='\0';
       	searchlen=len;
	searchpos=beg;
	return nextbacksearch(); 
	}

OFFTYPE Memory::nextbacksearch(void) {
        char buf[3][BLOCKSIZE];
        char *start,*vorig,*huidig;
	BLOCKTYPE bl;
        int bij;
	SIZE_T count,hierin;
/**	int endstr=searchlen-1; **/

	bl=((searchpos+searchlen)/BLOCKSIZE);
	hierin=((searchpos+searchlen)%BLOCKSIZE);

	vorig=buf[bl&1];
	if(((count=getblock(bl,vorig))>0)&&(hierin>=searchlen)) {
			for(start=vorig+hierin-searchlen;start>=vorig;) {
					if(table[*start]<0)
						start-=searchlen;
					else  {
						if((bij=table[*start])) 
							start-=bij;
						else {
							if(!memcmp(searchstr,start--,searchlen)) {
								searchpos=bl*BLOCKSIZE+(start-vorig+1);
								return searchpos--;
								}
							}

						}
					}
		}
	hierin=maxnum(1,searchlen-hierin);

        for(bl-- ;(bl>=0&&(huidig=buf[bl&1],((count=getblock(bl,huidig))>0)));bl--,vorig=huidig) {
		for(start=huidig+BLOCKSIZE;hierin<searchlen;) {
			if(table[*(start-hierin)]<0)
				hierin+=searchlen;
			else  {
				if((bij=table[*(start-hierin)])) 
					hierin+=bij;
				else {
					if(!(memcmp(searchstr+hierin,vorig,(searchlen-hierin))||memcmp(searchstr,start-hierin,hierin))) {
									searchpos=bl*BLOCKSIZE+BLOCKSIZE-hierin;
									return searchpos--;
									}
					hierin++;
					}
				}
			}
		start-=hierin;
		hierin=1;

                for(;start>=huidig;) {
					if(table[*start]<0)
						start-=searchlen;
					else  {
						if((bij=table[*start])) 
							start-=bij;
						else {
							if(!memcmp(searchstr,start--,searchlen)) {
								searchpos=bl*BLOCKSIZE+(start-huidig+1);
								return searchpos--;
								}
							}

						}

                                }

		}
	return OFFTYPEINVALID;
	}


OFFTYPE Memory::backicasesearch(OFFTYPE beg,char *str,int len) {
	int i;
	for(i=SCHAR_MIN;i<=SCHAR_MAX;i++)
		table[i]=-1;
       	for(i=len-1;i>=0;i--)  {
       		table[mklow(str[i])]=i;
       		table[mkup(str[i])]=i;
       		}
       	if(searchstr)
       		myfree( searchstr);
       	searchstr =myallocarp(char *,char,len+1);
       	for(i=0;i<len;i++)
       		searchstr[i]=mklow(str[i]);
       	searchstr[len]='\0';
       	searchlen=len;
	searchpos=beg;
	return nextbackicasesearch(); 
	}

OFFTYPE Memory::nextbackicasesearch(void) {
        char buf[3][BLOCKSIZE];
        char *start,*vorig,*huidig;
	BLOCKTYPE bl;
        int bij,hierin;
	SIZE_T count=searchlen;
//	int endstr=searchlen-1;

	bl=((searchpos+searchlen)/BLOCKSIZE);
	hierin=((searchpos+searchlen)%BLOCKSIZE);

	vorig=buf[bl&1];
	if(((count=getblock(bl,vorig))>0)&&(hierin>=searchlen)) {
			for(start=vorig+hierin-searchlen;start>=vorig;) {
					if(table[*start]<0)
						start-=searchlen;
					else  {
						if((bij=table[*start])) 
							start-=bij;
						else {
							if(!strncasecmp(searchstr,start--,searchlen)) {
								searchpos=bl*BLOCKSIZE+(start-vorig+1);
								return searchpos--;
								}
							}

						}
					}
		}
	hierin=maxnum(1,searchlen-hierin);

        for(bl-- ;(bl>=0&&(huidig=buf[bl&1],((count=getblock(bl,huidig))>0)));bl--,vorig=huidig) {
		for(start=huidig+BLOCKSIZE;hierin<searchlen;) {
			if(table[*(start-hierin)]<0)
				hierin+=searchlen;
			else  {
				if((bij=table[*(start-hierin)])) 
					hierin+=bij;
				else {
					if(!(strncasecmp(searchstr+hierin,vorig,(searchlen-hierin))||strncasecmp(searchstr,start-hierin,hierin))) {
									searchpos=bl*BLOCKSIZE+BLOCKSIZE-hierin;
									return searchpos--;
									}
					hierin++;
					}
				}
			}
		start-=hierin;
		hierin=1;

                for(;start>=huidig;) {
					if(table[*start]<0)
						start-=searchlen;
					else  {
						if((bij=table[*start])) 
							start-=bij;
						else {
							if(!strncasecmp(searchstr,start--,searchlen)) {
								searchpos=bl*BLOCKSIZE+(start-huidig+1);
								return searchpos--;
								}
							}

						}

                                }

		}
	return OFFTYPEINVALID;

	}

int Memory::setsearchgegs(OFFTYPE beg,char *str,int len) {
	initsearch();
	if(!searchexpr)
			return -1;
	searchpos=beg;
       	if(searchstr)
       		myfree( searchstr);
       	searchstr =myallocarp(char *,char,len+1);
	memmove(searchstr,str,len);
       	searchstr[len]='\0';
	searchlen=len;
	searchexpr->fastmap=(char *)tablebase;
	if(casesearching(this)) 
		searchexpr->translate=NULL;
	else {
		int i;
		unsigned char *ta;
		 ta=((unsigned char*)tablebase)+256;
		 for(i=0;i<0400;i++)
			ta[i]=i;
		 for(i='a';i<='z';i++)
			ta[i]=i-040;	
		 searchexpr->translate=( char*)ta;
		}

	if((regexerrorstring=re_compile_pattern(searchstr, searchlen, searchexpr))) {
		return -1;
	 	}

	return 0;
	}

#ifdef TEST
#include "basic.h"
int main(int argc, char **argv) {
#define MAXBUF 0xffff
	int pos,len;
	char buf[MAXBUF];
	char command[256]="cat   /tmp/memoryXXXXXX",*hierfile=command+6;
	if(argc!=2) {
		fprintf(stderr,"Gebruik: %s filename\n",argv[0]);
		exit(1);
		}
	Memory mem(argv[1]);

	if(mem.error())	{
		fprintf(stderr,"%s: error \n",argv[0]);
		exit(2);
		}
	printf("size=%d\n",mem.size());
	puts("Give filepostition and lenght (pos len)");
	while(gets(buf)) {
		if(buf[0]=='q')
			break;
		if((sscanf(buf,"%d %d",&pos,&len)<2)||len>MAXBUF)
			continue;
		int handle,newlen;
		newlen=mem.getpart(pos,len,buf);
		strcpyn(hierfile+11,"XXXXXX",239);
		if(!(mktemp(hierfile)))
			fatal("tmpnam(/tmp/memory) fails\n");
		puts(hierfile);
		if((handle=creat(hierfile,0600))<0)
			fatal("creat(%s)\n",hierfile);
		write(handle,buf,newlen);
		LCLOSE(handle);
		system(command);
		if((handle=LOPEN(hierfile,O_RDONLY BINARY_FLAG))<0)
			fatal("Can't open %s for readonly\n",hierfile);
		seekread(handle,0L,SEEK_SET,buf,newlen);
		LCLOSE(handle);
		len=mem.putpart(pos,len,buf);
		puts("Give filepostition and lenght (pos len)");
		}
	mem.tree.showtree();
	puts("Save file (j/n)");
	gets(buf);
	if(buf[0]=='j') {
		mem.saveall();
		puts("Saved");
		}
	mem.tree.showtree();
	return 0;
	}
#endif
