/*
*
@(SH) Funzioni per la gestione dei file ISAM
@(C$) PRIVATE
logname         : nome del file di LOG (GIORNALE)
INTTLOCK        : costante che indica alla funzione di lettura che e' stata chaimata dalla funzione di scrittura e quindi deve solo controllare lo stato di lock del record
ISLOCKED        : costante che indica che il record e' bloccato
@(VG$) PRIVATE
KSv, PosSv      : variabili di lavoro
PagSv, IndSv    : variabili di lavoro
IndActive       : stato indici  - TRUE = Aggiornati ad ogni modifica, FALSE = aggiorna solo i dati
isstate         : Stato transazione corrente
win,wisfd       : variabili di lavoro
isjournal       : TRUE scrive il giornale
openf : array di TUTTI i puntatori ai descrittori dei file ISAM aperti
-------------------------------------------------------------------------------
*/
#include                                "cisam.h"
#include                                "libdefs.h" 
#include 					"checks.h"
#include                                <memory.h>
#define logname                         "log.gen"
#define INTTLOCK                        0xF000
#define ISLOCKED                        225
#define NOALLOC                 (char **) -1
	TKey                            KSv;
	int                                     PosSv;
	RecNoType               PagSv,IndSv;
	BOOLEAN         IndActive = TRUE;
	int                                     isstate = NOTRANS ;
	int                     wln = -1;
	isfdptr wisfd;
	extern  BOOLEAN isjournal;
/* Guy moved them here from extcdecl.h */
  Str80    cprefix;
  isfdptr* openf;
	void    savekeystat(isdef *);
	void    restkeystat(isdef *,int );
	int             addkeys(isdef *,RecType ,int ,int *);
	int             delkeys(isdef *,RecType ,int ,int *);
	int             replkeys(isdef *,RecType ,RecType ,int ,int *);
#ifndef DOS
	void writeundo(int ,isdef *,RecType);
	void writelog(int ,isdef *,RecType);
	char *undoname(void);
	void getopenf(int ,RecType *);
#endif
/*
@($) savekeystat  ISAM
@(ID)
Salva la chiave corrente.
@(FD)
*/
	void savekeystat(isfd)
	isfdptr isfd;    /* descrittore del file ISAM */
		{
			strcpy(KSv,isfd->i.Key);
			IndSv = isfd->i.Ind;
			PosSv = isfd->i.Pos;
			PagSv = isfd->i.CurPag;
		}
/*
@($) restkeystat  ISAM
@(ID)
Ripristina la chiave corrente.
@(FD)
*/
	void restkeystat(isfd,knum)
	isfdptr isfd;  /* descrittore del file ISAM */
	int                     knum;  /* numero della chiave                    */
		{
			isfd->i.PN = knum - 1;
			strcpy(isfd->i.Key,KSv);
			isfd->i.Ind = IndSv;
			isfd->i.Pos     = PosSv;
			isfd->i.CurPag = PagSv;
		}
/*
@($) relisfd  ISAM
@(ID)
Vuota il descrittore del file .
@(FD)
*/
	void relisfd(isfd)
	isfdptr                 *isfd; /* descrittore del file ISAM */
	{
		free((char *) (*isfd)->d);
		free((char *) (*isfd)->r);
		free((char *) (*isfd));
	}
/*
@($) getisfd  ISAM
@(ID)
Alloca e carica il descrittore del file con numero logico "logicname".
@(FD)
*/
	void getisfd(isfd, logicname)
	isdef                           **isfd;    /* descrittore del file ISAM                   */
	int                                     logicname; /* numero logico del file */
	{
		(*isfd) = (isfdptr) malloc(sizeof(**isfd));
		(*isfd)->d = (FileDes *) malloc(sizeof(*((*isfd)->d)));
		(*isfd)->r = (RecDes *) malloc(sizeof(*((*isfd)->r)));
		COpenDir(ManuLock, NORDIR);
		CGetFile(logicname, (*isfd)->d, NoLock, NORDIR);
		if ((!(STREMPTY((*isfd)->d->SysName))) && ((*isfd)->d->SysName[0] ==  '%'))
			(*isfd)->ft = COMDIR;
		else
			(*isfd)->ft = NORDIR;
		CCloseDir(NORDIR);
		COpenDir(ManuLock, (*isfd)->ft);
		COpenFile(logicname, (*isfd)->d, NoLock, (*isfd)->ft);
		CCloseDir((*isfd)->ft);
		COpenRecDir(ManuLock, (*isfd)->ft);
		CGetRec(logicname,(*isfd)->r, (*isfd)->ft);
		CCloseRecDir((*isfd)->ft);
	}
	/*void dump(s,l)
	RecType s;
	int                     l;
	{
			message_box("dump : record:  %s ", &s[1]);
	}*/
/*
@(#) cisupdflags  ISAM
@(ID)
Aggiorna all'interno del direttorio i campi EOD e Flags.
Ritorna il codice di errore.
@(FD)
@(ISV)
wd   = riga relativa al file ISAM in oggetto nel Direttorio.
fdir = identificatore del file direttorio.
- Versione DOS e XENIX
@(FSV)
@(IN)
Il campo Flags viene aggiornato comunque, mentre EOD viene aggiornato solo
se il parametro di input "updateeod" e' TRUE.
@(FN)
*/
	int cisupdflags(isfd,err,updateeod)
	isdef                           *isfd; /* puntatore al descrittore del file ISAM */
	int                                     *err;  /* codice di errore                                      */
	BOOLEAN                 updateeod; /* se TRUE si aggiorna anche EOD                     */

	{
		FileDes         wd;

		*err = NoErr ;
		if (isfd->ln <= 0) return(*err) ;
		COpenDir( ManuLock, isfd->ft);
		COpenFile(isfd->ln, &wd, Lock, isfd->ft);
		if ((*err = fdir[isfd->ft].IOR) == NoErr)
		{
			wd.Flags = isfd->d->Flags;
/* #ifdef DOS
			if (updateeod) wd.EOD = isfd->d->EOD;
 #else */
			if ((updateeod) && (isfd->f.LockMode == ExclLock)) wd.EOD = isfd->d->EOD;
/* #endif  */
			CCloseFile(isfd->ln, &wd, isfd->ft);
		}
		CCloseDir(isfd->ft);
		return(*err);
	}

/*
@(#) cisgeteod  ISAM

@(ID)
Ritorna l' EOD del file.
@(FD)

@(ISV)

- Versione DOS e XENIX
@(FSV)

*/

	RecNoType cisgeteod(isfd,err)
	isfdptr                 isfd; /* puntatore al descrittore del file ISAM */
	int                                     *err;  /* codice di errore                                      */

	{

		*err = NoErr ;
		if (isfd->ln > 0)
		{
			COpenDir( ManuLock , isfd->ft);
			COpenFile(isfd->ln, isfd->d, NoLock, isfd->ft);
			CCloseDir(isfd->ft);
		}
		return(isfd->d->EOD) ;
	}

/*
@(#) cisopen  ISAM

@(ID)
Apre un file ISAM e alloca il buffer per un record a attiva la chiave 1 (uno).
Ritorna il codice di errore.
@(FD)

@(ISV)
werr  = variabile di lavoro che raccoglie il codice errore proveniente dalla CBCloseFile.

s = stringa di lavoro  per messaggi di errore.

- Versione DOS e XENIX
@(FSV)

@(IN)
@(FN)
*/

	int cisopen (isfd,logicname,record,mode,err)
	isfdptr                         *isfd; /* puntatore al descrittore del file */
	int                                             logicname; /* numero logico                               */
	RecType                         *record;   /* buffer per contenere un record              */
	unsigned int    mode;      /* modo di apertura (lock)                     */
	int                                             *err;      /* codice di errore                            */

	{
		*err = NoErr;
		if (openf[logicname - 1] != NULL)
			fatal_box("File n. %d already open", logicname);
#ifndef DOS
		if ((excllock(CInsPref(glockname, NORDIR), FALSE) == -1) && (errno == EACCES))
		  fatal_box("Can't open directory : Error n. %d ", errno);
#endif
		getisfd (isfd,logicname);
		COpen(&((*isfd)->f), (*isfd)->d->SysName, (*isfd)->d->LenR, 0, mode);
		if (*err = (*isfd)->f.IOR)
		{
			Str80 name; strcpy(name, (*isfd)->d->SysName);
			relisfd(isfd);
		  fatal_box("Can't open file n. %d (%s): error %d ", 
			    logicname, name, *err);
		}
		if ((*isfd)->r->NKeys)
		{
			Str80 name; strcpy(name, CGetIdxName((*isfd)->d->SysName));
			CBOpenFile (&((*isfd)->i), name, mode, err);
			if (*err)
			{
				CClose(&((*isfd)->f));
				relisfd(isfd);
				fatal_box("Can't open file n. %d (%s): error %d ", 
					  logicname, name, *err);
			}
#ifndef DOS
			else
				if (mode == ExclLock)
				{
					CBLockFile(&((*isfd)->i), err);
					if (*err)
					{
			int werr;
						CClose(&((*isfd)->f));
						CBCloseFile(&((*isfd)->i), &werr);
						relisfd(isfd);
						fatal_box("Can't open exclusively file n. %d: error %d ", logicname, *err);
					}
				}
#endif
		}
		if (record != NOALLOC)
			*record = (RecType) malloc((*isfd)->d->LenR);
		(*isfd)->ln = logicname;
		openf[logicname - 1] = *isfd;
		if ((*isfd)->r->NKeys) (*isfd)->i.PN = 0;
		return (*err);
	}

/*
@(#) ciscopyrec  ISAM

@(ID)
Copia un record dati da un record ad un altro.
Ritorna il codice di errore.
@(FD)

@(ISV)
d = riga del direttorio corrispondente al file in esame.
@(FSV)

@(IN)
@(FN)
*/

	int ciscopyrec(logicname,recdest, recsrc ,err)
	int                                             logicname; /* numero logico del file ISAM */
	RecType                         recdest;   /* buffer destinazione         */
	RecType                         recsrc;    /* buffer sorgente             */
	int                                             *err;      /* codice di errore            */

	{
		FileDes d;
		int                     ft;

		*err = NoErr;
		if (logicname < 0) logicname = -logicname;
		if (openf[logicname - 1] != NULL) d = *(openf[logicname - 1]->d);
		{
			COpenDir(ManuLock, NORDIR);
			CGetFile(logicname, &d, NoLock, NORDIR);
			if ((!(STREMPTY(d.SysName))) && (d.SysName[0] ==  '%')) ft = COMDIR;
			else ft = NORDIR;
			CCloseDir(NORDIR);
			COpenDir(ManuLock, ft);
			COpenFile(logicname, &d, NoLock, ft);
			CCloseDir(ft);
		}
		memcpy(recdest, recsrc, d.LenR);
		return(*err);
	}

/*
@(#) cisallocrec  ISAM

@(ID)
Alloca il buffer per un record.
Ritorna il codice di errore.
@(FD)

@(ISV)
d = riga del direttorio corrispondente al file in esame.
@(FSV)

@(IN)
@(FN)
*/

	int cisallocrec(logicname,record,err)
	int                                             logicname;  /* numero logico del file ISAM */
	RecType                         *record;    /* buffer per il record        */
	int                                             *err;       /* codice di errore            */

	{
		FileDes d;
		int                     ft;

		*err = NoErr;
		if (logicname < 0) logicname = -logicname;
		if (openf[logicname - 1] != NULL) d = *(openf[logicname - 1]->d);
		else
		{
			COpenDir(ManuLock, NORDIR);
			CGetFile(logicname, &d, NoLock, NORDIR);
			if ((!(STREMPTY(d.SysName))) && (d.SysName[0] ==  '%')) ft = COMDIR;
			else ft = NORDIR;
			CCloseDir(NORDIR);
			COpenDir(ManuLock, ft);
			COpenFile(logicname, &d, NoLock, ft);
			CCloseDir(ft);
		}
		*record = (RecType) malloc(d.LenR);
		if (*record == ((RecType) NULL)) return(ENOMEM);
		else return(*err);
	}

/*
@(#) cisclose  ISAM

@(ID)
Chiude un file ISAM e libera il buffer del record.
Ritorna il codice di errore.
@(FD)

@(ISV)
werr  = variabile di lavoro che raccoglie il codice errore proveniente dalla CBCloseFile.

s[20] = stringa di lavoro  per messaggi di errore.

- Versione DOS e XENIX
@(FSV)

@(IN)
Restituisce il codice di errore 
@(FN)
*/

	int cisclose(isfd,rec,err)
	isdef           **isfd; /* puntatore al descrittore del file */
	RecType *rec;   /* buffer per il record                            */
	int                     *err;   /* codice di errore                                */

	{
		int     werr = NoErr;

		*err = NoErr;
		if (((*isfd)->ln > 0) && ((*isfd == NULL) || (openf[(*isfd)->ln - 1] == NULL)))
		{
			if (*isfd != NULL) 
			  error_box("File n. % isclose : Error n. %d ", (*isfd)->ln, IsNotOpen);
			else 
			  error_box("isclose : errore n. %d ", IsNotOpen);
		}
		CClose(&((*isfd)->f));
		*err = ((*isfd)->f.IOR);
		if ((*isfd)->r->NKeys) 
		{
			CBCloseFile(&((*isfd)->i), &werr);
			if (werr != NoErr ) *err = werr;
		}
		if ((*isfd)->ln > 0)
			openf[(*isfd)->ln - 1] = NULL ;
		if ((rec != NULL) && (*rec != NULL))
			free(*rec);
		relisfd(isfd);
#ifndef DOS
		exclunlock(CInsPref(glockname, NORDIR), FALSE);
#endif
		if (*err)
		  fatal_box("isclose : Error n. %d ", *err);
		return (*err);
	}

/*
@(#) cisstart  ISAM

@(ID)
Esegue una lettura cambiando il numero di chiave attiva.
Ritorna il codice di errore.
@(FD)

@(IN)
	La variabile record in input contiene i campi necessari per la ricerca,
	in output contiene il record letto.

	La variabile mode e' formata da un comando di lock + comando di posizionamento
	. Se non si utilizza ISEQUAL o ISGREAT o ISGTEQ, il valore della variabile
	record non ha nessuna importanza.
@(FN)
*/

	int cisstart(isfd,keynum,record,mode,err)
	isfdptr                         isfd;   /* descrittore del file ISAM */
	int                                             keynum; /* numero della chiave                    */
	RecType                         record; /* buffer per il record */
	unsigned int    mode;   /* comando di lettura */
	int                                             *err;   /* codice di errore                       */

		{
			if(isfd == ((isfdptr) NULL)) return ((*err = IsNotOpen));
			*err = NoErr;
			if(!(keynum >= 1) && (keynum <= isfd->r->NKeys))
				return((*err = BTrPathErr));
			isfd->i.PN = keynum - 1;
			*err = cisread(isfd,record,mode,err);
			return(*err);
		}

/*
@(#) cisread  ISAM

@(ID)
Esegue una lettura utilizzando la chiave attiva.
Ritorna il codice di errore.
@(FD)

@(ISV)
rmode = variabile che contiene il tipo lettura utilizzato.

lmode = varibaile dhe contiene il tipo lock utilizzato.

knum  = numero chiave attiva.

junk  = variabile spazzatura per la chiamata alla funzione "sleep".

times = variabile di lavoro.

s = stringa contenente messaggio.

w     = descrittore finestra .

internaltlock = flag che verifica se la isread e' stata chiamata da iswrite per testare l' esistenza di un record.

@(FSV)

@(IN)
	La variabile record in input contiene i campi necessari per la ricerca,
	in output contiene il record letto.

	La variabile mode e' formata da un comando di lock + comando di posizionamento
	. Se non si utilizza ISEQUAL o ISGREAT o ISGTEQ, il valore della variabile
	record non ha nessuna importanza.
@(FN)
*/

	int cisread(isfd,record,mode,err)
	isfdptr                         isfd;  /* descrittore del file ISAM             */
	RecType                         record;/* buffer per il record                               */ 
	unsigned int    mode;  /* modo di lettura */
	int                                             *err;  /* codice di errore                                   */

		{
			unsigned int     rmode = (mode & READTYPES),
					lmode = (mode & RecLockTypes),
					knum = (isfd->i.PN+1);
			int     junk,times = 1;
			TKey key,key1,key2;
/*			char    s[120]; */
		  BOOLEAN        internaltlock   = (lmode == INTTLOCK);

				if (internaltlock) lmode = ShareLock;
			*err = NoErr ;
			if (isfd == ((isfdptr) NULL)) return ((*err = IsNotOpen));
			if (rmode & (IsPrevN + IsNextN))
			{
				times = rmode & BYTEMASK;
				if (rmode & IsPrevN) rmode = IsPrev;
				else rmode = IsNext;
			}
			if (rmode == IsCurr)
			{
				if (!isfd->RecNo) return((*err = IsNotCurr));
			}
			else
			{
				if (rmode == IsNext)
				{
					while ((times--) && (!*err))
					{
						CBNext(&isfd->i,knum,key1,&isfd->RecNo,err);
					}
				}
				else
				{
					if (rmode == IsPrev) 
					{
						while ((times--) && (!*err))
						{
							CBPrev(&isfd->i,knum,key1,&isfd->RecNo,err);
						}
					}
					else
					{
						if (rmode == IsFirst) MinKey(CCalcLenKey(isfd->r,knum),key);
						else
							if (rmode == IsLast) MaxKey(CCalcLenKey(isfd->r,knum),key);
							else
								CBuildKey(isfd->r,knum,record,key);
						CBRead(&isfd->i,knum,key,key1,&isfd->RecNo,err);
						if ((rmode == IsGreat) && (!*err))
							while ((strcmp(key,key1) == 0) && (!*err))
								CBNext (&isfd->i,knum,key1,&isfd->RecNo,err);
					}
				}
			}
			do
			{
				if (((*err) && (rmode == IsEqual)) ||
						((*err == BTrEOF) && (rmode == IsGreat)))
					CRead(&isfd->f,record,isfd->RecNo,NoLock);
				else
					CRead(&isfd->f,record,isfd->RecNo,lmode);
				if (TESTLOCK(isfd->f.IOR))
				{
					if (lmode == ShareLock)
					{
						if (!*err) *err = ISLOCKED;
						break;
					}
					message_box("Codice %s in uso da parte\ndi un altro utente.", key1);
					if (rmode != IsCurr)
					{
						CBReRead(&isfd->i,knum,key1,key2,isfd->RecNo,&isfd->RecNo,&junk);
						if (junk) strcpy(key1, key2) ;
					}
				}
				else 
					if (!*err) *err = isfd->f.IOR;
			} while (TESTLOCK(isfd->f.IOR)) ;
			if (((rmode == IsFirst) || (rmode == IsLast)) && (*err != BTrEmptyTree))
				*err = NoErr;
			if ((rmode == IsGtEq) && (*err != BTrEOF) && (*err != BTrEmptyTree))
				*err = NoErr ;
			if (DEADLOCK(*err)) return(*err = IsDeadLock);
			if (rmode == IsCurr)
			{
				CBuildKey(isfd->r,knum,record,key);
				CBReRead(&isfd->i,knum,key,key1,isfd->RecNo,&isfd->RecNo,&junk);
			}
			if (*err == BTrEmptyTree) CZeroRec(isfd->r, record);
			return(*err);
		}

/*
@($) addkeys  ISAM

@(ID)
Aggiunge all'indice le chiavi contenute nel record.
Ritorna il codice di errore.
@(FD)

@(ISV)
i,j  = contatori.

werr = codice errore restituito dalla CBDelete.

key  = valore delle chiavi.
@(FSV)

@(IN)
@(FN)
*/

	int addkeys (isfd,record,knum,err)
	isfdptr                 isfd;   /* descrittore del file ISAM */
	RecType                 record; /* buffer per il record            */
	int                                     knum;   /* numero chiave corrente                 */
	int                                     *err;   /* codice errore                          */

		{
			int     i,j,werr;
			TKey    key;

			for (i = 1;(i <= isfd->r->NKeys) && (!*err);i++)
			{
				CBuildKey(isfd->r,i,record,key);
				CBWrite(&isfd->i,i,key,isfd->RecNo,err);
				if (i == knum) savekeystat(isfd);
			}
			if (*err)
			{
				if (i == 2 && *err == BTrDupKeysNotAll) *err = IsReInsert;
				for (j = 1; (j < i); j++)
				{
					CBuildKey(isfd->r,j,record,key);
					CBDelete(&isfd->i,j,key,isfd->RecNo,&werr);
				}
			}
			else restkeystat(isfd,knum);
			return(*err);
		}

/*
@(#) ciswrite  ISAM

@(ID)
Aggiunge  un nuovo record al file ISAM.
Ritorna il codice di errore.
@(FD)

@(ISV)
werr = codice errore restituito.

knum = numero chiave attiva.

junk = variabile di lavoro per la chiamata di varie funzioni.

wrec = buffer di lavoro.
@(FSV)

@(IN)
	La variabile record in input contiene il record da aggiungere.
@(FN)
*/
			
	int ciswrite (isfd,record,err)
	isfdptr                 isfd;   /* descrittore del file ISAM    */
	RecType                 record; /* buffer per il record */
	int                                     *err;   /* codice di errore                             */

		{
			int                     knum = (isfd->i.PN+1), werr, junk;
			RecType wrec;
			RecNoType       neweox;

			*err = NoErr;
			if(isfd == ((isfdptr) NULL)) return((*err = IsNotOpen));
			if (isfd->ln > 0)
			{
				COpenDir (ManuLock, isfd->ft);
				COpenFile(isfd->ln,isfd->d, Lock, isfd->ft);
			}
			if (isfd->d->EOD == isfd->d->EOX)
			{
				neweox  = isfd->d->EOX / 20 + 1;
				if (neweox < 10) neweox = 10;
				if (demoflag)
					*err = IsFileFull;
				else
				{
					neweox += isfd->d->EOX;
					cisextend(isfd, isfd->ln, neweox, err);
				}
				if (*err == NoErr)
				{
					if (isfd->ln > 0)
					{
						COpenFile(isfd->ln,isfd->d, NoLock, isfd->ft);
						for (junk = 0; junk < isfd->r->NKeys; junk++)
							isfd->i.Base[junk].PEOX = neweox;
					}
					else
					{
						isfd->d->EOX = neweox;
						if (isfd->f.LockMode == ExclLock)
							for (junk = 0; junk < isfd->r->NKeys; junk++)
								isfd->i.Base[junk].PEOX = neweox;
					}
				}
				else
				{
					if (isfd->ln > 0)
					{
						COpenFile(isfd->ln,isfd->d, UnLock, isfd->ft);
						CCloseDir(isfd->ft);
					}
					isfd->RecNo = 0;
					if (DEADLOCK(*err)) *err = IsDeadLock;
					return((*err ? *err : (*err = IsFileFull)));
				}
			}
			IRecallRec(record);
			if (test_share() && isfd->f.LockMode != ExclLock)
			{
				wrec = malloc(isfd->d->LenR);
				memcpy(wrec, record, isfd->d->LenR);
				savekeystat(isfd);
				junk = cisstart(isfd, 1, wrec, INTTLOCK+IsEqual, &junk);
				restkeystat(isfd, knum);
				if ((junk == NoErr) || (junk == ISLOCKED))
				{
					*err = IsReInsert;
					if (isfd->ln > 0)
					{
						COpenFile(isfd->ln,isfd->d, UnLock, isfd->ft);
						CCloseDir(isfd->ft);
					}
					isfd->RecNo = 0;
					return(*err);
				}
				free(wrec);
			}
			isfd->RecNo = (++isfd->d->EOD);
			if ((isfd->r->NKeys) && IndActive) 
			{
				if(test_share() && isfd->f.LockMode != ExclLock)
					CBLockFile(&isfd->i,err) ;
				if (!addkeys(isfd, record, knum, err))
				{
					CWrite(&isfd->f,record,isfd->RecNo,NoLock);
					if ((*err = isfd->f.IOR))
					{
						isfd->RecNo = 0;
						junk = delkeys(isfd, record, knum, &werr);
					}
					else
						if (isfd->ln > 0)
							CCloseFile(isfd->ln,isfd->d, isfd->ft) ;
				}
				else isfd->d->EOD-- ;
				if(test_share() && isfd->f.LockMode != ExclLock)
					CBUnLockFile(&isfd->i, &werr) ;
			}
			else
			{
				CWrite(&isfd->f,record,isfd->RecNo,NoLock);
				if ((*err = isfd->f.IOR)) isfd->RecNo = 0;
				else CCloseFile(isfd->ln,isfd->d, isfd->ft) ;
			}
			if (!(*err))
			{
#ifndef DOS
				if (isstate == NOTRANS) writelog(FNWRITE, isfd, record);
				else writeundo(FNWRITE, isfd, record);
#endif
			}
			if (isfd->ln > 0)
				CCloseDir(isfd->ft);
			if (test_share())
			{
			  junk = cisunlock(isfd, &junk);
			  if (isstate == NOTRANS)
			    CLockRec(&isfd->f,isfd->RecNo,UnLock);
			  if (DEADLOCK(*err)) *err = IsDeadLock;
		        }
			return(*err);
		}

/*
@($) delkeys  ISAM

@(ID)
Cancella le chiavi contenute nel record dall'indice.
Ritorna il codice di errore.
@(FD)

@(ISV)
i,j  = contatori.

werr = codice errore da CBWrite.

key  = valori chiave.
@(FSV)

@(IN)
@(FN)
*/

	int delkeys (isfd,record,knum,err)
	isfdptr                 isfd;   /* descrittore del file ISAM */
	RecType                 record; /* buffer per il record            */
	int                                     knum;   /* numero della chiave attuale            */
	int                                     *err;   /* codice di errore                       */

		{
			int     i,j,werr;
			TKey    key;

			for (i = 1;(i <= isfd->r->NKeys)&&(!*err);i++)
			{
				CBuildKey(isfd->r,i,record,key);
				CBDelete(&isfd->i,i,key,isfd->RecNo,err);
				if (i == knum) savekeystat(isfd);
			}
			if (*err)
			{
				for (j = 1;(j < i);j++)
				{
					CBuildKey(isfd->r,j,record,key);
					CBWrite(&isfd->i,j,key,isfd->RecNo,&werr);
				}
			}
			else restkeystat(isfd,knum);
			return(*err);
		}

/*
@(#) cisdelete  ISAM

@(ID)
Cancella un record da un file ISAM.
Ritorna il codice di errore.
@(FD)

@(ISV)
knum = numero chiave successiva a quella attiva.

werr = codice errore da CBUnLockFile.

key1,key = valori chiave.

- Versione DOS e XENIX
@(FSV)

@(IN)
	La variabile record in input contiene il record da cancellare.
@(FN)
*/

	int cisdelete(isfd,record,err)
	isfdptr                 isfd;   /* descrittore del file ISAM */
	RecType                 record; /* buffer per il record            */
	int                                     *err;   /* codice di errore                       */

	{
		int             knum = (isfd->i.PN+1), werr;
		TKey    key,key1;

		if(isfd == ((isfdptr) NULL)) return((*err = IsNotOpen));
		*err = NoErr;
		savekeystat(isfd);
		CBuildKey(isfd->r,1,record,key);
		*err = NoErr ;
		CBRead(&isfd->i,1,key,key1,&isfd->RecNo,err);
		if (*err)
		{
			restkeystat(isfd,knum);
			return(*err);
		}
		CRead(&isfd->f, record, isfd->RecNo, NoLock);
		if ((*err = isfd->f.IOR))
		{
			restkeystat(isfd,knum);
			return(*err);
		}
		if ((isfd->r->NKeys) && IndActive)
		{
			if(test_share() && isfd->f.LockMode != ExclLock)
				CBLockFile(&isfd->i,err) ;
			delkeys(isfd, record, knum, err) ;
		}
		IDeleteRec(record);
		CWrite(&isfd->f,record,isfd->RecNo,UnLock);
		if((*err = isfd->f.IOR))
		{
			IRecallRec(record);
			CWrite(&isfd->f,record,isfd->RecNo,NoLock);
			if ((isfd->r->NKeys) && IndActive) addkeys(isfd, record, knum, err) ;
			restkeystat(isfd,knum);
		}
#ifndef DOS
		else
		{
			if (isstate == NOTRANS)
			{
				writelog(FNDELETE, isfd, NULL);
				CRead(&isfd->f,record,isfd->RecNo,UnLock);
			}
			else writeundo(FNDELETE, isfd, NULL);
		}
		if (test_share() && (isfd->r->NKeys) && IndActive &&
		    (isfd->f.LockMode != ExclLock)) 
			CBUnLockFile(&isfd->i, &werr) ;
#else
		if (test_share())
		{
		  CRead(&isfd->f,record,isfd->RecNo,UnLock);
		  if (isfd->r->NKeys && IndActive && 
		      (isfd->f.LockMode != ExclLock))
			CBUnLockFile(&isfd->i, &werr) ;
	        }
#endif
		return(*err);
	}

/*
@($) replkeys  ISAM

@(ID)
Rimpiazza le chiavi all'interno dell'indice.
Ritorna il codice di errore.
@(FD)

@(ISV)
i,j      = contatori.

werr     = codice errore ritornato da CBDelete e  CBWrite.

key,key1 = valori delle chiavi.
@(FSV)
*/

	int replkeys (isfd,oldrec,record,knum,err)
	isfdptr                 isfd;   /* descrittore del file ISAM */
	RecType                 oldrec; /* buffer contenente il vecchio record    */
	RecType                 record; /* buffer contenente il nuovo record */
	int                                     knum;   /* numero della chiave attuale            */
	int                                     *err;   /* codice di errore                       */

		{
			int     i,j,werr;
			TKey    key,key1;

			for (i = 1;(i <= isfd->r->NKeys)&&(!*err);i++)
			{
				CBuildKey(isfd->r,i,record,key);
				CBuildKey(isfd->r,i,oldrec,key1);
				if (strcmp(key,key1) != 0)
				{
					CBDelete(&isfd->i,i,key1,isfd->RecNo,err);
					if (*err) break;
					CBWrite(&isfd->i,i,key,isfd->RecNo,err);
					if (*err) CBWrite(&isfd->i,i,key1,isfd->RecNo,err);
					if (i == knum) savekeystat(isfd);
				}
			}
			if (*err)
			{
				for (j = 1;(j < i);j++)
				{
					CBuildKey(isfd->r,j,record,key);
					CBuildKey(isfd->r,j,oldrec,key1);
					if (strcmp(key,key1) != 0)
					{
						CBDelete (&isfd->i,j,key,isfd->RecNo,&werr);
						CBWrite(&isfd->i,j,key1,isfd->RecNo,&werr);
					}
				}
			}
			else restkeystat(isfd,knum);
			return(*err);
		}

/*
@(#) cisrewrite  ISAM

@(ID)
Aggiorna un record nel file ISAM.
Ritorna il codice di errore.
@(FD)

@(ISV)
knum = numero chiave successiva all'attuale.

werr = codice errore restituito da  CBUnLock.

key, key1 = valori delle chiavi.

oldrec    = buffer di lavoro.

- Versione DOS e XENIX
@(FSV)

@(IN)
	La variabile record in input contiene il record da aggiornare.
Utilizza la chiave 1 per  ritrovare il record da aggiornare.
@(FN)
*/

	int cisrewrite(isfd,record,err)
	isfdptr                 isfd;   /* descrittore del file isam  */
	RecType                 record; /* buffer contenente i record              */
	int                                     *err;   /* codice di errore                        */

		{
			int                     knum = (isfd->i.PN+1), werr;
			TKey            key,key1;
			RecType oldrec;

			*err = NoErr ;
			if(isfd == ((isfdptr) NULL)) return((*err = IsNotOpen));
			oldrec = (RecType) malloc(isfd->d->LenR);
			savekeystat(isfd);
			IRecallRec(record);
			CBuildKey(isfd->r,1,record,key);
			CBRead(&isfd->i,1,key,key1,&isfd->RecNo,err);
			if(*err)
			{
				restkeystat(isfd,knum);
				return(*err);
			}
			CRead(&isfd->f,oldrec,isfd->RecNo,NoLock);
			if ((*err = isfd->f.IOR))
			{
				restkeystat(isfd,knum);
				free(oldrec);
				return(*err);
			}
			if (memcmp(oldrec,record,isfd->d->LenR) == 0)
			{
				*err = NoErr;
				restkeystat(isfd,knum);
				CLockRec(&isfd->f,isfd->RecNo,UnLock);
				free(oldrec);
				return(*err);
			}
			if ((isfd->r->NKeys) && IndActive)
			{
				if(test_share() && isfd->f.LockMode != ExclLock)
					CBLockFile(&isfd->i, err) ;
				replkeys(isfd, oldrec, record, knum, err) ;
				if(test_share() && isfd->f.LockMode != ExclLock)
					CBUnLockFile(&isfd->i, &werr) ;
			}
			CWrite(&isfd->f,record,isfd->RecNo,NoLock);
			if ((*err = isfd->f.IOR))
			{
				CWrite(&isfd->f,oldrec,isfd->RecNo,NoLock);
				replkeys(isfd, record, oldrec, knum, err) ;
				restkeystat(isfd,knum);
			}
			else
#ifndef DOS
			{
				if (isstate == NOTRANS) 
				{
					writelog(FNREWRITE, isfd, record);
					CLockRec(&isfd->f,isfd->RecNo,UnLock);
				}
				else writeundo(FNREWRITE, isfd, oldrec);
			}

#else
			if (test_share())
			  CLockRec(&isfd->f,isfd->RecNo,UnLock);
#endif
			free(oldrec);
			return(*err);
		}

/*
@(#) cisdelcurr  ISAM

@(ID)
Cancella il record corrente.
Ritorna il codice di errore.
@(FD)
*/

	int cisdelcurr(isfd,err)
	isfdptr                 isfd; /* descrittore del file ISAM */
	int                                     *err; /* codice di errore                       */

		{
			if(isfd->RecNo) cisdelrec(isfd,isfd->RecNo,err);
			else *err = IsNotCurr;
			return(*err);
		}

/*
@(#) cisrewcurr  ISAM

@(ID)
Riscrive il record corrente.
Ritorna il codice di errore.
@(FD)

@(IN)
	La variabile record in input contiene il record da aggiornare.
@(FN)
*/

	int cisrewcurr(isfd,record,err)
	isfdptr                 isfd;   /* descrittore del file ISAM */
	RecType                 record; /* buffer contenente il record            */
	int                                     *err;   /* codice di errore                       */

		{
			if(isfd->RecNo) cisrewrec(isfd,isfd->RecNo,record,err);
			else *err = IsNotCurr;
			return (*err);
		}

/*
@(#) cisreadrec  ISAM

@(ID)
Legge un record di numero "recnum".
Ritorna il codice di errore.
@(FD)
*/

	int cisreadrec(isfd,recnum,record,mode,err)
	isfdptr                         isfd;   /* descrittore del file ISAM */
	RecNoType                       recnum; /* numero del record                      */
	RecType                         record; /* buffer per il record            */
	unsigned int    mode;   /* modo di lock                           */
	int                                             *err;   /* codice di errore                       */

		{
			isfd->RecNo = recnum;
			return(cisread(isfd,record,IsCurr+(mode & RecLockTypes),err));
		}

/*
@(#) ciswriterec  ISAM

@(ID)
Riscrive un record di numero "recnum".
@(FD)

@(IN)
	La variabile record in input contiene il record da aggiornare.
@(FN)

@(ISV)
knum   = numero chiave attiva.

werr   = codice errore restituito da CBUnLockFile.

oldrec = buffer di lavoro.

- Versione DOS e XENIX
@(FSV)
*/

	int cisrewrec(isfd,recnum,record,err)
	isfdptr                 isfd;   /* descrittore del file ISAM */
	RecNoType               recnum; /* numero del record da riscrivere        */
	RecType                 record; /* buffer per il record      */
	int                                     *err;   /* codice di errore                       */

		{
			int                     knum = (isfd->i.PN+1), werr;
			RecType oldrec;

			*err = NoErr;
			if (isfd == ((isfdptr) NULL)) return ((*err = IsNotOpen));
			oldrec = (RecType) malloc(isfd->d->LenR);
			isfd->RecNo = recnum;
			IRecallRec(record);
			CRead(&isfd->f,oldrec,isfd->RecNo,NoLock);
			if ((*err = isfd->f.IOR))
			{
				free(oldrec);
				return(*err);
			}
			if (memcmp(oldrec,record,isfd->d->LenR) == 0)
			{
				*err = NoErr;
				if (test_share())
				  CLockRec(&isfd->f,isfd->RecNo,UnLock);
				free(oldrec);
				return(*err);
			}
			if ((isfd->r->NKeys) && IndActive)
			{
				if (test_share() && isfd->f.LockMode != ExclLock)
					CBLockFile(&isfd->i, err) ;
				replkeys(isfd, oldrec, record, knum, err) ;
				if (test_share() && isfd->f.LockMode != ExclLock)
					CBUnLockFile(&isfd->i, &werr) ;
			}
			if (isstate == NOTRANS) CWrite(&isfd->f,record,isfd->RecNo,UnLock);
			else CWrite(&isfd->f,record,isfd->RecNo,NoLock);
			if ((*err = isfd->f.IOR))
			{
				CWrite(&isfd->f,oldrec,isfd->RecNo,NoLock);
				replkeys(isfd, record, oldrec, knum, err) ;
			}
#ifndef DOS
			else
			{
				if (isstate == NOTRANS)
				{
					writelog(FNREWRITE, isfd, record);
					CLockRec(&isfd->f,isfd->RecNo,UnLock);
				}
				else writeundo(FNREWRITE, isfd, oldrec);
			}
#else
			if (test_share())
			  CLockRec(&isfd->f,isfd->RecNo,UnLock);
#endif
			free(oldrec);
			return(*err);
		}
/*
@(#) cisdelrec  ISAM
@(ID)
Cancella un record utilizzando un numero di record.
Ritorna il codice di errore.
@(FD)
@(IN)
	La variabile record in input contiene il record da cancellare.
@(FN)
@(ISV)
knum   = numero della chiave attiva.
werr   = codice di errore restituito da CBUnLockFiles.
oldrec = buffer di lavoro.
key1   = valore della chiave.
- Versione DOS e XENIX
@(FSV)
*/
	int cisdelrec(isfd,recnum,err)
	isfdptr                 isfd;   /* descrittore del file ISAM */
	RecNoType               recnum; /* numero di record                       */
	int                                     *err;   /* codice di errore                       */
		{
			int                     knum = (isfd->i.PN+1), werr;
			int                     junk;
			RecType oldrec ;
			TKey            key1 ;
			*err = NoErr;
			if(isfd == (isfdptr) NULL) return ((*err = IsNotOpen));
			oldrec = (RecType) malloc(isfd->d->LenR);
			isfd->RecNo = recnum;
			CRead(&isfd->f, oldrec, isfd->RecNo, NoLock);
			if ((*err = isfd->f.IOR))
			{
				free(oldrec);
				return(*err);
			}
			if ((isfd->r->NKeys) && IndActive)
			{
				if(test_share() && isfd->f.LockMode != ExclLock)
					CBLockFile(&isfd->i, err) ;
				delkeys(isfd, oldrec, knum, err);
			}
			IDeleteRec(oldrec);
			CWrite(&isfd->f,oldrec,isfd->RecNo,UnLock);
			if ((*err = isfd->f.IOR))
			{
				IRecallRec(oldrec);
				CWrite(&isfd->f,oldrec,isfd->RecNo,NoLock);
				if ((isfd->r->NKeys) && IndActive) addkeys(isfd, oldrec, knum, err);
			}
#ifndef DOS
			else
			{
				if (isstate == NOTRANS)
				{
					writelog(FNDELETE, isfd, NULL);
					CLockRec(&isfd->f,isfd->RecNo,UnLock);
				}
				else writeundo(FNDELETE, isfd, NULL);
			}
			if (test_share() && (isfd->r->NKeys) && IndActive && (isfd->f.LockMode != ExclLock))
				CBUnLockFile(&isfd->i, &werr) ;
#else
			if (test_share())
			{
			  CLockRec(&isfd->f,isfd->RecNo,UnLock);
			  if (isfd->r->NKeys && IndActive &&
			      (isfd->f.LockMode != ExclLock))
				CBUnLockFile(&isfd->i, &werr) ;
		        }
#endif
			free(oldrec);
			isfd->RecNo = 0;
			return(*err);
		}
/*
@(#) cisgetrecno  ISAM
@(ID)
Restituisce il numero del record corrente.
@(FD)
*/
	RecNoType cisgetrecno(isfd, err)
	isfdptr                 isfd; /* descrittore del file ISAM */
	int                                     *err; /* codice di errore                       */
	
		{
			if (!isfd->RecNo) *err = IsNotCurr;
			else *err = NoErr;
			return(isfd->RecNo);
		}
/*
@(#) cislock  ISAM
@(ID)
Blocca il file ISAM.
@(FD)
@(ISV)
junk = variabile spazzatura per la chiamata di sleep.
@(FSV)
*/
	int cislock(isfd,err)
	isfdptr                 isfd; /* descrittore del file ISAM */
	int                                     *err; /* codice di errore                       */
		{
			int     junk;
			*err = NoErr ;
			if (lseek(isfd->f.F, 0L, 0) == -1) return ((*err = CIOResult()));
#ifndef DOS
			do
			{
				if (lockf(isfd->f.F,F_TLOCK,0L) == -1)
				{
					*err = CIOResult() ;
					junk = sleep(1) ;
				}
			} while (TESTLOCK(*err)) ;
#endif
			if(test_share() && isfd->f.LockMode != ExclLock)
				CBLockFile(&isfd->i,err);
			return(*err);
		}
/*
@(#) cisunlock  ISAM
@(ID)
Sblocca un file ISAM.
@(FD)
*/
	int cisunlock(isfd,err)
	isfdptr                 isfd; /* descrittore del file */
	int                                     *err; /* codice di errore                  */
		{
			return(cisrelease(isfd,err));
		}
/*
@(#) cisrelease  ISAM
@(ID)
Sblocca un file ISAM.
@(FD)
*/
	int cisrelease(isfd,err)
	isfdptr                 isfd; /* descrittore del file ISAM */
	int                                     *err; /* codice di errore                       */
		{
			*err = NoErr ;
#ifndef DOS
			if (lseek(isfd->f.F, 0L, 0) == -1) return ((*err = CIOResult()));
			do
			{
				if (lockf(isfd->f.F,F_ULOCK,0L) == -1) *err = CIOResult() ;
			} while (TESTLOCK(*err)) ;
#endif
			if(test_share() && isfd->f.LockMode != ExclLock)
				CBUnLockFile(&isfd->i,err);
			return(*err);
		}
/*
@(#) IndexOn  ISAM
@(ID)
Attiva Aggiornamento Indici.
@(FD)
@(IN)
Di default gli indici sono attivi.
@(FN)
*/
 void IndexOn()
	{
		IndActive = TRUE ;
	}
/*
@(#) IndexOff  ISAM
@(ID)
Disattiva l'aggiornamento Indici.
@(FD)
*/
 void IndexOff()
	{
		IndActive = FALSE ;
	}
#ifndef DOS
/*
@($) undoname  ISAM
@(ID)
Restituisce il nome del file di Undo.
@(FD)
@(ISV)
path  = stringa contenente il nome file.
@(FSV)
*/
 char *undoname()
	{
		static PathSt   path;
		TMPFNAME(path, "undo");
		return(path);
	}
/*
@($) writeundo  ISAM
@(ID)
Scrive una operazione effettuata nel file di Undo.
@(FD)
@(ISV)
fd    = puntatore al file.
uname = nome del file di undo.
lgh   = variabile di lavoro che contiene l' header del record di undo.
@(FSV)
*/
 void writeundo(fntype,isfd,record)
 int                    fntype;  /* operazione da effettuare              */
 isfdptr        isfd;    /* descrittore del file     */
 RecType        record;  /* buffer contenente il record           */
	{
		int                     fd;
		PathSt  uname;
		loghead lgh;
	
		if (isfd->ln <= 0) return ;
		strcpy(uname ,undoname());
		if ((fd = open(uname, O_WRONLY | O_CREAT | O_APPEND, 0666)) == -1)
		  fatal_box("Writeundo : Error n. %d ", errno);
		lgh.type = fntype;
		lgh.time = time(NULL);
		lgh.procid = getpid();
		lgh.userid = getuid();
		lgh.filenum = isfd->ln;
		lgh.recnum = isfd->RecNo;
		lgh.lenrec = isfd->d->LenR;
		if (write(fd, &lgh, sizeof(lgh)) == -1)
		  fatal_box("Writeundo : Error n. %d ", errno);
		if (fntype & (FNREWRITE))
			if (write(fd, record, lgh.lenrec) == -1)
				fatal_box("Writeundo : Error n. %d ", errno);
		if (close(fd) == -1)
		  fatal_box("Writeundo : Error n. %d ", errno);
	}
/*
@($) writelog  ISAM
@(ID)
Scrive sul file Giornale l'operazione effettuata.
@(FD)
@(ISV)
junk = variabile spazzatura per la chiamata di execunlock.
lname = nome del file Giornale (LOG).
fd    = puntatore al file giornale.
lgh   = testata del file giornale.
@(FSV)
*/
 void writelog(fntype,isfd,record)
 int                    fntype; /* operazione effetuata                   */
 isfdptr        isfd;   /* descrittore del file ISAM */
 RecType        record; /* buffer per il record */
	{
		int                     fd,junk;
		PathSt  lname;
		loghead lgh;
		if (!isjournal) return;
		if (isfd->ln <= 0) return ;
		strcpy(lname, CInsPref(logname, NORDIR));
		while (excllock(lname,TRUE) == -1) sleep(1);
		if ((fd = open(lname, O_WRONLY | O_CREAT | O_APPEND, 0666)) == -1)
		{
			junk = exclunlock(lname,TRUE);
		  fatal_box("Writelog : Error n. %d ", errno);
		}
		lgh.type = fntype + FNSTTRANS;
		lgh.time = time(NULL);
		lgh.procid = getpid();
		lgh.userid = getuid();
		if (fntype & (FNREWRITE + FNWRITE + FNDELETE))
		{
			lgh.filenum = isfd->ln;
			lgh.recnum = isfd->RecNo;
			lgh.lenrec = isfd->d->LenR;
		}
		else
		{
			lgh.filenum = 0;
			if (fntype == FNREORG) lgh.recnum = *((RecNoType *) record);
			else lgh.recnum = 0L;
			if (fntype == FNCHGREC) lgh.lenrec = sizeof(RecDes);
			else lgh.lenrec = 0;
		}
		if (write(fd, &lgh, sizeof(lgh)) == -1)
		{
			junk = exclunlock(lname,TRUE);
		  fatal_box("Writelog : Error n. %d ", errno);
		}
		if (fntype & (FNREWRITE + FNWRITE + FNCHGREC))
			if (write(fd, record, lgh.lenrec) == -1)
			{
				junk = exclunlock(lname,TRUE);
				fatal_box("Writelog : Error n. %d ", errno);
			}
		if (close(fd) == -1)
		  fatal_box("Writelog : Error n. %d ", errno);
		junk = exclunlock(lname,TRUE);
	}
#endif
/*
@(#) StTrans  ISAM
@(ID)
Inizia una transazione.
@(FD)
*/
 void StTrans()
	{
#ifndef DOS
		if (isstate == TRANS) EndTrans();
#endif
		isstate = TRANS;
	}
#ifndef DOS
/*
@($) getopenf  ISAM
@(ID)
Riconfigura il file di lavoro attivo sul file di numero logico "ln".
@(FD)
@(ISV)
junk = variabile spazzatura per la chiamata alla cisclose.
err  = codice di errore ritornato dalla cisopen.
@(FSV)
*/
 void getopenf(ln,record)
 int                    ln;      /* numero logico del file */
 RecType        *record; /* puntatore al buffer per il record            */
	{
		int     err,junk;
		if (openf[ln - 1] == NULL)
		{
			if (wln != ln)
			{
				if (wln != -1) junk = cisclose(&wisfd ,record ,&err);
				cisopen(&wisfd, ln, record, ManuLock, &err);
				wln = ln;
			}
		}
		else *record = realloc(*record, openf[ln - 1]->d->LenR);
	}
#endif
/*
@(#) EndTrans  ISAM
@(ID)
Chiude una transazione.
@(FD)
@(ISV)
fdl, fdu     = puntatori ai file di LOG e di Undo.
lname, uname = nomi dei file di LOG e di Undo.
lgh, lgh1    = variabili di lavoro contenenti le testate dei file di log.
nread        = variabile di lavoro per la chiamata alla read.
werr         = codice di errore ritornato dalla cisclose.
junk         = variabile spazzatura per la chiamata di exclunlock.
start        = variabile di lavoro.
record       = buffer di lavoro.
@(FSV)
*/
 void EndTrans()
	{
#ifndef DOS
		int                     fdl, fdu;
		PathSt  lname, uname;
		loghead lgh, lgh1;
		int                     nread, werr, junk, start = FNSTTRANS;
		RecType record;
		strcpy(lname ,CInsPref(logname, NORDIR));
		while (excllock(lname,TRUE) == -1) sleep(1);
		if (((fdl = open(lname, O_WRONLY | O_CREAT | O_APPEND, 0666)) == -1) ||
			 ((fdu = open(uname, O_RDONLY, 0666)) == -1))
		{
			junk = exclunlock(lname,TRUE);
		  fatal_box("Endtrans : Error n. %d ", errno);
		}
		while ((nread = read(fdu, &lgh, sizeof(lgh))) > 0)
		{
			lgh.type += start;
			start = 0;
			if (write(fdl, &lgh, sizeof(lgh)) == -1)
			{
				junk = exclunlock(lname,TRUE);
		  fatal_box("Endtrans : Error n. %d ", errno);
			}
			if (lgh.type == FNREWRITE)
				if (lseek(fdu, (long) lgh.lenrec, 1) == -1)
				{
					junk = exclunlock(lname,TRUE);
					fatal_box("Endtrans : Error n. %d ", errno);
				}
			getopenf(lgh.filenum, &record);
			CRead(&(openf[lgh.filenum - 1]->f), record, lgh.recnum, UnLock);
			if (write(fdl, record, lgh.lenrec) == -1)
			{
				junk = exclunlock(lname,TRUE);
				fatal_box("Endtrans : Error n. %d ", errno);
			}
		}
		if ((nread <= 0) || (close(fdu) == -1) || (close(fdl) == -1) ||
			 (unlink(uname) == -1))
		{
			junk = exclunlock(lname,TRUE);
		  fatal_box("Endtrans : Error n. %d ", errno);
		}
		if (wln != -1)
		{
			junk = cisclose(&wisfd, &record, &werr);
			wln = -1;
		}
		junk = exclunlock(lname,TRUE);
#endif
	}
/*
@(#) AbTrans  ISAM
@(ID)
Abortisce una transazione.
@(FD)
*/
 void AbTrans()
	{
#ifndef DOS
		int                     fd;
		PathSt  uname;
		loghead lgh;
		int                     nread, werr, junk;
		RecType record;
		RecType oldrec;
		strcpy(uname ,undoname());
		if ((fd = open(uname, O_RDONLY, 0666)) == -1)
		  fatal_box("Abtrans : Error n. %d ", errno);
		while ((nread = read(fd, &lgh, sizeof(lgh))) > 0)
		{
			getopenf(lgh.filenum, &record);
			if (oldrec == NULL) oldrec = malloc(lgh.lenrec);
			else oldrec = realloc(oldrec, lgh.lenrec);
			if (lgh.type & (FNREWRITE))
			{
				if ((nread = read(fd, record, lgh.lenrec)) <= 0)
				fatal_box("Abtrans : Error n. %d ", errno);
			}
			if (lgh.lenrec != openf[lgh.filenum - 1]->d->LenR)
		  fatal_box("Abtrans : Error n. %d ", IsNoMatch);
			CRead(&(openf[lgh.filenum - 1]->f), oldrec, lgh.recnum, NoLock);
			switch (lgh.type)
			{
				case FNREWRITE :
							junk = replkeys(openf[lgh.filenum - 1], oldrec, record,
											 openf[lgh.filenum - 1]->i.PN + 1, &werr);
							CWrite(&(openf[lgh.filenum - 1]->f), record, lgh.recnum, UnLock);
							break;
				case FNDELETE :
							IRecallRec(oldrec);
							junk = addkeys(openf[lgh.filenum - 1], oldrec,
											 openf[lgh.filenum - 1]->i.PN + 1, &werr);
							CWrite(&(openf[lgh.filenum - 1]->f), oldrec, lgh.recnum, UnLock);
							break;
				case FNWRITE :
							IDeleteRec(oldrec);
							junk = delkeys(openf[lgh.filenum - 1], oldrec,
											 openf[lgh.filenum - 1]->i.PN + 1, &werr);
							CWrite(&(openf[lgh.filenum - 1]->f), record, lgh.recnum, UnLock);
							break;
			}
		}
		if ((nread == -1) || (close(fd) == -1) || (unlink(uname) == -1))
		  fatal_box("Abtrans : Error n. %d ", errno);
		if (wln != -1)
		{
			junk = cisclose(&wisfd, &record, &werr);
			wln = -1;
		}
#endif
	}