/******************************************************************\ * XFILE Gestore file indice RMS V1.01 * * Antonio Vigliotti S.H.S Prima stesura: 01-Mar-1997 * *----------------------------------------------------------------* * Routine per la gestione dei file indice RMS. * * Conforme ANSI-C. * \******************************************************************/ #include #include #include #pragma nomember_alignment #include #pragma member_alignment #include #include #include #include #include #include #include "xfile.h" /*------------------------------------------------------*\ * CONSTANT DECLARATIVE * \*------------------------------------------------------*/ #define BUG_HUNTED 0 /*------------------------------------------------------*\ * TYPE DEFINITION * \*------------------------------------------------------*/ typedef struct FAB XFCB; typedef struct RAB XRCB; typedef struct XABKEY XKCB; /*------------------------------------------------------*\ * FUNCTION PROTOTIPES * \*------------------------------------------------------*/ /*------------------------------------------------------*\ * GLOBAL VARIABLES * \*------------------------------------------------------*/ /*------------------------------------------------------*\ * xopen: Apre un file ISAM ad indici RMS * * * * Usando la sintassi di fopen ritorna il file pointer * * di un indeXed FILE (XFILE). Se viene restituito un * * valore nullo, allora non e` stato possibile aprire * * il file. * * Input: * * Nome del file * * Modalità in minuscolo (Read,Write,Both,Append) * * Output: * * XFILE pointer * \*------------------------------------------------------*/ XFILE *xopen (const char *pszName, const char *pchMode) { XFILE *pxFile; XFCB *pxFcb; XKCB *pxKcb; XRCB *pxRcb; int iStatus; if (!pszName || !pchMode) return (NULL); /* Parametro valido */ if (*pchMode != 'r' && *pchMode != 'w' && *pchMode != 'b' && *pchMode != 'a') return (NULL); pxFile = malloc(sizeof(pxFile)); /* Alloco File Pointer */ pxFcb = malloc(sizeof(XFCB)); /* Alloco File Control Block */ pxKcb = malloc(sizeof(XKCB)); /* Alloco Key Access Block */ pxRcb = malloc(sizeof(XRCB)); /* Alloco Record Access Block */ if (!pxFile || !pxFcb || !pxKcb || !pxRcb) { if (!pxFile) free (pxFile); /* Dealloco File Pointer */ if (!pxFcb) free (pxFcb); /* Dealloco FCB */ if (!pxRcb) free (pxRcb); /* Dealloco RCB */ if (!pxKcb) free (pxKcb); /* Dealloco KCB */ return (NULL); /* Errore */ } pxFile->pxFcb = pxFcb; /* Puntatore al FCB */ pxFile->pxRcb = pxRcb; /* Puntatore al RCB */ pxFile->chOpnMode = *pchMode; /* Modo open */ *pxFcb = cc$rms_fab; /* Inizializzo FCB */ *pxKcb = cc$rms_xabkey; /* Inizializzo KAB */ *pxRcb = cc$rms_rab; /* Inizializzo RAB */ pxFcb->fab$l_fna = pszName; /* Nome file di sistema */ pxFcb->fab$b_fns = strlen(pszName); /* Lunghezza nome file */ pxFcb->fab$l_xab = (void *) pxKcb; /* Assegna KAB */ if (*pchMode == 'r') { pxFcb->fab$b_fac = FAB$M_GET; /* Modalita` di lettura */ pxFcb->fab$b_shr = (FAB$M_SHRGET | FAB$M_SHRPUT | FAB$M_SHRDEL | FAB$M_SHRUPD); /* File condiviso */ pxFile->chLockMode = 'r'; } else if (*pchMode == 'w' || *pchMode == 'a') { pxFcb->fab$b_fac = (FAB$M_PUT | FAB$M_UPD | FAB$M_DEL);/* Modalita` di scrittura */ pxFcb->fab$b_shr = (FAB$M_SHRGET | FAB$M_SHRPUT | FAB$M_SHRDEL | FAB$M_SHRUPD); /* File condiviso */ pxFile->chLockMode = 'w'; } else if (*pchMode == 'b') { pxFcb->fab$b_fac = (FAB$M_GET | FAB$M_PUT | FAB$M_UPD | FAB$M_DEL);/* Modalita` di scrittura */ pxFcb->fab$b_shr = (FAB$M_SHRGET | FAB$M_SHRPUT | FAB$M_SHRDEL | FAB$M_SHRUPD); /* File condiviso */ pxFile->chLockMode = 'w'; } pxFile->iTimeOut = 5; /* Default Time Out */ iStatus = sys$open(pxFcb); /* Open File */ if (iStatus == RMS$_NORMAL) /* Test di errore */ { pxRcb->rab$l_fab = pxFcb; /* Collego il FCB */ pxRcb->rab$b_ksz = pxKcb->xab$b_siz0; /* Imposto lunghezza chiave */ iStatus = sys$connect(pxRcb); } if (iStatus != RMS$_NORMAL) /* Test di errore */ { free (pxFile); /* Dealloco File Pointer */ free (pxFcb); /* Dealloco FCB */ free (pxKcb); /* Dealloco KAB */ free (pxRcb); /* Dealloco RAB */ return (NULL); /* Errore */ } return (pxFile); } /*------------------------------------------------------*\ * xclose: Chiude un file ISAM ad indici RMS * * * * Usa la sintassi di fclose. * * Input: * * puntatore XFILE (indeXed FILE) * * Output: * * nessuno * \*------------------------------------------------------*/ void xclose (XFILE *pxFile) { XFCB *pxFcb; XKCB *pxKcb; XRCB *pxRcb; /* Il 18 luglio 2000 veniva introdotta la gestione della write e la gestione del lock/unlock durante la lettura file. Nello stesso periodo veniva certificata una nuova versione di RunTime. La nuova versione di runtime AXPRTL e CWRTL10 con un nuovo livello di certificazione provocavano il crash del programma di menù. Le librerie venivano ritirate ed iniziava una caccia feroce al bug come risulta testimonianza da CMS. Il 22-09-2000 venivano estratti tutti i moduli in qualche modo interessati e veniva creato un programma di test riducendo le istruzioni del programma di menù. Il 24-09-2000 finalmente era fissato l'errore nella sequenza: KVINIT->KVEND->KCLVAX. Il 25-09-2000 queste routine erano ritagliate al fine di isolare il problema. Alle 15:30 di quel giorno l'isolamento delle istruzione qui seguito marcate e concettualmente corrette finalmente risolvevano il problema. La mancata deallocazione di pointer allocati dalla funzione XOPEN non sono quindi un errore ma una stretta volontà per evitare un probabile Bug del sistema operativo. Prima di riattivare queste istruzione leggete: 3 mesi di lavoro di ritardo nella consegna dei runtime ed dei programmi!!! */ if (pxFile) { pxFcb = pxFile->pxFcb; /* Estrazione FCB */ #if BUG_HUNTED pxRcb = pxFile->pxRcb; /* Estrazione RCB */ if (pxRcb) { sys$disconnect (pxRcb); /* Disconnetto Record Mgr */ pxRcb->rab$l_fab = NULL; /* Scollego il FCB */ } #endif if (pxFcb) { #if BUG_HUNTED (void *) pxKcb = pxFcb->fab$l_xab; /* Puntatore a KAB */ pxFcb->fab$l_xab = NULL; /* Puntatore a KAB */ #endif sys$close (pxFcb); /* Chiudo file */ #if BUG_HUNTED free (pxFcb); /* Dealloco FCB */ if (pxKcb) free (pxKcb); /* Dealloco KAB */ #endif } #if BUG_HUNTED if (pxRcb) free (pxRcb); /* Dealloco RAB */ #endif free (pxFile); /* Dealloco File Pointer */ } } /*------------------------------------------------------*\ * xread: Legge un record RMS con accesso diretto * * * * Legge un record di un file ISAM a indici RMS con la * * chiave passata. Se la lettura fallisce viene resti- * * tuito un puntatore nullo e la funzione xerror resti- * * tuisce il codice di errore RMS. * * Il record corrente è locked se la modalità delle * * transazioni è Write (default in open both-mode). In * * questo caso se il record è già locked non viene let- * * to. Se la modalità corrente è Read il record viene * * letto anche se locked da altro processo e non viene * * marcato locked. * * Input: * * puntatore indirizzo buffer di lettura * * puntatore stringa ASCIZ della chiave record * * numero di indice da usare (0=primario) * * dimesione del buffer (max byte da leggere) * * puntatore indeXed FILE (restituito da xopen) * * Output: * * Indirizzo buffer di lettura * \*------------------------------------------------------*/ char *xread (char *pchBufr, char * pszKey, const short iIdxKey, const short iMaxLen, XFILE *pxFile) { XFCB *pxFcb; XKCB *pxKcb; XRCB *pxRcb; short iKeyLen; int iStatus; if (!pchBufr || !pszKey || !pxFile || iMaxLen <= 0) { return (NULL); } pxFcb = pxFile->pxFcb; /* Estrazione FCB */ pxRcb = pxFile->pxRcb; /* Estrazione RCB */ if (!pxFcb) { return (NULL); /* FCB non valido */ } assert (pxFcb->fab$b_org == FAB$C_IDX); /* Parametro valido */ if (!pxRcb) { return (NULL); /* FCB non valido */ } assert (pxRcb->rab$l_fab == pxFcb); pxRcb->rab$b_rac = RAB$C_KEY; /* Leggo per Chiave passata */ pxRcb->rab$b_krf = iIdxKey; /* Numero di indice */ pxRcb->rab$l_kbf = pszKey; /* Chiave di lettura */ iKeyLen = strlen (pszKey); /* Lunghezza chiave passata */ (void *) pxKcb = pxFcb->fab$l_xab; /* Puntatore a KAB */ if (iKeyLen > pxKcb->xab$b_siz0 && iIdxKey == 0) iKeyLen = pxKcb->xab$b_siz0; pxRcb->rab$b_ksz = iKeyLen; /* Lunghezza della chiave */ if (pxFile->chLockMode == 'r') pxRcb->rab$l_rop = (RAB$M_NLK|RAB$M_RRL); /* Leggi anche locked */ else pxRcb->rab$l_rop = (RAB$M_TMO|RAB$M_WAT); /* Wait for record locked */ pxRcb->rab$b_tmo = pxFile->iTimeOut = 5; /* Default Time Out */ pxRcb->rab$l_ubf = pchBufr; /* Buffer di lettura */ pxRcb->rab$w_usz = iMaxLen; /* Max num. di caratteri */ iStatus = sys$get(pxRcb); while (iStatus == RMS$_PENDING) iStatus = sys$wait(pxRcb); if ((pxFile->chLockMode == 'r' && iStatus == RMS$_OK_RRL)/* Test di errore */ || iStatus == RMS$_NORMAL) return (pchBufr); /* Ok lettura */ else return (NULL); } /*------------------------------------------------------*\ * xseek: Legge un record RMS con accesso greater/equal * * * * Legge un record di un file ISAM a indici RMS con la * * chiave passata. Se la lettura fallisce viene resti- * * tuito un puntatore nullo e la funzione xerror resti- * * tuisce il codice di errore RMS. * * Rispetto ad xread il record è letto se esiste almeno * * un record con chiave uguale o maggiore di quella * * passata. Le regole di Lock sono quelle di xread. * * Input: * * puntatore indirizzo buffer di lettura * * puntatore stringa ASCIZ della chiave record * * numero di indice da usare (0=primario) * * dimesione del buffer (max byte da leggere) * * puntatore indeXed FILE (restituito da xopen) * * Output: * * Indirizzo buffer di lettura * \*------------------------------------------------------*/ char *xseek (char *pchBufr, char * pszKey, const short iIdxKey, const short iMaxLen, XFILE *pxFile) { XFCB *pxFcb; XKCB *pxKcb; XRCB *pxRcb; short iKeyLen; int iStatus; if (!pchBufr || !pszKey || !pxFile || iMaxLen <= 0) { return (NULL); } pxFcb = pxFile->pxFcb; /* Estrazione FCB */ pxRcb = pxFile->pxRcb; /* Estrazione RCB */ if (!pxFcb) { return (NULL); /* FCB non valido */ } assert (pxFcb->fab$b_org == FAB$C_IDX); /* Parametro valido */ if (!pxRcb) { return (NULL); /* FCB non valido */ } assert (pxRcb->rab$l_fab == pxFcb); pxRcb->rab$b_rac = RAB$C_KEY; /* Leggo per Chiave passata */ pxRcb->rab$b_krf = iIdxKey; /* Numero di indice */ pxRcb->rab$l_kbf = pszKey; /* Chiave di lettura */ iKeyLen = strlen (pszKey); /* Lunghezza chiave passata */ (void *) pxKcb = pxFcb->fab$l_xab; /* Puntatore a KAB */ if (iKeyLen > pxKcb->xab$b_siz0) iKeyLen = pxKcb->xab$b_siz0; pxRcb->rab$b_ksz = iKeyLen; /* Lunghezza della chiave */ pxRcb->rab$l_rop = RAB$V_KGE; pxRcb->rab$b_tmo = pxFile->iTimeOut = 5; /* Default Time Out */ pxRcb->rab$l_ubf = pchBufr; /* Buffer di lettura */ pxRcb->rab$w_usz = iMaxLen; /* Max num. di caratteri */ iStatus = sys$get(pxRcb); while (iStatus == RMS$_PENDING) iStatus = sys$wait(pxRcb); if ((pxFile->chLockMode == 'r' && iStatus == RMS$_OK_RRL)/* Test di errore */ || iStatus == RMS$_NORMAL) return (pchBufr); /* Ok lettura */ else return (NULL); } /************************************************************************\ * xnext Legge prossimo record RMS * * * * Sono passati l'indirizzo del buffer di lettura, la lunghezza massi- * * del buffer ed il puntatore al file. Viene letto il prossimo record. * * Puo` seguire una xread di posizionamento. * \************************************************************************/ char *xnext (char *pchBufr, XFILE *pxFile) { XFCB *pxFcb; XKCB *pxKcb; XRCB *pxRcb; int iStatus; if (!pchBufr || !pxFile) { return (NULL); } pxFcb = pxFile->pxFcb; /* Estrazione FCB */ pxRcb = pxFile->pxRcb; /* Estrazione RCB */ if (!pxFcb) { return (NULL); /* FCB non valido */ } assert (pxFcb->fab$w_mrs > 0); /* Parametro valido */ assert (pxFcb->fab$b_org == FAB$C_IDX); /* Parametro valido */ if (!pxRcb) { return (NULL); /* FCB non valido */ } assert (pxRcb->rab$l_fab == pxFcb); pxRcb->rab$b_rac = RAB$C_SEQ; /* Leggo sequenzialmente */ if (pxFile->chLockMode == 'r') pxRcb->rab$l_rop = (RAB$M_NLK|RAB$M_RRL); /* Leggi anche locked */ else pxRcb->rab$l_rop = (RAB$M_TMO|RAB$M_WAT); /* Wait for record locked */ pxRcb->rab$b_tmo = pxFile->iTimeOut = 5; /* Default Time Out */ pxRcb->rab$l_ubf = pchBufr; /* Buffer di lettura */ iStatus = sys$get(pxRcb); while (iStatus == RMS$_PENDING) iStatus = sys$wait(pxRcb); if ((pxFile->chLockMode == 'r' && iStatus == RMS$_OK_RRL)/* Test di errore */ || iStatus == RMS$_NORMAL) return (pchBufr); /* Ok lettura */ else return (NULL); } /*------------------------------------------------------*\ * xwrite: scrive un nuovo record RMS * * * * Scrive un nuovo record in un file ISAM a indici RMS. * * Il record non deve esistere. * * Input: * * puntatore indeXed FILE (restituito da xopen) * * puntatore indirizzo buffer di scrittura * * dimesione del buffer (max byte da scrivere) * * Output: * * numero di byte scritti. * \*------------------------------------------------------*/ size_t *xwrite (XFILE *pxFile, char *pchBufr, const short iMaxLen) { XFCB *pxFcb; XKCB *pxKcb; XRCB *pxRcb; short iKeyLen; int iStatus; if (!pchBufr || !pxFile) { return (0); } pxFcb = pxFile->pxFcb; /* Estrazione FCB */ pxRcb = pxFile->pxRcb; /* Estrazione RCB */ if (!pxFcb) { return (0); /* FCB non valido */ } assert (pxFcb->fab$b_org == FAB$C_IDX); /* Parametro valido */ if (!pxRcb) { return (0); /* FCB non valido */ } assert (pxRcb->rab$l_fab == pxFcb); pxRcb->rab$b_rac = RAB$C_KEY; /* Leggo per Chiave passata */ pxRcb->rab$l_rbf = pchBufr; /* Indirizzo buffer */ pxRcb->rab$w_rsz = iMaxLen; /* Lunghezza buffer */ pxRcb->rab$l_rop = (RAB$M_TMO|RAB$M_WAT); /* Wait for record locked */ pxRcb->rab$b_tmo = pxFile->iTimeOut = 5; /* Default Time Out */ iStatus = sys$put(pxRcb); while (iStatus == RMS$_PENDING) iStatus = sys$wait(pxRcb); if (iStatus == RMS$_NORMAL) return (iMaxLen); /* Ok lettura */ else return (0); } /*------------------------------------------------------*\ * xrewrite: riscrive un record RMS * * * * Riscrive un record in un file ISAM a indici RMS. Il * * record deve esistere. * * Input: * * puntatore indeXed FILE (restituito da xopen) * * puntatore indirizzo buffer di scrittura * * dimesione del buffer (max byte da scrivere) * * Output: * * numero di byte scritti. * \*------------------------------------------------------*/ size_t *xrewrite (XFILE *pxFile, char *pchBufr, const short iMaxLen) { XFCB *pxFcb; XKCB *pxKcb; XRCB *pxRcb; short iKeyLen; int iStatus; if (!pchBufr || !pxFile) { return (0); } pxFcb = pxFile->pxFcb; /* Estrazione FCB */ pxRcb = pxFile->pxRcb; /* Estrazione RCB */ if (!pxFcb) { return (0); /* FCB non valido */ } assert (pxFcb->fab$b_org == FAB$C_IDX); /* Parametro valido */ if (!pxRcb) { return (0); /* FCB non valido */ } assert (pxRcb->rab$l_fab == pxFcb); pxRcb->rab$b_rac = RAB$C_KEY; /* Leggo per Chiave passata */ pxRcb->rab$l_rbf = pchBufr; /* Indirizzo buffer */ pxRcb->rab$w_rsz = iMaxLen; /* Lunghezza buffer */ pxRcb->rab$l_rop = 0; /* Nessuna opzione */ iStatus = sys$update(pxRcb); while (iStatus == RMS$_PENDING) iStatus = sys$wait(pxRcb); if (iStatus == RMS$_NORMAL) return (iMaxLen); /* Ok lettura */ else return (0); } /*------------------------------------------------------*\ * xdelete: cancella un record RMS * * * * Cancella un record da un file ISAM a indici RMS. Il * * record deve esistere. * * Input: * * puntatore indeXed FILE (restituito da xopen) * * Output: * * Condizione di successo * \*------------------------------------------------------*/ BOOL xdelete (XFILE *pxFile) { XFCB *pxFcb; XKCB *pxKcb; XRCB *pxRcb; short iKeyLen; int iStatus; if (!pxFile) { return (FALSE); } pxFcb = pxFile->pxFcb; /* Estrazione FCB */ pxRcb = pxFile->pxRcb; /* Estrazione RCB */ if (!pxFcb) { return (FALSE); /* FCB non valido */ } assert (pxFcb->fab$b_org == FAB$C_IDX); /* Parametro valido */ if (!pxRcb) { return (FALSE); /* FCB non valido */ } assert (pxRcb->rab$l_fab == pxFcb); pxRcb->rab$l_rop = 0; /* Nessuna opzione */ iStatus = sys$delete(pxRcb); while (iStatus == RMS$_PENDING) iStatus = sys$wait(pxRcb); if (iStatus == RMS$_NORMAL) return (TRUE); /* Ok lettura */ else return (FALSE); } /*------------------------------------------------------*\ * xcreate: crea un archivio RMS * * * * Crea un archivio RMS. * * Input: * * Nome del file * * Stringa che descriva la struttura * * Output: * * XFILE pointer * \*------------------------------------------------------*/ XFILE *create (const char *pszName, const char *pszStruct) { return (NULL); } /*------------------------------------------------------*\ * xsettmo: imposta tempo di timeout * * * * Imposta il tempo di timeout del file. * * Input: * * puntatore indeXed FILE (restituito da xopen) * * tempo di timeout * * Output: * * tempo di timeout * \*------------------------------------------------------*/ short *xsettmo (XFILE *pxFile, short iTimeOut) { XFCB *pxFcb; XKCB *pxKcb; XRCB *pxRcb; if (!pxFile) { return (0); } pxFcb = pxFile->pxFcb; /* Estrazione FCB */ pxRcb = pxFile->pxRcb; /* Estrazione RCB */ if (!pxFcb) { return (0); /* FCB non valido */ } assert (pxFcb->fab$b_org == FAB$C_IDX); /* Parametro valido */ if (!pxRcb) { return (0); /* FCB non valido */ } pxFile->iTimeOut = iTimeOut; return (iTimeOut); } /*------------------------------------------------------*\ * setlmode: imposta lock mode * * * * Imposta la modalità di lock su file. * * Input: * * puntatore indeXed FILE (restituito da xopen) * * Modalità in minuscolo (Read,Write) * * Output: * * Modalità in minuscolo (Read,Write) * \*------------------------------------------------------*/ char xsetlmode (XFILE *pxFile, const char *pchMode) { XFCB *pxFcb; XKCB *pxKcb; XRCB *pxRcb; if (!pxFile) { return ('\0'); } pxFcb = pxFile->pxFcb; /* Estrazione FCB */ pxRcb = pxFile->pxRcb; /* Estrazione RCB */ if (!pxFcb) { return ('\0'); } assert (pxFcb->fab$b_org == FAB$C_IDX); /* Parametro valido */ if (!pxRcb) { return ('\0'); } if (*pchMode == 'r') pxFile->chLockMode = 'r'; else if (*pchMode == 'w') pxFile->chLockMode = 'w'; return (pxFile->chLockMode); } /************************************************************************\ * xerror Riporta il codice di errore dell'ultima operazione. * * * * Usa la sintassi del ferror. * \************************************************************************/ int xerror (const XFILE *pxFile) { XFCB *pxFcb; XRCB *pxRcb; if (!pxFile) { return (-1); } pxFcb = pxFile->pxFcb; /* Estrazione FCB */ if (pxFcb) { pxRcb = pxFile->pxRcb; /* Estrazione RCB */ if (!pxRcb) return (-1); /* Manca il RAB */ return (pxRcb->rab$l_sts); /* Riporta codice */ } else return (-1); }