home *** CD-ROM | disk | FTP | other *** search
/ Photo CD Demo 1 / Demo.bin / hdf / unix / hdf3_2r2 / src / hfile.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-10-29  |  102.7 KB  |  3,477 lines

  1. /***************************************************************************
  2. *
  3. *
  4. *                         NCSA HDF version 3.2r2
  5. *                            October 30, 1992
  6. *
  7. * NCSA HDF Version 3.2 source code and documentation are in the public
  8. * domain.  Specifically, we give to the public domain all rights for future
  9. * licensing of the source code, all resale rights, and all publishing rights.
  10. *
  11. * We ask, but do not require, that the following message be included in all
  12. * derived works:
  13. *
  14. * Portions developed at the National Center for Supercomputing Applications at
  15. * the University of Illinois at Urbana-Champaign, in collaboration with the
  16. * Information Technology Institute of Singapore.
  17. *
  18. * THE UNIVERSITY OF ILLINOIS GIVES NO WARRANTY, EXPRESSED OR IMPLIED, FOR THE
  19. * SOFTWARE AND/OR DOCUMENTATION PROVIDED, INCLUDING, WITHOUT LIMITATION,
  20. * WARRANTY OF MERCHANTABILITY AND WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE
  21. *
  22. ****************************************************************************
  23. */
  24.  
  25.  
  26. #ifdef RCSID
  27. static char RcsId[] = "@(#)$Revision: 1.6 $";
  28. #endif
  29. /*
  30. $Header: /hdf/hdf/v3.2r2/src/RCS/hfile.c,v 1.6 1992/10/23 00:14:11 koziol beta koziol $
  31.  
  32. $Log: hfile.c,v $
  33.  * Revision 1.6  1992/10/23  00:14:11  koziol
  34.  * Changed all DFIstr*() and DFImem*() calls to HDstr*() and HDmem*() calls
  35.  * #ifdef'd out the macros Jason defined for Hopen, Hclose, etc. for Vsets
  36.  * Replaced Vset VFREESPACE and VGETSPACE calls with actual calls to HDfreespace
  37.  * and HDgetspace
  38.  * Added a MS-Windows lower lower for file I/O (which may not be completely working
  39.  *
  40.  * Revision 1.4  1992/10/12  18:11:51  koziol
  41.  * Updated for v3.2r2 release
  42.  *
  43.  * Revision 1.3  1992/09/17  20:11:12  koziol
  44.  * Updated hfile.c with many different bugfixes...
  45.  *
  46.  * Revision 1.4  1992/09/15  21:04:06  chouck
  47.  * Removed DFACC_CREATE problems.  Restored some other changes that had
  48.  * gotten over-written
  49.  *
  50.  * Revision 1.3  1992/09/11  16:43:24  chouck
  51.  * Minor Mac fix
  52.  *
  53.  * Revision 1.2  1992/08/26  19:44:25  chouck
  54.  * Moved HDgettagname() into hkit.c and added calibration tag
  55.  *
  56.  * Revision 1.1  1992/08/25  21:40:44  koziol
  57.  * Initial revision
  58.  *
  59. */
  60. /*LINTLIBRARY*/
  61. /*+
  62.  FILE
  63.        hfile.c
  64.        HDF low level file I/O routines
  65.  EXPORTED ROUTINES
  66.        Hopen -- open or create a HDF file
  67.        Hclose -- close HDF file
  68.        Hstartread -- locate and position a read access elt on a tag/ref
  69.        Hnextread -- locate and position a read access elt on next tag/ref.
  70.        Hinquire -- inquire stats of an access elt
  71.        Hstartwrite -- set up a WRITE access elt for a write
  72.        Hseek -- position an access element to an offset in data element
  73.        Hread -- read the next segment from data element
  74.        Hwrite -- write next data segment to data element
  75.        Hendaccess -- to dispose of an access element
  76.        Hgetelement -- read in a data element
  77.        Hlength -- returns length of a data element
  78.        Hoffset -- get offset of data element in the file
  79.        Hputelement -- writes a data element
  80.        Hdupdd -- duplicate a data descriptor
  81.        Hdeldd -- delete a data descriptor
  82.        Hnewref -- returns a ref that is guaranteed to be unique in the file
  83.        Hishdf -- tells if a file is an HDF file
  84.        Hsync -- sync file with memory
  85.        Hnumber -- count number of occurrances of tag/ref in file
  86.        Hgetlibversion -- return version info on current HDF library
  87.        Hgetfileversion -- return version info on HDF file
  88.  AUTHOR
  89.        Chin_Chau Low
  90.  MODIFICATION HISTORY
  91.     12/12/91 Doug Ilg  Changed implementation of version tags.  Added
  92.                Hgetlibversion() and Hgetfileversion() (public) and
  93.                HIread_version() and HIupdate_version() (PRIVATE).
  94. +*/
  95. /*
  96.  SOME EXAMPLES
  97.        Example 1.  To create a HDF file and write a data element into it in
  98.        one go:
  99.  
  100.        int fileid;
  101.        int tag=100, ref;
  102.        char data[DATA_SIZE];
  103.  
  104.        ..create a file with clobber, use default ndds..
  105.        fileid = Hopen("myfile.hdf", DF_CREATE, 0);
  106.        ..get a new ref..
  107.        ref = Hnewref(fileid);
  108.        Hputelement(fileid, tag, ref, data, DATA_SIZE);
  109.  
  110.        Hclose(fileid);
  111.  
  112.        Example 2.  To read a data element in one go:
  113.  
  114.        int fileid;
  115.        int tag=100, ref=3;
  116.        long length;
  117.        char data[DATA_SIZE];
  118.  
  119.        ..open the file with read only..
  120.        fileid = Hopen("myfile.hdf", DFACC_READ, 0);
  121.        ..check length of data element..
  122.        length = Hlength(fileid, tag, ref);
  123.        if (length > DATA_SIZE) routine_with_larger_buffer();
  124.        else
  125.            Hgetelement(fileid, tag, ref, data);
  126.  
  127.        Example 3.  To write 2 data elements piece by piece
  128.  
  129.        int fileid;
  130.        int acc1, acc2;
  131.        int tag1=100, tag2=200;
  132.        int ref1=1, ref2=3;
  133.        char buf1[1000], buf2[500];
  134.  
  135.        fileid = Hopen("myfile.hdf", DF_CREATE, 0)
  136.        acc1 = Hstartwrite(fileid, tag1, ref1, ELT1_SIZE);
  137.        acc2 = Hstartwrite(fileid, tag2, ref2, ELT2_SIZE);
  138.  
  139.        Hwrite(acc1, 1000L, buf1);
  140.        Hwrite(acc2, 500L, buf2);
  141.        ..fill buffers again..
  142.        Hwrite(acc1, 1000L, buf1);
  143.        ..etc..
  144.        Hendaccess(acc1);
  145.        Hendaccess(acc2);
  146.  
  147.        Example 4.  To read 2 data element piece by piece
  148.  
  149.        int fileid;
  150.        int acc1, acc2;
  151.        int tag1=100, tag2=200;
  152.        int ref1=1, ref2=3;
  153.        char buf1[1000], buf2[500];
  154.  
  155.        fileid = Hopen("myfile.hdf", DFACC_READ, 0);
  156.        acc1 = Hstartread(fileid, tag1, ref1);
  157.        acc2 = Hstartread(fileid, tag2, ref2);
  158.  
  159.        Hread(acc1, 1000L, buf1);
  160.        Hread(acc2, 500L, buf2);
  161.        ..do something with data read..
  162.        Hread(acc1, 1000L, buf1);
  163.        ..etc..
  164.        Hendaccess(acc1);
  165.        Hendaccess(acc2);
  166. */
  167.  
  168. #define HMASTER
  169. #include "hdf.h"
  170. #undef HMASTER
  171. #include "herr.h"
  172. #include "hfile.h"
  173.  
  174. /*
  175. ** Prototypes for local functions
  176. */
  177. static int HIlock
  178.   PROTO((int32 file_id));
  179.  
  180. static int HIunlock
  181.   PROTO((int32 file_id));
  182.  
  183. static int HIchangedd
  184.   PROTO((dd_t *datadd, ddblock_t *block, int idx, int16 special,
  185.      VOIDP special_info, int32 (**special_func)()));
  186.  
  187. /*
  188. int INT32ENCODE(p, i)
  189. unsigned char *p;
  190. int32 i;
  191. {
  192. char *temp=p;
  193.  *(p) = (i >> 24) & 0xff; (p)++; *(p) = (i >> 16) & 0xff; (p)++; 
  194.   *(p) = (i >> 8) & 0xff; 
  195. (p)++;
  196. *(p) = (i) & 0xff; 
  197. (p)++; }
  198. */
  199.  
  200. /* Array of file records that contains all relevant
  201.    information on an opened HDF file.
  202.    See hfile.h for structure and members definition of filerec_t. */
  203.  
  204. struct filerec_t file_records[MAX_FILE];
  205.  
  206. /* Array of records of information on each access elements.
  207.    These will contain information like how to access the data element,
  208.    where in the data element the current access should start from, etc.
  209.    Allocated dynamically.
  210.    See hfile.h for definition. */
  211.  
  212. struct accrec_t *access_records = NULL;
  213.  
  214. /* Temporary memory space for doing some general stuff so we don't
  215.    have to allocate and deallocate memory all the time.  This space should
  216.    be "sufficiently" large, or at least 64 bytes long.  Routines using
  217.    tbuf should not assume that the buffer is longer than that. */
  218.  
  219. int32 int_tbuf[TBUF_SZ];
  220. uint8 *tbuf = (uint8 *)int_tbuf;
  221.  
  222. /* Function tables declarations.  These function tables contain pointers
  223.    to functions that help access each type of special element. */
  224.  
  225. /* Functions for accessing the linked block special
  226.    data element.  For definition of the linked block, see hblocks.c. */
  227.  
  228. extern int32 (*linked_funcs[])();
  229.  
  230. /* Functions for accessing external data elements, or data
  231.    elements that are in some other files.  For definition of the external
  232.    data element, see hext.c. */
  233.  
  234. extern int32 (*ext_funcs[])();
  235.  
  236. /* Table of these function tables for accessing special elements.  The first
  237.    member of each record is the speical code for that type of data element. */
  238.  
  239. functab_t functab[] = {
  240.     {SPECIAL_LINKED, linked_funcs},
  241.     {SPECIAL_EXT, ext_funcs},
  242.     {0, NULL}                  /* terminating record; add new record */
  243.                                /* before this line */
  244. };
  245.  
  246. /*
  247. ** Declaration of private functions. 
  248. */
  249. PRIVATE int HIget_file_slot
  250.   PROTO((char *path, char *FUNC));
  251.  
  252. PRIVATE bool HIvalid_magic
  253.   PROTO((hdf_file_t file, char *FUNC));
  254.  
  255. PRIVATE int HIfill_file_rec
  256.   PROTO((filerec_t *file_rec, char *FUNC));
  257.  
  258. PRIVATE int HIinit_file_dds
  259.   PROTO((filerec_t *file_rec, int16 ndds, char *FUNC));
  260.  
  261. PRIVATE int32 (**HIget_function_table PROTO((accrec_t *access_rec, char *FUNC)))();
  262.  
  263. PRIVATE int HIupdate_version
  264.   PROTO((int32));
  265.  
  266. PRIVATE int HIread_version
  267.   PROTO((int32));
  268.  
  269. /*--------------------------------------------------------------------------
  270.  NAME
  271.        Hopen -- Opens a HDF file.
  272.  USAGE
  273.        int32 Hopen(path, access, ndds)
  274.        char *path;             IN: Name of file to be opened.
  275.        int access;             IN: DFACC_READ, DFACC_WRITE, DFACC_CREATE
  276.                                    or any bitwise-or of the above.
  277.        int16 ndds;             IN: Number of dds in a block if this
  278.                                    file needs to be created.
  279.  RETURNS
  280.        On success returns file id, on failure returns -1.
  281.  DESCRIPTION
  282.        Opens a HDF file.  Returns the the file ID on success, or -1
  283.        on failure.
  284.  
  285.        Access equals DFACC_CREATE means discard existing file and
  286.        create new file.  If access is a bitwise-or of DFACC_CREATE
  287.        and anything else, the file is only created is it does not
  288.        exist.  DFACC_WRITE set in access also means that if the file
  289.        does not exist, it is created.  DFACC_READ is assumed to be
  290.        implied even if it is not set.  DFACC_CREATE implies
  291.        DFACC_WRITE.
  292.  
  293.        If the file is already opened and access is DFACC_CREATE:
  294.        error DFE_ALROPEN.
  295.        If the file is already opened, the requested access contains
  296.        DFACC_WRITE, and previous open does not allow write: attempt
  297.        to reopen the file with write permission.
  298.  
  299.        On successful exit,
  300.        * file_rec members are filled in correctly.
  301.        * file is opened with the relevant permission.
  302.        * information about dd's are set up in memory.
  303.        For new file, in addition,
  304.        * the file headers and initial information are set up properly.
  305.  
  306.  GLOBAL VARIABLES
  307.  COMMENTS, BUGS, ASSUMPTIONS
  308.  EXAMPLES
  309.  REVISION LOG
  310. --------------------------------------------------------------------------*/
  311. #ifdef PROTOTYPE
  312. int32 Hopen(char *path, intn access, int16 ndds)
  313. #else
  314. int32 Hopen(path, access, ndds)
  315.     char *path;                        /* Path of file to open */
  316.     intn access;                       /* Access mode */
  317.     int16 ndds;                        /* Number of dd's in each ddblock
  318.                                   if file is created */
  319. #endif
  320. {
  321.     char *FUNC="Hopen";                /* For HERROR */
  322.     int slot;                  /* File record slot */
  323.     filerec_t *file_rec;       /* File record */
  324.     int vtag = 0;        /* write version tag? */
  325.  
  326.     /* Clear errors and check args and all the boring stuff. */
  327.  
  328.     HEclear();
  329.     if (!path || ((access & DFACC_ALL) != access)) {
  330.        HERROR(DFE_ARGS);
  331.        return FAIL;
  332.     }
  333.  
  334.     /* Get a space to put the file information.
  335.        HIget_file_slot() also copies path into the record. */
  336.  
  337.     slot = HIget_file_slot(path, FUNC);
  338.     if (slot == FAIL) {
  339.         /* The slots are full. */
  340.        HERROR(DFE_TOOMANY);
  341.        return FAIL;
  342.     }
  343.     file_rec = &(file_records[slot]);
  344.  
  345.     if (file_rec->refcount) {
  346.        /* File is already opened, check that permission is okay. */
  347.  
  348.         /* If this request is to create a new file and file is still
  349.           in use, return error. */
  350.        if (access == DFACC_CREATE) {
  351.            HERROR(DFE_ALROPEN);
  352.            return FAIL;
  353.        }
  354.  
  355.        if ((access & DFACC_WRITE) && !(file_rec->access & DFACC_WRITE)) {
  356.            /* If the request includes writing, and if original open does not
  357.               provide for write, then try to reopen file for writing.
  358.               This cannot be done on OS (such as the SXOS) where only one
  359.               open is allowed per file at any time. */
  360. #ifndef NO_MULTI_OPEN
  361.            hdf_file_t f;
  362.  
  363.            f = HI_OPEN(file_rec->path, access);
  364.            if (OPENERR(f)) {
  365.                HERROR(DFE_DENIED);
  366.                return FAIL;
  367.            }
  368.  
  369.            /* Replace file_rec->file with new file pointer and
  370.               close old one. */
  371.  
  372.            if (HI_CLOSE(file_rec->file) == FAIL) {
  373.                HI_CLOSE(f);
  374.                HERROR(DFE_CANTCLOSE);
  375.                return FAIL;
  376.            }
  377.            file_rec->file = f;
  378. #else /* NO_MULTI_OPEN */
  379.            HERROR(DFE_DENIED);
  380.            return FAIL;
  381. #endif /* NO_MULTI_OPEN */
  382.        }
  383.  
  384.        /* There is now one more open to this file. */
  385.  
  386.        file_rec->refcount++;
  387.  
  388.     } else {
  389.  
  390.         /* Flag to see if file is new and needs to be set up. */
  391.        bool new_file=FALSE;
  392.  
  393.        /* Open the file, fill in the blanks and all the good stuff. */
  394.        if (access != DFACC_CREATE) {
  395.            /* try to open existing file */
  396.  
  397.            file_rec->file = HI_OPEN(file_rec->path, access);
  398.            if (OPENERR(file_rec->file)) {
  399.                if (access & DFACC_WRITE) {
  400.                    /* Seems like the file is not there, try to create it. */
  401.                    new_file = TRUE;
  402.                } else {
  403.                    HERROR(DFE_BADOPEN);
  404.                    return FAIL;
  405.                }
  406.            } else {
  407.                /* Open existing file successfully. */
  408.  
  409.                file_rec->access = access | DFACC_READ;
  410.  
  411.                /* Check to see if file is a HDF file. */
  412.  
  413.                if (!HIvalid_magic(file_rec->file, FUNC)) {
  414.                    HERROR(DFE_NOTDFFILE);
  415.                    HI_CLOSE(file_rec->file);
  416.                    return FAIL;
  417.                }
  418.  
  419.                /* Read in all the relevant data descriptor records. */
  420.  
  421.                if (HIfill_file_rec(file_rec, FUNC) == FAIL) {
  422.                    HERROR(DFE_BADOPEN);
  423.                    HI_CLOSE(file_rec->file);
  424.                    return FAIL;
  425.                }
  426.            }
  427.        }
  428.  
  429.        /* do *not* use else here */
  430.  
  431.        if (access == DFACC_CREATE || new_file) {
  432.            /* create the file */
  433.  
  434.         /* version tags */
  435.             vtag = 1;
  436.         /* end version tags */
  437.  
  438.            file_rec->file = HI_CREATE(path);
  439.            if (OPENERR(file_rec->file)) {
  440.                HERROR(DFE_BADOPEN);
  441.                return FAIL;
  442.            }
  443.  
  444.            /* set up the newly created (and empty) file with
  445.               the magic cookie and initial data descriptor records */
  446.  
  447.            if (HI_WRITE(file_rec->file, HDFMAGIC, MAGICLEN) == FAIL) {
  448.                HERROR(DFE_WRITEERROR);
  449.                return FAIL;
  450.            }
  451.            if (HIinit_file_dds(file_rec, ndds, FUNC) == FAIL) {
  452.                HERROR(DFE_WRITEERROR);
  453.                return FAIL;
  454.            }
  455.            file_rec->maxref = 0;
  456.            file_rec->access = new_file ? access | DFACC_READ : DFACC_ALL;
  457.        }
  458.        file_rec->refcount = 1;
  459.        file_rec->attach = 0;
  460.  
  461.        /* Set up the new pointers for empty space */
  462.        file_rec->null_block = file_rec->ddhead;
  463.        file_rec->null_idx   = -1;
  464.        
  465.        /* version tags */
  466.        if (vtag == 1)
  467.          HIupdate_version(FSLOT2ID(slot));
  468.      }
  469.  
  470.     file_rec->version_set = FALSE;
  471.  
  472.     HIread_version(FSLOT2ID(slot));
  473.     /* end version tags */
  474.     
  475.     return FSLOT2ID(slot);
  476.   }
  477.  
  478. /*--------------------------------------------------------------------------
  479.  NAME
  480.        Hclose -- close HDF file
  481.  USAGE
  482.        intn Hclose(id)
  483.        int id;                 IN: the file id to be closed
  484.  RETURNS
  485.        returns SUCCEED (0) if successful and FAIL (-1) if failed.
  486.  DESCRIPTION
  487.        closes an HDF file given the file id.  Id is first validated.  If
  488.        there are still access objects attached to the file, an error is
  489.        returned and the file is not closed.
  490.  GLOBAL VARIABLES
  491.  COMMENTS, BUGS, ASSUMPTIONS
  492.  EXAMPLES
  493.  REVISION LOG
  494. --------------------------------------------------------------------------*/
  495. #ifdef PROTOTYPE
  496. intn Hclose(int32 file_id)
  497. #else
  498. intn Hclose(file_id)
  499.     int32 file_id;             /* id of closing file */
  500. #endif
  501. {
  502.   register intn i;
  503.   char *FUNC="Hclose";       /* for HERROR */
  504.   filerec_t *file_rec;       /* file record pointer */
  505.   register tag_ref_list_ptr p, q;
  506.   
  507.   /* convert file id to file rec and check for validity */
  508.   
  509.   file_rec = FID2REC(file_id);
  510.   if (!file_rec || file_rec->refcount == 0) {
  511.     HERROR(DFE_ARGS);
  512.     return FAIL;
  513.   }
  514.   
  515.   /* version tags */
  516.   if ((file_rec->refcount > 0) && (file_rec->version.modified == 1))
  517.     HIupdate_version(file_id);
  518.   /* end version tags */
  519.   
  520.   /* decrease the reference count */
  521.   if (--file_rec->refcount == 0) {
  522.     ddblock_t *bl, *next;  /* current ddblock and next ddblock pointers.
  523.                                   for freeing ddblock linked list*/
  524.     
  525.     /* if file reference count is zero but there are still attached
  526.        access elts, reject this close. */
  527.     
  528.        if (file_rec->attach > 0) {
  529.          file_rec->refcount++;
  530.          HERROR(DFE_OPENAID);
  531.          HEreport("There are still %d active aids attached",file_rec->attach);
  532.          return FAIL;
  533.        }
  534.     
  535.     /* otherwise, nothing should still be using this file, close it */
  536. #if 0
  537.        if (HI_CLOSE(file_rec->file) == FAIL) {
  538.          HERROR(DFE_CLOSE);
  539.          return FAIL;
  540.        }
  541. #else
  542.     /* ignore any close error */
  543.     HI_CLOSE(file_rec->file);
  544. #endif
  545.     
  546.     /* free the ddblock linked list of this file record, the path name;
  547.        and reset some variables */
  548.     
  549.     for (bl = file_rec->ddhead; bl; bl = next) {
  550.       next = bl->next;
  551.       if (bl->ddlist) HDfreespace((VOIDP) bl->ddlist);
  552.       if (bl) HDfreespace((VOIDP)bl);
  553.     }
  554.     
  555.     for(i = 0; i < HASH_MASK + 1; i++) {
  556.       for(p = file_rec->hash[i]; p; p = q) {
  557.         q = p->next;
  558.         HDfreespace(p);
  559.       }
  560.       file_rec->hash[i] = NULL;
  561.     }
  562.     
  563.     file_rec->ddhead = (ddblock_t *) NULL;
  564.     if (file_rec->path) HDfreespace(file_rec->path);
  565.     file_rec->path = (char *)NULL;
  566.   }
  567.   
  568.   return SUCCEED;
  569. } /* Hclose */
  570.  
  571. /*--------------------------------------------------------------------------
  572.  
  573.  NAME
  574.        Hstartread -- locate and position a read access elt on a tag/ref
  575.  USAGE
  576.        int32 Hstartread(fileid, tag, ref)
  577.        int fileid;             IN: id of file to attach access element to
  578.        int tag;                IN: tag to search for
  579.        int ref;                IN: ref to search for
  580.  RETURNS
  581.        returns id of access element if successful, otherwise FAIL (-1)
  582.  DESCRIPTION
  583.        Searches the DD's for a particular tag/ref combination.  The
  584.        searching starts from the head of the DD list.  Wildcards can be
  585.        used for tag or ref (DFTAG_WILDCARD, DFREF_WILDCARD) and they match
  586.        any values.  If the search is successful, the access elt is
  587.        positioned to the start of that tag/ref, otherwise it is an error.
  588.        An access element is created and attached to the file.
  589.  GLOBAL VARIABLES
  590.  COMMENTS, BUGS, ASSUMPTIONS
  591.  EXAMPLES
  592.  REVISION LOG
  593. --------------------------------------------------------------------------*/
  594. #ifdef PROTOTYPE
  595. int32 Hstartread(int32 file_id, uint16 tag, uint16 ref)
  596. #else
  597. int32 Hstartread(file_id, tag, ref)
  598.     int32 file_id;             /* file id to read from */
  599.     uint16 tag;                        /* tag of elt to read */
  600.     uint16 ref;                        /* ref of elt to read */
  601. #endif
  602. {
  603.     char *FUNC="Hstartread";   /* for HERROR */
  604.     int slot;                  /* slot in access record array */
  605.     filerec_t *file_rec;       /* file record */
  606.     accrec_t *access_rec;      /* access record */
  607.  
  608.     /* clear error stack */
  609.  
  610.     HEclear();
  611.  
  612.     /* convert file id to file record and check for validity */
  613.  
  614.     file_rec = FID2REC(file_id);
  615.     if (!file_rec || file_rec->refcount == 0) {
  616.        HERROR(DFE_ARGS);
  617.        return FAIL;
  618.     }
  619.  
  620.     /* get a slot in the access record array */
  621.  
  622.     slot = HIget_access_slot();
  623.     if (slot == FAIL) {
  624.        HERROR(DFE_TOOMANY);
  625.        return FAIL;
  626.     }
  627.     access_rec = &(access_records[slot]);
  628.  
  629. #ifndef oldspecial
  630.     /* convert tag to base form */
  631.  
  632.     tag = BASETAG(tag);
  633. #endif
  634.  
  635.     /* search for the data element in the dd lists of the file */
  636.  
  637.     access_rec->file_id = file_id;
  638.     access_rec->block = file_rec->ddhead;
  639.     access_rec->idx = -1;
  640.     if (HIlookup_dd(file_rec, tag, ref, &access_rec->block, &access_rec->idx) == FAIL) {
  641.        HERROR(DFE_NOMATCH);
  642.        access_rec->used = FALSE;
  643.        return FAIL;
  644.     }
  645.  
  646.     /* if special data element, get the relevant special function table
  647.        and run the START READ function on this element */
  648.  
  649.     if (SPECIALTAG(access_rec->block->ddlist[access_rec->idx].tag)) {
  650.        access_rec->special_func = HIget_function_table(access_rec, FUNC);
  651.        if (!access_rec->special_func) {
  652.            HERROR(DFE_INTERNAL);
  653.            access_rec->used = FALSE;
  654.            return FAIL;
  655.        }
  656.        return (*access_rec->special_func[SP_STREAD])(access_rec);
  657.     }
  658.  
  659.     /* reset the data element and update file record */
  660.     access_rec->posn = 0;
  661.     access_rec->access = DFACC_READ;
  662.     access_rec->special = 0;
  663.     file_rec->attach++;
  664.  
  665.     return ASLOT2ID(slot);
  666. }   /* Hstartread() */
  667.  
  668. /*--------------------------------------------------------------------------
  669.  
  670.  NAME
  671.        Hnextread -- locate and position a read access elt on tag/ref.
  672.  USAGE
  673.        intn Hnextread(access_id, tag, ref, origin)
  674.        int32 access_id;         IN: id of a READ access elt
  675.        uint16 tag;              IN: the tag to search for
  676.        uint16 ref;              IN: ref to search for
  677.        int origin;              IN: from where to start searching
  678.  RETURNS
  679.        returns SUCCEED (0) if successful and FAIL (-1) otherwise
  680.  DESCRIPTION
  681.        Searches for the `next' DD that fits the tag/ref.  Wildcards
  682.        apply.  If origin is DF_START, search from start of DD list,
  683.        if origin is DF_CURRENT, search from current position, otherwise
  684.        origin should be DF_END which searches from end of file.
  685.        If the search is successful, then the access elt
  686.        is positioned at the start of that tag/ref, otherwise, it is not
  687.        modified.
  688.  GLOBAL VARIABLES
  689.  COMMENTS, BUGS, ASSUMPTIONS
  690.     DF_END _not_ supported yet!
  691.  EXAMPLES
  692.  REVISION LOG
  693.     Moved file_rec initialization in front of if statement instead
  694.     of inside it.
  695. --------------------------------------------------------------------------*/
  696. #ifdef PROTOTYPE
  697. intn Hnextread(int32 access_id, uint16 tag, uint16 ref, int origin)
  698. #else
  699. intn Hnextread(access_id, tag, ref, origin)
  700.     int32 access_id;           /* id of the read access record to modify */
  701.     uint16 tag;                        /* the tag to look for */
  702.     uint16 ref;                        /* the ref to look for */
  703.     int origin;                        /* where to start searching from */
  704. #endif
  705. {
  706.     char *FUNC="Hnextread";    /* for HERROR */
  707.     filerec_t *file_rec;       /* file record */
  708.     accrec_t *access_rec;      /* access record */
  709.     ddblock_t *block;
  710.     int32 idx;
  711.  
  712.     /* clear error stack and check validity of the access id */
  713.  
  714.     HEclear();
  715.     access_rec = AID2REC(access_id);
  716.     if (access_rec == (accrec_t *) NULL || !access_rec->used ||
  717.        access_rec->access != DFACC_READ ||
  718.        (origin != DF_START && origin != DF_CURRENT)) {
  719.        HERROR(DFE_ARGS);
  720.        return FAIL;
  721.     }
  722.  
  723.     /* DF_END is NOT supported yet !!!! */
  724.  
  725.     file_rec = FID2REC(access_rec->file_id);
  726.     if (file_rec == (filerec_t *) NULL || file_rec->refcount == 0) {
  727.         HERROR(DFE_INTERNAL);
  728.         return FAIL;
  729.     }
  730.  
  731.     /*
  732.      * if access record used to point to an external element we 
  733.      * need to close the file before moving on
  734.      */
  735.     if(access_rec->special == SPECIAL_EXT) {
  736.         if(HXIcloseAID(access_rec) == FAIL) {
  737.             HERROR(DFE_CANTCLOSE);
  738.             return FAIL;
  739.         }
  740.     }
  741.  
  742.     if (origin == DF_START) {
  743.        /* set up variables to start searching from beginning of file */
  744.        block = file_rec->ddhead;
  745.        idx = -1;
  746.  
  747.     } else {                   /* origin == CURRENT */
  748.        /* set up variables to start searching from the current position */
  749.  
  750.        block = access_rec->block;
  751.        idx = access_rec->idx;
  752.     }
  753.  
  754.     /* go look for the dd */
  755.  
  756.     if (HIlookup_dd(file_rec, tag, ref, &block, &idx) == FAIL) {
  757.        HERROR(DFE_NOMATCH);
  758.        return FAIL;
  759.     }
  760.  
  761.     /* found, so update the access record */
  762.  
  763.     access_rec->block = block;
  764.     access_rec->idx = idx;
  765.     if (SPECIALTAG(access_rec->block->ddlist[access_rec->idx].tag)) {
  766.  
  767.        /* special element, call special function to handle */
  768.  
  769.        access_rec->special_func = HIget_function_table(access_rec, FUNC);
  770.        if (!access_rec->special_func) {
  771.            HERROR(DFE_INTERNAL);
  772.            return FAIL;
  773.        }
  774.        HIunlock(access_rec->file_id); /* remove old attach to the file_rec */
  775.        return (int)(*access_rec->special_func[SP_STREAD])(access_rec);
  776.     }
  777.  
  778.     access_rec->special = 0;
  779.     access_rec->posn = 0;
  780.  
  781.     return SUCCEED;
  782. }   /* end Hnextread() */
  783.  
  784. /*--------------------------------------------------------------------------
  785.  
  786.  NAME
  787.        Hinquire -- inquire stats of an access elt
  788.  USAGE
  789.        intn Hinquire(access_id, pfile_id, ptag, pref, plength,
  790.                        poffset, pposn, paccess, pspecial)
  791.        int access_id;          IN: id of an access elt
  792.        int32 *pfile_id;        OUT: file id
  793.        uint16 *ptag;           OUT: tag of the element pointed to
  794.        uint16 *pref;           OUT: ref of the element pointed to
  795.        int32 *plength;         OUT: length of the element pointed to
  796.        int32 *poffset;         OUT: offset of elt in the file
  797.        int32 *pposn;           OUT: position pointed to within the data elt
  798.        int *paccess;           OUT: the access type of this access elt
  799.      int *pspecial;            OUT: special code
  800.  RETURNS
  801.        returns SUCCEED (0) if the access elt points to some data element,
  802.        otherwise FAIL (-1)
  803.  DESCRIPTION
  804.        Inquire statistics of the data element pointed to by access elt and
  805.        the access elt.  The access type is set if the access_id is valid even
  806.        if FAIL is returned.  If access_id is not valid then access is set to
  807.        zero (0).
  808.  GLOBAL VARIABLES
  809.  COMMENTS, BUGS, ASSUMPTIONS
  810.  EXAMPLES
  811.  REVISION LOG
  812. --------------------------------------------------------------------------*/
  813. #ifdef PROTOTYPE
  814. intn Hinquire(int32 access_id, int32 *pfile_id, uint16 *ptag, uint16 *pref,
  815.               int32 *plength, int32 *poffset, int32 *pposn, int16 *paccess,
  816.               int16 *pspecial)
  817. #else
  818. intn Hinquire(access_id, pfile_id, ptag, pref, plength, poffset, pposn,
  819.               paccess, pspecial)
  820.     int32 access_id;           /* access id */
  821.     int32 *pfile_id;           /* file id */
  822.     uint16 *ptag;              /* elt tag */
  823.     uint16 *pref;              /* elt ref */
  824.     int32 *plength;            /* length of element */
  825.     int32 *poffset;            /* offset of elt in the file */
  826.     int32 *pposn;              /* position in the data elt we are accessing */
  827.     int16 *paccess;              /* access mode */
  828.     int16 *pspecial;             /* special code */
  829. #endif
  830. {
  831.     char *FUNC="Hinquire";     /* for HERROR */
  832.     register accrec_t *access_rec;      /* access record */
  833.     register dd_t *dd;                  /* dd of access record */
  834.  
  835.     /* clear error stack and check validity of access id */
  836.  
  837.     HEclear();
  838.     access_rec = AID2REC(access_id);
  839.     if (access_rec == (accrec_t *) NULL || !access_rec->used) {
  840.        HERROR(DFE_ARGS);
  841.        return FAIL;
  842.     }
  843.  
  844.     /* if special elt, let special functions handle it */
  845.  
  846.     if (access_rec->special) {
  847.        return (int)(*access_rec->special_func[SP_INQUIRE])
  848.            (access_rec, pfile_id, ptag, pref, plength,
  849.             poffset, pposn, paccess, pspecial);
  850.     }
  851.  
  852.     /* get dd and fill in variables asked for (i.e. not NULL) */
  853.  
  854.     dd = &(access_rec->block->ddlist[access_rec->idx]);
  855.     if (pfile_id) *pfile_id = access_rec->file_id;
  856.     if (ptag) *ptag = dd->tag;
  857.     if (pref) *pref = dd->ref;
  858.     if (plength) *plength = dd->length;
  859.     if (poffset) *poffset = dd->offset;
  860.     if (pposn) *pposn = access_rec->posn;
  861.     if (paccess) *paccess = access_rec->access;
  862.     if (pspecial) *pspecial = 0;
  863.  
  864.     return SUCCEED;
  865. }   /* end Hinquire() */
  866.  
  867. /*--------------------------------------------------------------------------
  868.  
  869.  NAME
  870.        Hstartwrite -- set up a WRITE access elt for a write
  871.  USAGE
  872.        int32 Hstartwrite(fileid, tag, ref, len)
  873.        int fileid;             IN: id of file to write to
  874.        int tag;                IN: tag to write to
  875.        int ref;                IN: ref to write to
  876.        long length;            IN: the length of the data element
  877.  RETURNS
  878.        returns id of access element if successful and FAIL otherwise
  879.  DESCRIPTION
  880.        Set up a WRITE access elt to write out a data element.  The DD list
  881.        of the file is searched first.  If the tag/ref is found, it is
  882.        NOT replaced - the seek position is presumably at 0.
  883.                 If it does not exist, it is created.
  884.  GLOBAL VARIABLES
  885.  COMMENTS, BUGS, ASSUMPTIONS
  886.  EXAMPLES
  887.  REVISION LOG
  888. --------------------------------------------------------------------------*/
  889. #ifdef PROTOTYPE
  890. int32 Hstartwrite(int32 file_id, uint16 tag, uint16 ref, int32 length)
  891. #else
  892. int32 Hstartwrite(file_id, tag, ref, length)
  893.     int32 file_id;             /* file id */
  894.     uint16 tag;                        /* tag of elt to write */
  895.     uint16 ref;                        /* ref of elt to write */
  896.     int32 length;              /* length of elt to write */
  897. #endif
  898. {
  899.     char *FUNC="Hstartwrite";  /* for HERROR */
  900.     int slot;                  /* free access records array slot */
  901.     bool ddnew = FALSE;                /* is the dd a new one? */
  902.     filerec_t *file_rec;       /* file record */
  903.     accrec_t *access_rec;      /* access record */
  904.     /* version tags */
  905.     uint32 lmajorv, lminorv, lrelease;
  906.     uint32 fmajorv, fminorv, frelease;
  907.     char string[81];
  908.     int newver;
  909.     /* end version tags */
  910.  
  911.     /* clear error stack and check validity of file id */
  912.  
  913.     HEclear();
  914.     file_rec = FID2REC(file_id);
  915.     if (!file_rec || file_rec->refcount == 0) {
  916.        HERROR(DFE_ARGS);
  917.        return FAIL;
  918.     }
  919.  
  920.     /* can write in this file? */
  921.  
  922.     if (!(file_rec->access & DFACC_WRITE)) {
  923.        HERROR(DFE_DENIED);
  924.        return FAIL;
  925.     }
  926.  
  927.     /* get empty slot in access records */
  928.  
  929.     slot = HIget_access_slot();
  930.     if (slot == FAIL) {
  931.        HERROR(DFE_TOOMANY);
  932.        return FAIL;
  933.     }
  934.  
  935. #ifndef oldspecial
  936.     /* convert tag to base form */
  937.  
  938.     tag = BASETAG(tag);
  939. #endif
  940.  
  941.     /* set up access record to look for the dd */
  942.  
  943.     access_rec = &(access_records[slot]);
  944.     access_rec->file_id = file_id;
  945.     access_rec->block = file_rec->ddhead;
  946.     access_rec->idx = -1;
  947.     if (HIlookup_dd(file_rec, tag, ref, &access_rec->block, &access_rec->idx) == FAIL) {
  948.  
  949.        /* dd not found, so have to create new element */
  950.  
  951.        /* look for empty dd slot */
  952.        if (HIfind_dd((uint16)DFTAG_NULL, (uint16)DFREF_WILDCARD,
  953.                      &file_rec->null_block, &file_rec->null_idx) != FAIL) {
  954.  
  955.          access_rec->block = file_rec->null_block;
  956.          access_rec->idx   = file_rec->null_idx;
  957.  
  958.        } else {
  959.  
  960.            /* cannot find empty dd slot, so create new dd block */
  961.  
  962.            if (HInew_dd_block(file_rec, FILE_NDDS(file_rec), FUNC) == FAIL) {
  963.                HERROR(DFE_NOFREEDD);
  964.                access_rec->used = FALSE;
  965.                return FAIL;
  966.            } else {
  967.  
  968.                /* use dd slot in new dd block */
  969.  
  970.                access_rec->block = file_rec->ddlast;
  971.                access_rec->idx = 0;
  972.            }
  973.         }
  974.  
  975.        ddnew = TRUE;
  976.        if(HIadd_hash_dd(file_rec, tag, ref, access_rec->block, access_rec->idx)
  977.           == FAIL)
  978.          return(FAIL);
  979.  
  980.     } else if (SPECIALTAG(access_rec->block->ddlist[access_rec->idx].tag)) {
  981.  
  982.        /* found, if this elt is special, let special function handle it */
  983.  
  984.        access_rec->special_func = HIget_function_table(access_rec, FUNC);
  985.        if (!access_rec->special_func) {
  986.            HERROR(DFE_INTERNAL);
  987.            access_rec->used = FALSE;
  988.            return FAIL;
  989.        }
  990.        return (*access_rec->special_func[SP_STWRITE])(access_rec);
  991.     }
  992.  
  993.     /* the dd is pointed to by access_rec->block and access_rec->idx */
  994.  
  995. /*  if (ddnew || access_rec->block->ddlist[access_rec->idx].length < length) */
  996.     /* cannot write more bytes than are allocated for element */
  997.     if (!ddnew && (access_rec->block->ddlist[access_rec->idx].length < length)) {
  998.         HERROR(DFE_BADLEN);
  999.         HEreport("Values: old length %d   new length%d",
  1000.  
  1001.                 access_rec->block->ddlist[access_rec->idx].length, length);
  1002.         access_rec->used = FALSE;
  1003.         return FAIL;
  1004.     }
  1005.  
  1006.     if (ddnew)
  1007.          {
  1008.  
  1009.  
  1010.        /* have to allocate new space in the file for the data */
  1011.  
  1012.        int32 offset;           /* offset of this data element in file */
  1013.  
  1014.        /* place the data element at the end of the file and
  1015.         record its offset */
  1016.  
  1017.        if (HI_SEEKEND(file_rec->file) == FAIL) {
  1018.            HERROR(DFE_SEEKERROR);
  1019.            access_rec->used = FALSE;
  1020.            return FAIL;
  1021.        }
  1022.        offset = access_rec->block->ddlist[access_rec->idx].offset
  1023.            = HI_TELL(file_rec->file);
  1024.  
  1025.        /* reserve the space by marking the end of the element */
  1026.  
  1027.        if (HI_SEEK(file_rec->file, length-1+offset) == FAIL) {
  1028.            HERROR(DFE_SEEKERROR);
  1029.            access_rec->used = FALSE;
  1030.            return FAIL;
  1031.        }
  1032.        if (HI_WRITE(file_rec->file, tbuf, 1) == FAIL) {
  1033.            HERROR(DFE_WRITEERROR);
  1034.            access_rec->used = FALSE;
  1035.            return FAIL;
  1036.        }
  1037.  
  1038.        /* fill in dd record */
  1039.  
  1040.        access_rec->block->ddlist[access_rec->idx].tag = tag;
  1041.        access_rec->block->ddlist[access_rec->idx].ref = ref;
  1042.     }
  1043.  
  1044.     /* update dd in the file */
  1045.  
  1046.     if (ddnew && length > 0)
  1047.       access_rec->block->ddlist[access_rec->idx].length = length;
  1048.     if (HIupdate_dd(file_rec, access_rec->block,
  1049.                    access_rec->idx, FUNC) == FAIL) {
  1050.         access_rec->used = FALSE;
  1051.        return FAIL;
  1052.     }
  1053.  
  1054.     /* update the access record, and the file record */
  1055.  
  1056.     access_rec->posn = 0;
  1057.     access_rec->access = DFACC_WRITE;
  1058.     access_rec->file_id = file_id;
  1059.     access_rec->special = 0;
  1060.     file_rec->attach++;
  1061.     if (ref > file_rec->maxref) file_rec->maxref = ref;
  1062.  
  1063.     /*
  1064.      *  If this is the first time we are writting to this file
  1065.      *    update the version tags as needed
  1066.      */
  1067.  
  1068.     if(!file_rec->version_set) {
  1069.       /* version tags */
  1070.       /* get file version and set newver condition */
  1071.       newver = 0;
  1072.       
  1073.       if (Hgetfileversion(file_id, &fmajorv, &fminorv, &frelease,string)!=SUCCEED) {
  1074.         newver = 1;
  1075.         HEclear();
  1076.       }
  1077.       
  1078.       /* get library version */
  1079.       Hgetlibversion(&lmajorv, &lminorv, &lrelease, string);
  1080.       
  1081.       if (newver == 0) {
  1082.         if (lmajorv > fmajorv) {
  1083.           newver = 1;
  1084.         } else {
  1085.           if (lminorv > fminorv) {
  1086.             newver = 1;
  1087.           } else {
  1088.             if (lrelease > frelease) {
  1089.               newver = 1;
  1090.             } else {
  1091.               newver = 0;
  1092.             }
  1093.           }
  1094.         }
  1095.       }
  1096.       
  1097.       if (newver == 1) {
  1098.         file_rec->version.majorv = lmajorv;
  1099.         file_rec->version.minorv = lminorv;
  1100.         file_rec->version.release = lrelease;
  1101.         HIstrncpy(file_rec->version.string, string, 81);
  1102.         file_rec->version.modified = 1;
  1103.       }
  1104.       
  1105.       file_rec->version_set = TRUE;
  1106.  
  1107.     } /* test to set version tags */
  1108.       
  1109.     return ASLOT2ID(slot);
  1110. }   /* end Hstartwrite() */
  1111.  
  1112. /*--------------------------------------------------------------------------
  1113.  
  1114.  NAME
  1115.        Hseek -- position an access element to an offset in data element
  1116.  USAGE
  1117.        intn Hseek(access_id, offset, origin)
  1118.        int32 access_id;        IN: id of access element
  1119.        long offset;            IN: offset to seek to
  1120.        int origin;             IN: position to seek from by offset, 0: from
  1121.                                beginning; 1: current position; 2: end of
  1122.                                data element
  1123.  RETURNS
  1124.        returns FAIL (-1) if fail, SUCCEED (0) otherwise.
  1125.  DESCRIPTION
  1126.        Sets the position of an access element in a data element so that the
  1127.        next Hread or Hwrite will start from that position.  origin
  1128.        determines the position from which the offset should be added.  This
  1129.        routine fails if the access elt is not associated with any data
  1130.        element and if the seeked position is outside of the data element.
  1131.  GLOBAL VARIABLES
  1132.  COMMENTS, BUGS, ASSUMPTIONS
  1133.  EXAMPLES
  1134.  REVISION LOG
  1135. --------------------------------------------------------------------------*/
  1136. #ifdef PROTOTYPE
  1137. intn Hseek(int32 access_id, int32 offset, int origin)
  1138. #else
  1139. intn Hseek(access_id, offset, origin)
  1140.     int32 access_id;           /* access id */
  1141.     int32 offset;              /* offset in this element to seek to */
  1142.     int origin;                        /* origin in this elt to seek from */
  1143. #endif
  1144. {
  1145.     char *FUNC="Hseek";                /* for HERROR */
  1146.     accrec_t *access_rec;      /* access record */
  1147.  
  1148.     /* clear error stack and check validity of this access id */
  1149.  
  1150.     HEclear();
  1151.     access_rec = AID2REC(access_id);
  1152.     if (access_rec == (accrec_t *) NULL || !access_rec->used ||
  1153.        (origin != DF_START && origin != DF_CURRENT && origin != DF_END)) {
  1154.        HERROR(DFE_ARGS);
  1155.        return FAIL;
  1156.     }
  1157.  
  1158.     /* if special elt, use special function */
  1159.  
  1160.     if (access_rec->special) {
  1161.        return (*access_rec->special_func[SP_SEEK])(access_rec, offset, origin);
  1162.     }
  1163.  
  1164.     /* calculate real offset based on the origin and check for range */
  1165.  
  1166.     if (origin == DF_CURRENT) offset += access_rec->posn;
  1167.     if (origin == DF_END) offset +=
  1168.        access_rec->block->ddlist[access_rec->idx].length;
  1169.     if (offset < 0 ||
  1170.         offset >= access_rec->block->ddlist[access_rec->idx].length) {
  1171.       HERROR(DFE_BADSEEK);
  1172.       HEreport("Tried to seek to %d (object length:  %d)", offset,
  1173.                access_rec->block->ddlist[access_rec->idx].length);
  1174.  
  1175.       fprintf(stderr, "TAG/REF was %d %d\n", 
  1176.               access_rec->block->ddlist[access_rec->idx].tag, 
  1177.               access_rec->block->ddlist[access_rec->idx].ref);
  1178.  
  1179.       return FAIL;
  1180.     }
  1181.  
  1182.     /* set the new position */
  1183.  
  1184.     access_rec->posn = offset;
  1185.  
  1186.     return SUCCEED;
  1187. }   /* Hseek() */
  1188.  
  1189. /*--------------------------------------------------------------------------
  1190.  
  1191.  NAME
  1192.        Hread -- read the next segment from data element
  1193.  USAGE
  1194.        int32 Hread(access_id, length, data)
  1195.        int access_id;          IN: id of READ access element
  1196.        long length;            IN: length of segment to read in
  1197.        char *data;             OUT: pointer to data array to read to
  1198.  RETURNS
  1199.        returns length of segment actually read in if successful and FAIL
  1200.        (-1) otherwise
  1201.  DESCRIPTION
  1202.        Read in the next segment in the data element pointed to by the
  1203.        access elt.  If the data element is too short then it only reads
  1204.        to end of the data element.
  1205.  GLOBAL VARIABLES
  1206.  COMMENTS, BUGS, ASSUMPTIONS
  1207.  EXAMPLES
  1208.  REVISION LOG
  1209. --------------------------------------------------------------------------*/
  1210. #ifdef PROTOTYPE
  1211. int32 Hread(int32 access_id, int32 length, uint8 *data)
  1212. #else
  1213. int32 Hread(access_id, length, data)
  1214.     int32 access_id;           /* access id */
  1215.     int32 length;              /* length of data to read */
  1216.     uint8 *data;               /* data buffer to read into */
  1217. #endif
  1218. {
  1219.     char *FUNC="Hread";                /* for HERROR */
  1220.     filerec_t *file_rec;       /* file record */
  1221.     accrec_t *access_rec;      /* access record */
  1222.     dd_t *dd;                  /* current dd pointer */
  1223.  
  1224.     /* clear error stack and check validity of access id */
  1225.  
  1226.     HEclear();
  1227.     access_rec = AID2REC(access_id);
  1228.     if (access_rec == (accrec_t *) NULL || !access_rec->used ||
  1229. /*
  1230.        access_rec->access != DFACC_READ || 
  1231. */
  1232.         !data) {
  1233.        HERROR(DFE_ARGS);
  1234.        return FAIL;
  1235.     }
  1236.  
  1237.     /* special elt, so call special function */
  1238.  
  1239.     if (access_rec->special) {
  1240.        return (*access_rec->special_func[SP_READ])(access_rec, length, data);
  1241.     }
  1242.  
  1243.     /* check validity of file record */
  1244.     file_rec = FID2REC(access_rec->file_id);
  1245.     if (file_rec == (filerec_t *) NULL || file_rec->refcount == 0) {
  1246.        HERROR(DFE_INTERNAL);
  1247.        return FAIL;
  1248.     }
  1249.  
  1250.     /* get the dd of this data elt */
  1251.  
  1252.     dd = &(access_rec->block->ddlist[access_rec->idx]);
  1253.     if (length < 0){
  1254.        HERROR(DFE_BADSEEK);
  1255.        return FAIL;
  1256.     }
  1257.  
  1258.     /* seek to position to start reading and read in data */
  1259.  
  1260.     if (HI_SEEK(file_rec->file, access_rec->posn + dd->offset) == FAIL) {
  1261.        HERROR(DFE_SEEKERROR);
  1262.        return FAIL;
  1263.     }
  1264.  
  1265.     /* length == 0 means to read to end of element,
  1266.        if read length exceeds length of elt, read till end of elt */
  1267.  
  1268.     if (length == 0 || length + access_rec->posn > dd->length)
  1269.        length = dd->length - access_rec->posn;
  1270.  
  1271.     if (HI_READ(file_rec->file, data, length) == FAIL) {
  1272.        HERROR(DFE_READERROR);
  1273.        return FAIL;
  1274.     }
  1275.  
  1276.     /* move the position of the access record */
  1277.  
  1278.     access_rec->posn += length;
  1279.  
  1280.     return length;
  1281. }   /* Hread() */
  1282.  
  1283. /*--------------------------------------------------------------------------
  1284.  
  1285.  NAME
  1286.        Hwrite -- write next data segment to data element
  1287.  USAGE
  1288.        int32 Hwrite(access_id, len, data)
  1289.        int access_id;          IN: id of WRITE access element
  1290.        long len;               IN: length of segment to write
  1291.        char *data;             IN: pointer to data to write
  1292.  RETURNS
  1293.        returns length of segment successfully written, FAIL (-1) otherwise
  1294.  DESCRIPTION
  1295.        Write the data to data element where the last write or Hseek()
  1296.        stopped.  If the space reserved is less than the length to write,
  1297.        then only as much as can fit is written.  It is the responsibility
  1298.        of the user to insure that no two access elements are writing to the
  1299.        same data element.  It is possible to interlace writes to more than
  1300.        one data elements in the same file though.
  1301.  GLOBAL VARIABLES
  1302.  COMMENTS, BUGS, ASSUMPTIONS
  1303.  EXAMPLES
  1304.  REVISION LOG
  1305. --------------------------------------------------------------------------*/
  1306. #ifdef PROTOTYPE
  1307. int32 Hwrite(int32 access_id, int32 length, uint8 *data)
  1308. #else
  1309. int32 Hwrite(access_id, length, data)
  1310.     int32 access_id;           /* access id */
  1311.     int32 length;              /* length of data to write */
  1312.     uint8 *data;               /* data buffer */
  1313. #endif
  1314. {
  1315.     char *FUNC="Hwrite";       /* for HERROR */
  1316.     filerec_t *file_rec;       /* file record */
  1317.     accrec_t *access_rec;      /* access record */
  1318.     dd_t *dd;                  /* ptr to dd of current elt */
  1319.  
  1320.     /* clear error stack and check validity of access id */
  1321.  
  1322.     HEclear();
  1323.     access_rec = AID2REC(access_id);
  1324.     if (access_rec == (accrec_t *) NULL || !access_rec->used ||
  1325.        access_rec->access != DFACC_WRITE || !data) {
  1326.        HERROR(DFE_ARGS);
  1327.        return FAIL;
  1328.     }
  1329.  
  1330.     /* if special elt, call special function */
  1331.  
  1332.     if (access_rec->special) {
  1333.        return (*access_rec->special_func[SP_WRITE])(access_rec, length, data);
  1334.     }
  1335.  
  1336.     /* check validity of file record and get dd ptr */
  1337.  
  1338.     file_rec = FID2REC(access_rec->file_id);
  1339.     if (!file_rec || file_rec->refcount == 0) {
  1340.        HERROR(DFE_INTERNAL);
  1341.        return FAIL;
  1342.     }
  1343.     dd = &(access_rec->block->ddlist[access_rec->idx]);
  1344.  
  1345.     /* check validity of length and write data.
  1346.        NOTE: it is an error to attempt write past the end of the elt */
  1347.     if (length <= 0 || length + access_rec->posn > dd->length){
  1348.        HERROR(DFE_BADSEEK);
  1349.        return FAIL;
  1350.     }
  1351.     if (HI_SEEK(file_rec->file, access_rec->posn + dd->offset) == FAIL) {
  1352.        HERROR(DFE_SEEKERROR);
  1353.        return FAIL;
  1354.     }
  1355.     if (HI_WRITE(file_rec->file, data, length) == FAIL) {
  1356.        HERROR(DFE_WRITEERROR);
  1357.        return FAIL;
  1358.     }
  1359.  
  1360.     /* update position of access in elt */
  1361.  
  1362.     access_rec->posn += length;
  1363.  
  1364.     return length;
  1365. }   /* end Hwrite() */
  1366.  
  1367. /*--------------------------------------------------------------------------
  1368.  
  1369.  NAME
  1370.        Hendaccess -- to dispose of an access element
  1371.  USAGE
  1372.        int32 Hendaccess(access_id)
  1373.        int access_id;          IN: id of access element to dispose of
  1374.  RETURNS
  1375.        returns SUCCEED (0) if successful, FAIL (-1) otherwise
  1376.  DESCRIPTION
  1377.        Used to dispose of an access element.  If access elements are not
  1378.        disposed it will eventually become impossible to allocate new
  1379.        ones.
  1380.  
  1381.        If there are active aids Hclose will *NOT* close the file.  This
  1382.        is a very common problem when developing new code.
  1383.  GLOBAL VARIABLES
  1384.  COMMENTS, BUGS, ASSUMPTIONS
  1385.  EXAMPLES
  1386.  REVISION LOG
  1387. --------------------------------------------------------------------------*/
  1388. #ifdef PROTOTYPE
  1389. int32 Hendaccess(int32 access_id)
  1390. #else
  1391. int32 Hendaccess(access_id)
  1392.     int32 access_id;           /* access id */
  1393. #endif
  1394. {
  1395.     char *FUNC="Hendaccess";   /* for HERROR */
  1396.     filerec_t *file_rec;       /* file record */
  1397.     accrec_t *access_rec;      /* access record */
  1398.  
  1399.     /* check validity of access id */
  1400.     access_rec = AID2REC(access_id);
  1401.     if (!access_rec || !access_rec->used) {
  1402.        HERROR(DFE_ARGS);
  1403.        return FAIL;
  1404.     }
  1405.  
  1406.     /* if special elt, call special function */
  1407.  
  1408.     if (access_rec->special) {
  1409.        return (*access_rec->special_func[SP_END])(access_rec);
  1410.     }
  1411.  
  1412.     /* check validity of file record */
  1413.  
  1414.     file_rec = FID2REC(access_rec->file_id);
  1415.     if (!file_rec || file_rec->refcount == 0) {
  1416.        HERROR(DFE_INTERNAL);
  1417.        return FAIL;
  1418.     }
  1419.  
  1420.     /* update file and access records */
  1421.  
  1422.     file_rec->attach--;
  1423.     access_rec->used = FALSE;
  1424.  
  1425.     return SUCCEED;
  1426. }   /* end Hendaccess() */
  1427.  
  1428. /*--------------------------------------------------------------------------
  1429.  
  1430.  NAME
  1431.        Hgetelement -- read in a data element
  1432.  USAGE
  1433.        int Hgetelement(file_id, tag, ref, data)
  1434.        int file_id;            IN: id of the file to read from
  1435.        int tag;                IN: tag of data element to read
  1436.        int ref;                IN: ref of data element to read
  1437.        char *data;             OUT: buffer to read into
  1438.  RETURNS
  1439.        returns SUCCEED (0) if successful, FAIL (-1)
  1440.        otherwise
  1441.  DESCRIPTION
  1442.        Read in a data element from a HDF file and puts it into buffer
  1443.        pointed to by data.  The space allocated for buffer is assumed to be
  1444.        large enough.
  1445.  GLOBAL VARIABLES
  1446.  COMMENTS, BUGS, ASSUMPTIONS
  1447.  EXAMPLES
  1448.  REVISION LOG
  1449. --------------------------------------------------------------------------*/
  1450. #ifdef PROTOTYPE
  1451. int32 Hgetelement(int32 file_id, uint16 tag, uint16 ref, uint8 *data)
  1452. #else
  1453. int32 Hgetelement(file_id, tag, ref, data)
  1454.     int32 file_id;             /* id of file to read from */
  1455.     uint16 tag;                        /* tag of elt to read */
  1456.     uint16 ref;                        /* ref of elt to read */
  1457.     uint8 *data;                       /* data buffer to read into */
  1458. #endif
  1459. {
  1460.     char *FUNC="Hgetelement";  /* for HERROR */
  1461.     int32 access_id;           /* access record id */
  1462.     int32 length;              /* length of this elt */
  1463.     int32 ret;                 /* return code */
  1464.  
  1465.     /* clear error stack */
  1466.  
  1467.     HEclear();
  1468.  
  1469.     /* get the access record, get the length of the elt, read in data,
  1470.        and dispose of access record */
  1471.  
  1472.     access_id = Hstartread(file_id, tag, ref);
  1473.     if (access_id == FAIL) {
  1474.        HERROR(DFE_NOMATCH);
  1475.        return FAIL;
  1476.     }
  1477.     Hinquire(access_id, (int32 *)NULL, (uint16 *)NULL, (uint16 *)NULL, &length,
  1478.             (int32 *)NULL, (int32 *)NULL, (int16 *)NULL, (int16 *)NULL);
  1479.     if ((ret = Hread(access_id, 0, data)) == FAIL) {
  1480.        HERROR(DFE_READERROR);
  1481.     }
  1482.     (void) Hendaccess(access_id);
  1483.  
  1484.     return (ret == FAIL) ? ret : length;
  1485. }   /* Hgetelement() */
  1486.  
  1487. /*--------------------------------------------------------------------------
  1488.  
  1489.  NAME
  1490.        Hputelement -- writes a data element
  1491.  USAGE
  1492.        int Hputelement(fileid, tag, ref, data, length)
  1493.        int fileid;             IN: id of file
  1494.        int tag;                IN: tag of data element to put
  1495.        int ref;                IN: ref of data element to put
  1496.        char *data;             IN: pointer to buffer
  1497.        long length;            IN: length of data
  1498.  RETURNS
  1499.        returns SUCCEED (0) if successful and FAIL (-1) otherwise
  1500.  DESCRIPTION
  1501.        Writes a data element or replace an existing data element in a HDF
  1502.        file.  Uses Hwrite and its associated routines.
  1503.  GLOBAL VARIABLES
  1504.  COMMENTS, BUGS, ASSUMPTIONS
  1505.  EXAMPLES
  1506.  REVISION LOG
  1507. --------------------------------------------------------------------------*/
  1508. #ifdef PROTOTYPE
  1509. int Hputelement(int32 file_id, uint16 tag, uint16 ref, uint8 *data,
  1510.                int32 length)
  1511. #else
  1512. int Hputelement(file_id, tag, ref, data, length)
  1513.     int32 file_id;             /* file id to write to */
  1514.     uint16 tag;                /* tag of elt to write */
  1515.     uint16 ref;                /* ref of elt to write */
  1516.     uint8 *data;               /* data buffer to write */
  1517.     int32 length;              /* length of data to write */
  1518. #endif
  1519. {
  1520.     char *FUNC="Hputelement";  /* for HERROR */
  1521.     int32 access_id;           /* access record id */
  1522.     int32 ret;                  /* return code */
  1523.  
  1524.     /* clear error stack */
  1525.  
  1526.     HEclear();
  1527.  
  1528.     /* get access record, write out data and dispose of access record */
  1529.  
  1530.     access_id = Hstartwrite(file_id, tag, ref, length);
  1531.     if (access_id == FAIL) {
  1532.        HERROR(DFE_NOMATCH);
  1533.        return FAIL;
  1534.     }
  1535.     if ((ret = Hwrite(access_id, length, data)) == FAIL) {
  1536.        HERROR(DFE_WRITEERROR);
  1537.     }
  1538.     (void) Hendaccess(access_id);
  1539.  
  1540.     return (ret == length ? SUCCEED : FAIL);
  1541. }   /* end Hputelement() */
  1542.  
  1543. /*--------------------------------------------------------------------------
  1544.  
  1545.  NAME
  1546.        Hlength -- returns length of a data element
  1547.  USAGE
  1548.        int32 Hlength(fileid, tag, ref)
  1549.        int fileid;             IN: id of file
  1550.        int tag;                IN: tag of data element
  1551.        int ref;                IN: ref of data element
  1552.  RETURNS
  1553.        return the length of a data element
  1554.  DESCRIPTION
  1555.        returns length of data element if it is present in the file.  Return
  1556.        FAIL (-1) if it is not in the file or an error occurs.
  1557.  
  1558.        The current implementation is probably less efficient than it could be.
  1559.        However, because of special elements the code is much cleaner this way.
  1560.  GLOBAL VARIABLES
  1561.  COMMENTS, BUGS, ASSUMPTIONS
  1562.  EXAMPLES
  1563.  REVISION LOG
  1564. --------------------------------------------------------------------------*/
  1565. #ifdef PROTOTYPE
  1566. int32 Hlength(int32 file_id, uint16 tag, uint16 ref)
  1567. #else
  1568. int32 Hlength(file_id, tag, ref)
  1569.     int32 file_id;             /* file id of elt to inquire */
  1570.     uint16 tag;                        /* tag of id to inquire */
  1571.     uint16 ref;                        /* ref of id to inquire */
  1572. #endif
  1573. {
  1574.     char *FUNC="Hlength";      /* for HERROR */
  1575.     int32 access_id;           /* access record id */
  1576.     int32 length;              /* length of elt inquired */
  1577.     int ret;                   /* return code */
  1578.  
  1579.     /* clear error stack */
  1580.     HEclear();
  1581.  
  1582.     /* get access record, inquire about lebngth and then dispose of
  1583.        access record */
  1584.     access_id = Hstartread(file_id, tag, ref);
  1585.     if (access_id == FAIL) {
  1586.        HERROR(DFE_ARGS);
  1587.        return FAIL;
  1588.     }
  1589.     if ((ret = (int)Hinquire(access_id, (int32*)NULL, (uint16*)NULL,
  1590.                   (uint16*)NULL,&length, (int32*)NULL, (int32*)NULL,
  1591.                   (int16*)NULL, (int16*) NULL)) == FAIL) {
  1592.        HERROR(DFE_INTERNAL);
  1593.     }
  1594.     (void) Hendaccess(access_id);
  1595.  
  1596.     return (ret == FAIL) ? (int32) FAIL : length;
  1597. }   /* end Hlength() */
  1598.  
  1599. /*--------------------------------------------------------------------------
  1600.  
  1601.  NAME
  1602.        Hoffset -- get offset of data element in the file
  1603.  USAGE
  1604.        int32 Hoffset(fileid, tag, ref)
  1605.        int32 fileid;           IN: id of file
  1606.        uint16 tag;             IN: tag of data element
  1607.        uint16 ref;             IN: ref of data element
  1608.  RETURNS
  1609.        returns offset of data element if it is present in the file or FAIL (-1)
  1610.        if it is not.  This should be used for debugging purposes only since 
  1611.        the user should not have to know the actual offset of a data element in a file.
  1612.  
  1613.        Like Hlength().  This could be sped up by not going through Hstartread()
  1614.        but because of special elements it is easier this way
  1615.  DESCRIPTION
  1616.  GLOBAL VARIABLES
  1617.  COMMENTS, BUGS, ASSUMPTIONS
  1618.  EXAMPLES
  1619.  REVISION LOG
  1620. --------------------------------------------------------------------------*/
  1621. #ifdef PROTOTYPE
  1622. int32 Hoffset(int32 file_id, uint16 tag, uint16 ref)
  1623. #else
  1624. int32 Hoffset(file_id, tag, ref)
  1625.     int32 file_id;             /* file id of elt to inquire */
  1626.     uint16 tag;                        /* tag of elt to inquire */
  1627.     uint16 ref;                        /* ref of elt to inquire */
  1628. #endif
  1629. {
  1630.     char *FUNC="Hoffset";      /* for HERROR */
  1631.     int32 access_id;           /* access record id */
  1632.     int32 offset;              /* offset of elt inquired */
  1633.     int ret;                   /* return code */
  1634.  
  1635.     /* clear error stack */
  1636.  
  1637.     HEclear();
  1638.  
  1639.     /* get access record, inquire offset, and dispose of access record */
  1640.  
  1641.     access_id = Hstartread(file_id, tag, ref);
  1642.     if (access_id == FAIL) {
  1643.        HERROR(DFE_ARGS);
  1644.        return FAIL;
  1645.     }
  1646.     if ((ret = (int)Hinquire(access_id, (int32*)NULL, (uint16*)NULL,
  1647.                        (uint16*)NULL, (int32*)NULL, &offset, (int32*)NULL,
  1648.                        (int16*)NULL, (int16*) NULL)) == FAIL) {
  1649.        HERROR(DFE_INTERNAL);
  1650.     }
  1651.     (void) Hendaccess(access_id);
  1652.  
  1653.     return (ret == FAIL) ? (int32) FAIL : offset;
  1654. }   /* end Hoffset() */
  1655.  
  1656. /*--------------------------------------------------------------------------
  1657.  
  1658.  NAME
  1659.        Hdupdd -- duplicate a data descriptor
  1660.  USAGE
  1661.        int Hdupdd(file_id, tag, ref, old_tag, old_ref)
  1662.        int32 file_id;          IN: id of file
  1663.        uint16 tag;             IN: tag of new data descriptor
  1664.        uint16 ref;             IN: ref of new data descriptor
  1665.        uint16 old_tag;         IN: tag of data descriptor to duplicate
  1666.        uint16 old_ref;         IN: ref of data descriptor to duplicate
  1667.  RETURNS
  1668.        returns SUCCEED (0) if successful, FAIL (-1) otherwise
  1669.  DESCRIPTION
  1670.        Duplicates a data descriptor so that the new tag/ref points to the
  1671.        same data element pointed to by the old tag/ref.
  1672.  GLOBAL VARIABLES
  1673.  COMMENTS, BUGS, ASSUMPTIONS
  1674.  EXAMPLES
  1675.  REVISION LOG
  1676. --------------------------------------------------------------------------*/
  1677. #ifdef PROTOTYPE
  1678. int Hdupdd(int32 file_id, uint16 tag, uint16 ref,
  1679.           uint16 old_tag, uint16 old_ref)
  1680. #else
  1681. int Hdupdd(file_id, tag, ref, old_tag, old_ref)
  1682.     int32 file_id;             /* file id of dd's to duplicate */
  1683.     uint16 tag;                        /* tag of new duplicate dd */
  1684.     uint16 ref;                        /* ref of new duplicate dd */
  1685.     uint16 old_tag;            /* tag of old dd to duplicate */
  1686.     uint16 old_ref;            /* ref of old dd to duplicate */
  1687. #endif
  1688. {
  1689.     char *FUNC="Hdupdd";       /* for HERROR */
  1690.     filerec_t *file_rec;       /* file record */
  1691.     ddblock_t *block;          /* dd block fo old dd */
  1692.     ddblock_t *new_block;      /* dd block of new dd */
  1693.     int32 idx;                 /* index into dd list for old dd */
  1694.     int32 new_idx;             /* index into dd list for new dd */
  1695.  
  1696.     /* clear error stack and check validity of file id */
  1697.  
  1698.     HEclear();
  1699.     file_rec = FID2REC(file_id);
  1700.     if (file_rec == (filerec_t *) NULL || file_rec->refcount == 0) {
  1701.        HERROR(DFE_ARGS);
  1702.        return FAIL;
  1703.     }
  1704.  
  1705.     /* look for old dd and new dd in file record */
  1706.  
  1707.     new_block = block = file_rec->ddhead;
  1708.     new_idx = idx = -1;
  1709.     if (HIlookup_dd(file_rec, old_tag, old_ref, &block, &idx) == FAIL) {
  1710.        HERROR(DFE_NOMATCH);
  1711.        return FAIL;
  1712.     }
  1713.     if (FAIL != HIlookup_dd(file_rec, tag, ref, &new_block, &new_idx)) {
  1714.  
  1715.        /* dd already exist, cannot modify */
  1716.  
  1717.        HERROR(DFE_DUPDD);
  1718.        return FAIL;
  1719.     }
  1720.  
  1721.     /* look for empty dd to put new dd */
  1722.  
  1723.     new_block = file_rec->ddhead;
  1724.     new_idx = -1;
  1725.     if (HIlookup_dd(file_rec, (uint16)DFTAG_NULL, (uint16)DFTAG_WILDCARD,
  1726.                  &file_rec->null_block, &file_rec->null_idx) == FAIL) {
  1727.        if (HInew_dd_block(file_rec, FILE_NDDS(file_rec), FUNC) == FAIL) {
  1728.            HERROR(DFE_NOFREEDD);
  1729.            return FAIL;
  1730.        } else {
  1731.            new_block = file_rec->ddlast;
  1732.            new_idx = 0;
  1733.        }
  1734.     } else {
  1735.       new_block = file_rec->null_block;
  1736.       new_idx   = file_rec->null_idx;
  1737.     }
  1738.  
  1739.     /* fill in the new dd with details from old dd and update file with
  1740.        new dd */
  1741.  
  1742.     new_block->ddlist[new_idx].tag = tag;
  1743.     new_block->ddlist[new_idx].ref = ref;
  1744.     new_block->ddlist[new_idx].offset = block->ddlist[idx].offset;
  1745.     new_block->ddlist[new_idx].length = block->ddlist[idx].length;
  1746.  
  1747.     /* add the new thing to the hash table */
  1748.     if(HIadd_hash_dd(file_rec, tag, ref,  new_block, new_idx))
  1749.       return FAIL;                     
  1750.  
  1751.     return HIupdate_dd(file_rec, new_block, new_idx, FUNC);
  1752. }   /* end Hdupdd() */
  1753.  
  1754. /*--------------------------------------------------------------------------
  1755.  HIupdate_dd
  1756.  
  1757.  write an updated dd (in memory) to the file.
  1758. --------------------------------------------------------------------------*/
  1759. #ifdef PROTOTYPE
  1760. int HIupdate_dd(filerec_t *file_rec, ddblock_t *block, int32 idx, char *FUNC)
  1761. #else
  1762. int HIupdate_dd(file_rec, block, idx, FUNC)
  1763.     filerec_t *file_rec;       /* file record */
  1764.     ddblock_t *block;          /* dd block of updated dd */
  1765.     int32 idx;                 /* dd list index of updated dd */
  1766.     char *FUNC;                /* for HERROR */
  1767. #endif
  1768. {
  1769.     int32 offset;              /* offset of updated dd in file */
  1770.     uint8 *p;                  /* temp buffer ptr */
  1771.  
  1772.     /* look for offset of updated dd block in the file */
  1773.  
  1774.     if (block == file_rec->ddhead) {
  1775.  
  1776.        /* updated ddblock is the first one */
  1777.  
  1778.        offset = MAGICLEN + NDDS_SZ + OFFSET_SZ + (idx * DD_SZ);
  1779.  
  1780.     } else {
  1781.        offset = block->prev->nextoffset + NDDS_SZ + OFFSET_SZ +
  1782.            (idx * DD_SZ);
  1783.     }
  1784.  
  1785.     /* write in the updated dd */
  1786.  
  1787.     if (HI_SEEK(file_rec->file, offset) == FAIL) {
  1788.        HERROR(DFE_SEEKERROR);
  1789.        return FAIL;
  1790.     }
  1791.     p = tbuf;
  1792.     UINT16ENCODE(p, block->ddlist[idx].tag);
  1793.     UINT16ENCODE(p, block->ddlist[idx].ref);
  1794.     INT32ENCODE(p, block->ddlist[idx].offset);
  1795.     INT32ENCODE(p, block->ddlist[idx].length);
  1796.     if (HI_WRITE(file_rec->file, tbuf, DD_SZ) == FAIL) {
  1797.        HERROR(DFE_WRITEERROR);
  1798.        return FAIL;
  1799.     }
  1800.  
  1801.     return SUCCEED;
  1802. }
  1803.  
  1804. /*--------------------------------------------------------------------------
  1805.  
  1806.  NAME
  1807.        Hdeldd -- delete a data descriptor
  1808.  USAGE
  1809.        int Hdeldd(file_id, tag, ref)
  1810.        int file_id;            IN: id of file
  1811.        int tag;                IN: tag of data descriptor to delete
  1812.        int ref;                IN: ref of data descriptor to delete
  1813.  RETURNS
  1814.        returns SUCCEED (0) if successful, FAIL (-1) otherwise
  1815.  DESCRIPTION
  1816.        Deletes a data descriptor of tag/ref from the dd list of the file.
  1817.        This routine is unsafe and may leave a file in a condition that is
  1818.        not usable by some routines.  Use with care.
  1819.  GLOBAL VARIABLES
  1820.  COMMENTS, BUGS, ASSUMPTIONS
  1821.  EXAMPLES
  1822.  REVISION LOG
  1823. --------------------------------------------------------------------------*/
  1824. #ifdef PROTOTYPE
  1825. int Hdeldd(int32 file_id, uint16 tag, uint16 ref)
  1826. #else
  1827. int Hdeldd(file_id, tag, ref)
  1828.     int32 file_id;             /* file record id */
  1829.     uint16 tag;                        /* tag of dd to delete */
  1830.     uint16 ref;                        /* ref of dd to delete */
  1831. #endif
  1832. {
  1833.     char *FUNC="Hdeldd";       /* for HERROR */
  1834.     filerec_t *file_rec;       /* file record */
  1835.     ddblock_t *block;          /* dd block of deleted dd */
  1836.     int32 idx;                 /* dd list index of deleted dd */
  1837.  
  1838.     /* clear error stack and check validity of file record id */
  1839.  
  1840.     HEclear();
  1841.     file_rec = FID2REC(file_id);
  1842.     if (file_rec == (filerec_t *) NULL || file_rec->refcount == 0 ||
  1843.        tag == DFTAG_WILDCARD || ref == DFREF_WILDCARD) {
  1844.        HERROR(DFE_ARGS);
  1845.        return FAIL;
  1846.     }
  1847.  
  1848.     /* look for the deleted dd */
  1849.     if (HIlookup_dd(file_rec, tag, ref, &block, &idx) == FAIL) {
  1850.        HERROR(DFE_NOMATCH);
  1851.        return FAIL;
  1852.     }
  1853.  
  1854.     /* this may have thrown off our ending markers, reset to beginning */
  1855.  
  1856.     file_rec->null_block = file_rec->ddhead;
  1857.     file_rec->null_idx   = -1;
  1858.  
  1859.     /* mark the dd as empty and then update the file */
  1860.  
  1861.     block->ddlist[idx].tag = DFTAG_NULL;
  1862.  
  1863.     /* remove it from the hash table */
  1864.     if(HIdel_hash_dd(file_rec, tag, ref) == FAIL)
  1865.       return FAIL;
  1866.  
  1867.     return HIupdate_dd(file_rec, block, idx, FUNC);
  1868. }   /* end Hdeldd() */
  1869.  
  1870. /*--------------------------------------------------------------------------
  1871.  
  1872.  NAME
  1873.        Hnewref -- returns a ref that is guaranteed to be unique in the file
  1874.  USAGE
  1875.        uint16 Hnewref(file_id)
  1876.        int32 file_id;          IN: id of file
  1877.  RETURNS
  1878.        returns the ref number, 0 otherwise
  1879.  DESCRIPTION
  1880.        Returns a ref number that can be used with any tag to produce a
  1881.        unique tag/ref.  Successive calls to Hnewref will generate a
  1882.        strictly increasing sequence until the highest possible ref had been
  1883.        returned, then Hnewref will return unused ref's starting from 1.
  1884.  GLOBAL VARIABLES
  1885.  COMMENTS, BUGS, ASSUMPTIONS
  1886.  EXAMPLES
  1887.  REVISION LOG
  1888. --------------------------------------------------------------------------*/
  1889. #ifdef PROTOTYPE
  1890. uint16 Hnewref(int32 file_id)
  1891. #else
  1892. uint16 Hnewref(file_id)
  1893.     int32 file_id;             /* file record id */
  1894. #endif
  1895. {
  1896.     char *FUNC="Hnewref";      /* for HERROR */
  1897.     filerec_t *file_rec;       /* file record */
  1898.     uint16 ref;                        /* the new ref */
  1899.  
  1900.     /* clear error stack and check validity of file record id */
  1901.  
  1902.     HEclear();
  1903.     file_rec = FID2REC(file_id);
  1904.     if (file_rec == (filerec_t *) NULL || file_rec->refcount == 0) {
  1905.        HERROR(DFE_ARGS);
  1906.        return 0;
  1907.     }
  1908.  
  1909.     /* if maxref of this file is still below the maximum,
  1910.        just return next number */
  1911.     if (file_rec->maxref < MAX_REF) {
  1912.        return ++(file_rec->maxref);
  1913.     }
  1914.  
  1915.     /* otherwise, search for an empty ref */
  1916.  
  1917.     /* incredibly slow but unlikely situation */
  1918.  
  1919.     for (ref = 1; ref < MAX_REF; ref++) {
  1920.        ddblock_t *bl;
  1921.        int32 idx;
  1922.        bl = file_rec->ddhead;
  1923.        idx = -1;
  1924.        if (HIfind_dd((uint16)DFTAG_WILDCARD, ref, &bl, &idx) == FAIL)
  1925.            return ref;
  1926.     }
  1927.  
  1928.     return 0;
  1929. }
  1930.  
  1931. /*--------------------------------------------------------------------------
  1932.  
  1933.  NAME
  1934.        Hishdf -- tells if a file is an HDF file
  1935.  USAGE
  1936.        int32 Hishdf(path)
  1937.        char *path;             IN: name of file
  1938.  RETURNS
  1939.        returns TRUE (non-zero) if file is HDF, FALSE (0) otherwise
  1940.  DESCRIPTION
  1941.  GLOBAL VARIABLES
  1942.  COMMENTS, BUGS, ASSUMPTIONS
  1943.  EXAMPLES
  1944.  REVISION LOG
  1945. --------------------------------------------------------------------------*/
  1946.  
  1947. int32
  1948. #ifdef PROTOTYPE
  1949. Hishdf(char *filename)
  1950. #else
  1951. Hishdf(filename)
  1952.     char *filename;
  1953. #endif /* PROTOTYPE */
  1954. {
  1955.   char *FUNC = "Hishdf";
  1956.   
  1957. #if defined(VMS) || defined(MAC)
  1958.   
  1959.   int32 fid;
  1960.  
  1961.   fid = Hopen(filename, DFACC_READ, 0);
  1962.   if(fid == FAIL) return FALSE;
  1963.  
  1964.   Hclose(fid);
  1965.  
  1966.   return TRUE;
  1967.  
  1968. #else
  1969.  
  1970.   bool ret;
  1971.   hdf_file_t fp;
  1972.   char b[MAGICLEN];
  1973.   
  1974.     fp = HI_OPEN(filename, DFACC_READ);
  1975.     if (OPENERR(fp))
  1976.         return(FALSE);
  1977.     else {
  1978.         if(HI_SEEK(fp, 0) == FAIL) {
  1979.             HERROR(DFE_SEEKERROR);
  1980.             return FALSE;
  1981.           }
  1982.  
  1983.         if(HI_READ(fp, b, MAGICLEN) == FAIL) {
  1984.             HERROR(DFE_READERROR);
  1985.             return FALSE;
  1986.           }
  1987.         if(NSTREQ(b, HDFMAGIC, MAGICLEN)) ret = TRUE;
  1988.         else ret = FALSE;
  1989.  
  1990.         HI_CLOSE(fp);
  1991.         return(ret);
  1992.     }
  1993. #endif
  1994. } /* Hishdf */
  1995.  
  1996. /*--------------------------------------------------------------------------
  1997.  NAME
  1998.        Hsync -- sync file with memory
  1999.  USAGE
  2000.        int Hsync(file_id)
  2001.        int file_id;            IN: id of file
  2002.  RETURNS
  2003.        returns SUCCEED (0) if sucessful, FAIL (-1) otherwise
  2004.  DESCRIPTION
  2005.        Currently, the on-disk and in-memory representations are always
  2006.        the same.  Thus there is no real use for Hsync().  In the future,
  2007.        things may be buffered before being written out at which time
  2008.        Hsync() will be useful to sync up the on-disk representation.
  2009.  GLOBAL VARIABLES
  2010.  COMMENTS, BUGS, ASSUMPTIONS
  2011.  EXAMPLES
  2012.  REVISION LOG
  2013. --------------------------------------------------------------------------*/
  2014. /* ARGSUSED */
  2015. #ifdef PROTOTYPE
  2016. int Hsync(int32 file_id)
  2017. #else
  2018. int Hsync(file_id)
  2019.     int32 file_id;
  2020. #endif
  2021. {
  2022.     /* right now there's nothing that needs to be done */
  2023.     return SUCCEED;
  2024. }
  2025.  
  2026.  
  2027. /*--------------------------------------------------------------------------
  2028.  HDvalidfid
  2029.  
  2030.  Check to see if a file id is valid.  Used by external functions.
  2031. --------------------------------------------------------------------------*/
  2032. #ifdef PROTOTYPE
  2033. bool HDvalidfid(int32 file_id)
  2034. #else
  2035. bool HDvalidfid(file_id)
  2036.     int32 file_id;
  2037. #endif
  2038. {
  2039.     filerec_t *file_rec = FID2REC(file_id);
  2040.     if (!file_rec || file_rec->refcount == 0)
  2041.        return FALSE;
  2042.     else
  2043.        return TRUE;
  2044. }
  2045.  
  2046. /*--------------------------------------------------------------------------
  2047.  HDerr
  2048.  
  2049.  Closes a file and return FAIL.  Replacement for DFIerr in HDF3.1 and before
  2050. --------------------------------------------------------------------------*/
  2051. #ifdef PROTOTYPE
  2052. int HDerr(int32 file_id)
  2053. #else
  2054. int HDerr(file_id)
  2055.     int32 file_id;
  2056. #endif
  2057. {
  2058.     Hclose(file_id);
  2059.     return FAIL;
  2060. }
  2061.  
  2062.  
  2063. /*==========================================================================
  2064.  
  2065.   Internal Routines 
  2066.  
  2067. ==========================================================================*/
  2068.  
  2069.  
  2070.  
  2071.  
  2072. /*--------------------------------------------------------------------------
  2073.  HIchangedd
  2074.  
  2075.   function for setting access elements record if that record had been
  2076.    made special.  It actually just fills in the appropriate info
  2077. --------------------------------------------------------------------------*/
  2078. #ifdef PROTOTYPE
  2079. static int HIchangedd(dd_t *datadd, ddblock_t *block, int idx, int16 special,
  2080.               VOIDP special_info, int32 (**special_func)())
  2081. #else
  2082. static int HIchangedd(datadd, block, idx, special, special_info, special_func)
  2083.     dd_t *datadd;              /* dd that had been converted to special */
  2084.     ddblock_t *block;          /* new dd block of converted dd */
  2085.     int idx;                   /* next dd list index of converted dd */
  2086.     int16 special;             /* special code of converted dd */
  2087.     VOIDP special_info;        /* special info of converted dd */
  2088.     int32 (**special_func)();  /* special function table of converted dd */
  2089. #endif
  2090. {
  2091.     int i;                     /* temp index */
  2092.     int attached = 0;          /* number of accesses attached to this dd */
  2093.  
  2094.     /* go through access records to look for converted dd,
  2095.        and then update the matching records */
  2096.  
  2097.     for (i=0; i<MAX_FILE; i++)
  2098.        if (access_records[i].used) {
  2099.            dd_t *tdd =         /* ptr to dd of current access record */
  2100.                &access_records[i].block->ddlist[access_records[i].idx];
  2101.            if (tdd == datadd) {
  2102.                access_records[i].block = block;
  2103.                access_records[i].idx = idx;
  2104.                access_records[i].special = special;
  2105.                access_records[i].special_func = special_func;
  2106.                access_records[i].special_info = special_info;
  2107.                attached++;
  2108.            }
  2109.        }
  2110.  
  2111.     return attached;
  2112. }
  2113.  
  2114. /*--------------------------------------------------------------------------
  2115.  HIinit_file_dds
  2116.  
  2117.  Initialize the first dd block in memory and in new file
  2118. --------------------------------------------------------------------------*/
  2119. #ifdef PROTOTYPE
  2120. PRIVATE int HIinit_file_dds(filerec_t *file_rec, int16 ndds, char *FUNC)
  2121. #else
  2122. PRIVATE int HIinit_file_dds(file_rec, ndds, FUNC)
  2123.     filerec_t *file_rec;       /* file record */
  2124.     int16 ndds;        /* number of dd's to put in this block */
  2125.     char *FUNC;                        /* for HERROR */
  2126. #endif
  2127. {
  2128.     ddblock_t *block;          /* dd block to intialize */
  2129.     uint8 *p;                  /* temp buffer ptr */
  2130.     dd_t *list;                /* list of dd */
  2131.     register int i;            /* temp ints */
  2132.     register int16 n;
  2133.  
  2134.     /* 'reasonablize' the value of ndds.  0 means use default */
  2135.  
  2136.     if (0 == ndds)
  2137.        ndds = DEF_NDDS;
  2138.     else if (ndds < MIN_NDDS)
  2139.        ndds = MIN_NDDS;
  2140.  
  2141.     /* allocate the dd block in memory and initialize it */
  2142.  
  2143.     file_rec->ddhead = (ddblock_t *) HDgetspace(sizeof(ddblock_t));
  2144.     if (file_rec->ddhead == (ddblock_t *) NULL) {
  2145.        HERROR(DFE_NOSPACE);
  2146.        return FAIL;
  2147.     }
  2148.     block = file_rec->ddlast = file_rec->ddhead;
  2149.     block->prev = (ddblock_t *) NULL;
  2150.     block->ndds = ndds;
  2151.     block->next = (ddblock_t *) NULL;
  2152.     block->nextoffset = 0;
  2153.  
  2154.     /* write first dd block to file */
  2155.  
  2156.     p = tbuf;
  2157.     INT16ENCODE(p, block->ndds);
  2158.     INT32ENCODE(p, (int32) 0);
  2159.     if (HI_WRITE(file_rec->file, tbuf, NDDS_SZ+OFFSET_SZ) == FAIL) {
  2160.        HERROR(DFE_WRITEERROR);
  2161.        return FAIL;
  2162.     }
  2163.  
  2164.     /* allocate and initialize dd list */
  2165.  
  2166.     list = block->ddlist = (dd_t *) HDgetspace((uint32) ndds * sizeof(dd_t));
  2167.     if (list == (dd_t *) NULL) {
  2168.        HERROR(DFE_NOSPACE);
  2169.        return FAIL;
  2170.     }
  2171.     for (i = 0; i < ndds; i++) {
  2172.        list[i].tag = DFTAG_NULL;
  2173.        list[i].ref = 0;
  2174.        list[i].length = list[i].offset = 0;
  2175.     }
  2176.  
  2177.     /* write dd list to file */
  2178.  
  2179.     /* n is the maximum number of dd's in tbuf */
  2180.  
  2181.     n = sizeof(int_tbuf) / DD_SZ;
  2182.     if (n > ndds) n = ndds;
  2183.     p = tbuf;
  2184.  
  2185.     for (i = 0; i < n; i++) {
  2186.        UINT16ENCODE(p, (uint16)DFTAG_NULL);
  2187.        UINT16ENCODE(p, (uint16)0);
  2188.        INT32ENCODE(p, (int32)0);
  2189.        INT32ENCODE(p, (int32)0);
  2190.     }
  2191.     while (ndds > 0) {
  2192.        if (HI_WRITE(file_rec->file, tbuf, n*DD_SZ) == FAIL) {
  2193.            HERROR(DFE_WRITEERROR);
  2194.            return FAIL;
  2195.        }
  2196.        ndds -= n;
  2197.        if (n > ndds) n = ndds;
  2198.     }
  2199.  
  2200.     /* write the version string */
  2201.  
  2202.     /* commented out for version tags
  2203.     if (HI_WRITE(file_rec->file, HDF_VERSION, HDstrlen(HDF_VERSION)) == FAIL) {
  2204.         HERROR(DFE_WRITEERROR);
  2205.        return FAIL;
  2206.     }
  2207.     end of commenting out for version tags */
  2208.  
  2209.     /* no dd's yet, so maximum ref is 0 */
  2210.  
  2211.     file_rec->maxref = 0;
  2212.  
  2213.     /* blank out the hash table */
  2214.     for(i = 0; i < HASH_MASK + 1; i++) 
  2215.       file_rec->hash[i] = NULL;
  2216.  
  2217.     return SUCCEED;
  2218. }
  2219.  
  2220. /*--------------------------------------------------------------------------
  2221.  HIget_func_table
  2222.  
  2223.  get the function table for special elt of an access record
  2224. --------------------------------------------------------------------------*/
  2225. #ifdef PROTOTYPE
  2226. PRIVATE int32 (**HIget_function_table(accrec_t *access_rec, char *FUNC))()
  2227. #else
  2228. PRIVATE int32 (** HIget_function_table(access_rec, FUNC))()
  2229.     accrec_t *access_rec;      /* access record */
  2230.     char *FUNC;                        /* for HERROR */
  2231. #endif
  2232. {
  2233.     dd_t *dd;                  /* ptr to current dd */
  2234.     filerec_t *file_rec;       /* file record */
  2235.  
  2236.     /* read in the special code in the special elt */
  2237.  
  2238.     dd = &access_rec->block->ddlist[access_rec->idx];
  2239.     file_rec = FID2REC(access_rec->file_id);
  2240.     if (HI_SEEK(file_rec->file, dd->offset) == FAIL) {
  2241.        HERROR(DFE_SEEKERROR);
  2242.        return NULL;
  2243.     }
  2244.     if (HI_READ(file_rec->file, tbuf, 2) == FAIL) {
  2245.        HERROR(DFE_READERROR);
  2246.        return NULL;
  2247.     }
  2248.  
  2249.     /* using special code, look up function table in associative table */
  2250.  
  2251.     {
  2252.        register int i;
  2253.        uint8 *p;
  2254.        p = tbuf;
  2255.        INT16DECODE(p, access_rec->special);
  2256.        for (i=0; functab[i].key != 0; i++) {
  2257.            if (access_rec->special == functab[i].key)
  2258.                return functab[i].tab;
  2259.        }
  2260.     }
  2261.  
  2262.     return NULL;
  2263. }
  2264.  
  2265. /*--------------------------------------------------------------------------
  2266.  HIgetspinfo
  2267.  
  2268.  used by routines in special elt modules
  2269.  get information for a special elt
  2270. --------------------------------------------------------------------------*/
  2271. #ifdef PROTOTYPE
  2272. VOIDP HIgetspinfo(accrec_t *access_rec, uint16 tag, uint16 ref)
  2273. #else
  2274. VOIDP HIgetspinfo(access_rec, tag, ref)
  2275.     accrec_t *access_rec;      /* file record id */
  2276.     uint16 tag;                        /* tag of special elt */
  2277.     uint16 ref;                        /* ref of special elt */
  2278. #endif
  2279. {
  2280.     register int i;            /* temp index */
  2281.  
  2282.     /* search access records for the matching dd,
  2283.        and return special information */
  2284.  
  2285.     for (i=0; i< MAX_ACC; i++)
  2286.        if (access_records + i != access_rec &&
  2287.            access_records[i].used &&
  2288.            access_records[i].file_id == access_rec->file_id &&
  2289.            access_records[i].block->ddlist[access_records[i].idx].tag==tag &&
  2290.            access_records[i].block->ddlist[access_records[i].idx].ref == ref)
  2291.  
  2292.            return (VOIDP) access_records[i].special_info;
  2293.  
  2294.     return NULL;
  2295. }
  2296.  
  2297. /*--------------------------------------------------------------------------
  2298.  HIlock
  2299.  
  2300.  lock a file record.  This is used by special functions to prevent
  2301.  losing files taht are still accessed
  2302. --------------------------------------------------------------------------*/
  2303. #ifdef PROTOTYPE
  2304. static int HIlock(int32 file_id)
  2305. #else
  2306. static int HIlock(file_id)
  2307.     int32 file_id;             /* file record id to lock */
  2308. #endif
  2309. {
  2310.     char *FUNC="HIlock";       /* for HERROR */
  2311.  
  2312.     /* get file record and check validity */
  2313.  
  2314.     filerec_t *file_rec=FID2REC(file_id);
  2315.     if (!file_rec || file_rec->refcount == 0) {
  2316.         HERROR(DFE_ARGS);
  2317.         return FAIL;
  2318.     }
  2319.  
  2320.     /* lock the file record */
  2321.     file_rec->attach++;
  2322.  
  2323.     return SUCCEED;
  2324. }
  2325.  
  2326. /*--------------------------------------------------------------------------
  2327.  HIunlock
  2328.  
  2329.  unlock a previously locked file record
  2330. --------------------------------------------------------------------------*/
  2331. #ifdef PROTOTYPE
  2332. static int HIunlock(int32 file_id)
  2333. #else
  2334. static int HIunlock(file_id)
  2335.     int32 file_id;             /* file record to unlock */
  2336. #endif
  2337. {
  2338.     char *FUNC="HIunlock";     /* for HERROR */
  2339.  
  2340.     /* get file record and validate */
  2341.  
  2342.     filerec_t *file_rec=FID2REC(file_id);
  2343.     if (!file_rec || file_rec->refcount == 0) {
  2344.         HERROR(DFE_ARGS);
  2345.         return FAIL;
  2346.     }
  2347.  
  2348.     /* unlock the file record */
  2349.  
  2350.     file_rec->attach--;
  2351.  
  2352.     return SUCCEED;
  2353. }
  2354.  
  2355.  
  2356. /*--------------------------------------------------------------------------
  2357.  Hnumber
  2358.  
  2359.  Returns the number of instances of a tag in a file.
  2360. --------------------------------------------------------------------------*/
  2361. #ifdef PROTOTYPE
  2362. int Hnumber(int32 file_id, uint16 tag)
  2363. #else
  2364. int Hnumber(file_id, tag)
  2365.     int32 file_id;
  2366.     uint16 tag;
  2367. #endif
  2368. {
  2369.     char *FUNC="Hnumber";
  2370.     int n = 0;
  2371.     ddblock_t *block;
  2372.     int32 idx;
  2373.     filerec_t *file_rec = FID2REC(file_id);
  2374.  
  2375.     HEclear();
  2376.     if (!file_rec || file_rec->refcount == 0) {
  2377.        HERROR(DFE_ARGS);
  2378.        return FAIL;
  2379.     }
  2380.     block = file_rec->ddhead;
  2381.     idx = -1;
  2382.     for (;;) {
  2383.        if (HIfind_dd(tag, DFREF_WILDCARD, &block, &idx) == FAIL) break;
  2384.        n++;
  2385.     }
  2386.     return n;
  2387. }
  2388.  
  2389. /* "Special tag" routines */
  2390.  
  2391. /* The HDF tag space is divided as follows based on the 2 highest bits:
  2392.    00: NCSA reserved ordinary tags
  2393.    01: NCSA reserved special tags
  2394.    10, 11: User tags.
  2395.  
  2396.    It is relatively cheap to operate with special tags within the NCSA
  2397.    reserved tags range.  For users to specify special tags and their
  2398.    corresponding ordinary tag, the pair has to be added to the
  2399.    special_table. */
  2400.  
  2401. /* The special_table contains pairs of each tag and its corrsponding
  2402.    special tag.  The same table is also used to determine if a tag is
  2403.    special.  Add to this table any additional tag/special_tag pairs
  2404.    that might be necessary.  */
  2405.  
  2406. typedef struct special_table_t {
  2407.     uint16 tag;
  2408.     uint16 special_tag;
  2409. } special_table_t;
  2410.  
  2411. static special_table_t special_table[] = {
  2412. {0x8010, 0x4000 | 0x8010},             /* dummy */
  2413. };
  2414.  
  2415. #define SP_TAB_SZ (sizeof(special_table) / sizeof(special_table[0]))
  2416.  
  2417. /*--------------------------------------------------------------------------
  2418. --------------------------------------------------------------------------*/
  2419. #ifdef PROTOTYPE
  2420. uint16 HDmake_special_tag(uint16 tag)
  2421. #else
  2422. uint16 HDmake_special_tag(tag)
  2423.     uint16 tag;                        /* tag to convert */
  2424. #endif
  2425. {
  2426.     register int i;
  2427.  
  2428.     if (~tag & 0x8000)
  2429.        return (tag | 0x4000);
  2430.  
  2431.     for (i=0; i<SP_TAB_SZ; i++)
  2432.        if (special_table[i].tag == tag)
  2433.            return special_table[i].special_tag;
  2434.  
  2435.     return DFTAG_NULL;
  2436. }
  2437.  
  2438. /*--------------------------------------------------------------------------
  2439. --------------------------------------------------------------------------*/
  2440. #ifdef PROTOTYPE
  2441. bool HDis_special_tag(uint16 tag)
  2442. #else
  2443. bool HDis_special_tag(tag)
  2444.     uint16 tag;                        /* tag to check */
  2445. #endif
  2446. {
  2447.     register int i;
  2448.  
  2449.     if (~tag & 0x8000)
  2450.        return (tag & 0x4000) ? TRUE : FALSE;
  2451.  
  2452.     for (i=0; i<SP_TAB_SZ; i++)
  2453.        if (special_table[i].special_tag == tag)
  2454.            return TRUE;
  2455.  
  2456.     return FALSE;
  2457. }
  2458.  
  2459. /*--------------------------------------------------------------------------
  2460. --------------------------------------------------------------------------*/
  2461. #ifdef PROTOTYPE
  2462. uint16 HDbase_tag(uint16 tag)
  2463. #else
  2464. uint16 HDbase_tag(tag)
  2465.     uint16 tag;                        /* tag to convert */
  2466. #endif
  2467. {
  2468.     register int i;
  2469.  
  2470.     if (~tag & 0x8000)
  2471.        return (tag & ~0x4000);
  2472.  
  2473.     for (i=0; i<SP_TAB_SZ; i++)
  2474.        if (special_table[i].special_tag == tag)
  2475.            return special_table[i].special_tag;
  2476.  
  2477.     return tag;                        /* return itself */
  2478. }
  2479.  
  2480. /*--------------------------------------------------------------------------
  2481. **
  2482. ** NAME
  2483. **    Hgetlibversion -- return version info for current HDF library
  2484. ** USAGE
  2485. **    int Hgetlibversion(majorv, minorv, release, string)
  2486. **    uint32 *majorv;        OUT: majorv version number
  2487. **    uint32 *minorv;        OUT: minorv versoin number
  2488. **    uint32 *release;    OUT: release number
  2489. **    char   string[];    OUT: informational text string (80 chars)
  2490. ** RETURNS
  2491. **    returns SUCCEED (0).
  2492. ** DESCRIPTION
  2493. **    Copies values from #defines in hfile.h to provided buffers.
  2494. ** GLOBAL VARIABLES
  2495. ** COMMENTS, BUGS, ASSUMPTIONS
  2496. ** EXAMPLES
  2497. ** REVISION LOG
  2498. --------------------------------------------------------------------------*/
  2499. #ifdef PROTOTYPE
  2500. int Hgetlibversion(uint32 *majorv, uint32 *minorv, uint32 *release, char string[])
  2501. #else
  2502. int Hgetlibversion(majorv, minorv, release, string)
  2503. uint32 *majorv, *minorv, *release;
  2504. char string[];
  2505. #endif
  2506. {
  2507.     char *FUNC="Hgetlibversion";
  2508.  
  2509.     HEclear();
  2510.  
  2511.     *majorv = LIBVER_MAJOR;
  2512.     *minorv = LIBVER_MINOR;
  2513.     *release = LIBVER_RELEASE;
  2514.     HIstrncpy(string, LIBVER_STRING, 81);
  2515.     string[HDstrlen(string)] = '\0';
  2516.  
  2517.     return(SUCCEED);
  2518. }
  2519.  
  2520. /*--------------------------------------------------------------------------
  2521. **
  2522. ** NAME
  2523. **    Hgetfileversion -- return version info for HDF file
  2524. ** USAGE
  2525. **    int Hgetfileversion(file_id, majorv, minorv, release, string)
  2526. **    int32 file_id;        IN: handle of file
  2527. **    uint32 *majorv;        OUT: majorv version number
  2528. **    uint32 *minorv;        OUT: minorv versoin number
  2529. **    uint32 *release;    OUT: release number
  2530. **    char *string;        OUT: informational text string (80 chars)
  2531. ** RETURNS
  2532. **    returns SUCCEED (0) if successful and FAIL (-1) if failed.
  2533. ** DESCRIPTION
  2534. **    Copies values from file_records[] for given file to provided buffers.
  2535. ** GLOBAL VARIABLES
  2536. **    Reads file_records[]
  2537. ** COMMENTS, BUGS, ASSUMPTIONS
  2538. ** EXAMPLES
  2539. ** REVISION LOG
  2540. --------------------------------------------------------------------------*/
  2541. #ifdef PROTOTYPE
  2542. int Hgetfileversion(int32 file_id, uint32 *majorv, uint32 *minorv,
  2543.             uint32 *release, char string[])
  2544. #else
  2545. int Hgetfileversion(file_id, majorv, minorv, release, string)
  2546. int32 file_id;
  2547. uint32 *majorv, *minorv, *release;
  2548. char string[];
  2549. #endif
  2550. {
  2551.     filerec_t *file_rec;
  2552.     char *FUNC="Hgetfileversion";
  2553.  
  2554.  
  2555.     HEclear();
  2556.  
  2557.     file_rec = FID2REC(file_id);
  2558.     if (!file_rec || file_rec->refcount == 0) {
  2559.         HERROR(DFE_ARGS);
  2560.         return(FAIL);
  2561.     }
  2562.  
  2563.     *majorv = file_rec->version.majorv;
  2564.     *minorv = file_rec->version.minorv;
  2565.     *release = file_rec->version.release;
  2566.     HIstrncpy(string, file_rec->version.string, 81);
  2567.     string[HDstrlen(string)] = '\0';
  2568.  
  2569.     if (majorv == 0) {
  2570.         HERROR(DFE_NOMATCH);
  2571.         return(FAIL);
  2572.     } else
  2573.         return(SUCCEED);
  2574. }
  2575.  
  2576. #ifdef PC
  2577. /*--------------------------------------------------------------------------
  2578. **
  2579. ** NAME
  2580. **  HDfreadbig -- function specific to the PC to read in 32-bit sized buffers
  2581. ** USAGE
  2582. **  int32 HDfreadbig(buffer,size,fp)
  2583. **  VOIDP buffer;       IN: the buffer to put bytes into
  2584. **  int32 size;         IN: the number of bytes to read
  2585. **  FILE *fp;           IN: the file pointer for the file to read
  2586. ** RETURNS
  2587. **  returns the number of bytes read
  2588. ** DESCRIPTION
  2589. **  Because the IBM PC compilers use 16-bit number for fread, this function
  2590. **  blocks that up into 64kb blocks to read from a file.
  2591. ** GLOBAL VARIABLES
  2592. **  None
  2593. ** COMMENTS, BUGS, ASSUMPTIONS
  2594. ** EXAMPLES
  2595. ** REVISION LOG
  2596. --------------------------------------------------------------------------*/
  2597. #ifdef WIN3
  2598. #ifdef PROTOTYPE
  2599. int32 HDfreadbig(VOIDP buffer,int32 size,HFILE fp)
  2600. #else
  2601. int32 HDfreadbig(buffer,size,fp)
  2602. VOIDP buffer;
  2603. int32 size;
  2604. HFILE fp;
  2605. #endif
  2606. #else /* !WIN3 */
  2607. #ifdef PROTOTYPE
  2608. int32 HDfreadbig(VOIDP buffer,int32 size,FILE *fp)
  2609. #else
  2610. int32 HDfreadbig(buffer,size,fp)
  2611. VOIDP buffer;
  2612. int32 size;
  2613. FILE *fp;
  2614. #endif
  2615. #endif /* WIN3 */
  2616. {
  2617.     uint8 *b;           /* alias for the buffer */
  2618.     int32 bytes_read;   /* variable to accumulate the number of bytes read in */
  2619.  
  2620.     if(size<=UINT_MAX)   /* if the size is small enough read it in all at once */
  2621. #ifdef WIN3
  2622.         bytes_read=_lread(fp,buffer,(uint16)size);
  2623. #else
  2624.         bytes_read=fread(buffer,1,(uint16)size,fp);
  2625. #endif
  2626.     else {  /* number of bytes to read */
  2627.         bytes_read=0;
  2628.         b=buffer;
  2629.         while(size>UINT_MAX) {
  2630. #ifdef WIN3
  2631.             bytes_read+=_lread(fp,b,UINT_MAX);
  2632. #else
  2633.             bytes_read+=fread(b,1,UINT_MAX,fp);
  2634. #endif
  2635.             b+=UINT_MAX;
  2636.             size-=UINT_MAX;
  2637.           } /* end while */
  2638.         if(size>0)
  2639. #ifdef WIN3
  2640.             bytes_read+=_lread(fp,b,(uint16)size);
  2641. #else
  2642.             bytes_read+=fread(b,1,(uint16)size,fp);
  2643. #endif
  2644.       } /* end else */
  2645.     return(bytes_read);
  2646. }   /* end HDfreadbig() */
  2647.  
  2648. /*--------------------------------------------------------------------------
  2649. **
  2650. ** NAME
  2651. **  HDfwritebig -- function specific to the PC to write out 32-bit sized buffers
  2652. ** USAGE
  2653. **  int32 HDfwritebig(buffer,size,fp)
  2654. **  VOIDP buffer;       IN: the buffer to get bytes from
  2655. **  int32 size;         IN: the number of bytes to write
  2656. **  FILE *fp;           IN: the file pointer for the file to write
  2657. ** RETURNS
  2658. **  returns the number of bytes written
  2659. ** DESCRIPTION
  2660. **  Because the IBM PC compilers use 16-bit number for fwrite, this function
  2661. **  blocks that up into 64kb blocks to write to a file.
  2662. ** GLOBAL VARIABLES
  2663. **  None
  2664. ** COMMENTS, BUGS, ASSUMPTIONS
  2665. ** EXAMPLES
  2666. ** REVISION LOG
  2667. --------------------------------------------------------------------------*/
  2668. #ifdef WIN3
  2669. #ifdef PROTOTYPE
  2670. int32 HDfwritebig(VOIDP buffer,int32 size,HFILE fp)
  2671. #else
  2672. int32 HDfwritebig(buffer,size,fp)
  2673. VOIDP buffer;
  2674. int32 size;
  2675. HFILE fp;
  2676. #endif
  2677. #else /* !WIN3 */
  2678. #ifdef PROTOTYPE
  2679. int32 HDfwritebig(VOIDP buffer,int32 size,FILE *fp)
  2680. #else
  2681. int32 HDfwritebig(buffer,size,fp)
  2682. VOIDP buffer;
  2683. int32 size;
  2684. FILE *fp;
  2685. #endif
  2686. #endif /* WIN3 */
  2687. {
  2688.     uint8 *b;              /* alias for the buffer */
  2689.     int32 bytes_written;   /* variable to accum. the number of bytes written */
  2690.  
  2691.     if(size<=UINT_MAX)  /* if the size is small enough read it in all at once */
  2692. #ifdef WIN3
  2693.         bytes_written=_lwrite(fp,buffer,(uint16)size);
  2694. #else
  2695.         bytes_written=fwrite(buffer,1,(uint16)size,fp);
  2696. #endif
  2697.     else {  /* number of bytes to write */
  2698.         bytes_written=0;
  2699.         b=buffer;
  2700.         while(size>UINT_MAX) {
  2701. #ifdef WIN3
  2702.             bytes_written+=_lwrite(fp,b,UINT_MAX);
  2703. #else
  2704.             bytes_written+=fwrite(b,1,UINT_MAX,fp);
  2705. #endif
  2706.             b+=UINT_MAX;
  2707.             size-=UINT_MAX;
  2708.           } /* end while */
  2709.         if(size>0)
  2710. #ifdef WIN3
  2711.             bytes_written+=_lwrite(fp,b,(uint16)size);
  2712. #else
  2713.             bytes_written+=fwrite(b,1,(uint16)size,fp);
  2714. #endif
  2715.       } /* end else */
  2716.     return(bytes_written);
  2717. }   /* end HDfwritebig() */
  2718. #endif
  2719.  
  2720. /*--------------------------------------------------------------------------
  2721.  HIget_file_slot
  2722.  
  2723.  Searches the file record array for a matching record, or an empty slot.
  2724.  The file is considered the same if the path matches exactly.  This
  2725.  routine is unable to detect aliases, or how to compare relative and
  2726.  absolute paths.
  2727.  
  2728.  Error occurred is charged to the calling function.
  2729. --------------------------------------------------------------------------*/
  2730. #ifdef PROTOTYPE
  2731. PRIVATE int HIget_file_slot(char *path, char *FUNC)
  2732. #else
  2733. PRIVATE int HIget_file_slot(path, FUNC)
  2734.     char *path;                /* file path */
  2735.     char *FUNC;                /* Error is charged to calling function */
  2736. #endif
  2737. {
  2738.     int i;
  2739.     int slot;
  2740.  
  2741. #ifdef OLD_WAY
  2742.  
  2743.     if (!file_records) {
  2744.         /* The array has not been allocated.  Allocating file records
  2745.           dynamically. */
  2746.  
  2747.        file_records = (filerec_t *) HDgetspace((uint32)MAX_FILE * sizeof(filerec_t));
  2748.        if (!file_records) {
  2749.            HERROR(DFE_NOSPACE);
  2750.            return FAIL;
  2751.        }
  2752.  
  2753.        /* Initialize file records. */
  2754.  
  2755.        for (i = 0; i < MAX_FILE; i++) {
  2756.            file_records[i].path = (char *) NULL;
  2757.            file_records[i].ddhead = (ddblock_t *) NULL;
  2758.            file_records[i].refcount = 0;
  2759.        }
  2760.  
  2761.        /* Use the first slot. */
  2762.  
  2763.        file_records[0].version_set = FALSE;
  2764.  
  2765.        file_records[0].path = HDgetspace(HDstrlen(path)+1);
  2766.        HIstrncpy(file_records[0].path, path, HDstrlen(path)+1);
  2767.        return file_records[0].path ? 0 : FAIL;
  2768.     }
  2769.  
  2770. #endif /* OLD_WAY */
  2771.  
  2772.     /* Search for a matching or free slot. */
  2773.  
  2774.     slot = FAIL;
  2775.     for (i = 0; i < MAX_FILE; i++) {
  2776.  
  2777.         /* If there already is an active FID for this file return it
  2778.            thus, there will only ever be one FID per open file.
  2779.            This is a BUG if you want to open the file twice with
  2780.            different access privs each time. */
  2781.  
  2782.        if (file_records[i].path && STREQ(file_records[i].path, path))
  2783.            return i;
  2784.  
  2785.        /* Otherwise, record first free slot. */
  2786.  
  2787.        if (!file_records[i].refcount && slot == FAIL) {
  2788.            slot = i;
  2789.            file_records[i].path = (char *) NULL;
  2790.            file_records[i].ddhead = (ddblock_t *) NULL;
  2791.        }
  2792.  
  2793.     }
  2794.  
  2795.     if (slot == FAIL)
  2796.         /* No matching or free slot. */
  2797.         return FAIL;
  2798.  
  2799.     /* Fill empty slot with data. */
  2800.  
  2801.     file_records[slot].version_set = FALSE;
  2802.  
  2803.     if (file_records[slot].path) HDfreespace(file_records[slot].path);
  2804.     file_records[slot].path = HDgetspace(HDstrlen(path)+1);
  2805.     HIstrncpy(file_records[slot].path, path, HDstrlen(path)+1);
  2806.     return file_records[slot].path ? slot : FAIL;
  2807. }
  2808.  
  2809. /*--------------------------------------------------------------------------
  2810.  HIvalid_magic
  2811.  
  2812.  Checks the magic cookie at the beginning of an opened file to see
  2813.  if the file is a valid HDF file.
  2814. --------------------------------------------------------------------------*/
  2815. #ifdef PROTOTYPE
  2816. PRIVATE bool HIvalid_magic(hdf_file_t file, char *FUNC)
  2817. #else
  2818. PRIVATE bool HIvalid_magic(file, FUNC)
  2819.     hdf_file_t file;               /* File handle. */
  2820.     char *FUNC;                        /* Charge error to calling function. */
  2821. #endif
  2822. {
  2823.     char b[MAGICLEN];          /* Temporary buffer */
  2824.  
  2825.     /* Seek to beginning of the file. */
  2826.  
  2827.     if (HI_SEEK(file, 0) == FAIL) {
  2828.        HERROR(DFE_SEEKERROR);
  2829.        return FALSE;
  2830.     }
  2831.  
  2832.     /* Read in magic cookie and compare. */
  2833.  
  2834.     if (HI_READ(file, b, MAGICLEN) == FAIL) {
  2835.        HERROR(DFE_READERROR);
  2836.        return FALSE;
  2837.     }
  2838.     if (NSTREQ(b, HDFMAGIC, MAGICLEN)) return TRUE;
  2839.     else return FALSE;
  2840. }
  2841.  
  2842.  
  2843. /*--------------------------------------------------------------------------
  2844.  HIget_access_slot
  2845.  
  2846.  get a free access record slot
  2847. --------------------------------------------------------------------------*/
  2848. #ifdef PROTOTYPE
  2849. int HIget_access_slot(void)
  2850. #else
  2851. int HIget_access_slot()
  2852. #endif
  2853. {
  2854.     int i;                     /* temp index */
  2855.  
  2856.     /* access records not allocated yet.
  2857.        Allocate dynamically and initialize*/
  2858.  
  2859.     if (!access_records) {
  2860.        access_records = (accrec_t *) HDgetspace(MAX_ACC * sizeof(accrec_t));
  2861.        if (!access_records)    return FAIL;
  2862.        for (i = 0; i < MAX_ACC; i++)
  2863.            access_records[i].used = FALSE;
  2864.  
  2865.        /* use the first record */
  2866.  
  2867.        access_records[0].used = TRUE;
  2868.        return 0;
  2869.     }
  2870.  
  2871.     /* return the first unused record */
  2872.  
  2873.     for (i = 0; i < MAX_ACC; i++)
  2874.        if (!access_records[i].used) {
  2875.            access_records[i].used = TRUE;
  2876.            return i;
  2877.        }
  2878.  
  2879.     return FAIL;
  2880. } /* HIget_access_slot */
  2881.  
  2882. /*--------------------------------------------------------------------------
  2883.  HInew_dd_block
  2884.  
  2885.  create new ddblock
  2886. --------------------------------------------------------------------------*/
  2887. #ifdef PROTOTYPE
  2888. int HInew_dd_block(filerec_t *file_rec, int16 ndds, char *FUNC)
  2889. #else
  2890. int HInew_dd_block(file_rec, ndds, FUNC)
  2891.     filerec_t *file_rec;       /* file record */
  2892.     int16 ndds;                /* number of dd's to create in this ddblock */
  2893.     char *FUNC;                        /* function that this was called from */
  2894. #endif
  2895. {
  2896.     ddblock_t *block;          /* current dd block */
  2897.     int32 nextoffset;          /* offset of new ddblock */
  2898.     int32 offset;              /* offset to the offset of new ddblock */
  2899.     uint8 *p;                  /* temp buffer ptr */
  2900.     dd_t *list;                /* dd list array of new dd block */
  2901.     int i, n;                  /* temp integers */
  2902.  
  2903.     /* check integrity of file record */
  2904.  
  2905.     if (!file_rec->ddhead || !file_rec->ddlast) {
  2906.        HERROR(DFE_INTERNAL);
  2907.        return FAIL;
  2908.     }
  2909.  
  2910.     /* allocate new dd block record and fill in data */
  2911.  
  2912.     block = (ddblock_t *) HDgetspace(sizeof(ddblock_t));
  2913.     if (block == (ddblock_t *) NULL) {
  2914.        HERROR(DFE_NOSPACE);
  2915.        return FAIL;
  2916.     }
  2917.     block->ndds = ndds;
  2918.     block->next = (ddblock_t *) NULL;
  2919.     block->nextoffset = 0;
  2920.  
  2921.     /* put the new dd block at the end of the file */
  2922.  
  2923.     if (HI_SEEKEND(file_rec->file) == FAIL) {
  2924.        HERROR(DFE_SEEKERROR);
  2925.        return FAIL;
  2926.     }
  2927.     nextoffset = HI_TELL(file_rec->file);
  2928.     p = tbuf;
  2929.     INT16ENCODE(p, block->ndds);
  2930.     INT32ENCODE(p, (int32)0);
  2931.     if (HI_WRITE(file_rec->file, tbuf, NDDS_SZ+OFFSET_SZ) == FAIL) {
  2932.        HERROR(DFE_WRITEERROR);
  2933.        return FAIL;
  2934.     }
  2935.  
  2936.     /* set up the dd list of this dd block and put it in the file
  2937.        after the dd block header */
  2938.  
  2939.     p = tbuf;
  2940.     list = block->ddlist = (dd_t *) HDgetspace((uint32) ndds * sizeof(dd_t));
  2941.     if (list == (dd_t *) NULL) {
  2942.        HERROR(DFE_NOSPACE);
  2943.        return FAIL;
  2944.     }
  2945.     for (i = 0; i < ndds; i++) {
  2946.        list[i].tag = DFTAG_NULL;
  2947.        list[i].ref = 0;
  2948.        list[i].length = list[i].offset = 0;
  2949.     }
  2950.  
  2951.     /* n is the number of dds that could fit into tbuf at one time */
  2952.  
  2953.     n = sizeof(int_tbuf) / DD_SZ;
  2954.     if (n > ndds) n = ndds;
  2955.     for (i = 0; i < n; i++) {
  2956.        UINT16ENCODE(p, (uint16)DFTAG_NULL);
  2957.        UINT16ENCODE(p, (uint16)0);
  2958.        INT32ENCODE(p, (int32)0);
  2959.        INT32ENCODE(p, (int32)0);
  2960.     }
  2961.     while (ndds > 0) {
  2962.        if (HI_WRITE(file_rec->file, tbuf, n*DD_SZ) == FAIL) {
  2963.            HERROR(DFE_WRITEERROR);
  2964.            return FAIL;
  2965.        }
  2966.        ndds -= n;
  2967.        if (n > ndds) n = ndds;
  2968.     }
  2969.  
  2970.     /* update previously last ddblock to point to this new dd block */
  2971.  
  2972.     file_rec->ddlast->nextoffset = nextoffset;
  2973.     block->prev = file_rec->ddlast;
  2974.     file_rec->ddlast->next = block;
  2975.     if (file_rec->ddhead == file_rec->ddlast) {
  2976.        offset = MAGICLEN + NDDS_SZ;
  2977.     } else {
  2978.        offset = file_rec->ddlast->prev->nextoffset + NDDS_SZ;
  2979.     }
  2980.     p = tbuf;
  2981.     INT32ENCODE(p, nextoffset);
  2982.     if (HI_SEEK(file_rec->file, offset) == FAIL) {
  2983.        HERROR(DFE_SEEKERROR);
  2984.        return FAIL;
  2985.     }
  2986.     if (HI_WRITE(file_rec->file, tbuf, OFFSET_SZ) == FAIL) {
  2987.        HERROR(DFE_WRITEERROR);
  2988.        return FAIL;
  2989.     }
  2990.  
  2991.     /* update file record */
  2992.     file_rec->ddlast = file_rec->ddlast->next;
  2993.  
  2994.     return SUCCEED;
  2995. } /* HInew_dd_block */
  2996.  
  2997. /*--------------------------------------------------------------------------
  2998.  HIfill_file_rec
  2999.  
  3000.  Fill in a file record with data from the file, especially
  3001.  the data descriptors.
  3002. --------------------------------------------------------------------------*/
  3003. #ifdef PROTOTYPE
  3004. PRIVATE int HIfill_file_rec(filerec_t *file_rec, char *FUNC)
  3005. #else
  3006. PRIVATE int HIfill_file_rec(file_rec, FUNC)
  3007.     filerec_t *file_rec;       /* File record */
  3008.     char *FUNC;                        /* Charge error to calling function. */
  3009. #endif
  3010. {
  3011.   uint8 *p;               /* Temporary pointer. */
  3012.   int32 n;
  3013.   register intn ndds, i, idx;     /* Temporary integers. */
  3014.  
  3015.   /* Alloc start of linked list of ddblocks. */
  3016.   
  3017.   file_rec->ddhead = (ddblock_t *) HDgetspace(sizeof(ddblock_t));
  3018.   if (file_rec->ddhead == (ddblock_t *) NULL) {
  3019.     HERROR(DFE_NOSPACE);
  3020.     return FAIL;
  3021.   }
  3022.   
  3023.   /* Only one elt in linked list so head is also last. */
  3024.   
  3025.   file_rec->ddlast = file_rec->ddhead;
  3026.   file_rec->ddlast->next = (ddblock_t *) NULL;
  3027.   file_rec->ddlast->prev = (ddblock_t *) NULL;
  3028.   
  3029.   /* The first ddblock always starts after the magic number.
  3030.      Set it up so that we start reading from there. */
  3031.   
  3032.   if (HI_SEEK(file_rec->file, MAGICLEN) == FAIL) {
  3033.     HERROR(DFE_SEEKERROR);
  3034.     return FAIL;
  3035.   }
  3036.   
  3037.   /* Blank out hash table */
  3038.   for(i = 0; i < HASH_MASK + 1; i++)
  3039.       file_rec->hash[i] = NULL;
  3040.  
  3041.   /* Read in the dd's one at a time and determine the max ref in the file
  3042.      at the same time. */
  3043.   
  3044.   file_rec->maxref = 0;
  3045.   for (;;) {
  3046.     
  3047.     /* Read in the start of this dd block.
  3048.        Read data consists of ndds (number of dd's in this block) and
  3049.        offset (offset to the next ddblock). */
  3050.     
  3051.     if (HI_READ(file_rec->file, tbuf, NDDS_SZ+OFFSET_SZ) == FAIL) {
  3052.       HERROR(DFE_READERROR);
  3053.       return FAIL;
  3054.     }
  3055.     
  3056.     /* Decode the numbers. */
  3057.     
  3058.     p = tbuf;
  3059.     INT16DECODE(p, FILE_NDDS(file_rec));
  3060.     if (FILE_NDDS(file_rec) <= 0) {
  3061.       /* validity check */
  3062.       
  3063.       HERROR(DFE_CORRUPT);
  3064.       return FAIL;
  3065.     }
  3066.     INT32DECODE(p, file_rec->ddlast->nextoffset);
  3067.     
  3068.     /* Now that we know how many dd's are in this block,
  3069.        alloc memory for the records. */
  3070.     
  3071.     file_rec->ddlast->ddlist =
  3072.       (dd_t *) HDgetspace((uint32)FILE_NDDS(file_rec) * sizeof(dd_t));
  3073.     if (!file_rec->ddlast->ddlist) {
  3074.       HERROR(DFE_NOSPACE);
  3075.       return FAIL;
  3076.     }
  3077.     
  3078.     /* Read in dd's. */
  3079.     
  3080.     ndds = FILE_NDDS(file_rec);
  3081.     
  3082.     /* Since the tbuf might not be large enough to read in all the dd's
  3083.        at once, we try to read in chunks as large as possible. */
  3084.     
  3085.     /* n is number of dd's that could fit into tbuf at one time */
  3086.     
  3087.     n = sizeof(int_tbuf) / DD_SZ;
  3088.     if (n > ndds)
  3089.       n = ndds;
  3090.     
  3091.     /* Index of current dd in ddlist of this ddblock is 0. */
  3092.     
  3093.     idx = 0;
  3094.     
  3095.     while (ndds > 0) {
  3096.       /* ndds is the remaining number of dd's
  3097.          to be read in this block. */
  3098.       
  3099.       /* Read in a chunk of dd's from the file. */
  3100.       
  3101.       if (HI_READ(file_rec->file, tbuf, n * DD_SZ) == FAIL)
  3102.         HRETURN_ERROR(DFE_READERROR, FAIL);
  3103.  
  3104.       /* decode the dd's */
  3105.       
  3106.       p = tbuf;
  3107.       for (i = 0; i < n; i++, idx++) {
  3108.         UINT16DECODE(p, file_rec->ddlast->ddlist[idx].tag);
  3109.         UINT16DECODE(p, file_rec->ddlast->ddlist[idx].ref);
  3110.         INT32DECODE(p, file_rec->ddlast->ddlist[idx].offset);
  3111.         INT32DECODE(p, file_rec->ddlast->ddlist[idx].length);
  3112.         if (file_rec->maxref < file_rec->ddlast->ddlist[idx].ref)
  3113.           file_rec->maxref = file_rec->ddlast->ddlist[idx].ref;
  3114.         
  3115.         if(HIadd_hash_dd(file_rec, 
  3116.                          file_rec->ddlast->ddlist[idx].tag, 
  3117.                          file_rec->ddlast->ddlist[idx].ref, 
  3118.                          file_rec->ddlast, 
  3119.                          idx) == FAIL)
  3120.           return FAIL;
  3121.  
  3122.       }
  3123.       
  3124.       /* number of remaining dd's in this ddblock */
  3125.       
  3126.       ndds -= n;
  3127.       if (n > ndds) n = ndds;
  3128.     }
  3129.     
  3130.     if (file_rec->ddlast->nextoffset != 0) {
  3131.       /* More ddblocks in the file */
  3132.       
  3133.       /* extend the linked list */
  3134.       
  3135.       file_rec->ddlast->next = (ddblock_t *) HDgetspace((uint32)sizeof(ddblock_t));
  3136.       if (file_rec->ddlast->next == (ddblock_t *) NULL)
  3137.         HRETURN_ERROR(DFE_NOSPACE, FAIL);
  3138.       
  3139.       /* set up the file so next read will be at the next ddblock */
  3140.       
  3141.       if (HI_SEEK(file_rec->file, file_rec->ddlast->nextoffset) == FAIL)
  3142.         HRETURN_ERROR(DFE_SEEKERROR, FAIL);
  3143.       
  3144.       file_rec->ddlast->next->prev = file_rec->ddlast;
  3145.       file_rec->ddlast = file_rec->ddlast->next;
  3146.       file_rec->ddlast->next = (ddblock_t *) NULL;
  3147.       file_rec->ddlast->ddlist = (dd_t *) NULL;
  3148.       
  3149.     } else
  3150.       break;
  3151.   }
  3152.  
  3153.   return SUCCEED;
  3154. }
  3155.  
  3156.  
  3157. /*--------------------------------------------------------------------------
  3158. ** PRIVATE    PRIVATE        PRIVATE        PRIVATE        PRIVATE
  3159. ** NAME
  3160. **    HIupdate_version -- determine whether new version tag should be written
  3161. ** USAGE
  3162. **    int HIupdate_version(file_id)
  3163. **    int32 file_id;        IN: handle of file
  3164. ** RETURNS
  3165. **    returns SUCCEED (0) if successful and FAIL (-1) if failed.
  3166. ** DESCRIPTION
  3167. **    Writes out version numbers of current library as file version.
  3168. ** GLOBAL VARIABLES
  3169. **    Resets modified field of version field of appropriate file_records[]
  3170. **    entry.
  3171. ** COMMENTS, BUGS, ASSUMPTIONS
  3172. ** EXAMPLES
  3173. ** REVISION LOG
  3174. --------------------------------------------------------------------------*/
  3175. #ifdef PROTOTYPE
  3176. PRIVATE int HIupdate_version(int32 file_id)
  3177. #else
  3178. PRIVATE int HIupdate_version(file_id)
  3179. int32 file_id;
  3180. #endif
  3181. {
  3182.     /*
  3183.     uint32 lmajorv, lminorv, lrelease;
  3184.     */
  3185.     uint8 /*lstring[81],*/ lversion[LIBVER_LEN];
  3186.     filerec_t *file_rec;
  3187.     int ret;
  3188.     char *FUNC="Hupdate_version";
  3189.  
  3190.  
  3191.     HEclear();
  3192.  
  3193.     file_rec = FID2REC(file_id);
  3194.     if (!file_rec || file_rec->refcount == 0) {
  3195.         HERROR(DFE_ARGS);
  3196.         return(FAIL);
  3197.     }
  3198.  
  3199.     /* copy in-memory version to file */
  3200.     Hgetlibversion(&(file_rec->version.majorv), &(file_rec->version.minorv),
  3201.                &(file_rec->version.release), file_rec->version.string);
  3202.  
  3203.     {
  3204.     uint8 *p;
  3205.  
  3206.     p = lversion;
  3207.     UINT32ENCODE(p, file_rec->version.majorv);
  3208.     UINT32ENCODE(p, file_rec->version.minorv);
  3209.     UINT32ENCODE(p, file_rec->version.release);
  3210.     HIstrncpy((char*) p, file_rec->version.string, 80);
  3211.     }
  3212.  
  3213.     ret = Hputelement(file_id, DFTAG_VERSION, (uint16)1, lversion, 
  3214.               (uint32)sizeof(lversion));
  3215.  
  3216.     if (ret == SUCCEED) {
  3217.         file_rec->version.modified = 0;
  3218.         return(SUCCEED);
  3219.     } else {
  3220.         HERROR(DFE_INTERNAL);
  3221.         return(FAIL);
  3222.     }
  3223. }
  3224.  
  3225. /*--------------------------------------------------------------------------
  3226. ** PRIVATE    PRIVATE        PRIVATE        PRIVATE        PRIVATE
  3227. ** NAME
  3228. **    HIread_version -- reads a version tag from a file
  3229. ** USAGE
  3230. **    int HIread_version(file_id)
  3231. **    int32 file_id;        IN: handle of file
  3232. ** RETURNS
  3233. **    returns SUCCEED (0) if successful and FAIL (-1) if failed.
  3234. ** DESCRIPTION
  3235. **    Reads a version tag from the specified file into the version fields
  3236. **    of the appropriate filerec_t.  On failure, zeros are put in the version
  3237. **    number fields and NULLS in the string.
  3238. ** GLOBAL VARIABLES
  3239. **    Writes to version fields of appropriate file_records[] entry.
  3240. ** COMMENTS, BUGS, ASSUMPTIONS
  3241. ** EXAMPLES
  3242. ** REVISION LOG
  3243. --------------------------------------------------------------------------*/
  3244. #ifdef PROTOTYPE
  3245. PRIVATE int HIread_version(int32 file_id)
  3246. #else
  3247. PRIVATE int HIread_version(file_id)
  3248. int32 file_id;
  3249. #endif
  3250. {
  3251.     filerec_t *file_rec;
  3252.     uint8 fversion[LIBVER_LEN];
  3253.     char *FUNC="Hread_version";
  3254.  
  3255.  
  3256.     HEclear();
  3257.  
  3258.     file_rec = FID2REC(file_id);
  3259.     if (!file_rec || file_rec->refcount == 0) {
  3260.         HERROR(DFE_ARGS);
  3261.         return(FAIL);
  3262.     }
  3263.  
  3264.     if (Hgetelement(file_id, DFTAG_VERSION, 
  3265.                               (uint16)1, fversion) == FAIL) {
  3266.         file_rec->version.majorv = 0;
  3267.         file_rec->version.minorv = 0;
  3268.         file_rec->version.release = 0;
  3269.         HIstrncpy(file_rec->version.string, "", 81);
  3270.         file_rec->version.modified = 0;
  3271.         HERROR(DFE_INTERNAL);
  3272.         return(FAIL);
  3273.     } else {
  3274.         uint8 *p;
  3275.  
  3276.         p = fversion;
  3277.         UINT32DECODE(p, file_rec->version.majorv);
  3278.         UINT32DECODE(p, file_rec->version.minorv);
  3279.         UINT32DECODE(p, file_rec->version.release);
  3280.         HIstrncpy(file_rec->version.string, (char*) p, 80);
  3281.         file_rec->version.string[80]= '\0';
  3282.     }
  3283.     file_rec->version.modified = 0;
  3284.  
  3285.     return(SUCCEED);
  3286. }
  3287.  
  3288. /* end version tags */
  3289.  
  3290. #ifdef MAC
  3291. /*
  3292. *  Macintosh file stubs for HDF
  3293. *
  3294. *  Implement a subset of the C unbuffered file I/O stubs in the
  3295. *  Mac toolbox.
  3296. */
  3297.  
  3298. #include "Errors.h"
  3299. #ifdef MPW
  3300. #include "Strings.h"
  3301. #endif
  3302.  
  3303. static int32 hdfc = 1061109567L;    /* equal to '????' in ascii */
  3304. static int32 hdft = 1600085855L;    /* equal to '_HDF' in ascii */
  3305.  
  3306. #ifdef MPW
  3307. hdf_file_t
  3308. mopen(char *name, intn flags)
  3309. {
  3310.     hdf_file_t volref,rn;
  3311.     OSErr result;
  3312.     FInfo fndrInfo;
  3313.  
  3314.     GetVol(NULL,&volref);
  3315.     
  3316.     if (flags == DFACC_CREATE)   { /* we need to create it */
  3317.         
  3318.         result = getfinfo(name, volref, &fndrInfo);
  3319.         if (result != fnfErr)
  3320.             if( noErr != (result = fsdelete(name, volref)))
  3321.                 return FAIL;
  3322.         
  3323.         if (noErr != (result = create(name, volref, hdfc, hdft)))
  3324.             return FAIL;
  3325.         
  3326.     }
  3327.     
  3328.     if (noErr != (result = fsopen(name, volref, &rn)))
  3329.         return FAIL;
  3330.     
  3331.     if (flags & O_CREAT)    /* and truncate it */
  3332.         SetEOF(rn, 0);
  3333.     
  3334.     return(rn);  
  3335. }
  3336. #else
  3337.  
  3338. static Str255 pname;
  3339.  
  3340. hdf_file_t
  3341. mopen(char *name, intn flags)
  3342. {
  3343.     hdf_file_t volref,rn;
  3344.     OSErr result;
  3345.     FInfo fndrInfo;
  3346.  
  3347.     strcpy((char *) pname, (char *) name);
  3348.     CtoPstr(pname);
  3349.  
  3350.     result = GetVol(NULL,&volref);
  3351.     
  3352.     if (flags == DFACC_CREATE)   { /* we need to create it */
  3353.         
  3354.         result = GetFInfo(name, volref, &fndrInfo);
  3355.         if (result != fnfErr)
  3356.             if( noErr != (result = FSDelete(pname, volref)))
  3357.                 return FAIL;
  3358.         
  3359.         if (noErr != (result = Create(pname, volref, hdfc, hdft)))
  3360.             return FAIL;
  3361.         
  3362.     }
  3363.     
  3364.     if (noErr != (result = FSOpen(pname, volref, &rn)))
  3365.         return FAIL;
  3366.     
  3367.     if (flags & O_CREAT)    /* and truncate it */
  3368.         SetEOF(rn, 0L);
  3369.     
  3370.     return(rn);  
  3371. }
  3372.  
  3373. #endif
  3374.  
  3375. int32
  3376. mclose(hdf_file_t rn)
  3377. {
  3378.         return(FSClose(rn));
  3379. }
  3380.  
  3381. int32
  3382. mread(hdf_file_t rn, char *buf, int32 n)
  3383. {
  3384.     OSErr result;
  3385.  
  3386.         if (noErr != (result = FSRead( rn, &n, buf)))
  3387.                 return(FAIL);
  3388.  
  3389.         return(n);
  3390. }
  3391.  
  3392. int32
  3393. mwrite(hdf_file_t rn, char *buf, int32 n)
  3394. {
  3395.     OSErr result;
  3396.     
  3397.     if (noErr != (result = FSWrite( rn, &n, buf)))
  3398.         return(FAIL);
  3399.     
  3400.     return(n);
  3401. }
  3402.  
  3403. int32
  3404. mlseek(hdf_file_t rn, int32 n, int m)
  3405. {
  3406.     OSErr result;
  3407.     int32 newEOF;
  3408.  
  3409. #ifdef OLD_EXTD
  3410.     long pos, oldpos, logEOF;
  3411.     Ptr buffy;
  3412. #endif
  3413.     
  3414.     switch(m) {
  3415.     case 0:
  3416.     default:
  3417.         m = fsFromStart;
  3418.         break;
  3419.     case 1:
  3420.         m = fsFromMark;
  3421.         break;
  3422.     case 2:
  3423.         m = fsFromLEOF;
  3424.         break;
  3425.     }
  3426.     
  3427.     if (noErr != (result = SetFPos(rn, m, n)))
  3428.         {
  3429.             if(result == eofErr)
  3430.                 {
  3431. #ifdef OLD_EXTD
  3432.                     if(noErr != (result = GetEOF(rn, &logEOF)))
  3433.                         return FAIL;
  3434.                     
  3435.                     oldpos = pos = n - logEOF;
  3436.                     if(NULL == (buffy = NewPtr((Size) pos)))
  3437.                         return FAIL;
  3438.                     if (noErr != (result = FSWrite(rn, &pos, buffy)))
  3439.                         {
  3440.                             DisposPtr(buffy);
  3441.                             return FAIL;
  3442.                         }
  3443.                     DisposPtr(buffy);
  3444. #else
  3445.  
  3446.  
  3447.                     if(m != fsFromStart) {
  3448.                         printf("mlseek: m != fsFromStart, m=%d, n=%ld.\n", m, n);
  3449.                         return FAIL;
  3450.                     }
  3451.                     
  3452.                     newEOF = n;
  3453.                     if(noErr != (result = SetEOF(rn, newEOF)))
  3454.                         return FAIL;    
  3455.                     
  3456. #endif                     
  3457.                     
  3458.                     if (noErr != (result = SetFPos(rn, fsFromStart, n)))
  3459.                         return FAIL;
  3460.                 }
  3461.             else return FAIL;
  3462.         }
  3463.     
  3464.     if (noErr != (result = GetFPos(rn, &n)))
  3465.         return FAIL;
  3466.     
  3467.     if (m == fsFromMark) {
  3468.         return(n);
  3469.     } else {
  3470.         return(SUCCEED);
  3471.     }
  3472.  
  3473. }
  3474.  
  3475. #endif /* MAC */
  3476.  
  3477.