1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2  * Copyright by The HDF Group.                                               *
3  * Copyright by the Board of Trustees of the University of Illinois.         *
4  * All rights reserved.                                                      *
5  *                                                                           *
6  * This file is part of HDF.  The full HDF copyright notice, including       *
7  * terms governing use, modification, and redistribution, is contained in    *
8  * the COPYING file, which can be found at the root of the source code       *
9  * distribution tree, or in https://support.hdfgroup.org/ftp/HDF/releases/.  *
10  * If you do not have access to either file, you may request a copy from     *
11  * help@hdfgroup.org.                                                        *
12  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
13 
14 /* $Id$ */
15 
16 /*
17 FILE
18     hfiledd.c - DD & DD block management routines.
19 
20 REMARKS
21     These routines provide all the management for the DD list, both on disk
22     and in memory.  The DD list is read in from disk (or created in memory
23     for a new file) here and the tag tree and all the DD modifying functions
24     are in this module.  DO NOT MODIFY THE DD BLOCKS FROM OUTSIDE THIS FILE!
25 
26 DESIGN
27     The DD blocks are stored in memory in a very similar way to the way they
28     are stored in the file: in a doubly-linked list of DD blocks with each
29     block having a pointer to the array of DDs in it (in the file).  There
30     are additional memory structures which are indexed into the DD list which
31     are designed for faster access to certain manipulations of the DD list.
32     The tag_tree is a tbbt of the tags contained within the file.  Each
33     node of the tag_tree has a link to a bit-vector for keeping track of the
34     refs used for that tag and a link to a dynamic array pointers into the
35     DD list for each ref # used.
36 
37 BUGS/LIMITATIONS
38 
39 EXPORTED ROUTINES
40   User-level functions:
41     Hdupdd      - Duplicate a data descriptor
42     Hnumber     - Count number of occurrances of tag/ref in file
43     Hnewref     - Returns a ref that is unique in the file
44     Htagnewref  - Returns a ref that is unique in the file for a given tag
45     Hfind       - Locate the next object of a search in an HDF file
46     Hdeldd      - Delete a data descriptor
47 
48   Developer-level routines
49     HDcheck_tagref - Checks to see if tag/ref is in DD list i.e. created already
50     HDreuse_tagref - reuse a data descriptor preserving tag/refw(assumes DD exists)
51 
52   Tag/ref functions:
53     HTPcreate   - Create (& attach to) a tag/ref pair (inserts into DD list also)
54     HTPselect   - Attach to an existing DD in the DD list
55     HTPendaccess- End access to an attached DD in the DD list
56     HTPdelete   - Mark a tag/ref pair as free (marks space as free in DD list)
57                     (ends access to the tag/ref also)
58     HTPupdate   - Change the offset and/or length of a data object
59     HTPinquire  - Get the DD information for a DD (i.e. tag/ref/offset/length)
60     HTPis_special- Check if a DD id is associated with a special tag
61   DD list functions:
62     HTPstart    - Initialize the DD list from disk (creates the DD list in memory)
63     HTPinit     - Create a new DD list (creates the DD list in memory)
64     HTPsync     - Flush the DD list to disk (syncronizes with disk)
65     HTPend      - Close the DD list to disk (syncronizes with disk too)
66 LOCAL ROUTINES
67     HTIfind_dd      - find a specific DD in the file
68     HTInew_dd_block - create a new (empty) DD block
69     HTIupdate_dd    - update a DD on disk
70     HTIcount_dd     - counts the dd's of a certain type in file
71     HTIregister_tag_ref     - insert a ref into the tag tree for a file
72     HTIunregister_tag_ref   - remove a ref from the tag tree for a file
73 
74 OLD ROUTINES
75     HIlookup_dd             - find the dd record for an element
76     HIflush_dds             - flush changed DD blocks to file
77     HIinit_file_dds         - Initialize DD blocks for a new file
78     HIfill_file_rec         - read in all of the DDs
79     HIadd_hash_dd           - add a dd to the hash table
80     HIdel_hash_dd           - remove a dd from the hash table
81     HIfind_dd               - find the dd record for an element
82     HIcount_dd              - counts the dd's of a certain type in file
83     HInew_dd_block          - create a new (empty) DD block
84     HIupdate_dd             - write an updated dd to the file
85     HIregister_tag_ref      - mark a ref as used for a tag
86     HIunregister_tag_ref    - mark a ref as un-used for a tag
87 
88 AUTHOR
89    Quincey Koziol
90 
91 MODIFICATION HISTORY
92    12/20/95  - Starting writing specs & coding prototype
93 */
94 
95 #include "hdf.h"
96 #include "hfile.h"
97 
98 /* Private routines */
99 static intn HTIfind_dd(filerec_t * file_rec, uint16 look_tag, uint16 look_ref,
100             dd_t ** pdd, intn direction);
101 
102 static intn HTInew_dd_block(filerec_t * file_rec);
103 
104 static intn HTIupdate_dd(filerec_t * file_rec, dd_t * dd);
105 
106 static intn HTIcount_dd(filerec_t * file_rec, uint16 cnt_tag, uint16 cnt_ref,
107             uintn *all_cnt, uintn *real_cnt);
108 
109 static intn HTIregister_tag_ref(filerec_t * file_rec, dd_t *dd);
110 
111 static intn HTIunregister_tag_ref(filerec_t * file_rec, dd_t *dd_ptr);
112 
113 /* Local definitions */
114 /* The initial size of a ref dynarray */
115 #define REF_DYNARRAY_START  64
116 /* The increment of a ref dynarray */
117 #define REF_DYNARRAY_INCR   256
118 /* macros to encode and decode a DD */
119 #define DDENCODE(p, tag,ref,offset,length) \
120    {UINT16ENCODE(p, tag); \
121     UINT16ENCODE(p, ref); \
122     INT32ENCODE(p, offset); \
123     INT32ENCODE(p, length); \
124    }
125 #define DDDECODE(p, tag,ref,offset,length) \
126    {UINT16DECODE(p, tag); \
127     UINT16DECODE(p, ref); \
128     INT32DECODE(p, offset); \
129     INT32DECODE(p, length); \
130    }
131 
132 
133 /******************************************************************************
134  NAME
135      HTPstart - Initialize the DD list in memory
136 
137  DESCRIPTION
138     Reads the DD blocks from disk and creates the in-memory structures for
139     handling them.  This routine should only be called once for a given
140     file and HTPend should be called when finished with the DD list (i.e.
141     when the file is being closed).
142 
143  RETURNS
144     Returns SUCCEED if successful and FAIL otherwise
145 
146 *******************************************************************************/
HTPstart(filerec_t * file_rec)147 intn HTPstart(filerec_t *file_rec       /* IN:  File record to store info in */
148 )
149 {
150   CONSTR(FUNC, "HTPstart");	/* for HERROR */
151   uint8      *tbuf=NULL;  /* temporary buffer */
152   uintn       tbuf_size=0;    /* temporary buffer size */
153   int32       end_off = 0;	/* offset of the end of the file */
154   intn        ret_value = SUCCEED;
155 
156   HEclear();
157   /* Alloc start of linked list of ddblocks. */
158   file_rec->ddhead = (ddblock_t *) HDmalloc(sizeof(ddblock_t));
159   if (file_rec->ddhead == (ddblock_t *) NULL)
160     HGOTO_ERROR(DFE_NOSPACE, FAIL);
161 
162   /* Keep the filerec_t pointer around for each ddblock */
163   file_rec->ddhead->frec=file_rec;
164 
165   /* Only one elt in linked list so head is also last. */
166   file_rec->ddlast = file_rec->ddhead;
167   file_rec->ddlast->next = (ddblock_t *) NULL;
168   file_rec->ddlast->prev = (ddblock_t *) NULL;
169 
170   /* The first ddblock always starts after the magic number.
171   Set it up so that we start reading from there. */
172   file_rec->ddlast->myoffset = MAGICLEN;	/* set offset of block in file */
173   file_rec->ddlast->dirty = 0;	/* block does not need to be flushed */
174 
175   /* Initialize the tag tree */
176   file_rec->tag_tree = tbbtdmake(tagcompare, sizeof(uint16), TBBT_FAST_UINT16_COMPARE);
177 
178   /* Initialize the DD atom group (trying 256 hash currently, feel free to change */
179   if(HAinit_group(DDGROUP,256)==FAIL)
180     HGOTO_ERROR(DFE_INTERNAL, FAIL);
181 
182   /* Read in the dd's one at a time and determine the max ref in the file
183 	   at the same time. */
184   file_rec->maxref = 0;
185   for (;;)
186     {
187         ddblock_t *ddcurr;      /* ptr to the current DD block */
188         dd_t *curr_dd_ptr;      /* pointer to the current DD being read in */
189         uint8       ddhead[NDDS_SZ+OFFSET_SZ];   /* storage for the DD header */
190         uint8      *p;          /* Temporary buffer pointer. */
191         intn        ndds;       /* number of DDs in a block */
192         intn        i;          /* Temporary integer */
193 
194         /* Get a short-cut for the current DD block being read-in */
195         ddcurr=file_rec->ddlast;
196 
197         /* Go to the beginning of the DD block */
198         if (HPseek(file_rec, ddcurr->myoffset) == FAIL)
199           HGOTO_ERROR(DFE_SEEKERROR, FAIL);
200 
201         /* Read in the start of this dd block.
202            Read data consists of ndds (number of dd's in this block) and
203            offset (offset to the next ddblock). */
204         if (HP_read(file_rec, ddhead, NDDS_SZ + OFFSET_SZ) == FAIL)
205           HGOTO_ERROR(DFE_READERROR, FAIL);
206 
207         /* Decode the numbers. */
208         p = &ddhead[0];
209         INT16DECODE(p, ddcurr->ndds);
210         ndds = (intn)ddcurr->ndds;
211         if (ndds <= 0)		/* validity check */
212           HGOTO_ERROR(DFE_CORRUPT, FAIL);
213         INT32DECODE(p, ddcurr->nextoffset);
214 
215         /* check if the DD block is the last thing in the file */
216         /* (Unlikely, but possible (I think)) */
217         if (ddcurr->myoffset + (NDDS_SZ + OFFSET_SZ) + (ndds * DD_SZ) > end_off)
218           end_off = ddcurr->myoffset + (NDDS_SZ + OFFSET_SZ) + (ndds * DD_SZ);
219 
220         /* Now that we know how many dd's are in this block,
221            alloc memory for the records. */
222         ddcurr->ddlist = (dd_t *) HDmalloc((uint32) ndds * sizeof(dd_t));
223         if (ddcurr->ddlist==(dd_t *)NULL)
224           HGOTO_ERROR(DFE_NOSPACE, FAIL);
225 
226         /* Allocate memory for the temporary buffer also */
227         if(tbuf==NULL || ((uintn)ndds*DD_SZ)>tbuf_size)
228           {
229               if (tbuf!=(uint8 *)NULL)
230                   HDfree(tbuf);
231               tbuf_size=(uintn)ndds*DD_SZ;
232               tbuf=(uint8 *)HDmalloc(tbuf_size);
233               if (tbuf==(uint8 *)NULL)
234                 HGOTO_ERROR(DFE_NOSPACE, FAIL);
235           } /* end if */
236 
237         /* Index of current dd in ddlist of this ddblock is 0. */
238         curr_dd_ptr=ddcurr->ddlist;
239 
240         /* Read in a chunk of dd's from the file. */
241         if (HP_read(file_rec, tbuf, ndds * DD_SZ) == FAIL)
242           HGOTO_ERROR(DFE_READERROR, FAIL);
243 
244       /* decode the dd's */
245         p = tbuf;
246         for (i = 0; i < ndds; i++, curr_dd_ptr++)
247           {
248 	    DDDECODE(p, curr_dd_ptr->tag, curr_dd_ptr->ref,
249 		curr_dd_ptr->offset, curr_dd_ptr->length);
250             curr_dd_ptr->blk=ddcurr;
251 
252              /* check if maximum ref # exceeded */
253             if (file_rec->maxref < curr_dd_ptr->ref)
254               file_rec->maxref = curr_dd_ptr->ref;
255 
256             /* check if the data element is the last thing in the file */
257             if ((curr_dd_ptr->offset + curr_dd_ptr->length) > end_off)
258               end_off = curr_dd_ptr->offset + curr_dd_ptr->length;
259 
260             /* Add to the tag info tree */
261             if(curr_dd_ptr->tag!=DFTAG_NULL)
262                 if(HTIregister_tag_ref(file_rec,curr_dd_ptr)==FAIL)
263                     HGOTO_ERROR(DFE_INTERNAL, FAIL);
264           }
265 
266         if (ddcurr->nextoffset != 0)
267           {	/* More ddblocks in the file */
268               ddblock_t *ddnew;    /* ptr to the new DD block */
269 
270       /* extend the linked list */
271             ddcurr->next = ddnew = (ddblock_t *) HDmalloc((uint32) sizeof(ddblock_t));
272             if (ddnew == (ddblock_t *) NULL)
273               HGOTO_ERROR(DFE_NOSPACE, FAIL);
274 
275             ddnew->prev = ddcurr;
276             ddnew->next = (ddblock_t *) NULL;
277             ddnew->ddlist = (dd_t *) NULL;
278             ddnew->myoffset = ddcurr->nextoffset;
279             ddnew->dirty= FALSE;
280             file_rec->ddlast = ddnew;
281 
282             /* Keep the filerec_t pointer around for each ddblock */
283             ddnew->frec=file_rec;
284           }	/* end if */
285         else
286               break;
287       } /* end for */
288 
289     /* Update the DFTAG_NULL pointers */
290     file_rec->ddnull=NULL;
291     file_rec->ddnull_idx=(-1);
292 
293     /* Update the end of the file from the DD's we have read in */
294     file_rec->f_end_off = end_off;
295 
296 done:
297   if(ret_value == FAIL)
298     { /* Error condition cleanup */
299 
300     } /* end if */
301 
302   /* Normal function cleanup */
303   if(tbuf!=NULL)
304       HDfree(tbuf);
305 
306   return ret_value;
307 } /* end HTPstart() */
308 
309 /******************************************************************************
310  NAME
311      HTPinit - Create a new DD list in memory
312 
313  DESCRIPTION
314     Creates a new DD list in memory for a newly created file.  This routine
315     should only be called once for a given file and HTPend should be called
316     when finished with the DD list (i.e.  when the file is being closed).
317 
318  RETURNS
319     Returns SUCCEED if successful and FAIL otherwise
320 
321 *******************************************************************************/
HTPinit(filerec_t * file_rec,int16 ndds)322 intn HTPinit(filerec_t *file_rec,       /* IN: File record to store info in */
323     int16 ndds                          /* IN: # of DDs to store in each block */
324 )
325 {
326     CONSTR(FUNC, "HTPinit");    /* for HERROR */
327     ddblock_t  *block;          /* dd block to intialize */
328     uint8       ddhead[NDDS_SZ+OFFSET_SZ];   /* storage for the DD header */
329     uint8      *tbuf=NULL;      /* temporary buffer */
330     uint8      *p;              /* temp buffer ptr */
331     dd_t       *list;           /* list of dd */
332     intn        ret_value = SUCCEED;
333 
334     HEclear();
335     if (file_rec == NULL || ndds<0)	/* valid arguments */
336       HGOTO_ERROR(DFE_ARGS, FAIL);
337 
338     /* 'reasonablize' the value of ndds.  0 means use default */
339     if (0 == ndds)
340       ndds = DEF_NDDS;
341     else if (ndds < MIN_NDDS)
342       ndds = MIN_NDDS;
343 
344     /* allocate the dd block in memory and initialize it */
345     file_rec->ddhead = (ddblock_t *) HDmalloc(sizeof(ddblock_t));
346     if (file_rec->ddhead == (ddblock_t *) NULL)
347       HGOTO_ERROR(DFE_NOSPACE, FAIL);
348     block = file_rec->ddlast = file_rec->ddhead;
349     block->prev = (ddblock_t *) NULL;
350     block->ndds = ndds;
351     block->next = (ddblock_t *) NULL;
352     block->nextoffset = 0;
353     block->myoffset = MAGICLEN;
354     block->dirty = FALSE;
355 
356     /* Keep the filerec_t pointer around for each ddblock */
357     block->frec=file_rec;
358 
359     /* write first dd block header to file */
360     p = &ddhead[0];
361     INT16ENCODE(p, block->ndds);
362     INT32ENCODE(p, (int32) 0);
363     if (HP_write(file_rec, ddhead, NDDS_SZ + OFFSET_SZ) == FAIL)
364       HGOTO_ERROR(DFE_WRITEERROR, FAIL);
365 
366     /* allocate and initialize dd list */
367     list = block->ddlist = (dd_t *) HDmalloc((uint32) ndds * sizeof(dd_t));
368     if (list == (dd_t *) NULL)
369       HGOTO_ERROR(DFE_NOSPACE, FAIL);
370 
371     /* Fill the first memory DD block with NIL dd's */
372     list[0].tag = DFTAG_NULL;
373     list[0].ref = DFREF_NONE;
374     list[0].length = INVALID_LENGTH;
375     list[0].offset = INVALID_OFFSET;
376     list[0].blk = block;
377     HDmemfill(&list[1],&list[0],sizeof(dd_t),(uint32)(ndds-1));
378 
379     tbuf=(uint8 *)HDmalloc(ndds*DD_SZ);
380     if (tbuf == NULL)	/* check for DD list */
381       HGOTO_ERROR(DFE_NOSPACE, FAIL);
382 
383     /* Fill the first disk DD block with NIL dd's */
384     p = tbuf;
385     DDENCODE(p, (uint16) DFTAG_NULL, (uint16) DFREF_NONE,
386 	(int32) INVALID_LENGTH, (int32) INVALID_OFFSET);
387     HDmemfill(p,tbuf,DD_SZ,(uint32)(ndds-1));
388 
389     /* Write the NIL dd's out into the DD block on disk */
390     if (HP_write(file_rec, tbuf, ndds * DD_SZ) == FAIL)
391       HGOTO_ERROR(DFE_WRITEERROR, FAIL);
392 
393     /* Update the DFTAG_NULL pointers */
394     file_rec->ddnull=block;
395     file_rec->ddnull_idx=(-1);
396 
397     /* set the end of the file currently to the end of the first DD block */
398     file_rec->f_end_off = block->myoffset + (NDDS_SZ + OFFSET_SZ) + (block->ndds * DD_SZ);
399 
400     /* no dd's yet, so maximum ref is 0 */
401     file_rec->maxref = 0;
402 
403     /* Initialize the tag tree */
404     file_rec->tag_tree = tbbtdmake(tagcompare, sizeof(uint16), TBBT_FAST_UINT16_COMPARE);
405 
406     /* Initialize the DD atom group (trying 256 hash currently, feel free to change */
407     if(HAinit_group(DDGROUP,256)==FAIL)
408       HGOTO_ERROR(DFE_INTERNAL, FAIL);
409 
410 done:
411   if(ret_value == FAIL)
412     { /* Error condition cleanup */
413 
414     } /* end if */
415 
416   /* Normal function cleanup */
417   HDfree(tbuf);
418 
419   return ret_value;
420 } /* end HTPinit() */
421 
422 /******************************************************************************
423  NAME
424      HTPsync - Flush the DD list in memory
425 
426  DESCRIPTION
427     Syncronizes the in-memory copy of the DD list with the copy on disk by
428     writing out the DD blocks which have changed to disk.
429 
430  RETURNS
431     Returns SUCCEED if successful and FAIL otherwise
432 
433 *******************************************************************************/
HTPsync(filerec_t * file_rec)434 intn HTPsync(filerec_t *file_rec       /* IN:  File record to store info in */
435 )
436 {
437     CONSTR(FUNC, "HTPsync");	/* for HERROR */
438     ddblock_t  *block;		/* dd block to intialize */
439     uint8       ddhead[NDDS_SZ+OFFSET_SZ];   /* storage for the DD header */
440     uint8      *tbuf=NULL;  /* temporary buffer */
441     uintn       tbuf_size=0;    /* temporary buffer size */
442     uint8      *p;		/* temp buffer ptr */
443     dd_t       *list;		/* list of dd */
444     int16       ndds;		/* # of DDs per block */
445     intn        i;		/* temp ints */
446     intn        ret_value = SUCCEED;
447 
448     HEclear();
449     block = file_rec->ddhead;
450     if (block == NULL)	/* check for DD list */
451       HGOTO_ERROR(DFE_BADDDLIST, FAIL);
452 
453     while (block != NULL)
454       {	/* check all the blocks for flushing */
455         if (block->dirty == TRUE)
456           {	/* flush this block? */
457             if (HPseek(file_rec, block->myoffset) == FAIL)
458               HGOTO_ERROR(DFE_SEEKERROR, FAIL);
459 
460       /* write dd block header to file */
461             p = ddhead;
462             INT16ENCODE(p, block->ndds);
463             INT32ENCODE(p, block->nextoffset);
464             if (HP_write(file_rec, ddhead, NDDS_SZ + OFFSET_SZ) == FAIL)
465               HGOTO_ERROR(DFE_WRITEERROR, FAIL);
466 
467       /* n is the maximum number of dd's in tbuf */
468             ndds = block->ndds;
469             /* Allocate memory for the temporary buffer also */
470             if(tbuf==NULL || ((uintn)ndds*DD_SZ)>tbuf_size)
471               {
472                   if (tbuf!=(uint8 *)NULL)
473                       HDfree(tbuf);
474                   tbuf_size=(uintn)ndds*DD_SZ;
475                   tbuf=(uint8 *)HDmalloc(tbuf_size);
476                   if (tbuf==(uint8 *)NULL)
477                     HGOTO_ERROR(DFE_NOSPACE, FAIL);
478               } /* end if */
479 
480       /* write dd list to file */
481             list = &block->ddlist[0];	/* start at the first DD, go from there */
482             p = tbuf;
483             for (i = 0; i < ndds; i++, list++)
484 		DDENCODE(p, list->tag, list->ref, list->offset, list->length);
485 
486             if (HP_write(file_rec, tbuf, ndds * DD_SZ) == FAIL)
487               HGOTO_ERROR(DFE_WRITEERROR, FAIL);
488 
489             block->dirty = FALSE;	/* block has been flushed */
490           }	/* end if */
491         block = block->next;	/* advance to next block for file */
492       }		/* end while */
493 
494 done:
495   if(ret_value == FAIL)
496     { /* Error condition cleanup */
497 
498     } /* end if */
499 
500   /* Normal function cleanup */
501   if (tbuf!=(uint8 *)NULL)
502       HDfree(tbuf);
503 
504   return ret_value;
505 } /* end HTPsync() */
506 
507 /******************************************************************************
508  NAME
509      HTPend - Terminate the DD list in memory
510 
511  DESCRIPTION
512     Terminates access to the DD list in memory, writing the DD blocks out to
513     the disk (if they've changed).  After this routine is called, no further
514     access to tag/refs (or essentially any other HDF objects) can be performed
515     on the file.
516 
517  RETURNS
518     Returns SUCCEED if successful and FAIL otherwise
519 
520 *******************************************************************************/
HTPend(filerec_t * file_rec)521 intn HTPend(filerec_t *file_rec       /* IN:  File record to store info in */
522 )
523 {
524     CONSTR(FUNC, "HTPend");	/* for HERROR */
525     ddblock_t  *bl, *next;	/* current ddblock and next ddblock pointers.
526 				   for freeing ddblock linked list */
527     intn        ret_value = SUCCEED;
528 
529     HEclear();
530     if(HTPsync(file_rec)==FAIL)
531         HGOTO_ERROR(DFE_INTERNAL, FAIL);
532 
533     for (bl = file_rec->ddhead; bl!=NULL; bl = next)
534       {
535         next = bl->next;
536         if (bl->ddlist)
537           HDfree((VOIDP) bl->ddlist);
538         HDfree((VOIDP) bl);
539       }
540 
541     /* Chuck the tag info tree too */
542     tbbtdfree(file_rec->tag_tree,tagdestroynode,NULL);
543 
544     /* Shutdown the DD atom group */
545     if(HAdestroy_group(DDGROUP)==FAIL)
546       HGOTO_ERROR(DFE_INTERNAL, FAIL);
547 
548     file_rec->ddhead = (ddblock_t *) NULL;
549 
550 done:
551   if(ret_value == FAIL)
552     { /* Error condition cleanup */
553 
554     } /* end if */
555 
556   /* Normal function cleanup */
557 
558   return ret_value;
559 } /* end HTPend() */
560 
561 /******************************************************************************
562  NAME
563      HTPcreate - Create (and attach to) a tag/ref pair
564 
565  DESCRIPTION
566     Creates a new tag/ref pair in memory and inserts the tag/ref pair into the
567     DD list to be written out to disk.  This routine returns a DD id which can
568     be used in the other tag/ref routines to modify the DD.
569 
570  RETURNS
571     Returns DD id if successful and FAIL otherwise
572 
573 *******************************************************************************/
HTPcreate(filerec_t * file_rec,uint16 tag,uint16 ref)574 atom_t HTPcreate(filerec_t *file_rec,   /* IN: File record to store info in */
575     uint16 tag,                         /* IN: Tag to create */
576     uint16 ref                          /* IN: ref to create */
577 )
578 {
579     CONSTR(FUNC, "HTPcreate");  /* for HERROR */
580     dd_t *dd_ptr=NULL;          /* ptr to dd created */
581     atom_t ret_value=SUCCEED;
582 
583     HEclear();
584     if(file_rec==NULL || (tag==DFTAG_NULL || tag==DFTAG_WILDCARD) ||
585             ref==DFREF_WILDCARD)
586         HGOTO_ERROR(DFE_ARGS, FAIL);
587 
588     if(HTIfind_dd(file_rec,(uint16)DFTAG_NULL,(uint16)DFTAG_WILDCARD,
589             &dd_ptr,DF_FORWARD)==FAIL)
590       {
591         if (HTInew_dd_block(file_rec) == FAIL)
592           {
593             HGOTO_ERROR(DFE_NOFREEDD, FAIL);
594           }	/* end if */
595         else
596             dd_ptr=&file_rec->ddlast->ddlist[0];
597       } /* end if */
598 
599     /* Insert DD information into the DD list in memory */
600     dd_ptr->tag=tag;
601     dd_ptr->ref=ref;
602     /* the following assures object defintion in DD list
603        without data written for object. */
604     dd_ptr->offset=INVALID_OFFSET;
605     dd_ptr->length=INVALID_LENGTH;
606 
607     /* dd_ptr->blk should already be correctly set */
608 
609     /* Update the disk, etc. */
610     if(HTIupdate_dd(file_rec,dd_ptr)==FAIL)
611         HGOTO_ERROR(DFE_INTERNAL, FAIL);
612 
613     /* Mark off the ref # as 'used' in the tag tree & add to dynarray of refs */
614     if(HTIregister_tag_ref(file_rec,dd_ptr)==FAIL)
615         HGOTO_ERROR(DFE_INTERNAL, FAIL);
616 
617     /* Get the atom to return */
618     if((ret_value=HAregister_atom(DDGROUP,dd_ptr))==FAIL)
619         HGOTO_ERROR(DFE_INTERNAL, FAIL);
620 
621 done:
622   if(ret_value == FAIL)
623     { /* Error condition cleanup */
624 
625     } /* end if */
626 
627   /* Normal function cleanup */
628 
629   return ret_value;
630 }   /* HTPcreate() */
631 
632 /******************************************************************************
633  NAME
634      HTPselect - Attach to an existing tag/ref pair
635 
636  DESCRIPTION
637     Attaches to an existing tag/ref pair.  This routine returns a DD id which
638     can be used in the other tag/ref routines to modify the DD.
639 
640  RETURNS
641     Returns DD id if successful and FAIL otherwise
642 
643 *******************************************************************************/
HTPselect(filerec_t * file_rec,uint16 tag,uint16 ref)644 atom_t HTPselect(filerec_t *file_rec,   /* IN: File record to store info in */
645     uint16 tag,                         /* IN: Tag to select */
646     uint16 ref                          /* IN: ref to select */
647 )
648 {
649     CONSTR(FUNC, "HTPselect");  /* for HERROR */
650     dd_t *dd_ptr;         /* ptr to the DD info for the tag/ref */
651     tag_info **tip_ptr;   /* ptr to the ptr to the info for a tag */
652     tag_info *tinfo_ptr;  /* pointer to the info for a tag */
653     uint16 base_tag=BASETAG(tag);    /* corresponding base tag (if the tag is special) */
654     atom_t ret_value=SUCCEED;
655 
656     HEclear();
657     if(file_rec==NULL || (tag==DFTAG_NULL || tag==DFTAG_WILDCARD) ||
658             ref==DFREF_WILDCARD)
659         HGOTO_ERROR(DFE_ARGS, FAIL);
660 
661     /* Try to find the regular tag in the tag info tree */
662     if((tip_ptr=(tag_info **)tbbtdfind(file_rec->tag_tree,(VOIDP)&base_tag,NULL))==NULL)
663         HGOTO_DONE(FAIL); /* Not an error, we just didn't find the object */
664 
665     tinfo_ptr=*tip_ptr; /* get the pointer to the tag info */
666     if((dd_ptr=DAget_elem(tinfo_ptr->d,(intn)ref))==NULL)
667         HGOTO_DONE(FAIL); /* Not an error, we just didn't find the object */
668 
669     /* Get the atom to return */
670     if((ret_value=HAregister_atom(DDGROUP,dd_ptr))==FAIL)
671         HGOTO_ERROR(DFE_INTERNAL, FAIL);
672 
673 done:
674   if(ret_value == FAIL)
675     { /* Error condition cleanup */
676 
677     } /* end if */
678 
679   /* Normal function cleanup */
680 
681   return ret_value;
682 }   /* HTPselect() */
683 
684 /******************************************************************************
685  NAME
686      HTPendaccess - End access to an existing tag/ref pair
687 
688  DESCRIPTION
689     Ends access to an existing tag/ref pair.  Any further access to the tag/ref
690     pair may result in incorrect information being recorded about the DD in
691     memory or on disk.
692 
693  RETURNS
694     Returns SUCCEED if successful and FAIL otherwise
695 
696 *******************************************************************************/
HTPendaccess(atom_t ddid)697 intn HTPendaccess(atom_t ddid           /* IN: DD id to end access to */
698 )
699 {
700 #ifdef LATER
701     CONSTR(FUNC, "HTPendaccess"); /* for HERROR */
702 #endif /* LATER */
703     int32 ret_value=SUCCEED;
704 
705     /* Chuck the atom */
706     if(HAremove_atom(ddid)==NULL)
707         HGOTO_DONE(FAIL);
708 
709 done:
710   if(ret_value == FAIL)
711     { /* Error condition cleanup */
712 
713     } /* end if */
714 
715   /* Normal function cleanup */
716 
717   return ret_value;
718 }   /* HTPendaccess() */
719 
720 /******************************************************************************
721  NAME
722      HTPdelete - Delete an existing tag/ref pair
723 
724  DESCRIPTION
725     Deletes a tag/ref from the file.  Also ends access to the tag/ref pair.
726     Any further access to the tag/ref pair may result in incorrect information
727     being recorded about the DD in memory or on disk.
728 
729  RETURNS
730     Returns SUCCEED if successful and FAIL otherwise
731 
732 *******************************************************************************/
HTPdelete(atom_t ddid)733 intn HTPdelete(atom_t ddid              /* IN: DD id to delete */
734 )
735 {
736     CONSTR(FUNC, "HTPdelete"); /* for HERROR */
737     dd_t *dd_ptr;           /* ptr to the DD info for the tag/ref */
738     filerec_t * file_rec;
739     int32 ret_value=SUCCEED;
740 
741     HEclear();
742     /* Retrieve the atom's object, so we can delete the tag/ref */
743     if((dd_ptr=HAatom_object(ddid))==NULL)
744         HGOTO_ERROR(DFE_INTERNAL, FAIL);
745 
746     /* Grab this information, because the global dd_info will be deleted in HTIunregister_tag_ref */
747     file_rec=dd_ptr->blk->frec;
748 
749     /* Since we don't know where we are, reset the DFTAG_NULL pointers */
750     file_rec->ddnull=NULL;
751     file_rec->ddnull_idx=(-1);
752 
753     if (HPfreediskblock(file_rec,dd_ptr->offset,dd_ptr->length) == FAIL)
754         HGOTO_ERROR(DFE_INTERNAL, FAIL);
755 
756     /* Update the disk, etc. */
757     if(HTIupdate_dd(file_rec,dd_ptr)==FAIL)
758         HGOTO_ERROR(DFE_INTERNAL, FAIL);
759 
760     /* Remove the ref # as 'used' in the tag tree & delete from dynarray of refs */
761     if(HTIunregister_tag_ref(file_rec,dd_ptr)==FAIL)
762         HGOTO_ERROR(DFE_INTERNAL, FAIL);
763 
764     /* Destroy everything */
765     if(HAremove_atom(ddid)==NULL)
766         HGOTO_ERROR(DFE_INTERNAL, FAIL);
767 
768 done:
769   if(ret_value == FAIL)
770     { /* Error condition cleanup */
771 
772     } /* end if */
773 
774   /* Normal function cleanup */
775 
776   return ret_value;
777 }   /* HTPdelete() */
778 
779 /******************************************************************************
780  NAME
781      HTPupdate - Change the offset or length of an existing tag/ref pair
782 
783  DESCRIPTION
784     Updates a tag/ref in the file, allowing the length and/or offset to be
785     modified.
786 
787     Note: a value of '-2' for both 'length' and 'offset' are used to indicate
788     that the length or offset (respectively) is unchanged and should
789     remain the same. Kind of ugly but works for now.
790 
791  RETURNS
792     Returns SUCCEED if successful and FAIL otherwise
793 
794 *******************************************************************************/
HTPupdate(atom_t ddid,int32 new_off,int32 new_len)795 intn HTPupdate(atom_t ddid,             /* IN: DD id to update */
796     int32 new_off,                      /* IN: new offset for DD */
797     int32 new_len                       /* IN: new length for DD */
798 )
799 {
800     CONSTR(FUNC, "HTPupdate");  /* for HERROR */
801     dd_t *dd_ptr    = NULL;     /* ptr to the DD info for the tag/ref */
802     int32 dont_change = -2;     /* initialize to '-2' */
803     int32 ret_value = SUCCEED;
804 
805     HEclear();
806     /* Retrieve the atom's object, so we can update the DD */
807     if((dd_ptr=HAatom_object(ddid))==NULL)
808         HGOTO_ERROR(DFE_INTERNAL, FAIL);
809 
810     /* Update the tag/ref in memory */
811     if(new_len != dont_change)
812         dd_ptr->length=new_len;
813     if(new_off != dont_change)
814         dd_ptr->offset=new_off;
815 
816     /* Update the disk, etc. */
817     if(HTIupdate_dd(dd_ptr->blk->frec,dd_ptr)==FAIL)
818         HGOTO_ERROR(DFE_INTERNAL, FAIL);
819 
820 done:
821   if(ret_value == FAIL)
822     { /* Error condition cleanup */
823 
824     } /* end if */
825 
826   /* Normal function cleanup */
827 
828   return ret_value;
829 }   /* HTPupdate() */
830 
831 /******************************************************************************
832  NAME
833      HTPinquire - Get the DD information for a DD (i.e. tag/ref/offset/length)
834 
835  DESCRIPTION
836     Get the DD information for a DD id from the DD block.  Passing NULL for
837     any parameter does not try to update that parameter.
838 
839  RETURNS
840     Returns SUCCEED if successful and FAIL otherwise
841 
842 *******************************************************************************/
HTPinquire(atom_t ddid,uint16 * tag,uint16 * ref,int32 * off,int32 * len)843 intn HTPinquire(atom_t ddid,            /* IN: DD id to inquire about */
844     uint16 *tag,                        /* IN: tag of DD */
845     uint16 *ref,                        /* IN: ref of DD */
846     int32 *off,                         /* IN: offset of DD */
847     int32 *len                          /* IN: length of DD */
848 )
849 {
850     CONSTR(FUNC, "HTPinquire"); /* for HERROR */
851     dd_t *dd_ptr;               /* ptr to the DD info for the tag/ref */
852     intn ret_value=SUCCEED;
853 
854     HEclear();
855     /* Retrieve the atom's object, so we can update the DD */
856     if((dd_ptr=HAatom_object(ddid))==NULL)
857         HGOTO_ERROR(DFE_ARGS, FAIL);
858 
859     /* Get the information requested */
860     if(tag!=NULL)
861         *tag=dd_ptr->tag;
862     if(ref!=NULL)
863         *ref=dd_ptr->ref;
864     if(off!=NULL)
865         *off=dd_ptr->offset;
866     if(len!=NULL)
867         *len=dd_ptr->length;
868 
869 done:
870   if(ret_value == FAIL)
871     { /* Error condition cleanup */
872 
873     } /* end if */
874 
875   /* Normal function cleanup */
876 
877   return ret_value;
878 }   /* HTPinquire() */
879 
880 /******************************************************************************
881  NAME
882      HTPis_special - Check if a DD id is associated with a special tag
883 
884  DESCRIPTION
885     Checks if the tag for the DD id is a special tag.
886 
887  RETURNS
888     Returns TRUE(1)/FALSE(0)
889 
890 *******************************************************************************/
HTPis_special(atom_t ddid)891 intn HTPis_special(atom_t ddid             /* IN: DD id to inquire about */
892 )
893 {
894     CONSTR(FUNC, "HTPis_special"); /* for HERROR */
895     dd_t *dd_ptr;               /* ptr to the DD info for the tag/ref */
896     int32 ret_value=FAIL;
897 
898     HEclear();
899     /* Retrieve the atom's object, so we can update the DD */
900     if((dd_ptr=HAatom_object(ddid))==NULL)
901         HGOTO_ERROR(DFE_ARGS, FALSE);
902 
903     /* Get the information requested */
904     if(SPECIALTAG(dd_ptr->tag))
905         ret_value=TRUE;
906     else
907         ret_value=FALSE;
908 
909 done:
910   if(ret_value == FALSE)
911     { /* Error condition cleanup */
912 
913     } /* end if */
914 
915   /* Normal function cleanup */
916 
917   return ret_value;
918 }   /* HTPis_special() */
919 
920 /******************************************************************************
921  NAME
922      Hdupdd - Duplicate a data descriptor
923 
924  DESCRIPTION
925     Duplicates a data descriptor so that the new tag/ref points to the
926     same data element pointed to by the old tag/ref.  Return FAIL if
927     the given tag/ref are already in use.
928 
929  RETURNS
930     returns SUCCEED (0) if successful, FAIL (-1) otherwise
931 
932 *******************************************************************************/
Hdupdd(int32 file_id,uint16 tag,uint16 ref,uint16 old_tag,uint16 old_ref)933 intn Hdupdd(int32 file_id,      /* IN: File ID the tag/refs are in */
934         uint16 tag,             /* IN: Tag of new tag/ref */
935         uint16 ref,             /* IN: Ref of new tag/ref */
936         uint16 old_tag,         /* IN: Tag of old tag/ref */
937         uint16 old_ref          /* IN: Ref of old tag/ref */
938 )
939 {
940     CONSTR(FUNC, "Hdupdd"); /* for HERROR */
941     filerec_t  *file_rec;		/* file record */
942     atom_t      old_dd;         /* The DD id for the old DD */
943     atom_t      new_dd;         /* The DD id for the new DD */
944     int32       old_len;        /* The length of the old DD */
945     int32       old_off;        /* The offset of the old DD */
946     intn ret_value=SUCCEED;
947 
948     /* clear error stack and check validity of file id */
949     HEclear();
950     file_rec = HAatom_object(file_id);
951     if (BADFREC(file_rec))
952       HGOTO_ERROR(DFE_ARGS, FAIL);
953 
954     /* Attach to the old DD in the file */
955     if((old_dd=HTPselect(file_rec,old_tag,old_ref))==FAIL)
956       HGOTO_ERROR(DFE_NOMATCH, FAIL);
957 
958     /* Create the new DD in the file */
959     if((new_dd=HTPcreate(file_rec,tag,ref))==FAIL)
960       HGOTO_ERROR(DFE_DUPDD, FAIL);
961 
962     /* Retrieve the old offset & length */
963     if(HTPinquire(old_dd,NULL,NULL,&old_off,&old_len)==FAIL)
964         HGOTO_ERROR(DFE_INTERNAL, FAIL);
965 
966     /* Set the new DD's offset & length to the same as the old DD */
967     if(HTPupdate(new_dd,old_off,old_len)==FAIL)
968         HGOTO_ERROR(DFE_INTERNAL, FAIL);
969 
970     /* End access to the old & new DDs */
971     if(HTPendaccess(old_dd)==FAIL)
972         HGOTO_ERROR(DFE_INTERNAL, FAIL);
973     if(HTPendaccess(new_dd)==FAIL)
974         HGOTO_ERROR(DFE_INTERNAL, FAIL);
975 
976 done:
977   if(ret_value == FAIL)
978     { /* Error condition cleanup */
979 
980     } /* end if */
981 
982   /* Normal function cleanup */
983   return ret_value;
984 }   /* Hdupdd() */
985 
986 /******************************************************************************
987  NAME
988      Hnumber - Determine the number of objects of a given type
989 
990  DESCRIPTION
991     Determine how many objects of the given tag are in the file.
992     tag may be set to DFTAG_WILDCARD to get back the total number
993     of objects in the file.
994 
995     Note, a return value of zero is not a fail condition.
996 
997  RETURNS
998     the number of objects of type 'tag' else FAIL
999 
1000 *******************************************************************************/
Hnumber(int32 file_id,uint16 tag)1001 int32 Hnumber(int32 file_id,    /* IN: File ID the tag/refs are in */
1002         uint16 tag              /* IN: Tag to count */
1003 )
1004 {
1005     CONSTR(FUNC, "Hnumber");
1006     uintn       all_cnt;
1007     uintn       real_cnt;
1008     filerec_t  *file_rec;           /* file record */
1009     int32 ret_value=SUCCEED;
1010 
1011     /* convert file id to file record */
1012     file_rec = HAatom_object(file_id);
1013 
1014     HEclear();
1015     if (BADFREC(file_rec))
1016       HGOTO_ERROR(DFE_ARGS, FAIL);
1017 
1018     /* Go count the items with that tag */
1019     if (HTIcount_dd(file_rec, tag, DFREF_WILDCARD, &all_cnt, &real_cnt) == FAIL)
1020       HGOTO_ERROR(DFE_INTERNAL, FAIL);
1021 
1022     ret_value = (int32) real_cnt;
1023 
1024 done:
1025   if(ret_value == FAIL)
1026     { /* Error condition cleanup */
1027 
1028     } /* end if */
1029 
1030   /* Normal function cleanup */
1031   return ret_value;
1032 }   /* Hnumber() */
1033 
1034 /******************************************************************************
1035  NAME
1036      Hnewref - Returns a ref that is guaranteed to be unique in the file
1037 
1038  DESCRIPTION
1039     Returns a ref number that can be used with any tag to produce a
1040     unique tag/ref.  Successive calls to Hnewref will generate a
1041     strictly increasing sequence until the highest possible ref had been
1042     returned, then Hnewref will return unused ref's starting from 1.
1043 
1044  RETURNS
1045     returns the ref number, 0 otherwise
1046 
1047 *******************************************************************************/
1048 uint16
Hnewref(int32 file_id)1049 Hnewref(int32 file_id /* IN: File ID the tag/refs are in */)
1050 {
1051     CONSTR(FUNC, "Hnewref");
1052     filerec_t  *file_rec;	   /* file record */
1053     uint16      ref;		   /* the new ref */
1054     uint16      ret_value = DFREF_NONE;
1055     uint32      i_ref;        /* index for FOR loop */
1056 
1057     /* clear error stack and check validity of file record id */
1058     HEclear();
1059     file_rec = HAatom_object(file_id);
1060     if (BADFREC(file_rec))
1061         HGOTO_ERROR(DFE_ARGS, 0);
1062 
1063     /* if maxref of this file is still below the maximum,
1064      just return next number */
1065     if (file_rec->maxref < MAX_REF)
1066         ret_value = ++(file_rec->maxref);
1067     else
1068       { /* otherwise, search for an empty ref */
1069         /* incredibly slow but unlikely situation */
1070 /* This could possibly get replaced with some sort of bit-vector manipulation -QAK */
1071         for (i_ref = 1; i_ref <= (uint32)MAX_REF; i_ref++)
1072           {
1073             dd_t *dd_ptr=NULL;
1074             ref = (uint16)i_ref;
1075             if (HTIfind_dd(file_rec, (uint16) DFTAG_WILDCARD, ref, &dd_ptr, DF_FORWARD) == FAIL)
1076               {
1077                ret_value = ref; /* set return value to ref found */
1078                break; /* break out of loop */
1079               } /* end if */
1080           } /* end for */
1081       } /* end else */
1082 
1083 done:
1084   if(ret_value == DFREF_NONE)
1085     { /* Error condition cleanup */
1086 
1087     } /* end if */
1088 
1089   /* Normal function cleanup */
1090   return ret_value;
1091 }   /* Hnewref() */
1092 
1093 /******************************************************************************
1094  NAME
1095     Htagnewref  - returns a ref that is unique in the file for a given tag
1096 
1097  DESCRIPTION
1098     Returns a ref number that can be used with any tag to produce a
1099     unique tag/ref.  Successive calls to Hnewref will generate a
1100     strictly increasing sequence until the highest possible ref had been
1101     returned, then Hnewref will return unused ref's starting from 1.
1102 
1103  RETURNS
1104     returns the ref number, 0 otherwise
1105 
1106 *******************************************************************************/
1107 uint16
Htagnewref(int32 file_id,uint16 tag)1108 Htagnewref(int32 file_id,/* IN: File ID the tag/refs are in */
1109            uint16 tag    /* IN: Tag to search for a new ref for */)
1110 {
1111     CONSTR(FUNC, "Htagnewref");
1112     filerec_t  *file_rec;  /* file record */
1113     tag_info   *tinfo_ptr; /* pointer to the info for a tag */
1114     tag_info  **tip_ptr;   /* ptr to the ptr to the info for a tag */
1115     uint16      base_tag = BASETAG(tag); /* corresponding base tag (if the tag is special) */
1116     uint16      ret_value = DFREF_NONE;
1117 
1118     /* clear error stack and check validity of file record id */
1119     HEclear();
1120     file_rec = HAatom_object(file_id);
1121     if (BADFREC(file_rec))
1122         HGOTO_ERROR(DFE_ARGS, 0);
1123 
1124     if((tip_ptr = (tag_info **)tbbtdfind(file_rec->tag_tree,(VOIDP)&base_tag,NULL))==NULL)
1125         ret_value = 1;  /* The first available ref */
1126     else
1127       {   /* found an existing tag */
1128           tinfo_ptr = *tip_ptr; /* get the pointer to the tag info */
1129           if((ret_value = (uint16)bv_find(tinfo_ptr->b,-1,BV_FALSE)) == (uint16)FAIL)
1130               HGOTO_ERROR(DFE_BVFIND, 0);
1131       } /* end else */
1132 
1133 done:
1134   if(ret_value == 0)
1135     { /* Error condition cleanup */
1136 
1137     } /* end if */
1138 
1139   /* Normal function cleanup */
1140   return ret_value;
1141 }   /* Htagnewref() */
1142 
1143 /******************************************************************************
1144  NAME
1145     Hfind - locate the next object of a search in an HDF file
1146 
1147  DESCRIPTION
1148     Searches for the `next' DD that fits the search tag/ref.  Wildcards
1149     apply.  If origin is DF_FORWARD, search from current position forwards
1150     in the file, otherwise DF_BACKWARD searches backward from the current
1151     position in the file.  If *find_tag and *find_ref are both set to
1152     0, this indicates the beginning of a search, and the search will
1153     start from the beginning of the file if the direction is DF_FORWARD
1154     and from the and of the file if the direction is DF_BACKWARD.
1155 
1156  RETURNS
1157     returns SUCCEED (0) if successful and FAIL (-1) otherwise
1158 
1159 *******************************************************************************/
Hfind(int32 file_id,uint16 search_tag,uint16 search_ref,uint16 * find_tag,uint16 * find_ref,int32 * find_offset,int32 * find_length,intn direction)1160 intn Hfind(int32 file_id,       /* IN: file ID to search in */
1161         uint16 search_tag,      /* IN: the tag to search for (can be DFTAG_WILDCARD) */
1162         uint16 search_ref,      /* IN: ref to search for (can be DFREF_WILDCARD) */
1163         uint16 *find_tag,       /* IN: if (*find_tag==0) and (*find_ref==0) then start search */
1164                                 /* OUT: tag matching the search tag */
1165         uint16 *find_ref,       /* IN: if (*find_tag==0) and (*find_ref==0) then start search */
1166                                 /* OUT: ref matching the search ref */
1167         int32 *find_offset,     /* OUT: offset of the data element found */
1168         int32 *find_length,     /* OUT: length of the data element found */
1169         intn direction          /* IN: Direction to search in: */
1170                                 /*  DF_FORWARD searches forward from the current location */
1171                                 /*  DF_BACKWARD searches backward from the current location */
1172 )
1173 {
1174     CONSTR(FUNC, "Hfind");	/* for HERROR */
1175     filerec_t  *file_rec;		/* file record */
1176     dd_t       *dd_ptr;		   /* ptr to current ddlist searched */
1177     intn    ret_value = SUCCEED;
1178 
1179     /* clear error stack and check validity of the access id */
1180     HEclear();
1181     if (file_id == FAIL || /* search_ref > MAX_REF || */ find_tag == NULL
1182         || find_ref == NULL || find_offset == NULL || find_length == NULL
1183         || (direction != DF_FORWARD && direction != DF_BACKWARD))
1184       HGOTO_ERROR(DFE_ARGS, FAIL);
1185 
1186     file_rec = HAatom_object(file_id);
1187     if (BADFREC(file_rec))
1188       HGOTO_ERROR(DFE_INTERNAL, FAIL);
1189 
1190     dd_ptr = NULL;
1191     if (*find_ref != 0 || *find_tag != 0)
1192       {		/* continue a search */
1193         /* get the block and index of the last tag/ref found, to continue */
1194         if (HTIfind_dd(file_rec, *find_tag, *find_ref, &dd_ptr, direction) == FAIL)
1195           HGOTO_ERROR(DFE_NOMATCH, FAIL);
1196       }		/* end else */
1197 
1198     /* Go get the next match in the given direction */
1199     if (HTIfind_dd(file_rec, search_tag, search_ref, &dd_ptr, direction) == FAIL)
1200       HGOTO_DONE(FAIL); /* Not an error, we just didn't find the object */
1201 
1202     *find_tag = dd_ptr->tag;
1203     *find_ref = dd_ptr->ref;
1204     *find_offset = dd_ptr->offset;
1205     *find_length = dd_ptr->length;
1206 
1207 done:
1208     if(ret_value == FAIL)
1209       { /* Error condition cleanup */
1210 
1211       } /* end if */
1212 
1213   /* Normal function cleanup */
1214     return ret_value;
1215 }	/* end Hfind() */
1216 
1217 /******************************************************************************
1218  NAME
1219      HDcheck_tagref - Checks to see if tag/ref is in DD list i.e. created already
1220 
1221  DESCRIPTION
1222      Routine checks to see if tag/ref exists in the DD list i.e. has
1223      been created.
1224 
1225  RETURNS
1226      0-> tag/ref does not exist
1227      1-> tag/ref exists
1228     -1-> function failed
1229 
1230 *******************************************************************************/
1231 intn
HDcheck_tagref(int32 file_id,uint16 tag,uint16 ref)1232 HDcheck_tagref(int32  file_id, /* IN: id of file */
1233                uint16 tag,     /* IN: Tag to check */
1234                uint16 ref      /* IN: ref to check */)
1235 {
1236     CONSTR(FUNC, "HDcheck_tagref");  /* for HERROR */
1237     filerec_t *file_rec = NULL;  /* file record */
1238     dd_t      *dd_ptr = NULL;    /* ptr to the DD info for the tag/ref */
1239     tag_info **tip_ptr = NULL;   /* ptr to the ptr to the info for a tag */
1240     tag_info  *tinfo_ptr = NULL; /* pointer to the info for a tag */
1241     uint16     base_tag;         /* corresponding base tag (if the tag is special) */
1242     intn       ret_value = 1;  /* default tag/ref exists  */
1243 
1244     /* clear error stack */
1245     HEclear();
1246 
1247     /* check args */
1248     file_rec = HAatom_object(file_id);
1249     if(file_rec == NULL
1250        || (tag == DFTAG_NULL || tag==DFTAG_WILDCARD)
1251        ||  ref == DFREF_WILDCARD)
1252         HGOTO_ERROR(DFE_ARGS, -1);
1253 
1254     base_tag = BASETAG(tag);
1255 
1256     /* Try to find the regular tag in the tag info tree */
1257     if((tip_ptr = (tag_info **)tbbtdfind(file_rec->tag_tree,
1258                                          (VOIDP)&base_tag,NULL)) == NULL)
1259         HGOTO_DONE(0); /* Not an error, we just didn't find the object */
1260 
1261     tinfo_ptr = *tip_ptr; /* get the pointer to the tag info */
1262     if((dd_ptr = DAget_elem(tinfo_ptr->d,(intn)ref)) == NULL)
1263         HGOTO_DONE(0); /* Not an error, we just didn't find the object */
1264 
1265     /* found if we reach here*/
1266     ret_value = 1;
1267 
1268 done:
1269   if(ret_value == -1)
1270     { /* Error condition cleanup */
1271 
1272     } /* end if */
1273 
1274   /* Normal function cleanup */
1275 
1276   return ret_value;
1277 }   /* HDcheck_tagref() */
1278 
1279 /************************************************************************
1280 NAME
1281    HDreuse_tagref -- reuse a data descriptor preserving tag/ref(assumes DD exists)
1282 
1283 DESCRIPTION
1284    Reuses the data descriptor of tag/ref in the dd list of the file.
1285    The tag/ref must already exist in the DD list.
1286    This routine is unsafe and may leave a file in a condition that is
1287    not usable by some routines.  Use with care. Not valid for
1288    special elments right now. Used for allowing the data to change
1289    and move somewhere else in the file for non-special elements.
1290    Must be carefully if apply to higher-level objects like GR's and SDS
1291    that are comprised of other objects.
1292    Usefull when re-writing simple elements whose size changes while
1293    preserving the original tag/ref of the element since other elements
1294    might refer to this element by tag/ref e.g. in a Vgroup.
1295 
1296    NOTE: this routine is similiar to Hdeldd() but with a different name
1297 
1298 RETURNS
1299    returns SUCCEED (0) if successful, FAIL (-1) otherwise
1300 ************************************************************************/
1301 intn
HDreuse_tagref(int32 file_id,uint16 tag,uint16 ref)1302 HDreuse_tagref(int32 file_id, /* IN: id of file */
1303                uint16 tag,    /* IN: tag of data descriptor to reuse */
1304                uint16 ref     /* IN: ref of data descriptor to reuse */ )
1305 {
1306   CONSTR(FUNC, "HDreusedd");   /* for HERROR */
1307   filerec_t  *file_rec = NULL; /* file record */
1308   atom_t      ddid;            /* ID for the DD */
1309   intn        ret_value = SUCCEED;
1310 
1311   /* clear error stack and check validity of file record id */
1312   HEclear();
1313 
1314   file_rec = HAatom_object(file_id);
1315   if (BADFREC(file_rec) || tag == DFTAG_WILDCARD || ref == DFREF_WILDCARD)
1316     HGOTO_ERROR(DFE_ARGS, FAIL);
1317 
1318   /* look for the dd to reuse */
1319   if ((ddid = HTPselect(file_rec, tag, ref)) == FAIL)
1320     HGOTO_ERROR(DFE_NOMATCH, FAIL);
1321 
1322   /* could reuse space in file by calling HPfreediskblock() routine
1323      but it does nothing for now. For later. */
1324   /* if (HPfreediskblock(file_rec,dd_ptr->offset,dd_ptr->length) == FAIL)
1325       HGOTO_ERROR(DFE_INTERNAL, FAIL); */
1326 
1327   /* reuse the dd by setting the offset and length to
1328      INVALID_OFFSET and INVALID_LENGTH*/
1329   if (HTPupdate(ddid,INVALID_OFFSET, INVALID_LENGTH) == FAIL)
1330     HGOTO_ERROR(DFE_INTERNAL, FAIL);
1331 
1332  /* We leave the ref # as 'used' in the tag tree and
1333     dont' delete from dynarray of refs. */
1334 
1335   /* Remove DD from atom group since it should get re-created in Hstartaccess().
1336      This could be handled better if Hstartaccess() was revamped
1337      to not create new access records for existing tag/ref pairs
1338      as well as revamping a few other routines. */
1339   if(HAremove_atom(ddid)==NULL)
1340       HGOTO_ERROR(DFE_INTERNAL, FAIL);
1341 
1342 done:
1343   if(ret_value == FAIL)
1344     { /* Error condition cleanup */
1345 
1346     } /* end if */
1347 
1348   /* Normal function cleanup */
1349   return ret_value;
1350 }	/* end HDreuse_tagref */
1351 
1352 /*--------------------------------------------------------------------------
1353 NAME
1354    Hdeldd -- delete a data descriptor
1355 USAGE
1356    intn Hdeldd(file_id, tag, ref)
1357    int32 file_id;            IN: id of file
1358    int16 tag;                IN: tag of data descriptor to delete
1359    int16 ref;                IN: ref of data descriptor to delete
1360 RETURNS
1361    returns SUCCEED (0) if successful, FAIL (-1) otherwise
1362 DESCRIPTION
1363    Deletes a data descriptor of tag/ref from the dd list of the file.
1364    This routine is unsafe and may leave a file in a condition that is
1365    not usable by some routines.  Use with care.
1366    For example, if this element is contained in a Vgroup, that group
1367    will *NOT* get updated to reflect that this element has been deleted.
1368 
1369 --------------------------------------------------------------------------*/
Hdeldd(int32 file_id,uint16 tag,uint16 ref)1370 intn Hdeldd(int32 file_id, uint16 tag, uint16 ref)
1371 {
1372   CONSTR(FUNC, "Hdeldd");		/* for HERROR */
1373   filerec_t  *file_rec;		/* file record */
1374   atom_t      ddid;         /* ID for the DD */
1375   intn        ret_value = SUCCEED;
1376 
1377   /* clear error stack and check validity of file record id */
1378   HEclear();
1379   file_rec = HAatom_object(file_id);
1380   if (BADFREC(file_rec) || tag == DFTAG_WILDCARD || ref == DFREF_WILDCARD)
1381     HGOTO_ERROR(DFE_ARGS, FAIL);
1382 
1383   /* look for the dd to delete */
1384   if ((ddid=HTPselect(file_rec, tag, ref)) == FAIL)
1385     HGOTO_ERROR(DFE_NOMATCH, FAIL);
1386 
1387   /* delete the dd */
1388   if (HTPdelete(ddid) == FAIL)
1389     HGOTO_ERROR(DFE_CANTDELDD, FAIL);
1390 
1391 done:
1392   if(ret_value == FAIL)
1393     { /* Error condition cleanup */
1394 
1395     } /* end if */
1396 
1397   /* Normal function cleanup */
1398   return ret_value;
1399 }	/* end Hdeldd */
1400 
1401 #ifdef DEBUGGING
1402 /*--------------------------------------------------------------------------
1403  NAME
1404     HTPdump_dds -- Dump out the dd information for a file
1405  USAGE
1406     intn HTPdump_dds(file_id)
1407         int32 file_id;              IN: file ID of HDF file to dump
1408         FILE *fout;                 IN: file stream to output to
1409  RETURNS
1410     returns SUCCEED (0) if successful and FAIL (-1) if failed.
1411  DESCRIPTION
1412     Prints out all the information (that you could _ever_ want to know) about
1413     the dd blocks and dd list for a file.
1414 
1415 --------------------------------------------------------------------------*/
HTPdump_dds(int32 file_id,FILE * fout)1416 intn HTPdump_dds(int32 file_id, FILE *fout)
1417 {
1418   CONSTR(FUNC, "HTPdump_dds");
1419   filerec_t  *file_rec;		/* file record */
1420   int         ret_value = SUCCEED;
1421 
1422   /* clear error stack and check validity of file record id */
1423   HEclear();
1424   file_rec = HAatom_object(file_id);
1425   if (BADFREC(file_rec))
1426     HGOTO_ERROR(DFE_ARGS, FAIL);
1427 
1428 /* Print out each DD block */
1429     {
1430         ddblock_t   *block=file_rec->ddhead;    /* dd block currently dumping */
1431         intn blk_count=0;       /* Count of the number of blocks we've dumped */
1432         intn i;                 /* local counting variable */
1433 
1434         while(block!=NULL)
1435           {
1436             dd_t *curr_dd;      /* current dd to dump */
1437 
1438             fprintf(fout,"DD block %d\n",blk_count);
1439             fprintf(fout,"# of DDs: %d, next block offset=%ld\n",(int)block->ndds,(long)block->nextoffset);
1440             fprintf(fout,"DD block offset: %ld, dirty?=%d\n",(long)block->myoffset,(int)block->dirty);
1441             for(i=0, curr_dd=block->ddlist; i<block->ndds; i++,curr_dd++)
1442                 fprintf(fout,"%5d: tag/ref=(%5u/%5u), offset=%7ld, length=%7ld\n",(int)i,(unsigned)curr_dd->tag,(unsigned)curr_dd->ref,(long)curr_dd->offset,(long)curr_dd->length);
1443             blk_count++;
1444             block=block->next;
1445           } /* end while */
1446     } /* End of ddblock dumping code */
1447 
1448 /* Dump the tag tree */
1449     {
1450         VOIDP      *t;
1451 
1452         if (NULL != (t = (VOIDP *) tbbtfirst((TBBT_NODE *) * (file_rec->tag_tree))))
1453           {   /* found at least one node in the tree */
1454             tag_info *tinfo_ptr;  /* pointer to the info for a tag */
1455 
1456             do
1457               { /* dump each node */
1458                 intn size;      /* # of elements in the array */
1459                 intn i;         /* local counting variable */
1460 
1461                 tinfo_ptr = (tag_info *) * t;   /* get actual pointer to the tag info */
1462                 fprintf(fout,"Tag: %u\n",tinfo_ptr->tag);
1463 
1464                 /* Dump the ref # dynarray */
1465                 if((size=DAsize_array(tinfo_ptr->d))!=FAIL)
1466                   {
1467                     VOIDP elem;
1468 
1469                     fprintf(fout,"dynarray size=%d\n",size);
1470                     for(i=0; i<size; i++)
1471                       {
1472                         elem=DAget_elem(tinfo_ptr->d,i);
1473                         if(elem!=NULL)
1474                             fprintf(fout,"dynarray[%d]=%p\n",i,elem);
1475                       } /* end for */
1476                   } /* end if */
1477 
1478                 /* Dump the ref # bit-vector */
1479                 if((size=bv_size(tinfo_ptr->b))!=FAIL)
1480                   {
1481                     intn bit;
1482 
1483                     fprintf(fout,"bitvector size=%d\n",size);
1484                     fprintf(fout,"bits set:");
1485                     for(i=0; i<size; i++)
1486                       {
1487                         bit=bv_get(tinfo_ptr->b,i);
1488                         if(bit!=BV_FALSE)
1489                             fprintf(fout,"%5d",i);
1490                       } /* end for */
1491                     fprintf(fout,"\n");
1492                   } /* end if */
1493 
1494                 /* Get the next tag node */
1495                 t = (VOIDP *) tbbtnext((TBBT_NODE *) t);
1496               } while(t!=NULL);
1497           }
1498         else
1499             fprintf(fout,"No nodes in tag tree\n");
1500     } /* End of tag node dumping */
1501 
1502 done:
1503   if(ret_value == FAIL)
1504     { /* Error condition cleanup */
1505 
1506     } /* end if */
1507 
1508   /* Normal function cleanup */
1509 
1510   return ret_value;
1511 }	/* HTPdump_dds */
1512 #endif /* DEBUGGING */
1513 
1514 
1515 
1516 /* Private, static, internal routines.  Do not call from outside this module */
1517 
1518 /*--------------------------------------------------------------------------
1519  NAME
1520     HTInew_dd_block -- create a new (empty) DD block
1521  USAGE
1522     intn HTInew_dd_block(file_rec)
1523 
1524     filerec_t  * file_rec;        IN: file record
1525  RETURNS
1526     returns SUCCEED (0) if successful and FAIL (-1) if failed.
1527  DESCRIPTION
1528     Create a new DDblock in the file.  Update the previously last DDblock so
1529     that its offset points to the newly created one.
1530 
1531 --------------------------------------------------------------------------*/
HTInew_dd_block(filerec_t * file_rec)1532 static intn HTInew_dd_block(filerec_t * file_rec)
1533 {
1534     CONSTR(FUNC, "HTInew_dd_block");    /* for HERROR */
1535     int32       nextoffset;		/* offset of new ddblock */
1536     uint8       ddhead[NDDS_SZ+OFFSET_SZ];   /* storage for the DD header */
1537     int32       offset;			/* offset to the offset of new ddblock */
1538     ddblock_t *block;           /* Block the DD is located in */
1539     dd_t       *list;			/* dd list array of new dd block */
1540     uint8      *p;              /* Temporary buffer pointer. */
1541     intn        ndds;                   /* number of ndds in new DD block */
1542     intn        ret_value = SUCCEED;
1543 
1544     HEclear();
1545     /* check integrity of file record */
1546     if (file_rec->ddhead==NULL || file_rec->ddlast==NULL)
1547       HGOTO_ERROR(DFE_INTERNAL, FAIL);
1548 
1549     /* allocate new dd block record and fill in data */
1550     if ((block = (ddblock_t *) HDmalloc(sizeof(ddblock_t))) == NULL)
1551       HGOTO_ERROR(DFE_NOSPACE, FAIL);
1552     block->ndds = (int16)(ndds = (intn)file_rec->ddhead->ndds);    /* snarf from first block */
1553     block->next = (ddblock_t *) NULL;
1554     block->nextoffset = 0;
1555 
1556     /* Keep the filerec_t pointer around for each ddblock */
1557     block->frec=file_rec;
1558 
1559     /* get room for the new DD block in the file */
1560     if ((nextoffset = HPgetdiskblock(file_rec, NDDS_SZ + OFFSET_SZ + (ndds * DD_SZ), TRUE)) == FAIL)
1561       HGOTO_ERROR(DFE_SEEKERROR, FAIL);
1562     block->myoffset = nextoffset;	/* set offset of new block */
1563     block->dirty = (uintn)file_rec->cache; /* if we're caching, wait to write DD block */
1564 
1565     if (file_rec->cache)	/* if we are caching, wait to update previous DD block */
1566       file_rec->dirty |= DDLIST_DIRTY;	/* indicate file needs to be flushed */
1567     else
1568       {
1569         p = ddhead;
1570         INT16ENCODE(p, block->ndds);
1571         INT32ENCODE(p, (int32) 0);
1572         if (HP_write(file_rec, ddhead, NDDS_SZ + OFFSET_SZ) == FAIL)
1573           HGOTO_ERROR(DFE_WRITEERROR, FAIL);
1574       }		/* end else */
1575 
1576     /* set up the dd list of this dd block and put it in the file
1577      after the dd block header */
1578     list = block->ddlist = (dd_t *) HDmalloc((uint32) ndds * sizeof(dd_t));
1579     if (list == (dd_t *) NULL)
1580       HGOTO_ERROR(DFE_NOSPACE, FAIL);
1581 
1582     /* Fill the block with NIL tags */
1583     list[0].tag = DFTAG_NULL;
1584     list[0].ref = DFREF_NONE;
1585     list[0].length = INVALID_LENGTH;
1586     list[0].offset = INVALID_OFFSET;
1587     list[0].blk = block;
1588     HDmemfill(&list[1],&list[0],sizeof(dd_t),(uint32)ndds-1);
1589 
1590     if (file_rec->cache!=0)
1591       {	/* if we are caching, wait to update previous DD block */
1592         uint8 *tbuf;    /* temporary buffer */
1593 
1594         tbuf=(uint8 *)HDmalloc(ndds*DD_SZ);
1595         if(tbuf==(uint8 *)NULL)
1596             HGOTO_ERROR(DFE_NOSPACE, FAIL);
1597 
1598         p = tbuf;
1599 	DDENCODE(p, (uint16) DFTAG_NULL, (uint16) DFREF_NONE,
1600 	    (int32) INVALID_LENGTH, (int32) INVALID_OFFSET);
1601         HDmemfill(p,tbuf,DD_SZ,(uint32)(ndds-1));
1602 
1603         if (HP_write(file_rec, tbuf, ndds * DD_SZ) == FAIL)
1604           HGOTO_ERROR(DFE_WRITEERROR, FAIL);
1605 
1606         HDfree(tbuf);
1607       }		/* end if */
1608 
1609     /* update previously last ddblock to point to this new dd block */
1610     file_rec->ddlast->nextoffset = nextoffset;
1611     block->prev = file_rec->ddlast;
1612     file_rec->ddlast->next = block;
1613     if (file_rec->cache)
1614       {	/* if we are caching, wait to update previous DD block */
1615         file_rec->dirty |= DDLIST_DIRTY;	/* indicate file needs to be flushed */
1616         file_rec->ddlast->dirty = TRUE;	/* indicate this block needs to be flushed */
1617       }	/* end if */
1618     else
1619       {
1620         if (file_rec->ddhead == file_rec->ddlast)
1621           offset = MAGICLEN + NDDS_SZ;
1622         else
1623           offset = file_rec->ddlast->prev->nextoffset + NDDS_SZ;
1624         p = ddhead;
1625         INT32ENCODE(p, nextoffset);
1626         if (HPseek(file_rec, offset) == FAIL)
1627           HGOTO_ERROR(DFE_SEEKERROR, FAIL);
1628         if (HP_write(file_rec, ddhead, OFFSET_SZ) == FAIL)
1629           HGOTO_ERROR(DFE_WRITEERROR, FAIL);
1630       }	/* end else */
1631 
1632     /* update file record */
1633     file_rec->ddlast = block;
1634 
1635     /* set the end of the file to the end of the current DD block */
1636     file_rec->f_end_off = block->myoffset + (NDDS_SZ + OFFSET_SZ) + (block->ndds * DD_SZ);
1637 
1638 done:
1639   if(ret_value == FAIL)
1640     { /* Error condition cleanup */
1641 
1642     } /* end if */
1643 
1644   /* Normal function cleanup */
1645 
1646   return ret_value;
1647 }	/* HTInew_dd_block */
1648 
1649 /*--------------------------------------------------------------------------
1650  NAME
1651     HTIfind_dd -- find a specific DD in the file
1652  USAGE
1653     int HTIfind_dd(file_rec, tag, ref, dd_ptr, direction)
1654         filerec_t *  file_rec;       IN:  file record to search
1655         uint16       tag;            IN:  tag of element to find
1656         uint16       ref;            IN:  ref of element to find
1657         dd_t      ** pdd;            OUT: pointer to the DD in memory
1658         intn         direction;      IN:  direction to search
1659                                         (DF_FORWARD / DF_BACKWARD)
1660  RETURNS
1661     returns SUCCEED (0) if successful and FAIL (-1) if failed.
1662  DESCRIPTION
1663     Find the dd with tag and ref, by returning the block where the dd resides
1664     and the index of the dd in the ddblock ddlist.
1665 
1666 --------------------------------------------------------------------------*/
HTIfind_dd(filerec_t * file_rec,uint16 look_tag,uint16 look_ref,dd_t ** pdd,intn direction)1667 static intn HTIfind_dd(filerec_t * file_rec, uint16 look_tag, uint16 look_ref,
1668             dd_t ** pdd, intn direction)
1669 {
1670 #ifdef LATER
1671     CONSTR(FUNC, "HTIfind_dd");    /* for HERROR */
1672 #endif /* LATER */
1673     intn idx;          /* index into ddlist of current dd searched */
1674     ddblock_t *block;  /* ptr to current ddblock searched */
1675     dd_t *list;        /* ptr to current ddlist searched */
1676     uint16      special_tag;    /* corresponding special tag */
1677     intn        ret_value = SUCCEED;
1678 
1679     HEclear();
1680     /* Create the special version of the tag to search for also */
1681     special_tag = MKSPECIALTAG(look_tag);
1682 
1683     if(look_tag!=DFTAG_WILDCARD && look_ref!=DFTAG_WILDCARD)
1684       { /* easy to optimize case, looking for a specific tag/ref pair */
1685           tag_info **tip_ptr;   /* ptr to the ptr to the info for a tag */
1686           tag_info *tinfo_ptr;  /* pointer to the info for a tag */
1687           dd_t *dd_ptr;         /* ptr to the DD info for a tag/ref */
1688           uint16 base_tag=BASETAG(look_tag);    /* corresponding base tag (if the tag is special) */
1689 
1690           /* Try to find the regular tag in the tag info tree */
1691           if((tip_ptr=(tag_info **)tbbtdfind(file_rec->tag_tree,(VOIDP)&base_tag,NULL))==NULL)
1692               HGOTO_DONE(FAIL); /* Not an error, we just didn't find the object */
1693 
1694           tinfo_ptr=*tip_ptr; /* get the pointer to the tag info */
1695           if((dd_ptr=DAget_elem(tinfo_ptr->d,(intn)look_ref))==NULL)
1696               HGOTO_DONE(FAIL); /* Not an error, we just didn't find the object */
1697 
1698           *pdd=dd_ptr;
1699           HGOTO_DONE(SUCCEED);
1700       } /* end if */
1701     else
1702       { /* handle wildcards, etc. */
1703         if (direction == DF_FORWARD)
1704           {   /* search forward through the DD list */
1705             if(*pdd==NULL)
1706               {
1707                 block=file_rec->ddhead;
1708                 idx=0;
1709               } /* end if */
1710             else
1711               {
1712                 block=(*pdd)->blk;
1713                 idx=((*pdd)-&block->ddlist[0])+1;
1714               } /* end else */
1715             if(look_tag==DFTAG_WILDCARD && look_ref==DFREF_WILDCARD)
1716               { /* Both tag & ref are wildcards */
1717                 for (; block; block = block->next)
1718                   {
1719                     list = &block->ddlist[idx];
1720                     for (; idx < block->ndds; idx++, list++)
1721                       {
1722                         /* skip the empty dd's */
1723                         if (list->tag == DFTAG_NULL)
1724                             continue;
1725 
1726                         /* we have a match !! (anything matches! :-) */
1727                         *pdd=list;
1728                         HGOTO_DONE(SUCCEED);
1729                       }	/* end for */
1730 
1731                     /* start from beginning of the next dd list */
1732                     idx = 0;
1733                   }	/* end for */
1734               } /* end if */
1735             else if(look_tag==DFTAG_NULL && look_ref==DFTAG_WILDCARD)
1736               { /* special case for quick lookup of empty DD's */
1737                 if(file_rec->ddnull==NULL)
1738                     block=file_rec->ddhead;
1739                 else
1740                     block=file_rec->ddnull;
1741                 if(file_rec->ddnull_idx<0)
1742                     idx=0;
1743                 else
1744                     idx=file_rec->ddnull_idx+1;
1745 
1746                 for (; block; block = block->next)
1747                   {
1748                     list = &block->ddlist[idx];
1749                     for (; idx < block->ndds; idx++, list++)
1750                       {
1751                         /* skip the empty dd's */
1752                         if (list->tag == DFTAG_NULL)
1753                           {
1754                             /* we have a match !! */
1755                             *pdd=list;
1756 
1757                             /* Update the DFTAG_NULL pointers */
1758                             file_rec->ddnull=block;
1759                             file_rec->ddnull_idx=idx;
1760 
1761                             HGOTO_DONE(SUCCEED);
1762                           } /* end if */
1763                       }	/* end for */
1764 
1765                     /* start from beginning of the next dd list */
1766                     idx = 0;
1767                   }	/* end for */
1768               } /* end if */
1769             else if(look_tag==DFTAG_WILDCARD)
1770               { /* tag is wildcard */
1771                 for (; block; block = block->next)
1772                   {
1773                     list = &block->ddlist[idx];
1774                     for (; idx < block->ndds; idx++, list++)
1775                       {
1776                         /* skip the empty dd's */
1777                         if (list->tag == DFTAG_NULL)
1778                             continue;
1779 
1780                         if (list->ref == look_ref)
1781                           {
1782                             /* we have a match !! */
1783                             *pdd=list;
1784                             HGOTO_DONE(SUCCEED);
1785                           } /* end if */
1786                       }	/* end for */
1787 
1788                     /* start from beginning of the next dd list */
1789                     idx = 0;
1790                   }	/* end for */
1791               } /* end if */
1792             else if(look_ref==DFREF_WILDCARD)
1793               { /* ref is wildcard */
1794 #ifndef OLD_WAY
1795                 if(special_tag==DFTAG_NULL)
1796                   {
1797 /* Change this to lookup the next used ref # in the bitvector or dynarray -QAK */
1798                     for (; block; block = block->next)
1799                       {
1800                         list = &block->ddlist[idx];
1801                         for (; idx < block->ndds; idx++, list++)
1802                           {
1803                             /* skip the empty dd's */
1804                             if (list->tag == DFTAG_NULL && look_tag != DFTAG_NULL)
1805                                 continue;
1806 
1807                             if (list->tag == look_tag)
1808                               {
1809                                 /* we have a match !! */
1810                                 *pdd=list;
1811                                 HGOTO_DONE(SUCCEED);
1812                               } /* end if */
1813                           }	/* end for */
1814 
1815                         /* start from beginning of the next dd list */
1816                         idx = 0;
1817                       }	/* end for */
1818                   } /* end if */
1819                 else
1820                   {
1821                     for (; block; block = block->next)
1822                       {
1823                         list = &block->ddlist[idx];
1824                         for (; idx < block->ndds; idx++, list++)
1825                           {
1826                             /* skip the empty dd's */
1827                             if (list->tag == DFTAG_NULL && look_tag != DFTAG_NULL)
1828                                 continue;
1829 
1830                             if (list->tag == look_tag || list->tag == special_tag)
1831                               {
1832                                 /* we have a match !! */
1833                                 *pdd=list;
1834                                 HGOTO_DONE(SUCCEED);
1835                               } /* end if */
1836                           }	/* end for */
1837 
1838                         /* start from beginning of the next dd list */
1839                         idx = 0;
1840                       }	/* end for */
1841                   } /* end else */
1842 #else /* OLD_WAY */
1843 /* Hmm, not working yet?... -QAK */
1844                 tag_info **tip_ptr;   /* ptr to the ptr to the info for a tag */
1845                 tag_info *tinfo_ptr;  /* pointer to the info for a tag */
1846                 dd_t *dd_ptr;         /* ptr to the DD info for a tag/ref */
1847                 uint16 base_tag=BASETAG(look_tag);    /* corresponding base tag (if the tag is special) */
1848                 int32 last_ref;       /* the last ref # found */
1849                 uint16 found_ref;     /* next ref # found */
1850 
1851                 /* Try to find the regular tag in the tag info tree */
1852                 if((tip_ptr=(tag_info **)tbbtdfind(file_rec->tag_tree,(VOIDP)&base_tag,NULL))==NULL)
1853                     HGOTO_ERROR(DFE_BADTAG, FAIL);
1854 
1855                 tinfo_ptr=*tip_ptr; /* get the pointer to the tag info */
1856                 if(*pdd==NULL) /* check if we are searching from the beginning */
1857                     last_ref=-1;
1858                 else
1859                     last_ref=block->ddlist[idx].ref;
1860                 if((found_ref=bv_find(tinfo_ptr->b,last_ref,1))==(uint16)FAIL)
1861                   HGOTO_ERROR(DFE_BVFIND, FAIL);
1862 
1863                 if((dd_ptr=DAget_elem(tinfo_ptr->d,found_ref))==NULL)
1864                   HGOTO_ERROR(DFE_BADREF, FAIL);
1865 
1866                 *pdd=dd_ptr;
1867                 HGOTO_DONE(SUCCEED);
1868 #endif /* OLD_WAY */
1869               } /* end if */
1870             else
1871               { /* Both tag & ref are not wildcards */
1872                 for (; block; block = block->next)
1873                   {
1874                     list = &block->ddlist[idx];
1875                     for (; idx < block->ndds; idx++, list++)
1876                       {
1877                         /* skip the empty dd's */
1878                         if (list->tag == DFTAG_NULL && look_tag != DFTAG_NULL)
1879                             continue;
1880 
1881                         if ((list->tag == look_tag
1882                             || (special_tag != DFTAG_NULL && list->tag == special_tag))
1883                             && list->ref == look_ref)
1884                         {
1885                             /* we have a match !! */
1886                             *pdd=list;
1887                             HGOTO_DONE(SUCCEED);
1888                         }	/* end if */
1889                       }	/* end for */
1890 
1891                     /* start from beginning of the next dd list */
1892                     idx = 0;
1893                   }	/* end for */
1894               } /* end else */
1895           }		/* end if */
1896         else if (direction == DF_BACKWARD)
1897           {	  /* search backward through the DD list */
1898             if(*pdd==NULL)
1899               {
1900                 block=file_rec->ddlast;
1901                 idx=block->ndds-1;
1902               } /* end if */
1903             else
1904               {
1905                 block=(*pdd)->blk;
1906                 idx=((*pdd)-&block->ddlist[0])-1;
1907               } /* end else */
1908             for (; block;)
1909               {
1910                 list = block->ddlist;
1911                 for (; idx >= 0; idx--)
1912                   {
1913                       /* skip the empty dd's */
1914                     if (list[idx].tag == DFTAG_NULL && look_tag != DFTAG_NULL)
1915                       continue;
1916 
1917                     if (((look_tag == DFTAG_WILDCARD || list[idx].tag == look_tag)
1918                        || (special_tag != DFTAG_NULL && list[idx].tag == special_tag))
1919                        && (look_ref == DFREF_WILDCARD || list[idx].ref == look_ref))
1920                       {
1921 
1922                         /* we have a match !! */
1923                         *pdd=&list[idx];
1924                         HGOTO_DONE(SUCCEED);
1925                       }	/* end if */
1926                 }	/* end for */
1927 
1928               /* start from beginning of the next dd list */
1929               block = block->prev;
1930               if (block != NULL)
1931                   idx = block->ndds - 1;
1932               }	/* end for */
1933           }		/* end if */
1934       } /* end else */
1935 
1936     /* If we get here, we've failed */
1937     ret_value=FAIL;
1938 
1939 done:
1940   if(ret_value == FAIL)
1941     { /* Error condition cleanup */
1942 
1943     } /* end if */
1944 
1945   /* Normal function cleanup */
1946 
1947   return ret_value;
1948 }	/* HTIfind_dd */
1949 
1950 /*--------------------------------------------------------------------------
1951  NAME
1952     HTIupdate_dd -- update a DD on disk
1953  USAGE
1954     int HTIupdate_dd(file_rec, dd_ptr)
1955         filerec_t *file_rec;    IN: id of file
1956         dd_t      *dd_ptr;      IN: pointer to dd to update
1957  RETURNS
1958     returns SUCCEED (0) if successful and FAIL (-1) if failed.
1959  DESCRIPTION
1960    Takes appropriate action to note that a DD in a DD block has changed
1961 
1962 --------------------------------------------------------------------------*/
HTIupdate_dd(filerec_t * file_rec,dd_t * dd_ptr)1963 static intn HTIupdate_dd(filerec_t * file_rec, dd_t * dd_ptr)
1964 {
1965     CONSTR(FUNC, "HTIupdate_dd");   /* for HERROR */
1966     ddblock_t  *block;              /* DD block the dd is in */
1967     int32       idx;                /* index of the DD in the DD block */
1968     intn        ret_value = SUCCEED;
1969 
1970     HEclear();
1971     block=dd_ptr->blk;
1972     idx=dd_ptr-&block->ddlist[0];
1973     if (file_rec->cache)
1974       {		/* if caching is on, postpone update until later */
1975         file_rec->dirty |= DDLIST_DIRTY;
1976         block->dirty = TRUE;
1977       } /* end if */
1978     else
1979       {
1980         int32       offset;         /* offset of updated dd in file */
1981         uint8       tbuf[DD_SZ];    /* storage for the DD */
1982         uint8      *p;              /* temp buffer ptr */
1983 
1984         /* look for offset of updated dd block in the file */
1985         offset = block->myoffset + (NDDS_SZ + OFFSET_SZ) + (idx * DD_SZ);
1986 
1987         /* write in the updated dd */
1988         if (HPseek(file_rec, offset) == FAIL)
1989           HGOTO_ERROR(DFE_SEEKERROR, FAIL);
1990 
1991         p = tbuf;
1992 	DDENCODE(p, dd_ptr->tag, dd_ptr->ref, dd_ptr->offset, dd_ptr->length);
1993         if (HP_write(file_rec, tbuf, DD_SZ) == FAIL)
1994           HGOTO_ERROR(DFE_WRITEERROR, FAIL);
1995       } /* end else */
1996 
1997     /* check whether to incr. offset of end of file */
1998     /* not certain whether this is actually necessary, but better safe than */
1999     /* sorry later... -QAK */
2000     if ((dd_ptr->offset != INVALID_OFFSET && dd_ptr->length != INVALID_LENGTH) &&
2001         ( dd_ptr->offset +  dd_ptr->length) > file_rec->f_end_off)
2002       file_rec->f_end_off = dd_ptr->offset + dd_ptr->length;
2003 
2004 done:
2005   if(ret_value == FAIL)
2006     { /* Error condition cleanup */
2007 
2008     } /* end if */
2009 
2010   /* Normal function cleanup */
2011 
2012   return ret_value;
2013 }	/* HTIupdate_dd */
2014 
2015 /* ----------------------------- HTIcount_dd ------------------------------ */
2016 /*
2017 NAME
2018    HTIcount_dd -- counts the dd's of a certain type in file
2019 USAGE
2020    intn HTIcount_dd(file_rec, tag, ref, all_cnt, real_cnt)
2021    filerec_t *  file_rec;       IN:  file record to search
2022    uint16       tag;            IN:  tag of element to find
2023                                      (can be DFTAG_WILDCARD)
2024    uint16       ref;            IN:  ref of element to find
2025                                      (can be DFREF_WILDCARD)
2026    uintn       *all_cnt;        OUT: Count of all the tag/ref pairs
2027                                      found, including DFTAG_NULL and
2028                                      DFTAG_FREE
2029    uintn       *real_cnt;       OUT: Count of all the tag/ref pairs
2030                                      found, excluding DFTAG_NULL and
2031                                      DFTAG_FREE
2032 RETURNS
2033    SUCCEED / FAIL
2034 DESCRIPTION
2035    Counts the number of tag/ref pairs in a file.
2036 
2037    This routine keeps track of and returns to the user the number
2038    of all tag/refs and the number of "real" tag/refs found.
2039    "Real" tag/refs are any except DFTAG_NULL & DFTAG_FREE.
2040 
2041    This routine always counts the total tag/refs in the file, no
2042    provision is made for partial searches.
2043 
2044 ---------------------------------------------------------------------------*/
HTIcount_dd(filerec_t * file_rec,uint16 cnt_tag,uint16 cnt_ref,uintn * all_cnt,uintn * real_cnt)2045 static intn HTIcount_dd(filerec_t * file_rec, uint16 cnt_tag, uint16 cnt_ref,
2046            uintn *all_cnt, uintn *real_cnt)
2047 {
2048     uintn       t_all_cnt = 0;  /* count of all tag/refs found */
2049     uintn       t_real_cnt = 0; /* count of all tag/refs except NULL & FREE */
2050     intn        idx;            /* index into ddlist of current dd searched */
2051     ddblock_t  *block;          /* ptr to current ddblock searched */
2052     dd_t       *dd_ptr;         /* ptr to current ddlist searched */
2053     uint16      special_tag;    /* corresponding special tag */
2054 
2055     HEclear();
2056     /* search for special version also */
2057     special_tag = MKSPECIALTAG(cnt_tag);
2058 
2059 /* Change these algorithms to take advantage of the dynamic arrays for tags -QAK */
2060     switch(cnt_tag)
2061       {
2062           case DFTAG_WILDCARD:
2063               for (block = file_rec->ddhead; block != NULL; block = block->next)
2064                 {
2065                     t_all_cnt += (uintn)block->ndds;
2066 
2067                     dd_ptr = block->ddlist;
2068                     for (idx = 0; idx < block->ndds; idx++, dd_ptr++)
2069                       {
2070                           /* skip the empty dd's */
2071                           if (dd_ptr->tag == DFTAG_NULL || dd_ptr->tag == DFTAG_FREE)
2072                               continue;
2073 
2074                           if ((cnt_ref == DFREF_WILDCARD || dd_ptr->ref == cnt_ref))
2075                                 t_real_cnt++;
2076                   }	/* end for */
2077                 }		/* end for */
2078               break;
2079 
2080           case DFTAG_NULL:
2081           case DFTAG_FREE:
2082               for (block = file_rec->ddhead; block != NULL; block = block->next)
2083                 {
2084                     t_all_cnt += (uintn)block->ndds;
2085 
2086                     dd_ptr = block->ddlist;
2087                     for (idx = 0; idx < block->ndds; idx++, dd_ptr++)
2088                           if ((dd_ptr->tag == cnt_tag
2089                             || (special_tag != DFTAG_NULL && dd_ptr->tag == special_tag))
2090                            && (cnt_ref == DFREF_WILDCARD || dd_ptr->ref == cnt_ref))
2091                                 t_real_cnt++;
2092                 }		/* end for */
2093               break;
2094 
2095           default:
2096               if(special_tag==DFTAG_NULL)
2097                 {
2098                   for (block = file_rec->ddhead; block != NULL; block = block->next)
2099                     {
2100                         t_all_cnt += (uintn)block->ndds;
2101 
2102                         dd_ptr = block->ddlist;
2103                         for (idx = 0; idx < block->ndds; idx++, dd_ptr++)
2104                             if (dd_ptr->tag == cnt_tag
2105                              && (dd_ptr->ref == cnt_ref || cnt_ref == DFREF_WILDCARD))
2106                                   t_real_cnt++;
2107                     }		/* end for */
2108                 } /* end if */
2109               else
2110                 {
2111                   if(cnt_ref==DFREF_WILDCARD)
2112                     {
2113                       for (block = file_rec->ddhead; block != NULL; block = block->next)
2114                         {
2115                             t_all_cnt += (uintn)block->ndds;
2116 
2117                             idx=0;
2118                             dd_ptr = block->ddlist;
2119                             if(block->ndds%2 == 1)
2120                                 if (dd_ptr->tag == cnt_tag || dd_ptr->tag == special_tag)
2121                                   {
2122                                     t_real_cnt++;
2123                                     idx++;
2124                                     dd_ptr++;
2125                                   } /* end if */
2126                             for (; idx < block->ndds; idx++, dd_ptr++)
2127                               {
2128                                   if (dd_ptr->tag == cnt_tag || dd_ptr->tag == special_tag)
2129                                       t_real_cnt++;
2130                                   idx++;
2131                                   dd_ptr++;
2132                                   if (dd_ptr->tag == cnt_tag || dd_ptr->tag == special_tag)
2133                                       t_real_cnt++;
2134                               } /* end for */
2135                         }		/* end for */
2136                     } /* end if */
2137                   else
2138                     {
2139                       for (block = file_rec->ddhead; block != NULL; block = block->next)
2140                         {
2141                             t_all_cnt += (uintn)block->ndds;
2142 
2143                             dd_ptr = block->ddlist;
2144                             for (idx = 0; idx < block->ndds; idx++, dd_ptr++)
2145                                 if ((dd_ptr->tag == cnt_tag || dd_ptr->tag == special_tag)
2146                                    && dd_ptr->ref == cnt_ref)
2147                                       t_real_cnt++;
2148                         }		/* end for */
2149                     } /* end else */
2150                 } /* end else */
2151               break;
2152       } /* end switch */
2153 
2154     *all_cnt = t_all_cnt;
2155     *real_cnt = t_real_cnt;
2156     return (SUCCEED);
2157 }	/* HTIcount_dd */
2158 
2159 /*--------------------------------------------------------------------------
2160  NAME
2161     HTIregister_tag_ref -- mark a ref # as used for a tag
2162  USAGE
2163     intn HTIregister_tag_ref(file_rec, dd_ptr)
2164         filerec_t  * file_rec;        IN: file record
2165         dd_t  * dd_ptr;               IN: pointer to the dd the tag/ref is in
2166  RETURNS
2167     returns SUCCEED (0) if successful and FAIL (-1) if failed.
2168  DESCRIPTION
2169     Marks a ref # as used for a given tag.
2170 
2171 --------------------------------------------------------------------------*/
2172 static intn
HTIregister_tag_ref(filerec_t * file_rec,dd_t * dd_ptr)2173 HTIregister_tag_ref(filerec_t * file_rec, dd_t *dd_ptr)
2174 {
2175   CONSTR(FUNC, "HTIregister_tag_ref");
2176   tag_info *tinfo_ptr;  /* pointer to the info for a tag */
2177   tag_info **tip_ptr;   /* ptr to the ptr to the info for a tag */
2178   uint16 base_tag=BASETAG(dd_ptr->tag);      /* the base tag for the tag tree */
2179   int         ret_value = SUCCEED;
2180 
2181   HEclear();
2182   /* Add to the tag info tree */
2183   if((tip_ptr=(tag_info **)tbbtdfind(file_rec->tag_tree,(VOIDP)&base_tag,NULL))==NULL)
2184     {   /* a new tag was found */
2185       if((tinfo_ptr=(tag_info *)HDcalloc(1,sizeof(tag_info)))==NULL)
2186           HGOTO_ERROR(DFE_NOSPACE, FAIL);
2187       tinfo_ptr->tag=base_tag;
2188 
2189       /* Insert the tag node into the tree */
2190       tbbtdins(file_rec->tag_tree, (VOIDP) tinfo_ptr, NULL);
2191 
2192       /* Take care of the bit-vector */
2193       if((tinfo_ptr->b=bv_new(-1,BV_EXTENDABLE))==NULL)
2194           HGOTO_ERROR(DFE_BVNEW, FAIL);
2195       /* Set the 0'th bit in the bit-vector (cannot be stored in HDF files) */
2196       /* Yes, this is a kludge due to ref # zero not being used -QAK */
2197       if(bv_set(tinfo_ptr->b,0,BV_TRUE)==FAIL)
2198           HGOTO_ERROR(DFE_BVSET, FAIL);
2199 
2200       /* Take care of the dynarray */
2201       if((tinfo_ptr->d=DAcreate_array(REF_DYNARRAY_START,REF_DYNARRAY_INCR))==NULL)
2202           HGOTO_ERROR(DFE_INTERNAL, FAIL);
2203     } /* end if */
2204   else
2205     {   /* found an existing tag */
2206         intn ref_bit;    /* bit of the ref # in the tag info */
2207 
2208         tinfo_ptr=*tip_ptr; /* get the pointer to the tag info */
2209         if((ref_bit=bv_get(tinfo_ptr->b,(intn)dd_ptr->ref))==FAIL)
2210             HGOTO_ERROR(DFE_BVGET, FAIL);
2211         if(ref_bit==BV_TRUE)
2212             HGOTO_ERROR(DFE_DUPDD, FAIL);
2213     } /* end else */
2214 
2215   /* Set the bit in the bit-vector */
2216   if(bv_set(tinfo_ptr->b,(intn)dd_ptr->ref,BV_TRUE)==FAIL)
2217       HGOTO_ERROR(DFE_BVSET, FAIL);
2218 
2219   /* Insert the DD info into the dynarray for later use */
2220   if(DAset_elem(tinfo_ptr->d,(intn)dd_ptr->ref,(VOIDP)dd_ptr)==FAIL)
2221       HGOTO_ERROR(DFE_INTERNAL, FAIL);
2222 
2223 done:
2224   if(ret_value == FAIL)
2225     { /* Error condition cleanup */
2226 
2227       if(tinfo_ptr->d!=NULL)
2228           DAdestroy_array(tinfo_ptr->d,0);
2229     } /* end if */
2230 
2231   /* Normal function cleanup */
2232 
2233   return ret_value;
2234 }	/* HTIregister_tag_ref */
2235 
2236 /*--------------------------------------------------------------------------
2237  NAME
2238     HTIunregister_tag_ref -- mark a ref # as free for a tag
2239  USAGE
2240     intn HTIunregister_tag_ref(file_rec, tag, ref)
2241         filerec_t  * file_rec;        IN: file record
2242         dd_t  *dd_ptr;                IN: DD of the tag/ref to unregister
2243  RETURNS
2244     returns SUCCEED (0) if successful and FAIL (-1) if failed.
2245  DESCRIPTION
2246     Marks a ref # as free for a given tag.
2247 
2248 --------------------------------------------------------------------------*/
HTIunregister_tag_ref(filerec_t * file_rec,dd_t * dd_ptr)2249 static intn HTIunregister_tag_ref(filerec_t * file_rec, dd_t *dd_ptr)
2250 {
2251   CONSTR(FUNC, "HTIunregister_tag_ref");
2252   tag_info *tinfo_ptr;  /* pointer to the info for a tag */
2253   tag_info **tip_ptr;   /* ptr to the ptr to the info for a tag */
2254   uint16 base_tag=BASETAG(dd_ptr->tag);      /* the base tag for the tag tree */
2255   int         ret_value = SUCCEED;
2256 
2257   HEclear();
2258   /* Add to the tag info tree */
2259   if((tip_ptr=(tag_info **)tbbtdfind(file_rec->tag_tree,(VOIDP)&base_tag,NULL))==NULL)
2260     {
2261       HGOTO_ERROR(DFE_BADTAG, FAIL);
2262     } /* end if */
2263   else
2264     {   /* found an existing tag */
2265         intn ref_bit;    /* bit of the ref # in the tag info */
2266 
2267         tinfo_ptr=*tip_ptr; /* get the pointer to the tag info */
2268         if((ref_bit=bv_get(tinfo_ptr->b,(intn)dd_ptr->ref))==FAIL)
2269             HGOTO_ERROR(DFE_BVGET, FAIL);
2270         if(ref_bit==BV_FALSE)
2271             HGOTO_ERROR(DFE_INTERNAL, FAIL);
2272         if(bv_set(tinfo_ptr->b,(intn)dd_ptr->ref,BV_FALSE)==FAIL)
2273             HGOTO_ERROR(DFE_BVSET, FAIL);
2274 
2275         /* Delete the DD info from the tag tree */
2276         if(DAdel_elem(tinfo_ptr->d,(intn)dd_ptr->ref)==NULL)
2277             HGOTO_ERROR(DFE_INTERNAL, FAIL);
2278 
2279         /* Delete the tag/ref from the file */
2280         dd_ptr->tag=DFTAG_NULL;
2281     } /* end else */
2282 
2283 done:
2284   if(ret_value == FAIL)
2285     { /* Error condition cleanup */
2286 
2287     } /* end if */
2288 
2289   /* Normal function cleanup */
2290 
2291   return ret_value;
2292 }	/* HTIunregister_tag_ref */
2293 
2294 /* ---------------------------- tagcompare ------------------------- */
2295 /*
2296    Compares two tag B-tree keys for equality.  Similar to memcmp.
2297 
2298    *** Only called by B-tree routines, should _not_ be called externally ***
2299  */
2300 intn
tagcompare(VOIDP k1,VOIDP k2,intn cmparg)2301 tagcompare(VOIDP k1, VOIDP k2, intn cmparg)
2302 {
2303   intn  ret_value;
2304   /* shut compiler up */
2305   cmparg = cmparg;
2306 
2307   ret_value = ((intn) ((*(uint16 *) k1) - (*(uint16 *) k2)));    /* valid for integer keys */
2308 
2309   return ret_value;
2310 }   /* tagcompare */
2311 
2312 /* ---------------------------- tagdestroynode ------------------------- */
2313 /*
2314    Frees tag B-Tree nodes
2315 
2316    *** Only called by B-tree routines, should _not_ be called externally ***
2317  */
2318 VOID
tagdestroynode(VOIDP n)2319 tagdestroynode(VOIDP n)
2320 {
2321     tag_info *t=(tag_info *)n;
2322 
2323     if(t->b!=NULL)
2324         bv_delete(t->b);
2325     if(t->d!=NULL)
2326         DAdestroy_array(t->d,0);
2327     HDfree((VOIDP) n);
2328 }   /* tagdestroynode */
2329 
2330