/*
 *
 @(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"
#ifdef __WATCOMC__
#include <malloc.h>
#else
#include                                <memory.h>
#endif
#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); 
    isfd = NULL;
    if (*err == 13)
    {              
      if (mode == ExclLock)
        fatal_box("L'archivio n. %d (%s) non puo' essere aperto in modo esclusivo", logicname, name);    
      else
        fatal_box("L'archivio n. %d (%s) e' stato aperto in modo esclusivo da un altro programma", logicname, name);    
    }  
    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);
      isfd = NULL;
      if (*err == 13)
      {              
        if (mode == ExclLock)
          fatal_box("L'indice n. %d (%s) non puo' essere aperto in modo esclusivo", logicname, name);    
        else
          fatal_box("L'indice n. %d (%s) e' stato aperto in modo esclusivo da un altro programma", logicname, name);    
      }  
      fatal_box("Can't open index 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;
  RecNoType       neweox;

  *err = NoErr;
  if(isfd == ((isfdptr) NULL)) return((*err = IsNotOpen));
  if (isfd->ln > 0)
  {
    COpenDir (ManuLock, isfd->ft);
    COpenFile(isfd->ln,isfd->d, NoLock, 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)
        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)
  {
    RecType wrec = malloc(isfd->d->LenR);
    memcpy(wrec, record, isfd->d->LenR);
    savekeystat(isfd);
    junk = cisstart(isfd, 1, wrec, NoLock+IsEqual, &junk);
    restkeystat(isfd, knum);
    free(wrec);

    if ((junk == NoErr) || (junk == ISLOCKED))
    {
      *err = IsReInsert;
      if (isfd->ln > 0)
        CCloseDir(isfd->ft);
      isfd->RecNo = 0;
      return(*err);
    }
  }
  if (isfd->ln > 0)
  {
    COpenFile(isfd->ln,isfd->d, Lock, isfd->ft);
  }
  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 (isfd->ln > 0)                            
    {
      CCloseFile(isfd->ln,isfd->d, isfd->ft) ; 
    }     
    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 (*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;
  savekeystat(isfd);
  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
}

