From fa080de7afc95aa1c19a6e6fc0e0708ced2eadc4 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Wed, 8 Jul 2015 20:46:52 -0400 Subject: Initial commit --- noao/twodspec/multispec/dbio/dbio.h | 24 ++ noao/twodspec/multispec/dbio/dbio.x | 564 ++++++++++++++++++++++++++++++++++++ noao/twodspec/multispec/dbio/mkpkg | 9 + 3 files changed, 597 insertions(+) create mode 100644 noao/twodspec/multispec/dbio/dbio.h create mode 100644 noao/twodspec/multispec/dbio/dbio.x create mode 100644 noao/twodspec/multispec/dbio/mkpkg (limited to 'noao/twodspec/multispec/dbio') diff --git a/noao/twodspec/multispec/dbio/dbio.h b/noao/twodspec/multispec/dbio/dbio.h new file mode 100644 index 00000000..dd9f65f1 --- /dev/null +++ b/noao/twodspec/multispec/dbio/dbio.h @@ -0,0 +1,24 @@ + +# Definitions for subset DBIO + +define SZ_DB_KEY 79 # Size of database reference keys +define MAX_DB_DES 10 # Maximum number of DBIO descriptors +define DB_ERRCODE 1000 # Start of DBIO error codes + +# DBIO descriptor + +define LEN_DB_DES 3 + +define DB_FD Memi[$1] # The database FIO descriptor +define DB_DIC Memi[$1+1] # Pointer to the dictionary memory +define DB_UPDATE Memi[$1+2] # Has dictionary been change [y/n] + +# DBIO dictionary entry. Each entry is referenced with the pointer to the +# dictionary memory ($1) and the entry number ($2). + +define LEN_DB_ENTRY 43 + +define DB_KEY Memi[$1+($2-1)*LEN_DB_ENTRY] # Key +define DB_OFFSET Meml[$1+($2-1)*LEN_DB_ENTRY+40] # File Offset +define DB_SZ_ELEM Memi[$1+($2-1)*LEN_DB_ENTRY+41] # Element size +define DB_DIM Memi[$1+($2-1)*LEN_DB_ENTRY+42] # Number of elements diff --git a/noao/twodspec/multispec/dbio/dbio.x b/noao/twodspec/multispec/dbio/dbio.x new file mode 100644 index 00000000..faa21cef --- /dev/null +++ b/noao/twodspec/multispec/dbio/dbio.x @@ -0,0 +1,564 @@ + +include +include +include "dbio.h" + +.help dbio 2 "Subset Database I/O Procedures" +.sh +1. Introduction + + These DBIO procedures are a subset of the general +DBIO design described in "Specifications of the IRAF DBIO Interface" by +Doug Tody (Oct 1983). It is designed to allow programs written using +the subset DBIO to be easily converted to the full DBIO. It's features +are: +.ls 4 1. +Database open and close. +.le +.ls 4 2. +Reference to entries by a (possibly) subscripted record name string. +.le +.ls 4 3. +Ability to add new record types as desired. +.le +.ls 4 4. +Error recovery procedure to cleanup after an uncaught error. +.le + +The primary limitations are: +.ls 4 1. +No aliases. +.le +.ls 4 2. +No datatyping and no self-describing structures. +.le +.ls 4 3. +No deletions of entries. +.le +.sh +2. Procedures + +.nf + db = dbopen (file_name, mode, max_entries) + db = dbreopen (db) + dbclose (db) + dbenter (db, record_name, sz_elem, nreserve) + y/n = dbaccess (db, record_name) + nread = dbread (db, reference, buf, maxelems) + dbwrite (db, reference, buf, nelems) +.fi + + A new, empty database is created by opening with access modes NEW_FILE +or TEMP_FILE. The dictionary will be intialized to allow max_entries +number of dictionary entries. The other legal access modes are READ_ONLY and +READ_WRITE. The max_entries argument is not used with these modes. To create +a new entry in the database the name of the record, the size of a record +element, and the maximum number of such records to be stored are specified. +This differs from the full DBIO specification in that a record is described +only by a size instead of a datatype. Also it is not possible to increase +the number of elements once it has been entered. The database read and +write procedures do no type conversion. They read procedure returns +the number of elements read. If a reference is not found in the +dictionary in either reading or writing an error condition occurs. +Also an attempt to read or write an element exceeding the dimension +entered in the dictionary will create an error condition. +.endhelp + + +# DBOPEN, DBREOPEN -- Open a database file. + +pointer procedure dbopen (file_name, ac_mode, db_nentries) + +# Procedure dbopen parameters: +char file_name[SZ_FNAME] # Database filename +int ac_mode # Access mode (new,temp,r,rw) +int db_nentries # Creation dictionary size + +# Entry dbreopen parameters: +pointer dbreopen # Function type +pointer db_old # Old database descriptor + +int mode +pointer fd, db # FIO descriptor and DBIO descriptor +pointer dic +int nelem, nentries + +bool strne() +int open(), dbread(), reopen() +errchk db_getdes, calloc, dbenter, dbread, db_init + +begin + # Check for valid access mode. Valid modes require read permission. + # If a valid access mode open database with FIO. + mode = ac_mode + if ((mode == WRITE_ONLY) || (mode == APPEND)) + call error (DB_ERRCODE + 0, "Invalid database access mode") + fd = open (file_name, mode, BINARY_FILE) + goto 10 + +entry dbreopen (db_old) + + fd = reopen (DB_FD(db_old), mode) + + # Get DBIO descriptor +10 call db_getdes (db) + DB_FD(db) = fd + + # If the database is being created enter the dictionary in the file. + # If the database already exists read the current dictionary and + # check to see if the file is a database. + switch (mode) { + case NEW_FILE, TEMP_FILE: + # Allocate dictionary space and enter it in the database. + # The request entries is increased by one for the dictionary + # database entry itself. + nentries = db_nentries + 1 + call calloc (dic, nentries * LEN_DB_ENTRY, TY_STRUCT) + DB_DIC(db) = dic + call dbenter (db, "db_dictionary", LEN_DB_ENTRY * SZ_STRUCT, + nentries) + case READ_ONLY, READ_WRITE: + # Read dictionary. + call db_init (db, 1) + dic = DB_DIC(db) + nelem = dbread (db, "db_dictionary", Memi[dic], 1) + if (nelem != 1) + call error (DB_ERRCODE + 1, "Error reading database dictionary") + if (strne (DB_KEY(dic, 1), "db_dictionary")) + call error (DB_ERRCODE + 2, "File is not a database") + + nentries = DB_DIM(dic, 1) + call db_init (db, nentries) + dic = DB_DIC(db) + nelem = dbread (db, "db_dictionary", Memi[dic], nentries) + if (nelem != nentries) + call error (DB_ERRCODE + 3, "Error reading database dictionary") + } + + return (db) +end + + +# DB_INIT -- Initialize the program dictionary space + +procedure db_init (db, db_nentries) + +pointer db +int db_nentries + +pointer dic + +long note() +errchk mfree, calloc, seek + +begin + # Allocate dictionary memory + dic = DB_DIC(db) + if (dic != NULL) + call mfree (dic, TY_STRUCT) + call calloc (dic, db_nentries * LEN_DB_ENTRY, TY_STRUCT) + DB_DIC(db) = dic + + # Fill in dictionary entry + call strcpy ("db_dictionary", DB_KEY(dic, 1), SZ_DB_KEY) + DB_SZ_ELEM(dic, 1) = LEN_DB_ENTRY * SZ_STRUCT + DB_DIM(dic, 1) = db_nentries + call seek (DB_FD(db), BOF) + DB_OFFSET(dic, 1) = note (DB_FD(db)) +end + +# DBENTER -- Make a new entry in the database dictionary and reserve +# file space in the database. + +procedure dbenter (db, record_name, sz_elem, nreserve) + +pointer db # DBIO descriptor +char record_name[SZ_DB_KEY] # Record name string +int sz_elem # Size of record element in CHARS +int nreserve # Number of record elements to reserve + +int i +int sz_reserve, sz_buf +pointer dic, buf + +bool streq() +int fstati() +long note() + +errchk calloc, dbclose, write, seek + +begin + # Check access mode + if (fstati(DB_FD(db), F_WRITE) == NO) + call error (DB_ERRCODE + 4, "Database is read only") + + # Find the last entry. Check for attempts to redefine an + # entry and to overflow the dictionary. + dic = DB_DIC(db) + for (i = 1; i <= DB_DIM(dic, 1); i = i + 1) { + if (DB_DIM(dic, i) == 0) + break + if (streq (record_name, DB_KEY(dic, i))) + call error (DB_ERRCODE + 5, "Attempt to redefine dictionary entry") + } + if ((i > 1) && (i > DB_DIM(dic, 1))) + call error (DB_ERRCODE + 6, "Database dictionary is full") + + # Make dictionary entry + call strcpy (record_name, DB_KEY(dic, i), SZ_DB_KEY) + DB_SZ_ELEM(dic, i) = sz_elem + DB_DIM(dic, i) = nreserve + call seek (DB_FD(db), EOF) + DB_OFFSET(dic, i) = note (DB_FD(db)) + DB_UPDATE(db) = YES + + # Initialize file space to zero. Zero file blocks for efficiency. + sz_reserve = sz_elem * nreserve + sz_buf = min (fstati (DB_FD(db), F_BLKSIZE), sz_reserve) + call calloc (buf, sz_buf, TY_CHAR) + + while (sz_reserve > 0) { + call write (DB_FD(db), Memc[buf], sz_buf) + sz_reserve = sz_reserve - sz_buf + sz_buf = min (sz_buf, sz_reserve) + } + call mfree (buf, TY_CHAR) +end + +# DBACCESS -- Is data reference in the database? + +bool procedure dbaccess (db, record_name) + +pointer db # DBIO descriptor +char record_name[SZ_DB_KEY] # Record name string + +int i +pointer dic + +bool streq() + +begin + dic = DB_DIC(db) + for (i = 1; i <= DB_DIM(dic, 1); i = i + 1) { + if (DB_DIM(dic, i) == 0) + return (FALSE) + if (streq (record_name, DB_KEY(dic, i))) + return (TRUE) + } + return (FALSE) +end + + +# DBNEXTNAME -- Return name of the next dictionary entry. + +int procedure dbnextname (db, previous, outstr, maxch) + +pointer db # DBIO descriptor +char previous[ARB] +char outstr[ARB] +int maxch + +int i +pointer dic + +bool streq(), strne() + +begin + dic = DB_DIC(db) + i = 1 + if (strne (previous, "")) { + for (; i <= DB_DIM(dic, 1); i = i + 1) { + if (DB_DIM(dic, i) == 0) + return (EOF) + if (streq (previous, DB_KEY(dic, i))) + break + } + } + i = i + 1 + if ((i > DB_DIM(dic, 1)) || (DB_DIM(dic, i) == 0)) + return (EOF) + else + call strcpy (DB_KEY(dic, i), outstr, maxch) + + return (OK) +end + + +#DBREAD - Read data from the database. +# The number of data elements read is returned. + +int procedure dbread (db, ref, buf, maxelems) + +pointer db # Database file descriptor +char ref[ARB] # Data reference +char buf[ARB] # Data buffer +int maxelems # Number of elements to be read + +int i, j +int stat, sz_elem, index, nread +long offset +pointer dic + +int strncmp(), strlen(), stridxs(), ctoi() +bool streq() +int read() +errchk read, dbclose + +begin + dic = DB_DIC(db) + + # Decode the data reference and set the file offset and the size + # of the data element. If a valid data reference is not found + # then a read status of 0 is returned. + + j = stridxs ("[", ref) + for (i = 1; i <= DB_DIM(dic, 1); i = i + 1) { + if (DB_DIM(dic, i) == 0) + call error (DB_ERRCODE + 7, "Database request not found") + if (j == 0) { + if (streq (ref, DB_KEY(dic, i))) + break + } else { + if (strlen (DB_KEY(dic, i)) == j - 1) + if (strncmp (ref, DB_KEY(dic, i), j - 1) == 0) + break + } + } + + offset = DB_OFFSET(dic, i) + sz_elem = DB_SZ_ELEM(dic, i) + nread = maxelems + if (j > 0) { + j = ctoi (ref, j + 1, index) + if (j > 0) { + if (maxelems > DB_DIM(dic, i) - index + 1) { + call error (DB_ERRCODE + 8, "Database request out of bounds") + } + offset = offset + (index - 1) * sz_elem + } + } + + # Seek and read the data + call seek (DB_FD(db), offset) + stat = read (DB_FD(db), buf, sz_elem * nread) / sz_elem + return (stat) +end + + +# DBWRITE - Write data to the database. + +procedure dbwrite (db, ref, buf, nelems) + +pointer db # DBIO descriptor +char ref[ARB] # Data reference +char buf[ARB] # Data buffer +int nelems # Number of elements to written + +int i, j +int sz_elem, index, nwritten +long offset +pointer dic + +int strncmp(), strlen(), stridxs(), ctoi() +bool streq() +errchk write, dbclose + +begin + dic = DB_DIC(db) + + # Decode the data reference and set the file offset and the size + # of the data element. If a valid data reference is not found + # then the data is not written and a write status of 0 is returned. + + j = stridxs ("[", ref) + for (i = 1; i <= DB_DIM(dic, 1); i = i + 1) { + if (DB_DIM(dic, i) == 0) + call error (DB_ERRCODE + 9, "Database request not found") + if (j == 0) { + if (streq (ref, DB_KEY(dic, i))) + break + } else { + if (strlen (DB_KEY(dic, i)) == j - 1) + if (strncmp (ref, DB_KEY(dic, i), j - 1) == 0) + break + } + } + + offset = DB_OFFSET(dic, i) + sz_elem = DB_SZ_ELEM(dic, i) + nwritten = nelems + if (j > 0) { + j = ctoi (ref, j + 1, index) + if (j > 0) { + if (nelems > DB_DIM(dic, i) - index + 1) { + call error (DB_ERRCODE + 10, "Database request out of bounds") + } + offset = offset + (index - 1) * sz_elem + } + } + + # Seek and write the data + call seek (DB_FD(db), offset) + call write (DB_FD(db), buf, sz_elem * nwritten) + return +end + + +# DBCLOSE -- Update the dictionary in the database, close the database +# and free DBIO descriptor. + +procedure dbclose (db) + +pointer db + +begin + # Update dictionary in database + if (DB_UPDATE(db) == YES) + call dbwrite (db, "db_dictionary", Memi[DB_DIC(db)], + DB_DIM(DB_DIC(db), 1)) + + call close (DB_FD(db)) + call db_freedes (db) +end + + +# Procedures accessing the DBIO descriptor list. +# +# DB_GETDES -- Allocate and return a DBIO descriptor. Post error recovery. +# DB_FREEDES -- Close a database and free allocated memory. +# DB_ERROR -- Take error recovery action by closing all open databases. + +procedure db_getdes (db) + +pointer db # Allocated DBIO descriptor + +extern db_error() +errchk malloc() + +int ndes # Number of allocated DBIO descriptors +pointer dbdes[MAX_DB_DES] # DBIO descriptor list + +common /dbiocom/ ndes, dbdes + +int init +data init/YES/ + +begin + if (init == YES) { + ndes = 0 + init = NO + } + + # Check to see if the requested descriptor would overflow the descriptor + # list. If not allocate memory for the descriptor otherwise + # start error handling. On the first call post the error handler. + + if (ndes == MAX_DB_DES) + call error (DB_ERRCODE + 11, "Attempt to open too many database files") + + ndes = ndes + 1 + call malloc (dbdes[ndes], LEN_DB_DES, TY_STRUCT) + db = dbdes[ndes] + DB_FD(db) = NULL + DB_DIC(db) = NULL + DB_UPDATE(db) = NO + + if (ndes == 1) + call onerror (db_error) +end + + +# DB_FREEDES -- Close a database and free allocated memory. + +procedure db_freedes (db) + +pointer db # DBIO descriptor to be freed + +int i + +int ndes # Number of allocated DBIO descriptors +pointer dbdes[MAX_DB_DES] # DBIO descriptor list + +common /dbiocom/ ndes, dbdes + +begin + + # Locate the specified descriptor in the descriptor list. + # If the descriptor is not in the list do nothing. + # If the descriptor is in the list free allocated + # memory and remove the entry from the list. + + for (i = 1; (i <= ndes) && (db != dbdes[i]); i = i + 1) + ; + if (i > ndes) + return + + if (DB_DIC(db) != NULL) + call mfree (DB_DIC(db), TY_STRUCT) + call mfree (db, TY_STRUCT) + + if (i < ndes) + dbdes[i] = dbdes[ndes] + ndes = ndes - 1 +end + + +# DB_ERROR -- Take error recovery action by closing all open databases. + +procedure db_error (error_code) + +int error_code # Error code + +int i + +int ndes # Number of allocated DBIO descriptors +pointer dbdes[MAX_DB_DES] # DBIO descriptor list + +common /dbiocom/ ndes, dbdes + +begin + # Let fio_cleanup deal with the open files and the system + # restart deal with freeing the stack. This procedure + # cleans up the dbio descriptors and updates the database + # dictionary. + + do i = 1, ndes + # Update dictionary in database. Catch errors. + if (DB_UPDATE(dbdes[i]) == YES) + iferr (call dbwrite (dbdes[i], "db_dictionary", + Memi[DB_DIC(dbdes[i])], DB_DIM(DB_DIC(dbdes[i]), 1))) + call erract (EA_WARN) + + call db_freedes (dbdes[i]) +end + + +int procedure dbgeti (db, key, type) + +pointer db +char key[ARB] +char type[ARB] + +int i +pointer dic + +bool streq() + +begin + dic = DB_DIC(db) + for (i = 1; i <= DB_DIM(dic, 1); i = i + 1) { + if (DB_DIM(dic, i) == 0) + call error (0, "Key not in database") + if (streq (key, DB_KEY(dic, i))) + break + } + if (i > DB_DIM(dic, 1)) + call error (0, "Key not in database") + + if (streq (type, "r_len")) + return (DB_DIM(dic, i)) + else if (streq (type, "r_size")) + return (DB_SZ_ELEM(dic, i)) + else + call error (0, "Unknown database key attribute") +end diff --git a/noao/twodspec/multispec/dbio/mkpkg b/noao/twodspec/multispec/dbio/mkpkg new file mode 100644 index 00000000..f1aee503 --- /dev/null +++ b/noao/twodspec/multispec/dbio/mkpkg @@ -0,0 +1,9 @@ +# Multispec/dbio library. + +$checkout libpkg.a ../ +$update libpkg.a +$checkin libpkg.a ../ + +libpkg.a: + dbio.x dbio.h + ; -- cgit