/***************************************************************************** * * 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); }