/*****************************************************************************
*
* NCSA HDF version 3.10
* July 1, 1990
*
* NCSA HDF Version 3.10 source code and documentation are in the public
* domain. Specifically, we give to the public domain all rights for
future
* licensing of the source code, all resale rights, and all publishing
rights.
*
* We ask, but do not require, that the following message be included in
all
* derived works:
*
* Portions developed at the National Center for Supercomputing
Applications at
* the University of Illinois at Urbana-Champaign.
*
* THE UNIVERSITY OF ILLINOIS GIVES NO WARRANTY, EXPRESSED OR IMPLIED,
FOR THE
* SOFTWARE AND/OR DOCUMENTATION PROVIDED, INCLUDING, WITHOUT
LIMITATION,
* WARRANTY OF MERCHANTABILITY AND WARRANTY OF FITNESS FOR A PARTICULAR
PURPOSE
*
*****************************************************************************/
#ifdef RCSID
static char RcsId??(??) = "@(#)$Revision: 3.4 $"
#endif
/*
$Header: /pita/work/HDF/dev/RCS/src/df.c,v 3.4 90/06/29 10:07:31 mfolk
beta $
$Log: df.c,v $
* Revision 3.4 90/06/29 10:07:31 mfolk
* *** empty log message ***
*
* Revision 3.3 90/05/23 15:53:29 clow
* added MACRO "DF_OPENERR" to give uniform error open checking,
* especially for unbufferred I/O open
*
*/
/*-----------------------------------------------------------------------------
* File: df.c
* Purpose: HDF low level file access
* Invokes: df.h
* Contents:
* DFImemcopy: copy bytes, on machines with no memcpy equivalents
* DFopen: open HDF file
* DFclose: close HDF file
* DFIseedDDs: read data descriptors into memory
* DFIcheck: check that dfile is a valid HDF file pointer
* DFdescriptors: return a list of the data descriptors in the HDF
file
* DFnumber: count the number of occurrences of a given tag in the HDF
file
* DFsetfind: set up a search
* DFfind: search for tag/ref combination
* DFIfind: internal routine to actually perform search
* DFIemptyDD: find an empty DD in the HDF file, or create one
* DFaccess: set up a read/write on a data element
* DFstart: set up a read/write on a data element
* DFread: read a portion of a data element
* DFseek: seek to new position within data element
* DFwrite: write portion of a data element
* DFupdate: write out updated DDs to HDF file
* DFstat: provide status information about HDF file
* DFgetelement: read an entire data element
* DFputelement: write an entire data element
* DFdup: create an additional descriptor for a data element
* DFdel: delete a data element
* DFnewref: Get an unused reference number
* DFishdf: is this an HDF file?
* DFerrno: return value of DFerror
* DFIerr: close a file saving DFerror, return -1, for error
handling.
* Remarks: These are the only routines which access HDF files directly
*---------------------------------------------------------------------------*/
#define DFMASTER
#include "df.h"
#define CKMALLOC( x, ret) { if (!x) { DFerror = DFE_NOSPACE; \
return(ret); } }
#define CKSEEK(x,y,z, ret) { if (DF_SEEK( x,(long)y,z) <0) \
{DFerror = DFE_SEEKERROR; return(ret); } }
#ifdef IBM /* START JES 90 */
#define CKSEEKEND(x,y,z, ret) { rewind( x ); \
if (DF_SKEND( x,(long)y,z) <0) \
{DFerror = DFE_SEEKERROR; return(ret); } }
#else /* END JES 90 */
#define CKSEEKEND(x,y,z, ret) { if (DF_SKEND( x,(long)y,z) <0) \
{DFerror = DFE_SEEKERROR; return(ret); } }
#endif /* JES 90 */
#ifdef VMS
#define CKREAD(x,y,z,f, ret) { \
int32 currfileposn; \
currfileposn = DF_TELL(f); \
if (DF_READ( (char*)x, (int)(y), (int)(z), (f))<0) \
{ DFerror = DFE_READERROR; return(ret); } \
DF_SEEK(f, (long) (currfileposn + y*z), 0); \
}
#else /*VMS*/
#define CKREAD(x,y,z,f, ret) { \
if (DF_READ( (char*)x, (int)(y), (int)(z), (f))<0) \
{ DFerror = DFE_READERROR; return(ret); } \
}
#endif /*VMS*/
#define CKWRITE(x,y,z,f, ret) { if (DF_WRITE( (char*)x, (int)y, \
(int)z,f)<0) \
{DFerror = DFE_WRITEERROR; return(ret); } }
/*
* Important Internal Variables
*/
static DF *DFlist=NULL; /* pointer to list of open DFs */
static int DFinuse=0; /* How many are currently in use */
static uint16 DFmaxref; /* which is the largest ref used? */
static unsigned char *DFreflist=NULL; /* list of refs in use */
static char patterns??(??) = {0x80, 0x40, 0x20, 0x10, 0x08,
0x04, 0x02, 0x01};
#ifdef MAC
/*
* Macintosh file stubs for HDF
*
* Implement a subset of the C unbuffered file I/O stubs in the
* Mac toolbox.
*/
static int hdfc = 'Puf2', hdft = '_HDF';
mopen(name, flags)
char *name;
int flags;
{
short volref,rn;
GetVol(NULL,&volref);
if (flags & O_CREAT) /* we
need to create it */
create(name, volref, hdfc, hdft);
if (0 != fsopen(name, volref, &rn))
return(-1);
return(rn);
}
mclose(rn)
int rn;
{
return(FSClose(rn));
}
mread(rn, buf, n)
int rn,n;
char *buf;
{
if (0 != FSRead( rn, &n, buf))
return(-1);
return(n);
}
mwrite(rn, buf, n)
int rn,n;
char *buf;
{
if (0 != FSWrite( rn, &n, buf))
return(-1);
return(n);
}
mlseek(rn, n, m)
int rn,n,m;
{
switch(m) {
case 0:
default:
m = 1;
break;
case 1:
m = 3;
break;
case 2:
m = 2;
break;
}
if (0 != SetFPos(rn, m, n))
return(-1);
if (0 != GetFPos(rn, &n))
return(-1);
return(n);
}
#endif /* MAC */
/*-----------------------------------------------------------------------------
* Name: DFImemcopy
* Purpose: Copy bytes from one place to another
* Inputs: from, to: source and destination for copy
* length: number of bytes to copy
* Returns: 0 on success, -1 on failure with DFerror set
* Users: HDF systems programmers, on machines without memcpy
equivalents
* Remarks: assumes non-overlapping
* Intended for machines on which memcppy etc. do not work
*---------------------------------------------------------------------------*/
DFImemcopy( from, to, length)
char *from, *to;
register int length;
{
length++;
while (--length) *to++ = *from++;
return(0);
}
/*-----------------------------------------------------------------------------
* Name: DFopen
* Purpose: open DF file if it exists, else create it if write access
* Inputs: name: name of file to open
* access: DFACC_READ, DFACC_WRITE, DFACC_CREATE, DFACC_ALL
* ndds: number of dds in a block
* Returns: DF ptr to open file on success, NULL on failure with
DFerror set
* Invokes: DFIseedDDs
* Users: HDF programmers, many HDF user-level routines, utilities
* Remarks: Contains hooks for multiple DF files open simultaneously
*---------------------------------------------------------------------------*/
DF *DFopen( name, access, ndds )
char *name;
int access;
int ndds;
{
int created, i; /* created is true if file is newly
created */
/* error checking */
DFerror = DFE_NOERROR;
if (!(*name)) { /* check name */
DFerror = DFE_BADNAME;
return(NULL);
}
if ((access & (DFACC_ALL))!= access || access==0) { /* check
access */
DFerror = DFE_BADACC;
return(NULL);
}
if (DFinuse >= DF_MAXDFS) { /* is DF table filled up? */
DFerror = DFE_TOOMANY;
return(NULL);
}
/* open file, set it up */
/* set up space for list of DFs */
if (!DFlist) {
DFlist = (DF *) DFIgetspace(DF_MAXDFS * sizeof(DF));
for (i=0; i=DF_MAXDFS) { /* no free slot */
DFerror = DFE_TOOMANY;
return(NULL);
}
if (access == DFACC_CREATE)
{
created = 1;
access = DFACC_WRITE; /* equivalent to write
*/
}
else
created = 0;
/************************************************/
/* Either: the file was supposed to be created */
/* or it did not exist */
/* note that for ibm systems, if a dd statement */
/* was supplied and the file was supposed to */
/* be created then an empty one accually exists */
/************************************************/
if (created || DF_OPENERR(DFlist??(i??).file = DF_OPEN(name,
DF_RDACCESS)))
{
/*******************************************/
/* if we are supposed to be reading a file */
/* that doesnt exist then its an error */
/*******************************************/
if (access<2) /* file does not exist, check if read
access */
{
DFerror = DFE_FNF; /* file not found */
return(NULL);
}
/*******************************************/
/* issue an open to creat the file and */
/* then immediately close it */
/*******************************************/
#ifdef MAC /* JES 90 */
DF_CLOSE(DF_CREAT(name, 0666));
#else /*MAC*/ /* JES 90 */
#ifdef IBM /* JES 90 */
DF_CLOSE( DF_OPEN( name, DF_CRACCESS ) ); /* JES 90 */
#else /*IBM*/ /* JES 90 */
close (DF_CREAT( name, 0666)); /* else create the file */
#endif /*IBM*/ /* JES 90 */
#endif /*MAC*/
created=1;
}
/************************************************/
/* else if the file is not being created and */
/* does in fact exist, do this */
/* Note: on non-ibm systems, the fact that the */
/* file exists means it was previously created */
/* for ibm systems, the fact that it does exist */
/* could mean that an empty one was created via */
/* a dd statement as this job was initiated. */
/************************************************/
else
{ /* JES 90 */
#ifdef IBM /* JES 90 */
/********************************************/
/* dfacc_all means any access including */
/* create or write */
/* for non-ibm systems if dfacc_all is reall*/
/* create, the file wouldnt have been found */
/* and we would have taken care of it above */
/* for ibm systems, an empty one could have */
/* been created via a dd statement, so we */
/* can fall down here even if create was */
/* intended. */
/* in that case, we will know its create */
/* because we wont find the magic bytes */
/********************************************/
if( access == DFACC_ALL ) /* JES 90 */
{ /* JES 90 */
char magick??( 4 ??); /* JES 90 */
CKREAD( magick, 4, 1, DFlist??(i??).file, NULL); /* JES 90 */
if ( strncmp(magick,DF_MAGICK,4) ) /* JES 90 */
created = 1; /* JES 90 */
} /* JES 90 */
#endif /*IBM*/ /* JES 90 */
/*******************************************/
/* issue a close to conteract the open */
/* that happened successfully above */
/*******************************************/
DF_CLOSE(DFlist??(i??).file); /* open successful, close it */
} /* JES 90 */
/************************************************/
/* now that the file is created, */
/* open file with correct access mode */
/************************************************/
if ( DF_OPENERR(DFlist??(i??).file = DF_OPEN( name,
((access>1) ? DF_WRACCESS : DF_RDACCESS ))) )
{
DFerror = DFE_BADOPEN;
return(NULL);
}
/************************************************/
/* if the file is created, */
/* create the header DDH and DD's */
/************************************************/
if (created) /* Create a DDH and DD's for a new file */
{
DFdd dd;
DFddh ddh;
char magick??(4??);
int j;
strncpy(magick, DF_MAGICK, 4); /* magick number */
CKWRITE( magick,4,1,DFlist??(i??).file, NULL);
ddh.next=0; /* only one DDH */
if (ndds<=0)
DFlist??(i??).defdds = DF_DEFAULTDDS;
else
DFlist??(i??).defdds = ndds; /* set up number of DDs in
block */
ddh.dds = DFlist??(i??).defdds;
dd.tag=DFTAG_NULL; /* set up empty DD */
dd.ref=0; /* offset, length don't care */
#ifdef DF_STRUCTOK /* okay to write structures? */
CKWRITE( &ddh, sizeof(DFddh), 1, DFlist??(i??).file, NULL); /*
write it */
#else /*DF_STRUCTOK*/
{
register char *p;
/* copy structure into buffer, write it out */
p = DFtbuf;
INT16WRITE( p, ddh.dds); /* header */
INT32WRITE( p, ddh.next);
CKWRITE( DFtbuf, 6, 1, DFlist??(i??).file, NULL); /* 6=header
size */
}
#endif /*DF_STRUCTOK*/
for (j=0; jnext->dd??(0??)); /* first dd is in 2nd
dle */
dd->tag = DFTAG_MT;
dd->ref = DF_MT;
dd->offset = 0;
dd->length = 0;
}
DFinuse++; /* no of DF slots in use */
return( &DFlist??(i??)); /* DF file pointer */
}
/*-----------------------------------------------------------------------------
* Name: DFclose
* Purpose: Write out updated DDs, close DF file
* Inputs: dfile: pointer to open DF file
* Returns: 0 on success, -1 on failure with DFerror set
* Invokes: DFIcheck
* Users: HDF programmers, many HDF user-level routines, utilities
*---------------------------------------------------------------------------*/
int DFclose( dfile)
DF *dfile;
{
DFdle *prev, *current; /* DLEs being written out */
int i;
DFerror = DFE_NOERROR;
if ( DFIcheck(dfile)) /* is dfile a valid pointer? */
return(-1);
if (dfile->type!=1) { /* 0 is a closed file or unused
slot */
DFerror= DFE_NOTOPEN;
return(-1);
}
prev=dfile->list; /* start of DLE list */
while (current=prev->next) { /* for all DLEs */
if (dfile->changed) { /* if file modified, write it
out */
/* current DD should be written at location
prev->ddh.next */
CKSEEK( dfile->file, (long) prev->ddh.next,0, -1);
if (current->ddh.dds) { /* if any DDs to write out */
#ifdef DF_STRUCTOK
CKWRITE( ¤t->ddh, sizeof(DFddh)+
current->ddh.dds*sizeof(DFdd), 1, dfile->file, -1);
#else /*DF_STRUCTOK*/
{ /* write out dd struct elements */
register char *p;
p = DFtbuf;
INT16WRITE( p, current->ddh.dds);
INT32WRITE( p, current->ddh.next);
for (i=0; iddh.dds; i++) {
UINT16WRITE( p, current->dd??(i??).tag);
UINT16WRITE( p, current->dd??(i??).ref);
INT32WRITE( p, current->dd??(i??).offset);
INT32WRITE( p, current->dd??(i??).length);
}
CKWRITE( DFtbuf, 6+i*12, 1, dfile->file, -1);
/* 6=size of DDH, 12=size of DD */
}
#endif /*DF_STRUCTOK*/
}
}
DFIfreespace((char*)prev);
prev=current;
}
DFIfreespace((char*)prev); /* get rid of the last one */
if ( (DF_CLOSE( dfile->file)) !=0) {
DFerror = DFE_CANTCLOSE;
return(-1);
}
/* reset structure values */
dfile->last_ref= 0;
dfile->last_tag= 0;
dfile->type=0;
dfile->access=0;
dfile->file= 0;
dfile->list= (DFdle *) 0L;
DFinuse--;
return(0);
}
/*-----------------------------------------------------------------------------
* Name: DFIseedDDs
* Purpose: read DDs in file into memory
* Inputs: dfile: pointer to open DF file
* Returns: 0 on success, -1 on failure with DFerror set
* Users: HDF systems programmers, DFopen
*---------------------------------------------------------------------------*/
int DFIseedDDs(dfile)
DF *dfile;
{
DFdle *list;
DFddh ddh;
int i,n; /* n = no. of DDs in block */
DFerror = DFE_NOERROR;
if (dfile->list) {
DFerror = DFE_SEEDTWICE; /* ### NOTE: Internal error! */
return(-1);
}
dfile->list= (DFdle *) DFIgetspace(sizeof(DFdle));
/* includes one DD - unused */
CKMALLOC( dfile->list, -1);
list=dfile->list;
list->next=NULL; /* No other lists (yet) */
list->ddh.next= (int32)4L; /* next is at 4 in file */
list->ddh.dds= -1; /* flag so this is not written */
DFmaxref = 0; /* largest ref found till now is 0
*/
while (list->ddh.next) { /* while more headers to read */
CKSEEK( dfile->file, list->ddh.next, 0, -1);
/* read headers */
#ifdef DF_STRUCTOK
CKREAD( &ddh, sizeof(DFddh), 1, dfile->file, -1);
#else /*DF_STRUCTOK*/
{
register char *p;
p = DFtbuf;
CKREAD( DFtbuf, 6, 1, dfile->file, -1); /* 6 = size of
header */
INT16READ( p, ddh.dds);
INT32READ( p, ddh.next);
}
#endif /*DF_STRUCTOK*/
n =ddh.dds;
/* read in DDs */
list->next= (DFdle *)
DFIgetspace((unsigned)
(sizeof(DFdle)+ (n-1)* sizeof(DFdd)));
/* note space for 1 DD included in DLE
*/
CKMALLOC( list->next, -1);
list=list->next;
list->next=NULL;
DFmovmem((char*)&ddh, (char*)&(list->ddh),
sizeof(DFddh) ); /* Copy ddh */
if (n) {
#ifdef DF_STRUCTOK
CKREAD( &list->dd??(0??), sizeof(DFdd), n, dfile->file, -1);
/* load DD's */
#else /*DF_STRUCTOK*/
{
register char *p;
p = DFtbuf;
CKREAD( DFtbuf, n*12, 1, dfile->file, -1); /* 12=size
of DD */
for (i=0; idd??(i??).tag);
UINT16READ( p, list->dd??(i??).ref);
INT32READ( p, list->dd??(i??).offset);
INT32READ( p, list->dd??(i??).length);
}
}
#endif /*DF_STRUCTOK*/
}
/* Remember highest ref found - ignore MTs */
for (i=0; idd??(i??).ref > DFmaxref) && (list->dd??(i??).tag !=
DFTAG_MT))
DFmaxref = list->dd??(i??).ref;
}
return(0);
}
/*-----------------------------------------------------------------------------
* Name: DFIcheck
* Purpose: check if dfile argument represents a valid DF file
* Inputs: dfile: pointer to open DF file
* Returns: 0 on success, -1 on failure with DFerror set
* Users: HDF systems programmers, several routines in this file
*---------------------------------------------------------------------------*/
int DFIcheck( dfile)
DF *dfile;
{
DFerror = DFE_NOERROR;
if (!dfile) {
DFerror = DFE_DFNULL;
return(-1);
}
if ((dfile->access & DFACC_ALL) != dfile->access)
DFerror = DFE_BADACC;
if ((dfile->type >1) || (dfile->type <-1))
DFerror = DFE_ILLTYPE;
if (!dfile->list)
DFerror= DFE_BADDDLIST;
if (DFerror)
return(-1);
else
return(0);
}
/*-----------------------------------------------------------------------------
* Name: DFdescriptors
* Purpose: return a list of all the DDs in the file
* Inputs: dfile: pointer to open DF file
* ptr: pointer to space for the list of DDs
* begin, num: the list starts at DD numbered begin, and
contains
* a maximum of num entries
* Returns: number of DDs returned in the list
* Invokes: DFIcheck
* Users: HDF programmers, other routines and utilities
*---------------------------------------------------------------------------*/
int DFdescriptors(dfile, ptr, begin, num)
DF *dfile;
DFdesc ptr??(??);
int begin, num;
{
DFdle *DLEp;
int i,ddnum=0;
if ( DFIcheck(dfile))
return(-1);
if (begin<0) begin = 0;
if (num<0) num = 0;
ddnum = 0;
for (DLEp=dfile->list; DLEp; DLEp=DLEp->next)
for (i=0; iddh.dds; i++, ddnum++)
if (ddnum>=begin) {
if (ddnumdd??(i??);
}
else
return(num);
}
return(ddnum-begin);
}
/*-----------------------------------------------------------------------------
* Name: DFnumber
* Purpose: return the number of occurrences of the given tag in the
HDF file
* Inputs: dfile: pointer to open DF file
* tag: tag to count occurrences of
* Returns: number of occurrences of tag in file, -1 on error with
DFerror set
* if tag is DFTAG_WILDCARD, count occurrences of all tags
* Invokes: DFIcheck
* Users: HDF programmers, other routines and utilities
*---------------------------------------------------------------------------*/
int DFnumber(dfile, tag)
DF *dfile;
uint16 tag;
{
DFdle *DLEp;
int i, ntag=0;
if ( DFIcheck(dfile))
return(-1);
for (DLEp=dfile->list; DLEp; DLEp=DLEp->next)
if (tag==DFTAG_WILDCARD) ntag += DLEp->ddh.dds;
else {
for (i=0; iddh.dds; i++)
if (DLEp->dd??(i??).tag == tag) ntag++;
}
return(ntag);
}
/*-----------------------------------------------------------------------------
* Name: DFsetfind
* Purpose: set up parameters for a wildcard find
* Inputs: dfile: pointer to open DF file
* tag, ref: tag and ref of element to search for, 0 is
wildcard
* Returns: 0 on success, -1 on failure
* Invokes: DFIcheck
* Users: HDF programmers, several utilities
*---------------------------------------------------------------------------*/
int DFsetfind( dfile, tag, ref)
DF *dfile;
uint16 tag,ref;
{
if ( DFIcheck(dfile))
return(-1);
/* remember tag, ref for subsequent searches */
dfile->last_tag=tag;
dfile->last_ref=ref;
dfile->last_dle=NULL; /* flag value: nothing found so far
*/
return(0);
}
/*-----------------------------------------------------------------------------
* Name: DFfind
* Purpose: perform wildcard searches - sets up parameters, calls
DFIfind
* Inputs: dfile: pointer to open DF file
* ptr: ptr to put in DD when found
* Returns: 0 on success, -1 on failure
* if success, DD matching specification is copied to *ptr
* Invokes: DFIcheck, DFIfind
* Users: HDF programmers, several utilities
*---------------------------------------------------------------------------*/
int DFfind(dfile, ptr)
DF *dfile;
DFdesc *ptr;
{
DFdle *cDLEp;
int cdd;
uint16 tag, ref, ltag,lref;
int isfirst=1;
if ( DFIcheck(dfile))
return(-1);
DFerror = DFE_NOERROR;
tag = dfile->last_tag; /* tag, ref being searched for */
ref = dfile->last_ref;
if (dfile->last_dle) { /* something found previously */
isfirst = 0;
ltag= dfile->last_dle->dd??( dfile->last_dd ??).tag; /* prev
tag, ref */
lref= dfile->last_dle->dd??( dfile->last_dd ??).ref;
} else {
ltag = lref = 0;
}
if ((tag!=DFTAG_NULL) && /* empty DDs are invisible on finds
*/
!DFIfind( dfile, tag, ref, isfirst, ltag, lref, &cDLEp, &cdd))
{
*ptr = cDLEp->dd??(cdd??); /* if found, copy dd to ptr */
dfile->last_dd = cdd; /* set last_dle and last_dd to DD
found */
dfile->last_dle= cDLEp;
return(0);
} else {
DFerror = DFE_NOMATCH;
ptr->tag = 0;
ptr->ref = 0;
return(-1);
}
}
/*-----------------------------------------------------------------------------
* Name: DFIfind
* Purpose: perform wildcard searches
* Inputs: dfile: pointer to open DF file
* tag, ref: tag, ref (possibly wildcard) being searched for
* isfirst: 1 if first call to DFIfind for this tag/ref, else
0
* ltag, lref: last tag and ref returned for this search,
* don't care if isfirst set
* cDLEp, cddp: pointers to DLE and DD number to return
matched DD in
* Returns: 0 on success, -1 on failure
* if success, cDLEp and cddp are set to point to matched DD
* Users: HDF system programmers, DFfind, HDF utilities, many
routines
* Remarks: The searching algorithm is a little complex. It returns
entries
* in the sorting order of refs, then tags. Even after a
candidate
* is found, searching continues till best candidate found.
Best way
* to check if conditions: work it out independently for
yourself!
*---------------------------------------------------------------------------*/
int DFIfind( dfile, tag, ref, isfirst, ltag, lref, cDLEp, cddp)
DF *dfile;
DFdle **cDLEp;
int *cddp;
int isfirst; /* 1 if no prev search, 0
otherwise */
uint16 tag, ref, ltag, lref;
{
DFdle *DLEp;
int i, found=0;
uint16 ctag=0, cref=0, wtag,wref; /* ctag, cref: tag, ref found so
far */
/* wtag, wref: tag, ref being
checked */
DLEp=dfile->list; /* start of DLE list */
if (tag && ref) { /* No wildcards */
if (isfirst) { /* if not already found */
while (DLEp) { /* go through list */
for (i=0; iddh.dds; i++) { /* for all DDs
*/
if (DLEp->dd??(i??).tag==tag &&
DLEp->dd??(i??).ref==ref)
{*cDLEp=DLEp; *cddp=i; return(0);}
}
DLEp=DLEp->next;
}
}
}
else if (tag && !ref) /* wildcard ref */
while (DLEp) {
for (i=0; iddh.dds; i++) {
wtag=DLEp->dd??(i??).tag;
wref=DLEp->dd??(i??).ref;
/* condition = tag match, better than found so far (if any),
follows what was returned last time (if any) */
if ( (wtag==tag) && (!found || (wreflref)))
{ ctag=wtag; cref=wref; *cDLEp=DLEp;
*cddp=i;found=1;}
}
DLEp=DLEp->next;
}
else if (!tag && ref) /* wildcard tag */
while (DLEp) {
for (i=0; iddh.dds; i++) {
wtag=DLEp->dd??(i??).tag;
wref=DLEp->dd??(i??).ref;
if ((wref==ref) && (isfirst || (wtag>ltag)) &&
(!found || (wtagnext;
}
else if (!tag && !ref) /* wildcard tag & ref */
while (DLEp) {
for (i=0; iddh.dds; i++) {
wtag=DLEp->dd??(i??).tag;
wref=DLEp->dd??(i??).ref;
if ((isfirst || (wref>lref) || (wref==lref &&
wtag>ltag)) &&
(!found || (wrefnext;
}
return(found-1); /* 0 or -1 */
}
/*-----------------------------------------------------------------------------
* Name: DFIemptyDD
* Purpose: find an empty DD to use, or create a block of DDs if
necessary
* Inputs: dfile: pointer to open DF file
* Returns: pointer to an empty DD
* Invokes: DFIfind
* Users: HDF system programmers, DFaccess, DFdup
*---------------------------------------------------------------------------*/
DFdd *DFIemptyDD(dfile)
DF *dfile;
{
DFdle *cDLEp;
int cdd;
if (!DFIfind( dfile, DFTAG_NULL, DFREF_WILDCARD, 1, 0, 0, &cDLEp,
&cdd))
return(&(cDLEp->dd??(cdd??))); /* there is an empty DD */
else { /* add new DDH block */
int32 fpos;
DFdle *p, *dle;
DFddh ddh;
DFdd dd;
int j;
CKSEEKEND( dfile->file, (long) 0, 2, NULL); /* go to end of df
*/
fpos= (int32) DF_TELL(dfile->file);
ddh.dds= dfile->defdds; /* Initialize ddh */
ddh.next= 0;
dd.tag=DFTAG_NULL; /* and all DD's */
dd.ref=0;
#ifdef DF_STRUCTOK
CKWRITE( &ddh, sizeof(DFddh), 1, dfile->file, NULL);
#else /*DF_STRUCTOK*/
{
register char *p;
p = DFtbuf;
INT16WRITE( p, ddh.dds);
INT32WRITE( p, ddh.next);
CKWRITE( DFtbuf, 6, 1, dfile->file, NULL); /* 6 = size of
header */
}
#endif /*DF_STRUCTOK*/
for (j=0; jfile, NULL);
#else /*DF_STRUCTOK*/
{
register char *p;
p = DFtbuf;
UINT16WRITE( p, dd.tag);
UINT16WRITE( p, dd.tag);
INT32WRITE( p, dd.offset);
INT32WRITE( p, dd.length);
CKWRITE( DFtbuf, 12, 1, dfile->file, NULL); /* 12=size
of dd */
}
#endif /*DF_STRUCTOK*/
}
p=dfile->list; /* find end of list */
while (p->next) p= p->next;
p->ddh.next=fpos; /* new dd goes at end of
file */
dle=(DFdle *)
DFIgetspace((unsigned)
(sizeof(DFdle)+(ddh.dds-1)*sizeof(DFdd)));
/* one dd included in dle */
CKMALLOC(dle, NULL);
p->next=dle; /* insert dle at end of
list */
dle->next=NULL;
DFmovmem((char*)&ddh, (char*)&dle->ddh,sizeof(DFddh));
for (j=0; jdd??(j??), sizeof(DFdd));
return(&(dle->dd??(0??)));
}
#ifdef PC
return(NULL); /* dummy, for return value checking */
#endif /*PC*/
}
/*-----------------------------------------------------------------------------
* Name: DFaccess
* Purpose: set up read/write access to a data element
* Inputs: dfile: pointer to open DF file
* tag, ref: id of element
* access: "r", "w", "a" (append)
* Returns: 0 on success, -1 on failure
* Invokes: DFIcheck, DFIfind, DFIemptyDD
* Users: HDF programmers, utilities, DFgetelement, DFputelement
* Remarks: if "a", data element will be copied to end of file, since
it
* cannot be extended in place if it is in the middle of the
file
*---------------------------------------------------------------------------*/
int DFaccess(dfile, tag, ref, access)
DF *dfile;
uint16 tag, ref;
char *access;
{
DFdle *cDLEp;
int cdd;
char *storage=NULL; /* for copying data if append access */
char accmode;
DFerror = DFE_NOERROR;
if (DFIcheck(dfile) )
return( -1);
if (!tag) {
DFerror = DFE_BADTAG;
return(-1);
}
if (!ref) {
DFerror = DFE_BADREF;
return(-1);
}
/* set up and check access modes */
accmode = *access;
switch (accmode) {
case 'r': dfile->up_access = DFACC_READ; break;
case 'a':
case 'w': dfile->up_access = DFACC_WRITE; break;
default: DFerror = DFE_BADACC; return(-1);
}
if ((dfile->up_access & dfile->access) != dfile->up_access) {
DFerror = DFE_BADACC;
return(-1);
}
/* Find DD of element to be updated */
if (!DFIfind( dfile, tag, ref, 1, 0 , 0, &cDLEp, &cdd))
dfile->up_dd = &(cDLEp->dd??(cdd??)); /* DD of element to be
updated */
else { /* No such DD */
if (accmode=='r') {
DFerror = DFE_NOMATCH;
return(-1);
}
accmode = 'w'; /* append is really write if no current
data */
dfile->up_dd = DFIemptyDD(dfile); /* find an empty DD to
use */
if (!dfile->up_dd) return(-1);
dfile->up_dd->tag = tag; /* fill in DD block
*/
dfile->up_dd->ref = ref;
dfile->up_dd->length = 0;
}
if (accmode!='w') { /*for read, DFaccess positions fp at
element */
/* for append also, we need to read
element */
CKSEEK(dfile->file, (long) dfile->up_dd->offset, 0, -1);
}
else dfile->up_dd->length = 0; /* throws away any existing data */
if (accmode!='r') {
dfile->changed = 1; /* if write/append, file modified
*/
if ((accmode=='a') && (dfile->up_dd->length)) {
/* allocate storage to read current data */
storage =
(char*)DFIgetspace((unsigned)(dfile->up_dd->length));
CKMALLOC( storage, -1 );
CKREAD( storage, dfile->up_dd->length, 1, dfile->file,
-1);
}
CKSEEKEND( dfile->file, (long) 0, 2, -1); /* go to end of df
*/
/* find the offset of the end of file */
dfile->up_dd->offset = (int32) DF_TELL(dfile->file);
if ((accmode=='a') && dfile->up_dd->length) { /* copy old
data */
CKWRITE( storage, dfile->up_dd->length, 1, dfile->file,
-1);
/* note this leaves fp positioned correctly for write
*/
}
if (storage) DFIfreespace(storage);
}
if (DFmaxref < ref) DFmaxref = ref; /* note ref is
used */
if (DFreflist) DFreflist??(ref/8??) |= patterns??(ref%8??); /* set ref'th
bit */
return(0);
}
/*-----------------------------------------------------------------------------
* Name: DFstart
* Purpose: set up read/write access to a data element - alternate to
DFaccess
* Inputs: dfile: pointer to open DF file
* tag, ref: id of element
* access: "r", "w", "a" (append)
* Returns: 0 on success, -1 on failure
* Invokes: DFaccess
* Users: Accidental/old-time users, intending to use DFaccess
* Remarks: none
*---------------------------------------------------------------------------*/
int DFstart(dfile, tag, ref, access)
DF *dfile;
uint16 tag, ref;
char *access;
{
return(DFaccess(dfile, tag, ref, access));
}
/*-----------------------------------------------------------------------------
* Name: DFread
* Purpose: read bytes from DF file (part of element specified by
DFaccess)
* Inputs: dfile: pointer to open DF file
* ptr: pointer to space to read data into
* len: number of bytes to read
* Returns: number of bytes read on success, -1 on failure
* Invokes: DFIcheck
* Users: HDF programmers, DFgetelement
*---------------------------------------------------------------------------*/
int32 DFread( dfile, ptr, len)
DF *dfile;
char *ptr;
int32 len;
{
int32 maxlen;
#ifdef VMS
int32 totalread;
int32 readsize;
#endif /*VMS*/
DFerror = DFE_NOERROR;
if (DFIcheck(dfile) )
return( (int32) -1);
if (!dfile->up_dd) {
DFerror = DFE_BADCALL;
return((int32) -1);
}
if (!(dfile->up_access & DFACC_READ)) {
DFerror = DFE_BADACC;
return((int32) -1);
}
if (!ptr) {
DFerror = DFE_BADPTR;
return((int32) -1);
}
maxlen = dfile->up_dd->length -
((int32) DF_TELL(dfile->file) - dfile->up_dd->offset);
if (len>maxlen) len = maxlen;
if (len<0) { /* will also catch reads from beyond
element */
DFerror = DFE_BADLEN;
return(-1);
}
#ifdef VMS
totalread = 0;
while (totalread512) readsize = 512;
CKREAD( &ptr??(totalread??), (int)readsize, 1, dfile->file, -1);
totalread += readsize;
}
#else /*VMS*/
if (len) { /* NOTE: cast to (int) will limit to 64K on 16 bit
m/cs */
CKREAD( ptr, (int) len, 1, dfile->file, -1);
}
#endif /*VMS*/
return(len);
}
/*-----------------------------------------------------------------------------
* Name: DFseek
* Purpose: seek to a position, within element specified by DFaccess
* Inputs: dfile: pointer to open DF file
* offset: offset from beginning of element
* Returns: offset of actual position seek'ed to from beginning of
element
* Invokes: DFIcheck
* Users: HDF programmers
*---------------------------------------------------------------------------*/
int32 DFseek( dfile, offset)
DF *dfile;
int32 offset;
{
DFerror = DFE_NOERROR;
if (DFIcheck(dfile) )
return( -1);
if (!dfile->up_dd) {
DFerror = DFE_BADCALL;
return(-1);
}
if (!(dfile->up_access & DFACC_READ)) {
DFerror = DFE_BADACC;
return(-1);
}
if (offset > dfile->up_dd->length) {
offset = dfile->up_dd->length;
DFerror = DFE_BADSEEK;
}
CKSEEK( dfile->file, (long) dfile->up_dd->offset + offset, 0, -1);
return(offset);
}
/*-----------------------------------------------------------------------------
* Name: DFwrite
* Purpose: write bytes to DF file (part of element specified by
DFaccess)
* Inputs: dfile: pointer to open DF file
* ptr: pointer to data to be written
* len: number of bytes to written
* Returns: number of bytes written on success, -1 on failure
* Invokes: DFIcheck
* Users: HDF programmers, DFputelement
*---------------------------------------------------------------------------*/
int32 DFwrite( dfile, ptr, len)
DF *dfile;
char *ptr;
int32 len;
{
#ifdef VMS
int32 totalwritten;
int32 writesize;
#endif /*VMS*/
DFerror = DFE_NOERROR;
if (DFIcheck(dfile) )
return( -1);
if (!(dfile->up_dd)) {
DFerror = DFE_BADCALL;
return(-1);
}
if (!(dfile->up_access & DFACC_WRITE)) {
DFerror = DFE_RDONLY;
return(-1);
}
if (!ptr) {
DFerror = DFE_BADPTR;
return(-1);
}
if (len<0) {
DFerror = DFE_BADLEN;
return(-1);
}
if (!(dfile->changed)) { /* if an update between writes,
re-seek */
CKSEEK( dfile->file, (long) dfile->up_dd->offset +
dfile->up_dd->length,
0, -1);
}
#ifdef VMS
totalwritten = 0;
while (totalwritten512) writesize = 512; /* write at most 512 at a
time */
CKWRITE( &ptr??(totalwritten??), (int)writesize, 1, dfile->file,
-1);
totalwritten += writesize;
}
#else /*VMS*/
if (len) { CKWRITE( ptr, len, 1, dfile->file, -1); }
#endif /*VMS*/
dfile->up_dd->length += len;
return(len);
}
/*-----------------------------------------------------------------------------
* Name: DFupdate
* Purpose: write out updated DD blocks to file
* Inputs: dfile: pointer to open DF file
* Returns: 0 on success, -1 on failure
* Invokes: DFIcheck
* Users: HDF programmers
*---------------------------------------------------------------------------*/
int DFupdate( dfile)
DF *dfile;
{
DFdle *prev, *current;
int i;
DFerror = DFE_NOERROR;
if ( DFIcheck(dfile))
return(-1);
if (dfile->type!=1) {
DFerror= DFE_NOTOPEN;
return(-1);
}
prev=dfile->list; /* start of DLE list */
if (dfile->changed) { /* modified */
while (current=prev->next) {
CKSEEK( dfile->file, (long) prev->ddh.next,0, -1);
if (current->ddh.dds) {
#ifdef DF_STRUCTOK
CKWRITE( ¤t->ddh, sizeof(DFddh) +
(current->ddh.dds*sizeof(DFdd)), 1, dfile->file,
-1);
#else /*DF_STRUCTOK*/
{
register char *p;
p = DFtbuf;
INT16WRITE( p, current->ddh.dds);
INT32WRITE( p, current->ddh.next);
for (i=0; iddh.dds; i++) {
UINT16WRITE( p, current->dd??(i??).tag);
UINT16WRITE( p, current->dd??(i??).ref);
INT32WRITE( p, current->dd??(i??).offset);
INT32WRITE( p, current->dd??(i??).length);
}
CKWRITE( DFtbuf, 6+i*12, 1, dfile->file, -1);
/* 6= size of DDH, 12=size of DD */
}
#endif /*DF_STRUCTOK*/
}
prev=current;
}
DF_FLUSH(dfile->file); /* ensure everything is
written */
}
dfile->changed=0;
return(0);
}
/*-----------------------------------------------------------------------------
* Name: DFstat
* Purpose: provide status information about DF file
* Inputs: dfile: pointer to open DF file
* dfinfo: ptr to space where to place information on HDF file
* Returns: 0 on success, -1 on failure
* Invokes: DFIcheck
* Users: HDF programmers
*---------------------------------------------------------------------------*/
int DFstat(dfile, dfinfo)
DF *dfile;
struct DFdata *dfinfo;
{
DFerror = DFE_NOERROR;
if (DFIcheck(dfile) )
return( -1);
/* This is version number of program. More will be added later
*/
dfinfo->version = DFVERSION;
return(0);
}
/*-----------------------------------------------------------------------------
* Name: DFgetelement
* Purpose: read a data element from df file
* Inputs: dfile: pointer to open DF file
* tag, ref: id of data element
* ptr: space to put data element in
* Returns: number of bytes read on success, -1 on failure
* Invokes: DFaccess, DFread
* Users: HDF programmers, utilities, many other routines
*---------------------------------------------------------------------------*/
int32 DFgetelement( dfile, tag, ref, ptr)
DF *dfile;
uint16 tag, ref;
char *ptr;
{
if ( DFaccess( dfile, tag, ref, "r")<0) return((int32) -1);
return( DFread( dfile, ptr, (int32) dfile->up_dd->length));
}
/*-----------------------------------------------------------------------------
* Name: DFputelement
* Purpose: write a data element to df file
* Inputs: dfile: pointer to open DF file
* tag, ref: id of data element
* ptr: pointer to data element to be written
* len: length of data element
* Returns: 0 on success, -1 on failure
* Invokes: DFaccess, DFwrite
* Users: HDF programmers, utilities, many other routines
*---------------------------------------------------------------------------*/
int DFputelement( dfile, tag, ref, ptr, len)
DF *dfile;
uint16 tag, ref;
char *ptr;
int32 len;
{
if ( DFaccess( dfile, tag, ref, "w")<0) return(-1);
if( DFwrite( dfile, ptr, len)<0) return(-1);
return(0);
}
/*-----------------------------------------------------------------------------
* Name: DFdup
* Purpose: Add a new tag/ref for existing data
* Inputs: dfile: pointer to open DF file
* itag, iref: new id of data element
* otag, oref: current id of data element
* Returns: 0 on success, -1 on failure
* Invokes: DFIcheck, DFIfind, DFIemptyDD
* Users: HDF programmers, utilities, many other routines
*---------------------------------------------------------------------------*/
int DFdup(dfile, itag, iref, otag, oref)
DF *dfile;
uint16 itag, iref, otag, oref; /* new, existing tag/refs */
{
DFdle *odlep, *idlep;
int ocdd, icdd;
DFdd *newdd;
DFerror = DFE_NOERROR;
if (DFIcheck(dfile) )
return( -1);
if (DFIfind( dfile, otag, oref, 1, 0, 0, &odlep, &ocdd)<0) {
DFerror = DFE_NOMATCH; /* existing tag/ref does not exist!
*/
return(-1);
}
if (!DFIfind( dfile, itag, iref, 1, 0, 0, &idlep, &icdd))
newdd = &idlep->dd??(icdd??); /* replaces existing DD */
else {
newdd = DFIemptyDD(dfile); /* find empty DD */
if (!newdd) return(-1);
newdd->tag = itag;
newdd->ref = iref;
if (DFmaxref < iref) DFmaxref = iref; /* mark iref as
used */
if (DFreflist) DFreflist??(iref/8??) |= patterns??(iref%8??);
}
newdd->offset = odlep->dd??(ocdd??).offset;
newdd->length = odlep->dd??(ocdd??).length;
dfile->changed = 1;
return(0);
}
/*-----------------------------------------------------------------------------
* Name: DFdel
* Purpose: Delete a data element from file
* Inputs: dfile: pointer to open DF file
* tag, ref: id of data element
* Returns: 0 on success, -1 on failure
* Invokes: DFIcheck, DFIfind
* Users: HDF programmers, utilities, many other routines
* Remarks: Data element is not deleted, only the reference to it is
changed
*---------------------------------------------------------------------------*/
int DFdel(dfile, tag, ref)
DF *dfile;
uint16 tag, ref;
{
DFdle *dlep;
int cdd;
DFerror = DFE_NOERROR;
if (DFIcheck(dfile) )
return( -1);
if (DFIfind( dfile, tag, ref, 1, 0, 0, &dlep, &cdd)<0) {
DFerror = DFE_NOMATCH; /* nothing to delete */
return(-1);
}
dlep->dd??(cdd??).tag = DFTAG_NULL;
dlep->dd??(cdd??).ref = 0;
dfile->changed = 1;
return(0);
}
/*-----------------------------------------------------------------------------
* Name: DFnewref
* Purpose: Get an ununsed reference number
* Inputs: dfile: pointer to HDF file
* tag: tag for which ref is needed
* Returns: unused ref number if found. 0 with DFerror set if not.
* Users: HDF programmers, for adding data elements
* Invokes: DFIcheck
* Remarks: Currently, returns a ref which is not used with any tag,
except
* possibly DFTAG_MT
*---------------------------------------------------------------------------*/
uint16 DFnewref(dfile)
DF *dfile;
{
DFdle *DLEp;
int i,j;
DFerror = DFE_NOERROR;
if (DFIcheck(dfile) )
return ((uint16) 0);
if (DFmaxref < 65535) /* 65535 = largest 16-bit uint =
largest ref */
return(++DFmaxref);
/* allocate a bit array of 65536 bits - one for each ref */
if (DFreflist==NULL) {
if ((DFreflist = (unsigned char *) DFIgetspace(8192)) == NULL)
return((uint16) 0); /* 8192 = 65536/8 */
for (i=1; i<8192; i++) DFreflist??(i??) = 0; /* initialize */
DFreflist??(0??) = 0x80; /* ref 0 is not to be allocated
*/
for (DLEp=dfile->list; DLEp; DLEp=DLEp->next) /* go through all
DDs */
for (i=0; iddh.dds; i++)
if (DLEp->dd??(i??).tag != DFTAG_MT) /* set ref'th bit
to 1 */
DFreflist??(DLEp->dd??(i??).ref/8??) |=
patterns??(DLEp->dd??(i??).ref%8??);
}
for (i=0; i<8192; i++)
if (DFreflist??(i??) != 0xff) break; /* if ff, all refs taken */
if (i==8192) {
DFerror = DFE_NOREF;
return((uint16) 0);
}
for (j=0; j<8; j++) {
if (!(DFreflist??(i??) & patterns??(j??))) { /* ref j is not allocated
*/
DFreflist??(i??) |= patterns??(j??); /* ref j is now in use */
return((uint16) (i*8 + j)); /* ref to use */
}
}
return((uint16) 0); /* this statement should not be reached
*/
}
/*-----------------------------------------------------------------------------
* Name: DFishdf
* Purpose: Is this an HDF file?
* Inputs: filename: name of HDF file
* Returns: 0 if it is an HDF file, -1 if not. DFerror is set to open
error
* if any, else to DFE_NOERROR
* Users: HDF systems programmers, for checking files
* Invokes: DFopen, DFclose
* Remarks: none
*---------------------------------------------------------------------------*/
DFishdf(filename)
char *filename;
{
DF *dfile;
DFerror = DFE_NOERROR;
dfile = DFopen(filename, DFACC_READ, -1);
if (dfile==NULL) return(-1);
return(DFclose(dfile));
}
/*-----------------------------------------------------------------------------
* Name: DFerrno
* Purpose: return value of DFerror
* Inputs: none
* Returns: value of DFerror
* Users: HDF users, programmers
* Invokes: none
* Remarks: none
*---------------------------------------------------------------------------*/
int DFerrno()
{
return(DFerror);
}
/*-----------------------------------------------------------------------------
* Name: DFIerr
* Purpose: Close a file and return on error. save DFerror
* Inputs: dfile: pointer to HDF file to close
* Returns: -1
* Users: HDF systems programmers, for error handling
* Invokes: DFclose
* Remarks: Used to centralize some error handling
*---------------------------------------------------------------------------*/
int DFIerr(dfile)
DF *dfile;
{
int saveerror;
saveerror = DFerror;
if (dfile!=NULL) (void) DFclose(dfile);
DFerror = saveerror;
return(-1);
}