/* * @(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 #else #include #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 }