/* * l z v i o . c * For VMS V4 only. */ /* * Problems: * If you open a second input file (getting rms attributes) * it aborts with an internal "fatal" error (15820C LIB-F-FATERRLIB) */ /* * Make TESTING_FDLIO non-zero to enable test code. * * Edit History */ #ifndef TESTING_FDLIO #define TESTING_FDLIO 0 #endif /* * RMS/FDL record level i/o routines for Vax-11 C V4 or greater only. * Rather crude. * * The following are provided: * * #define FDLSTUFF char * #include descrip * * FDLSTUFF * * fdl_open(filename, fdl_descriptor) * char *filename; * struct dsc$descriptor *fdl_descriptor; * Initializes internal buffers and opens this existing * file for input. The filename may not contain wildcards. * On (successful) return, fdl_descriptor will point to * an initialized fdl specification. The description * string will be in malloc'ed memory. The caller does not * initialize the fdl_descriptor. Returns NULL on error. * (Note an error will be returned if the file is not * block-oriented.) * * When you don't need the fdl_descriptor information * any more, free it by calling * fdl_free(fdl_descriptor); * if fdl_descriptor is NULL on entry, the file is opened * normally (fdl information is not collected). * * FDLSTUFF * * fdl_create(fdl_descriptor, override_filename) * struct dsc$descriptor *fdl_descriptor; * char *override_filename; * Creates a file using the fdl specification. * If override_filename is not NULL and not equal to "", * it will override the filename specified in the fdl. * fdl_write() is used to write data to the file. * Returns NULL on error. * * if fdl_descriptor is NULL, the file is created using * the name in override_filename (which must be present). * The file is created in "undefined" record format. * * fdl_free(fdl_descriptor) * struct dsc$descriptor *fdl_descriptor; * Releases the fdl descriptor block. * * int * fdl_read(buffer, buffer_length, r) * char *buffer; * int buffer_length; * FDLSTUFF *r; * Read buffer_length bytes from the file (using SYS$READ). * No expansion or interpretation. buffer_length had * better be even or you're asking for trouble. Returns * the actual number of bytes read. The file has been * opened by fdl_open. * * int * fdl_write(buffer, buffer_length, r) * char *buffer; * int buffer_length; * FDLSTUFF *r; * Write buffer_length bytes to the file (using SYS$WRITE). * No expansion or interpretation. buffer_length had * better be even or you're asking for trouble. Returns * the actual number of bytes written. The file was opened * by fdl_create(); * * fdl_getname(r, buffer) * FDLSTUFF *r; * char *buffer; * Copies the currently open file's name to the caller's * data buffer buffer. * * long * fdl_fsize(r) * Returns the size in bytes of the opened file. * * fdl_dump(fdl_descriptor, fd) * struct dsc$descriptor *fdl_descriptor; * FILE *fd; * Writes the fdl info to the indicated file with * line breaks in appropriate places. * * fdl_message(r, why) * FDLSTUFF *r; * char *why; * All system-level routines set a global value, fdl_status. * fdl_message() prints the error message text corresponding * to the current value of fdl_status. The message printed * has the format: * why current_filename: error_message. * If why is NULL, only the error_message is printed. */ #include "lz.h" #if VMS_V4 #include rms #include ssdef #include descrip #include devdef #ifndef FDL$M_FDL_SIGNAL #define FDL$M_FDL_SIGNAL 1 /* Signal errors if set */ #endif #ifndef FDL$M_FDL_STRING #define FDL$M_FDL_STRING 2 /* Use string for fdl text */ #endif #if TESTING_FDLIO #define SIGNAL_ON_ERROR FDL$M_FDL_SIGNAL #else #define SIGNAL_ON_ERROR 0 #endif #define TRUE 1 #define FALSE 0 #define EOS 0 typedef struct FDLSTUFF { struct RAB rab; /* Record access buffer */ struct FAB fab; /* File access buffer */ struct NAM nam; /* File name buffer */ struct XABFHC xab; /* Extended attributes block */ char starname[NAM$C_MAXRSS + 1]; /* Wild file name */ char filename[NAM$C_MAXRSS + 1]; /* Open file name */ } FDLSTUFF; int fdl_status; /* Set to last rms call status */ static FDLSTUFF * fail(r, why, name) FDLSTUFF *r; /* Buffer */ char *why; /* A little commentary */ char *name; /* Argument to perror */ /* * Problem exit routine */ { #if TESTING_FDLIO if (name == NULL && r != NULL) name = r->fab.fab$l_fna; message(r, why, name); #endif if (r != NULL) free(r); return (NULL); } FDLSTUFF * fdl_open(filename, fdl_descriptor) char *filename; /* What to open */ struct dsc$descriptor *fdl_descriptor; /* Result descriptor */ /* * Open the file. Returns NULL on failure, else a pointer to RMS stuff. * Which is equivalently a pointer to the RAB. (Note that the RAB points * in turn to the FAB.) * * Return the file's fdl descriptor in the user-supplied (uninitialized) * descriptor. */ { register FDLSTUFF *r; int retlen; int badblk; struct FAB *fab_add; struct RAB *rab_add; static int flags = (FDL$M_FDL_STRING | SIGNAL_ON_ERROR); extern FDLSTUFF *fdl_setup(); if ((r = fdl_setup(filename)) == NULL) return (NULL); /* * Now open the file. */ r->fab.fab$b_fac = FAB$M_GET | FAB$M_BIO; /* Block I/O only */ if ((fdl_status = sys$open(&r->fab)) != RMS$_NORMAL) { return (fail(r, "opening file", NULL)); } if ((r->fab.fab$l_dev & DEV$M_REC) != 0) { fail(r, "Record only device"); fdl_close(r); return (NULL); } r->rab.rab$l_rop = RAB$M_BIO; /* Block I/O only */ if ((fdl_status = sys$connect(&r->rab)) != RMS$_NORMAL) return (fail(r, "connecting after open", NULL)); if (fdl_descriptor != NULL) { /* * Now, get the file attributes */ fdl_descriptor->dsc$w_length = 4096; fdl_descriptor->dsc$b_dtype = DSC$K_DTYPE_VT; fdl_descriptor->dsc$b_class = DSC$K_CLASS_D; fdl_descriptor->dsc$a_pointer = malloc(4096); fab_add = &r->fab; rab_add = &r->rab; if ((fdl_status = fdl$generate( &flags, &fab_add, &rab_add, 0, 0, fdl_descriptor, &badblk, &retlen)) != SS$_NORMAL) { fdl_free(fdl_descriptor); sys$close(&r->fab); return(fail(r, "getting fdl info", NULL)); } /* * Success, null-terminate fdl info and squeeze the block. */ fdl_descriptor->dsc$a_pointer[retlen] = EOS; fdl_descriptor->dsc$a_pointer = realloc(fdl_descriptor->dsc$a_pointer, retlen + 1); fdl_descriptor->dsc$w_length = retlen; } return (r); } FDLSTUFF * fdl_create(fdl_descriptor, override_filename) struct dsc$descriptor *fdl_descriptor; /* Result descriptor */ char *override_filename; /* What to open */ /* * Create the file, Returns NULL on failure, else a pointer to RMS stuff. * Which is equivalently a pointer to the RAB. (Note that the RAB points * in turn to the FAB.) The file is open for writing using fdl_write. * * Uses the filename in the descriptor block, or the override filename * if supplied (non-NULL and not == ""); * * If fdl_descriptor is NULL, the override_filename is opened normally. */ { register FDLSTUFF *r; int retlen; int badblk; static int flags = (FDL$M_FDL_STRING | SIGNAL_ON_ERROR); struct dsc$descriptor newname; struct dsc$descriptor *newname_ptr; int fid_block[3]; char created_name[NAM$C_MAXRSS + 1]; struct dsc$descriptor created_name_des = { NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, &created_name[0] }; extern FDLSTUFF *fdl_setup(); if (fdl_descriptor == NULL) { if ((r = fdl_setup(override_filename)) == NULL) return (NULL); r->fab.fab$b_fac = FAB$M_PUT | FAB$M_BIO; /* Block I/O only */ r->fab.fab$l_fop |= (FAB$M_NAM | FAB$M_SQO | FAB$M_BIO); r->fab.fab$b_org = FAB$C_SEQ; /* Sequential only */ r->fab.fab$b_rfm = FAB$C_UDF; /* Undefined format */ if ((fdl_status = sys$create(&r->fab)) & 01 == 0) return (fail(r, "creating (sys$create)")); goto exit; } if (override_filename == NULL || override_filename[0] == '\0') newname_ptr = NULL; else { newname_ptr = &newname; newname.dsc$w_length = strlen(override_filename); newname.dsc$b_dtype = DSC$K_DTYPE_T; newname.dsc$b_class = DSC$K_CLASS_S; newname.dsc$a_pointer = override_filename; } if ((fdl_status = fdl$create(fdl_descriptor, newname_ptr, /* New file name if any */ 0, /* Default filename */ &created_name_des, /* Resultant filename */ &fid_block[0], /* File ID block */ &flags, /* FDL flag bits */ 0, /* Statement number */ &retlen, /* Created name length */ 0, 0) /* Create status, stv */ ) & 01 == 0) { return(fail(NULL, "creating (fdl$create)", NULL)); } created_name[retlen] = '\0'; if ((r = fdl_setup(created_name)) == NULL) return (NULL); /* * Now, open the file for output. */ r->fab.fab$b_fac = FAB$M_PUT | FAB$M_BIO; /* Block I/O only */ if ((fdl_status = sys$open(&r->fab)) != RMS$_NORMAL) { return (fail(r, "opening created file", NULL)); } exit: if ((r->fab.fab$l_dev & DEV$M_REC) != 0) { fail(r, "Record only device"); fdl_close(r); return (NULL); } r->rab.rab$l_rop = RAB$M_BIO; /* Block I/O only */ if ((fdl_status = sys$connect(&r->rab)) != RMS$_NORMAL) return (fail(r, "connecting after create", NULL)); return (r); } static FDLSTUFF * fdl_setup(filename) char *filename; /* * Initializes rms blocks and parses file name. Returns the * FDL data block on success, NULL on error. */ { register FDLSTUFF *r; if ((r = (char *)malloc(sizeof (FDLSTUFF))) == NULL) return (NULL); r->fab = cc$rms_fab; /* Preset fab, */ r->nam = cc$rms_nam; /* name block */ r->rab = cc$rms_rab; /* and record block */ r->xab = cc$rms_xabfhc; /* file header block */ r->fab.fab$l_nam = &r->nam; /* fab -> name block */ r->fab.fab$l_xab = &r->xab; /* fab -> file header */ r->fab.fab$l_fna = filename; /* Argument filename */ r->fab.fab$b_fns = strlen(filename); /* ... size */ r->rab.rab$l_fab = &r->fab; /* rab -> fab */ /* Stuff the name block */ r->nam.nam$l_esa = r->starname; /* Expanded filename */ r->nam.nam$b_ess = NAM$C_MAXRSS + 1; /* ... size */ r->nam.nam$b_rss = NAM$C_MAXRSS + 1; /* ... max size */ if ((fdl_status = sys$parse(&r->fab)) != RMS$_NORMAL) { return (fail(r, "parsing", filename)); } ((char *)r->nam.nam$l_esa)[r->nam.nam$b_esl] = EOS; r->fab.fab$l_fna = r->nam.nam$l_esa; /* File name */ r->fab.fab$b_fns = r->nam.nam$b_esl; /* Length */ r->fab.fab$l_fop |= FAB$M_NAM; /* Use name block */ return (r); } fdl_free(fdl_descriptor) struct dsc$descriptor *fdl_descriptor; /* * Release the descriptor */ { if (fdl_descriptor->dsc$a_pointer != NULL) { free(fdl_descriptor->dsc$a_pointer); fdl_descriptor->dsc$a_pointer = NULL; } } fdl_close(r) register FDLSTUFF *r; { if ((fdl_status = sys$close(&r->fab)) != RMS$_NORMAL) return(fail(r, "close", NULL)); free(r); } int fdl_read(buffer, buffer_length, r) char *buffer; /* Record */ int buffer_length; /* Record length */ register FDLSTUFF *r; /* Record info. */ /* * Read the next record from the file. Returns number of bytes read or * -1 on any error. fdl_status has the status. */ { r->rab.rab$l_ubf = buffer; r->rab.rab$w_usz = buffer_length; r->rab.rab$l_bkt = 0; if ((fdl_status = sys$read(&r->rab)) != RMS$_NORMAL) { #if TESTING_FDLIO if (fdl_status != RMS$_EOF) { fdl_message(r, "error return from sys$read"); sleep(1); } #endif return (-1); } return (r->rab.rab$w_rsz); } int fdl_write(buffer, buffer_length, r) char *buffer; /* Record */ int buffer_length; /* Record length */ register FDLSTUFF *r; /* Record info. */ /* * Write the next record to the file. Returns number of bytes written or * -1 on any error. fdl_status has the status. */ { r->rab.rab$l_rbf = buffer; r->rab.rab$w_rsz = buffer_length; r->rab.rab$l_bkt = 0; if ((fdl_status = sys$write(&r->rab)) != RMS$_NORMAL) { #if TESTING_FDLIO fdl_message(r, "error return from sys$write"); sleep(1); #endif return (-1); } return (r->rab.rab$w_rsz); } fdl_getname(r, buffer) FDLSTUFF *r; /* File pointer */ char *buffer; /* Where to put it */ /* * Return current file name */ { strcpy(buffer, r->fab.fab$l_fna); return (buffer); } long fdl_fsize(r) FDLSTUFF *r; /* File pointer */ /* * Return current file size */ { return (((long) r->xab.xab$l_ebk * 512) + r->xab.xab$w_ffb); } fdl_message(r, why) FDLSTUFF *r; char *why; /* * Print error message */ { extern char *vms_etext(); if (why == NULL) { fprintf(stderr, "\n%s\n\n", vms_etext(fdl_status)); } else { fprintf(stderr, "\n%s%s%s: %s\n\n", why, (why[0] == EOS) ? "" : " ", (r == NULL) ? "" : r->fab.fab$l_fna, vms_etext(fdl_status)); } } static char errname[257]; /* Error text stored here */ static $DESCRIPTOR(err, errname); /* descriptor for error text */ static char * vms_etext(errorcode) int errorcode; { char *bp; short errlen; /* Actual text length */ lib$sys_getmsg(&errorcode, &errlen, &err, &15); /* * Trim trailing junk. */ for (bp = &errname[errlen]; --bp >= errname;) { if (isgraph(*bp) && *bp != ' ') break; } bp[1] = EOS; return(errname); } static message(r, why, name) FDLSTUFF *r; /* Buffer */ char *why; /* A little commentary */ char *name; /* File name */ /* * Print error message */ { fprintf(stderr, "\nRMS error %x when %s %s\n", fdl_status, why, (name == NULL) ? "" : name); fprintf(stderr, "\"%s\"\n", vms_etext(fdl_status)); } fdl_dump(fdl_descriptor, fd) struct dsc$descriptor *fdl_descriptor; FILE *fd; /* * Dump the descriptor to fd. */ { register char *tp, *end; tp = fdl_descriptor->dsc$a_pointer; end = tp + fdl_descriptor->dsc$w_length; while (tp < end) { if (*tp == '"') { do { putc(*tp++, fd); } while (*tp != '"'); } putc(*tp, fd); if (*tp++ == ';') putc('\n', fd); } } #if TESTING_FDLIO /* * Test program for rms io */ #include char line[133]; char filename[133]; char buffer[2048]; main(argc, argv) int argc; char *argv[]; { FDLSTUFF *old; FDLSTUFF *new; int size, total, nrecords; struct dsc$descriptor fdl_info; /* Result descriptor */ for (;;) { fprintf(stderr, "Old file name: "); fflush(stdout); if (gets(line) == NULL) break; if (line[0] == EOS) continue; if ((old = fdl_open(line, &fdl_info)) == NULL) { fprintf(stderr, "open failed\n"); continue; } fprintf(stderr, "New file name: "); if (gets(line) == NULL) break; if ((new = fdl_create(&fdl_info, line)) == NULL) { fprintf(stderr, "create failed\n"); fdl_free(&fdl_info); continue; } fdl_getname(old, buffer); fprintf(stderr, "Fdl for \"%s\", size %ld\n", buffer, fdl_fsize(old)); fdl_dump(&fdl_info, stderr); total = nrecords = 0; while ((size = fdl_read(buffer, sizeof buffer, old)) > 0) { fdl_write(buffer, size, new); nrecords++; total += size; } fdl_close(old); fdl_close(new); fprintf(stderr, "copied %d records, %d bytes total\n", nrecords, total); fdl_free(&fdl_info); } } #endif #endif