/****************************************************************************** * * NSSDC/CDF CDF library miscellaneous functions, part 1. * * Version 1.3e, 18-Nov-97, Hughes STX. * * Modification history: * * V1.0 19-Dec-94, J Love Original version. * V1.0a 29-Dec-94, J Love WriteBuffer: increment buffer pointer in the * case where the memory allocation failed. * V1.1 13-Jan-95, J Love Encode/decode changes. More cache-residency. * Allow all possible extensions on all machines. * V1.1a 19-Jan-95, J Love IRIX 6.x (64-bit). * V1.1b 24-Feb-95, J Love Solaris 2.3 IDL i/f. * V1.2 21-Mar-95, J Love POSIX. * V1.2a 18-Apr-95, J Love More POSIX. MEMLOG_. * V1.2b 19-Apr-95, J Love Memory functions moved to `cdfmem.c'. * V1.2c 7-Sep-95, J Love Corrected status codes being returned. Try * progressively smaller temporary buffers in * `WriteVarElems'. * V1.3 10-Sep-96, J Love CDF V2.6. * V1.3a 21-Feb-97, J Love Removed RICE. * V1.3b 28-Feb-97, J Love Windows NT for MS Visual C/C++ on an IBM PC. * V1.3c 11-Sep-97, J Love Magic numbers are now uInt32. * V1.3d 20-Oct-97, J Love Properly cast the uInt32 magic numbers. More * Windows NT. * V1.3e 18-Nov-97, J Love Even more Windows NT. * V2.0 08/Apr-04, M liu Replaced VSTREAM.STATS with VSTREAM_STATS. * V2.1 13-Oct-06, M Liu Changed to allow upper and lower case CDF * name to be used on win32. * ******************************************************************************/ #include "cdflib.h" #include "cdflib64.h" #include "cdfrev.h" /****************************************************************************** * CorrectV20eof. ******************************************************************************/ STATICforIDL CDFstatus CorrectV20eof (CDF) struct CDFstruct *CDF; { CDFstatus pStatus = CDF_OK; Int32 eof = 0, size, vOffset, aOffset, eOffset, nAttrs, nEntries; int varX, attrX, entryX; /**************************************************************************** * Check if CDR is last internal record. ****************************************************************************/ if (!sX(ReadCDR(CDF->fp,CDF->CDRoffset, CDR_RECORDSIZE,&size, CDR_NULL),&pStatus)) return pStatus; eof = MaxInt32 (eof, CDF->CDRoffset + size); /**************************************************************************** * Check if GDR is last internal record. ****************************************************************************/ if (!sX(ReadGDR(CDF->fp,CDF->GDRoffset, GDR_RECORDSIZE,&size, GDR_NULL),&pStatus)) return pStatus; eof = MaxInt32 (eof, CDF->GDRoffset + size); /**************************************************************************** * Scan through rVDRs checking if each is the last internal record. Note * that V2.0 CDFs won't have zVDRs, VXRs, or VVRs. ****************************************************************************/ if (!sX(ReadGDR(CDF->fp,CDF->GDRoffset, GDR_rVDRHEAD,&vOffset, GDR_NULL),&pStatus)) return pStatus; for (varX = 0; varX < CDF->NrVars; varX++) { if (!sX(ReadVDR(CDF,CDF->fp,vOffset,FALSE, VDR_RECORDSIZE,&size, VDR_NULL),&pStatus)) return pStatus; eof = MaxInt32 (eof, vOffset + size); if (!sX(ReadVDR(CDF,CDF->fp,vOffset,FALSE, VDR_VDRNEXT,&vOffset, VDR_NULL),&pStatus)) return pStatus; } /**************************************************************************** * Scan through the ADRs checking if each is the last internal record. ****************************************************************************/ if (!sX(ReadGDR(CDF->fp,CDF->GDRoffset, GDR_NUMATTR,&nAttrs, GDR_ADRHEAD,&aOffset, GDR_NULL),&pStatus)) return pStatus; for (attrX = 0; attrX < nAttrs; attrX++) { if (!sX(ReadADR(CDF->fp,aOffset, ADR_RECORDSIZE,&size, ADR_NULL),&pStatus)) return pStatus; eof = MaxInt32 (eof, aOffset + size); /************************************************************************* * Scan through the ArEDRs checking if each is the last internal record. * Note that V2.0 CDFs won't have AzEDRs. *************************************************************************/ if (!sX(ReadADR(CDF->fp,aOffset, ADR_AgrEDRHEAD,&eOffset, ADR_NgrENTRIES,&nEntries, ADR_NULL),&pStatus)) return pStatus; for (entryX = 0; entryX < nEntries; entryX++) { if (!sX(ReadAEDR(CDF->fp,eOffset, AEDR_RECORDSIZE,&size, AEDR_NULL),&pStatus)) return pStatus; eof = MaxInt32 (eof, eOffset + size); if (!sX(ReadAEDR(CDF->fp,eOffset, AEDR_AEDRNEXT,&eOffset, AEDR_NULL),&pStatus)) return pStatus; } if (!sX(ReadADR(CDF->fp,aOffset, ADR_ADRNEXT,&aOffset, ADR_NULL),&pStatus)) return pStatus; } /**************************************************************************** * Save correct EOF and return. ****************************************************************************/ if (!sX(WriteGDR(CDF->fp,CDF->GDRoffset, GDR_EOF,&eof, GDR_NULL),&pStatus)) return pStatus; return pStatus; } /****************************************************************************** * CorrectV20offsets. ******************************************************************************/ STATICforIDL CDFstatus CorrectV20offsets (CDF) struct CDFstruct *CDF; { CDFstatus pStatus = CDF_OK; Int32 zero = 0, size, vOffset, aOffset, eOffset, nAttrs, nEntries; int varX, attrX, entryX; /**************************************************************************** * Scan through rVDRs fixing the next VDR field of the last one (setting it * to an offset of zero). Note that V2.0 CDFs won't have zVDRs, VXRs, or * VVRs. ****************************************************************************/ if (!sX(ReadGDR(CDF->fp,CDF->GDRoffset, GDR_rVDRHEAD,&vOffset, GDR_NULL),&pStatus)) return pStatus; for (varX = 0; varX < CDF->NrVars; varX++) { if (!sX(ReadVDR(CDF,CDF->fp,vOffset,FALSE, VDR_RECORDSIZE,&size, VDR_NULL),&pStatus)) return pStatus; if (varX == CDF->NrVars - 1) { if (!sX(WriteVDR(CDF,CDF->fp,vOffset,FALSE, VDR_VDRNEXT,&zero, VDR_NULL),&pStatus)) return pStatus; } else { if (!sX(ReadVDR(CDF,CDF->fp,vOffset,FALSE, VDR_VDRNEXT,&vOffset, VDR_NULL),&pStatus)) return pStatus; } } /**************************************************************************** * Scan through the ADRs fixing the next ADR field of the last one (setting * it to an offset of zero). ****************************************************************************/ if (!sX(ReadGDR(CDF->fp,CDF->GDRoffset, GDR_NUMATTR,&nAttrs, GDR_ADRHEAD,&aOffset, GDR_NULL),&pStatus)) return pStatus; for (attrX = 0; attrX < nAttrs; attrX++) { if (!sX(ReadADR(CDF->fp,aOffset, ADR_RECORDSIZE,&size, ADR_NULL),&pStatus)) return pStatus; /************************************************************************* * Scan through the ArEDRs fixing the next ArEDR field of the last one * (setting it to an offset of zero). Note that V2.0 CDFs won't have * AzEDRs. *************************************************************************/ if (!sX(ReadADR(CDF->fp,aOffset, ADR_AgrEDRHEAD,&eOffset, ADR_NgrENTRIES,&nEntries, ADR_NULL),&pStatus)) return pStatus; for (entryX = 0; entryX < nEntries; entryX++) { if (!sX(ReadAEDR(CDF->fp,eOffset, AEDR_RECORDSIZE,&size, AEDR_NULL),&pStatus)) return pStatus; if (entryX == nEntries - 1) { if (!sX(WriteAEDR(CDF,CDF->fp,eOffset, AEDR_AEDRNEXT,&zero, AEDR_NULL),&pStatus)) return pStatus; } else { if (!sX(ReadAEDR(CDF->fp,eOffset, AEDR_AEDRNEXT,&eOffset, AEDR_NULL),&pStatus)) return pStatus; } } if (attrX == nAttrs - 1) { if (!sX(WriteADR(CDF->fp,aOffset, ADR_ADRNEXT,&zero, ADR_NULL),&pStatus)) return pStatus; } else { if (!sX(ReadADR(CDF->fp,aOffset, ADR_ADRNEXT,&aOffset, ADR_NULL),&pStatus)) return pStatus; } } return pStatus; } /****************************************************************************** * UpdateDotCDF. * If this routine is called when aborting a CDF, we cannot assume that * the CDF structure is complete - it may have been only partially initialized * when the CDF was aborted. If it is called to save the CDF without closing * it, the data will be properly preserved. ******************************************************************************/ STATICforIDL CDFstatus UpdateDotCDF (CDF) struct CDFstruct *CDF; { CDFstatus pStatus = CDF_OK; int varN; struct VarStruct *Var; Logical zVar; /************************************************************************** * Update r/zVariables depending on the variable type... **************************************************************************/ for (zVar = 0; zVar <= 1; zVar++) { if (BOO(zVar,CDF->zVars,CDF->rVars) != NULL) { Int32 nVars = BOO(zVar,CDF->NzVars,CDF->NrVars); for (varN = 0; varN < nVars; varN++) { Var = BOO(zVar,CDF->zVars[varN],CDF->rVars[varN]); if (Var != NULL) { switch (Var->vType) { case SPARSE_RECORDS_: { if (!sX(FlushStage(CDF,Var),&pStatus)) break; /* No `break' is intentional. */ case STANDARD_: if (Var->maxWritten < Var->maxAllocated) { Int32 padFrom = Var->maxWritten + 1; if (!sX(PadUnRecords(CDF,Var,padFrom, Var->maxAllocated),&pStatus)) break; Var->maxWritten = Var->maxAllocated; } break; } case COMPRESSED_: case SPARSE_COMPRESSED_RECORDS_: if (!sX(FlushStage(CDF,Var),&pStatus)) break; break; case SPARSE_ARRAYS_: case SPARSE_RECORDS_AND_ARRAYS_: sX (UNKNOWN_SPARSENESS, &pStatus); break; case IN_MULTI_: break; default: sX (CDF_INTERNAL_ERROR, &pStatus); break; } } } } } return pStatus; } /****************************************************************************** * CloseVarFiles. * * Close the open variable files of the specified CDF. This routine closes all * of the open variable files regardless of the number of errors detected. * * Because this routine is called when aborting a CDF, we cannot assume * that the CDF structure is complete. Eg., it may have been only partially * initialized when the CDF was aborted. ******************************************************************************/ STATICforIDL CDFstatus CloseVarFiles (CDF) struct CDFstruct *CDF; { CDFstatus pStatus = CDF_OK; struct VarStruct *Var; int varN; /**************************************************************************** * If a multi-file CDF, close the variable files. ****************************************************************************/ if (!CDF->singleFile) { /************************************************************************** * Close rVariable files. If the pointer to the rVariable is NULL, then * the rVariable has yet to be initialized (and is obviously closed). **************************************************************************/ if (CDF->rVars != NULL) { for (varN = 0; varN < CDF->NrVars; varN++) { Var = CDF->rVars[varN]; if (Var != NULL) { if (Var->fp != NULL) { if (!CLOSEv(Var->fp,NULL,NULL)) sX (VAR_CLOSE_ERROR, &pStatus); Var->fp = NULL; } } } } /************************************************************************** * Close zVariable files. If the pointer to the zVariable is NULL, then * the zVariable has yet to be initialized (and is obviously closed). **************************************************************************/ if (CDF->zVars != NULL) { for (varN = 0; varN < CDF->NzVars; varN++) { Var = CDF->zVars[varN]; if (Var != NULL) { if (Var->fp != NULL) { if (!CLOSEv(Var->fp,NULL,NULL)) sX (VAR_CLOSE_ERROR, &pStatus); Var->fp = NULL; } } } } } return pStatus; } /****************************************************************************** * WriteAccess. * Close and then reopen a CDF for read/write access (it was opened with * read-only access initially). If the CDF is earlier than CDF V2.5, then * some of the fields will have to be fixed and the CDR will be truncated for * a shorter copyright length (unless the CDF is being deleted in which case * it would be a waste of time to do these things). ******************************************************************************/ STATICforIDL Logical WriteAccess (CDF, forDelete, pStatus) struct CDFstruct *CDF; Logical forDelete; /* Is the write access is needed to delete the CDF? */ CDFstatus *pStatus; /* Returned status. */ { #if BUILD_READ_ONLY_DISTRIBUTION *pStatus = READ_ONLY_DISTRIBUTION; return FALSE; #else char pathName[DU_MAX_PATH_LEN+1]; vSTATS vStats; /*************************************************************************** * Check if write access already. ***************************************************************************/ if (CDF->status == READ_WRITE) return TRUE; /*************************************************************************** * Check if this CDF is in read-only mode. ***************************************************************************/ if (CDF->readOnly) { *pStatus = READ_ONLY_MODE; return FALSE; } /*************************************************************************** * Close (the possibly compressed) dotCDF file and the variable files (if * a multi-file CDF). An uncompressed dotCDF file and any scratch files * stay open. ***************************************************************************/ if (!CLOSEv(CDF->dotFp,NULL,&vStats)) { CDF->dotFp = NULL; AbortAccess (CDF, noUPDATE, noDELETE); return FALSE; } CDF->dotFp = NULL; AddTOvStats (&CDF->dotCDFvStats, &vStats); #if defined(DEBUG) DisplayVs (getenv("VSTREAM_STATS"), "DotCDF..", &vStats); #endif if (!sX(CloseVarFiles(CDF),pStatus)) { AbortAccess (CDF, noUPDATE, noDELETE); return FALSE; } /*************************************************************************** * Open dotCDF file with read-write access. If read-write access is not * allowed, try to return to read-only access. If reopening with read-only * access fails, free CDF structures as if CDF had been closed. ***************************************************************************/ BuildFilePath (CDFt, CDF->CDFname, CDF->no_append, CDF->upper_case_ext, CDF->version_numbers, 0L, pathName); CDF->dotFp = V_open (pathName, READ_PLUS_a_mode); if (CDF->dotFp == NULL) { CDF->dotFp = V_open (pathName, READ_ONLY_a_mode); if (CDF->dotFp == NULL) { AbortAccess (CDF, noUPDATE, noDELETE); *pStatus = CDF_OPEN_ERROR; return FALSE; } else { CDF->status = READ_ONLY; *pStatus = NO_WRITE_ACCESS; /* Don't return yet. */ } } else CDF->status = READ_WRITE; /*************************************************************************** * If the CDF is not compressed, reassign the "working" file pointer and * reset the cache size (unless deleting). If the CDF is compressed, the * cache size of the "working" file pointer does not have to be reset. ***************************************************************************/ if (CDF->uDotFp == NULL) { CDF->fp = CDF->dotFp; if (!forDelete) { if (!CACHEv(CDF->fp,CDF->workingCacheSize)) { *pStatus = BAD_CACHE_SIZE; AbortAccess (CDF, noUPDATE, noDELETE); return FALSE; } } } /*************************************************************************** * Fix various fields (if write access was obtained) unless write access * was needed to delete the CDF. ***************************************************************************/ if (CDF->status == READ_WRITE && !forDelete) { Int32 versionNew = CDF_LIBRARY_VERSION, releaseNew = CDF_LIBRARY_RELEASE, incrementNew = CDF_LIBRARY_INCREMENT; uInt32 magicNumber1 = V2magicNUMBER_1, magicNumber2 = V2magicNUMBER_2u; char copyRight[CDF_COPYRIGHT_LEN+1]; /************************************************************************* * Update magic numbers. *************************************************************************/ if (!SEEKv(CDF->fp,(long)V2_MAGIC_OFFSET_1,vSEEK_SET)) { AbortAccess (CDF, noUPDATE, noDELETE); *pStatus = CDF_WRITE_ERROR; return FALSE; } if (!Write32(CDF->fp,(Int32 *)&magicNumber1)) { AbortAccess (CDF, noUPDATE, noDELETE); *pStatus = CDF_WRITE_ERROR; return FALSE; } if (!Write32(CDF->fp,(Int32 *)&magicNumber2)) { AbortAccess (CDF, noUPDATE, noDELETE); *pStatus = CDF_WRITE_ERROR; return FALSE; } /************************************************************************* * If a V2.0 CDF, correct the EOF field. *************************************************************************/ if (CDF->badEOF) { if (!sX(CorrectV20eof(CDF),pStatus)) { AbortAccess (CDF, noUPDATE, noDELETE); return FALSE; } CDF->badEOF = FALSE; } /************************************************************************* * If a V2.0 CDF, correct the terminating offset fields. NOTE: Fix these * fields before the other "fixing" routines (which may depend on these * fields). *************************************************************************/ if (CDF->badTerminatingOffsets) { if (!sX(CorrectV20offsets(CDF),pStatus)) { AbortAccess (CDF, noUPDATE, noDELETE); return FALSE; } CDF->badTerminatingOffsets = FALSE; } /************************************************************************* * If prior to CDF V2.1.1, then change the data type associated with the * "EPOCH" rVariable/rEntries to CDF_EPOCH. *************************************************************************/ if (CDF->fakeEPOCH) { if (!sX(CorrectEPOCH(CDF),pStatus)) { AbortAccess (CDF, noUPDATE, noDELETE); return FALSE; } CDF->fakeEPOCH = FALSE; } /************************************************************************* * If prior to CDF V2.5, then truncate the CDR for a shorter copyright * field and shorten each VDR to reclaim the wasted space. *************************************************************************/ if (CDF->wastedSpace) { if (!sX(ShortenCDR(CDF),pStatus)) { AbortAccess (CDF, noUPDATE, noDELETE); return FALSE; } if (!sX(ShortenVDRs(CDF),pStatus)) { AbortAccess (CDF, noUPDATE, noDELETE); return FALSE; } CDF->wastedSpace = FALSE; } /************************************************************************* * If prior to CDF V2.5, then convert all assumed scopes to definite * scopes. *************************************************************************/ if (CDF->assumedScopes) { if (!sX(CorrectScopes(CDF),pStatus)) { AbortAccess (CDF, noUPDATE, noDELETE); return FALSE; } CDF->assumedScopes = FALSE; } /************************************************************************* * Fix blocking factors for variables having a recVary of NOVARY. *************************************************************************/ if (!sX(CorrectBlockingFactors(CDF),pStatus)) { AbortAccess (CDF, noUPDATE, noDELETE); return FALSE; } /************************************************************************* * Update version/release/increment - should never happen as for older * versioned (V2.7 and older) CDFs, we want to keep its original data * structure. *************************************************************************/ if (isLFS(CDF)) { /* It should be false all the time. */ if (!sX(WriteCDR(CDF->fp,V2_CDR_OFFSET, CDR_VERSION,&versionNew, CDR_RELEASE,&releaseNew, CDR_INCREMENT,&incrementNew, CDR_NULL),pStatus)) { AbortAccess (CDF, noUPDATE, noDELETE); return FALSE; } } /************************************************************************* * Update copyright. *************************************************************************/ CDFcopyRight (copyRight); NulPad (copyRight, CDF_COPYRIGHT_LEN); if (!sX(WriteCDR(CDF->fp,V2_CDR_OFFSET, CDR_COPYRIGHT,copyRight, CDR_NULL),pStatus)) { AbortAccess (CDF, noUPDATE, noDELETE); return FALSE; } } /*************************************************************************** * Return based on whether or not write access was obtained. ***************************************************************************/ return (CDF->status == READ_WRITE); #endif } /****************************************************************************** * WriteBuffer. * Write occurs at current offset (assumed to have been set before this * routine is called). On IBM PCs, it is assumed that `nBytes' will not * exceed 65535. ******************************************************************************/ STATICforIDL CDFstatus WriteBuffer (CDF, fp, dataType, numElems, buffer) struct CDFstruct *CDF; vFILE *fp; Int32 dataType; Int32 numElems; void *buffer; { CDFstatus pStatus = CDF_OK; size_t nElemBytes = CDFelemSize(dataType); size_t nBytes = (size_t) (numElems * nElemBytes); double eValue; Int32 elemN; Byte *ptr; void *tBuffer; /**************************************************************************** * Try to encode/write entire buffer. ****************************************************************************/ tBuffer = cdf_AllocateMemory (nBytes, NULL); if (tBuffer != NULL) { if (!sX(ConvertBuffer(HostEncoding(),CDF->encoding,CDF->negToPosFp0, dataType,numElems,buffer,tBuffer),&pStatus)) { cdf_FreeMemory (tBuffer, NULL); return pStatus; } if (!WRITEv(tBuffer,1,nBytes,fp)) { cdf_FreeMemory (tBuffer, NULL); return CDF_WRITE_ERROR; } cdf_FreeMemory (tBuffer, NULL); return pStatus; } /**************************************************************************** * If that failed, encode/write one element at a time. ****************************************************************************/ for (elemN = 0, ptr = buffer; elemN < numElems; elemN++, ptr += nElemBytes) { if (!sX(ConvertBuffer(HostEncoding(),CDF->encoding, CDF->negToPosFp0,dataType,1L,ptr, &eValue),&pStatus)) return pStatus; if (!WRITEv(&eValue,1,nElemBytes,fp)) return CDF_WRITE_ERROR; } return pStatus; } /****************************************************************************** * NegativeZeroReal4. * Checks for -0.0 (on any type computer). Assumed to be in host encoding. ******************************************************************************/ VISIBLE_PREFIX Logical NegativeZeroReal4 (value) float *value; { #if defined(FP1cpu) || defined(FP2cpu) return (*((uInt32 *) value) == (uInt32) 0x80000000); #endif #if defined(FP3cpu) || defined(FP4cpu) /**************************************************************************** * On VAXes and DEC Alphas running OpenVMS/POSIXshell we're only interested * in the sign bit and exponent. ****************************************************************************/ return ((*((uInt32 *) value) & (uInt32) 0x0000FF80) == (uInt32) 0x00008000); #endif } /****************************************************************************** * NegativeZeroReal8. * Checks for -0.0 (on any type computer). Assumed to be in host encoding. ******************************************************************************/ VISIBLE_PREFIX Logical NegativeZeroReal8 (value) double *value; { #if defined(FP1cpu) return ((*((uInt32 *) value) == (uInt32) 0x80000000) && (*((uInt32 *) value+1) == (uInt32) 0x00000000)); #endif #if defined(FP2cpu) return ((*((uInt32 *) value) == (uInt32) 0x00000000) && (*((uInt32 *) value+1) == (uInt32) 0x80000000)); #endif #if defined(FP3cpu) /**************************************************************************** * On VAXes and DEC Alphas running OpenVMS/POSIXshell in D_FLOAT mode we're * only interested in the sign bit and exponent (which are in the first * longword [32-bit]). ****************************************************************************/ return ((*((uInt32 *) value) & (uInt32) 0x0000FF80) == (uInt32) 0x00008000); #endif #if defined(FP4cpu) /**************************************************************************** * On DEC Alphas running OpenVMS/POSIXshell in G_FLOAT mode we're only * interested in the sign bit and exponent (which are in the first longword * [32-bit]). ****************************************************************************/ return ((*((uInt32 *) value) & (uInt32) 0x0000FFF0) == (uInt32) 0x00008000); #endif } /****************************************************************************** * StripTrailingBlanks. ******************************************************************************/ STATICforIDL void StripTrailingBlanks (string) char *string; { int i; for (i = strlen(string) - 1; i >= 0 && string[i] == ' '; i--) { string[i] = NUL; } return; } /****************************************************************************** * MakeUpperString. * Convert string to upper-case. ******************************************************************************/ VISIBLE_PREFIX void MakeUpperString (string) char *string; { int i; for (i = 0; string[i] != NUL; i++) { string[i] = (char) MakeUpper((int)string[i]); } return; } /****************************************************************************** * MakeLowerString. * Convert string to lower-case. ******************************************************************************/ VISIBLE_PREFIX void MakeLowerString (string) char *string; { int i; for (i = 0; string[i] != NUL; i++) { string[i] = (char) MakeLower((int)string[i]); } return; } /****************************************************************************** * SetBit32. ******************************************************************************/ STATICforIDL void SetBit32 (value, bit) Int32 *value; int bit; { *value = *value | (1 << bit); return; } /****************************************************************************** * ClearBit32. ******************************************************************************/ STATICforIDL void ClearBit32 (value, bit) Int32 *value; int bit; { *value = *value & ~(1 << bit); return; } /****************************************************************************** * FindCDF. * Tries various extensions on the specified CDF path to see if the CDF * exists. The extensions tried are those which should be present on the * various platforms plus the extensions which might be generated by a CD-ROM * driver. Finally, the pathname is tried without an extension being added * in case the CDF had been renamed with a different extension or no extension. ******************************************************************************/ STATICforIDL CDFstatus FindCDF (path, no_append, upper, version) char *path; /* Base pathname. */ Logical *no_append; /* Should extensions/version numbers be appended? */ Logical *upper; /* Should extensions be upper case? */ Logical *version; /* Should a version number of `;1' be appended? */ { char pathT[DU_MAX_PATH_LEN+1]; strcpyX (pathT, path, DU_MAX_PATH_LEN); strcatX (pathT, ".cdf", DU_MAX_PATH_LEN); if (IsReg(pathT)) { *no_append = FALSE; *upper = FALSE; *version = FALSE; return CDF_OK; } strcpyX (pathT, path, DU_MAX_PATH_LEN); strcatX (pathT, ".CDF", DU_MAX_PATH_LEN); if (IsReg(pathT)) { *no_append = FALSE; *upper = TRUE; *version = FALSE; return CDF_OK; } strcpyX (pathT, path, DU_MAX_PATH_LEN); strcatX (pathT, ".cdf;1", DU_MAX_PATH_LEN); if (IsReg(pathT)) { *no_append = FALSE; *upper = FALSE; *version = TRUE; return CDF_OK; } strcpyX (pathT, path, DU_MAX_PATH_LEN); strcatX (pathT, ".CDF;1", DU_MAX_PATH_LEN); if (IsReg(pathT)) { *no_append = FALSE; *upper = TRUE; *version = TRUE; return CDF_OK; } #if defined(unix) || defined(dos) strcpyX (pathT, path, DU_MAX_PATH_LEN); MakeUpperString (pathT); strcatX (pathT, ".CDF", DU_MAX_PATH_LEN); if (IsReg(pathT)) { *no_append = FALSE; *upper = TRUE; *version = FALSE; return CDF_OK; } strcpyX (pathT, path, DU_MAX_PATH_LEN); MakeUpperString (pathT); if (IsReg(pathT)) { *no_append = TRUE; *upper = TRUE; *version = FALSE; return CDF_OK; } #endif if (IsReg(path)) { *no_append = TRUE; *upper = FALSE; *version = FALSE; return CDF_OK; } return NO_SUCH_CDF; } /****************************************************************************** * BuildFilePath. ******************************************************************************/ STATICforIDL void BuildFilePath (fileType, pathBase, noAppend, upperCase, versionNumber, varN, pathX) int fileType; /* Type of file. */ char *pathBase; /* Base pathname. */ Logical noAppend; /* Should extensions/version numbers be appended? */ Logical upperCase; /* Should uppercase extensions be appended? */ Logical versionNumber; /* Should a version number of `;1' be appended? */ Int32 varN; /* Variable number. N/a if a `cdf' file. */ char pathX[DU_MAX_PATH_LEN+1]; /* The expanded path w/ extensions/version numbers. */ { ExpandPath (pathBase, pathX); if (!noAppend) { switch (fileType) { case CDFt: strcatX (pathX, (upperCase ? ".CDF" : ".cdf"), DU_MAX_PATH_LEN); break; case Vt: strcatX (pathX, (upperCase ? ".V" : ".v"), DU_MAX_PATH_LEN); sprintf (EofS(pathX), "%d", varN); break; case Zt: strcatX (pathX, (upperCase ? ".Z" : ".z"), DU_MAX_PATH_LEN); sprintf (EofS(pathX), "%d", varN); break; } strcatX (pathX, (versionNumber ? ";1" : ""), DU_MAX_PATH_LEN); } return; } /****************************************************************************** * NulPad. * Pads with NUL characters to the length specified. Also NUL-terminates * the string. ******************************************************************************/ STATICforIDL void NulPad (string, length) char *string; int length; { int i; for (i = strlen(string); i < length; i++) string[i] = NUL; string[length] = NUL; return; } /****************************************************************************** * UpdateMaxRec. ******************************************************************************/ STATICforIDL CDFstatus UpdateMaxRec (CDF, Var, recNum) struct CDFstruct *CDF; /* In: Pointer to CDF. */ struct VarStruct *Var; /* In: Pointer to variable. */ Int32 recNum; /* In: Possible new maximum record number. */ { CDFstatus pStatus = CDF_OK; if (recNum > Var->maxRec) { Var->maxRec = recNum; if (!sX(WriteVDR(CDF,CDF->fp,Var->VDRoffset,Var->zVar, VDR_MAXREC,&recNum, VDR_NULL),&pStatus)) return pStatus; } if (!Var->zVar) { if (recNum > CDF->rMaxRec) { CDF->rMaxRec = recNum; if (!sX(WriteGDR(CDF->fp,CDF->GDRoffset, GDR_rMAXREC,&recNum, GDR_NULL),&pStatus)) return pStatus; } } return pStatus; } /****************************************************************************** * CalcDimParms. * Calculates a variable's number of dimensions, dimension sizes, and * dimension variances depending on the current zMode. ******************************************************************************/ STATICforIDL CDFstatus CalcDimParms (CDF, offset, zVar, numDimsP, dimSizesP, dimVarysP) struct CDFstruct *CDF; /* In: Pointer to CDF. */ Int32 offset; /* In: Offset of VDR. */ Logical zVar; /* In: TRUE if a true zVariable. FALSE if a true rVariable. */ Int32 *numDimsP; /* Out: Number of dimensions. */ Int32 dimSizesP[]; /* Out: Dimension sizes. */ Int32 dimVarysP[]; /* Out: Dimension variances. */ { CDFstatus pStatus = CDF_OK; int dN; Int32 tNumDims, tDimSizes[CDF_MAX_DIMS], tDimVarys[CDF_MAX_DIMS]; Int32 numDims, dimSizes[CDF_MAX_DIMS], dimVarys[CDF_MAX_DIMS]; /**************************************************************************** * Determine `true' parameters. ****************************************************************************/ if (zVar) { if (!sX(ReadVDR(CDF,CDF->fp,offset,TRUE, VDR_zNUMDIMS,&tNumDims, VDR_zDIMSIZES,tDimSizes, VDR_DIMVARYS,tDimVarys, VDR_NULL),&pStatus)) return pStatus; } else { if (!sX(ReadGDR(CDF->fp,CDF->GDRoffset, GDR_rNUMDIMS,&tNumDims, GDR_rDIMSIZES,tDimSizes, GDR_NULL),&pStatus)) return pStatus; if (!sX(ReadVDR(CDF,CDF->fp,offset,FALSE, VDR_DIMVARYS,tDimVarys, VDR_NULL),&pStatus)) return pStatus; } /**************************************************************************** * Determine parameters based on zMode and if r/zVariable. ****************************************************************************/ if (CDF->zMode == zMODEon2 && !zVar) { for (dN = 0, numDims = 0; dN < tNumDims; dN++) { if (tDimVarys[dN]) { dimSizes[(int)numDims] = tDimSizes[dN]; dimVarys[(int)numDims] = VARY; numDims++; } } } else { numDims = tNumDims; for (dN = 0; dN < tNumDims; dN++) { dimSizes[dN] = tDimSizes[dN]; dimVarys[dN] = tDimVarys[dN]; } } /**************************************************************************** * Assign those values requested. ****************************************************************************/ ASSIGNnotNULL (numDimsP, numDims) ASSIGNnotNULLarray (dimSizesP, numDims, dimSizes) ASSIGNnotNULLarray (dimVarysP, numDims, dimVarys) return pStatus; } /****************************************************************************** * NULterminateMAX. * NUL-terminate a string but only if a NUL is not found before the maximum * length is reached. ******************************************************************************/ STATICforIDL void NULterminateMAX (string, maxLen) char *string; size_t maxLen; { int i; for (i = 0; i < (int) maxLen; i++) if (string[i] == NUL) return; string[maxLen] = NUL; return; } /****************************************************************************** * ClearBytes. ******************************************************************************/ VISIBLE_PREFIX void ClearBytes (buffer, firstByte, lastByte) void *buffer; int firstByte; int lastByte; { int i; for (i = firstByte; i <= lastByte; i++) ((Byte *)buffer)[i] = 0; return; } /****************************************************************************** * WasteIR. ******************************************************************************/ STATICforIDL CDFstatus WasteIR (CDF, wasteOffset, size) struct CDFstruct *CDF; Int32 wasteOffset; Int32 size; { CDFstatus pStatus = CDF_OK; struct UIRstruct newUIR, firstUIR, tUIR, nextUIR; Int32 tOffset, nextOffset, UIRhead; /**************************************************************************** * Begin initializing UIR. ****************************************************************************/ newUIR.RecordSize = size; newUIR.RecordType = UIR_; /**************************************************************************** * Check that the internal record being wasted is big enough for the `next' * and `previous' fields. If not, mark it as wasted but don't place it in * the linked list of UIRs. Note that there will always be enough room for * the `size' and `type' fields. If not, an internal logic error has occured. ****************************************************************************/ if (size < UIR_BASE_SIZE) { if (size < UUIR_BASE_SIZE) return CDF_INTERNAL_ERROR; if (!sX(WriteUIR(CDF->fp,wasteOffset, UIR_RECORDSIZE,&(newUIR.RecordSize), UIR_RECORDTYPE,&(newUIR.RecordType), UIR_NULL),&pStatus)) return pStatus; return pStatus; } /**************************************************************************** * Read offset of first UIR. ****************************************************************************/ if (!sX(ReadGDR(CDF->fp,CDF->GDRoffset, GDR_UIRHEAD,&UIRhead, GDR_NULL),&pStatus)) return pStatus; /**************************************************************************** * Check if no UIRs exist yet. ****************************************************************************/ if (UIRhead == 0) { newUIR.NextUIR = 0; newUIR.PrevUIR = 0; if (!sX(WriteUIR(CDF->fp,wasteOffset, UIR_RECORD,&newUIR, UIR_NULL),&pStatus)) return pStatus; UIRhead = wasteOffset; if (!sX(WriteGDR(CDF->fp,CDF->GDRoffset, GDR_UIRHEAD,&UIRhead, GDR_NULL),&pStatus)) return pStatus; return pStatus; } /**************************************************************************** * At least one UIR exists, check if the new UIR is before the first UIR. ****************************************************************************/ if (wasteOffset < UIRhead) { if (!sX(ReadUIR(CDF->fp,UIRhead, UIR_RECORD,&firstUIR, UIR_NULL),&pStatus)) return pStatus; newUIR.NextUIR = UIRhead; newUIR.PrevUIR = 0; if (!sX(WriteUIR(CDF->fp,wasteOffset, UIR_RECORD,&newUIR, UIR_NULL),&pStatus)) return pStatus; firstUIR.PrevUIR = wasteOffset; if (!sX(WriteUIR(CDF->fp,UIRhead, UIR_RECORD,&firstUIR, UIR_NULL),&pStatus)) return pStatus; UIRhead = wasteOffset; if (!sX(WriteGDR(CDF->fp,CDF->GDRoffset, GDR_UIRHEAD,&UIRhead, GDR_NULL),&pStatus)) return pStatus; return pStatus; } /**************************************************************************** * The new UIR is not before the first UIR. Scan the UIRs to find the point * at which it should be inserted. ****************************************************************************/ tOffset = UIRhead; if (!sX(ReadUIR(CDF->fp,tOffset, UIR_RECORD,&tUIR, UIR_NULL),&pStatus)) return pStatus; while (tUIR.NextUIR != 0) { if (wasteOffset < tUIR.NextUIR) { nextOffset = tUIR.NextUIR; if (!sX(ReadUIR(CDF->fp,nextOffset, UIR_RECORD,&nextUIR, UIR_NULL),&pStatus)) return pStatus; newUIR.NextUIR = tUIR.NextUIR; newUIR.PrevUIR = tOffset; if (!sX(WriteUIR(CDF->fp,wasteOffset, UIR_RECORD,&newUIR, UIR_NULL),&pStatus)) return pStatus; tUIR.NextUIR = wasteOffset; if (!sX(WriteUIR(CDF->fp,tOffset, UIR_RECORD,&tUIR, UIR_NULL),&pStatus)) return pStatus; nextUIR.PrevUIR = wasteOffset; if (!sX(WriteUIR(CDF->fp,nextOffset, UIR_RECORD,&nextUIR, UIR_NULL),&pStatus)) return pStatus; return pStatus; } tOffset = tUIR.NextUIR; if (!sX(ReadUIR(CDF->fp,tOffset, UIR_RECORD,&tUIR, UIR_NULL),&pStatus)) return pStatus; } /**************************************************************************** * The new UIR is going to be the last UIR. ****************************************************************************/ newUIR.NextUIR = 0; newUIR.PrevUIR = tOffset; if (!sX(WriteUIR(CDF->fp,wasteOffset, UIR_RECORD,&newUIR, UIR_NULL),&pStatus)) return pStatus; tUIR.NextUIR = wasteOffset; if (!sX(WriteUIR(CDF->fp,tOffset, UIR_RECORD,&tUIR, UIR_NULL),&pStatus)) return pStatus; return pStatus; } /****************************************************************************** * AllocateIR. ******************************************************************************/ STATICforIDL CDFstatus AllocateIR (CDF, size, offset) struct CDFstruct *CDF; /* In: Pointer to CDF. */ Int32 size; /* In: Size of internal record (bytes). */ Int32 *offset; /* Out: Offset of allocated internal record. */ { CDFstatus pStatus = CDF_OK; Int32 sOffset, eOffset, tSize, UIRhead, eof, uir_ = UIR_; struct UIRstruct sUIR, eUIR; /**************************************************************************** * Read EOF and offset of first UIR from GDR. ****************************************************************************/ if (!sX(ReadGDR(CDF->fp,CDF->GDRoffset, GDR_UIRHEAD,&UIRhead, GDR_EOF,&eof, GDR_NULL),&pStatus)) return pStatus; /**************************************************************************** * If UIRs exist, try to use one or more of them (if contiguous) for the new * internal record. ****************************************************************************/ if (UIRhead != 0) { sOffset = UIRhead; if (!sX(ReadUIR(CDF->fp,sOffset, UIR_RECORD,&sUIR, UIR_NULL),&pStatus)) return pStatus; eOffset = sOffset; eUIR = sUIR; tSize = sUIR.RecordSize; for (;;) { /*********************************************************************** * Check if the starting to ending UIRs are the exact size needed. ***********************************************************************/ if (size == tSize) { if (!sX(RemoveUIRs(CDF,sOffset,eOffset),&pStatus)) return pStatus; if (!sX(WriteIrSize(CDF->fp,sOffset,&size),&pStatus)) return pStatus; if (!sX(WriteIrType(CDF->fp,sOffset,&uir_),&pStatus)) return pStatus; *offset = sOffset; return pStatus; } /*********************************************************************** * Check if the starting to ending UIRs are big enough for the new * internal record and for a new UIR to fill the remaining space. ***********************************************************************/ if (size + UIR_BASE_SIZE <= tSize) { if (!sX(RemoveUIRs(CDF,sOffset,eOffset),&pStatus)) return pStatus; if (!sX(WasteIR(CDF,sOffset+size,tSize-size),&pStatus)) { return pStatus; } if (!sX(WriteIrSize(CDF->fp,sOffset,&size),&pStatus)) return pStatus; if (!sX(WriteIrType(CDF->fp,sOffset,&uir_),&pStatus)) return pStatus; *offset = sOffset; return pStatus; } /*********************************************************************** * Check if the end of the UIRs has been reached. If so, check if the * ending UIR is the last IR in the dotCDF file. ***********************************************************************/ if (eUIR.NextUIR == 0) { if (eOffset + eUIR.RecordSize == eof) { /******************************************************************* * The ending UIR is the last internal record in the CDF. Check to * see if after allocating the new internal record less than * UIR_BASE_SIZE bytes will remain before the EOF. If so, waste an * internal record at the location of those bytes so that a UIR is * at the end (rather than stranded bytes). *******************************************************************/ if (!sX(RemoveUIRs(CDF,sOffset,eOffset),&pStatus)) return pStatus; if (size < tSize) { if (!sX(WasteIR(CDF,sOffset+size, UIR_BASE_SIZE),&pStatus)) return pStatus; eof = sOffset + size + UIR_BASE_SIZE; } else eof = sOffset + size; if (!sX(WriteGDR(CDF->fp,CDF->GDRoffset, GDR_EOF,&eof, GDR_NULL),&pStatus)) return pStatus; if (!sX(WriteIrSize(CDF->fp, sOffset, &size),&pStatus)) return pStatus; if (!sX(WriteIrType(CDF->fp, sOffset, &uir_),&pStatus)) return pStatus; *offset = sOffset; return pStatus; } else { /******************************************************************* * Non-UIRs follow the ending UIR. The new internal record will * have to be allocated at the EOF. *******************************************************************/ *offset = eof; if (!sX(WriteIrSize(CDF->fp,eof,&size),&pStatus)) return pStatus; if (!sX(WriteIrType(CDF->fp,eof,&uir_),&pStatus)) return pStatus; eof += size; if (!sX(WriteGDR(CDF->fp,CDF->GDRoffset, GDR_EOF,&eof, GDR_NULL),&pStatus)) return pStatus; return pStatus; } } /*********************************************************************** * If the next UIR is contiguous with the ending UIR, make it the ending * UIR. Otherwise, make the next UIR the starting and ending UIRs. ***********************************************************************/ if (eOffset + eUIR.RecordSize == eUIR.NextUIR) { eOffset = eUIR.NextUIR; if (!sX(ReadUIR(CDF->fp,eOffset, UIR_RECORD,&eUIR, UIR_NULL),&pStatus)) return pStatus; tSize += eUIR.RecordSize; } else { sOffset = eUIR.NextUIR; if (!sX(ReadUIR(CDF->fp,sOffset, UIR_RECORD,&sUIR, UIR_NULL),&pStatus)) return pStatus; eOffset = sOffset; eUIR = sUIR; tSize = sUIR.RecordSize; } } } /**************************************************************************** * No UIRs exist. The new internal record will have to be allocated at the * EOF. ****************************************************************************/ *offset = eof; if (!sX(WriteIrSize(CDF->fp,eof,&size),&pStatus)) return pStatus; if (!sX(WriteIrType(CDF->fp,eof,&uir_),&pStatus)) return pStatus; eof += size; if (!sX(WriteGDR(CDF->fp,CDF->GDRoffset, GDR_EOF,&eof, GDR_NULL),&pStatus)) return pStatus; return pStatus; } /****************************************************************************** * ResizeIR. ******************************************************************************/ STATICforIDL CDFstatus ResizeIR (CDF, curOffset, newSize, newOffset, move, success) struct CDFstruct *CDF; Int32 curOffset; /* In: Current offset of internal record. */ Int32 newSize; /* In: New size of internal record. This may be smaller or larger than the current size. */ Int32 *newOffset; /* Out: New offset of internal record. This variable is not modified if an error occurs or the internal record cannot be extended (when `move' is FALSE). */ Logical move; /* In: TRUE if the internal record can be moved if necessary. */ Logical *success; /* Out: TRUE if the internal record was successfully extended (whether or not it had to be moved). */ { CDFstatus pStatus = CDF_OK; Int32 curSize; Int32 eof; /**************************************************************************** * Determine current size of internal record. ****************************************************************************/ if (!sX(ReadIrSize(CDF->fp,curOffset,&curSize),&pStatus)) return pStatus; /**************************************************************************** * Check sizes... ****************************************************************************/ if (newSize > curSize) { /************************************************************************** * The internal record is growing. First check if it is the last one in * the CDF. **************************************************************************/ if (!sX(ReadGDR(CDF->fp,CDF->GDRoffset, GDR_EOF,&eof, GDR_NULL),&pStatus)) return pStatus; if (curOffset + curSize == eof) { /************************************************************************ * Last internal record. Simply extend the CDF. ************************************************************************/ ASSIGNnotNULL (newOffset, curOffset) eof += (newSize - curSize); if (!sX(WriteGDR(CDF->fp,CDF->GDRoffset, GDR_EOF,&eof, GDR_NULL),&pStatus)) return pStatus; if (!sX(WriteIrSize(CDF->fp, curOffset, &newSize),&pStatus)) return pStatus; ASSIGNnotNULL (success, TRUE) return pStatus; } else { /************************************************************************ * Not the last internal record. If the internal record may be moved, * first mark it as unused and then allocate a new internal record. * Marking it unused first allows the possibility that if will be used * as part of the allocated internal record. If the internal record can * not be moved, check if unused records immediately follow. ************************************************************************/ if (move) { if (!sX(WasteIR(CDF,curOffset,curSize),&pStatus)) return pStatus; if (!sX(AllocateIR(CDF,newSize,newOffset),&pStatus)) return pStatus; ASSIGNnotNULL (success, TRUE) return pStatus; } else { Int32 sOffset, eOffset, tSize, UIRhead, irType; struct UIRstruct sUIR, eUIR; /********************************************************************** * First check if there are any UIRs in the CDF. This is done because * CDF V2.5.0* (alpha/beta) created UIRs without the next and previous * UIR fields and didn't use the `UIRhead' field in the GDR. Because * we don't want to use UIRs in those CDFs (because they are not the * same as the current UIRs), this will keep us from doing so (because * the `UIRhead' fields will always contain zero if a V2.5.0* CDF). **********************************************************************/ if (!sX(ReadGDR(CDF->fp,CDF->GDRoffset, GDR_UIRHEAD,&UIRhead, GDR_NULL),&pStatus)) return pStatus; if (UIRhead == 0) { ASSIGNnotNULL (success, FALSE) return pStatus; } /********************************************************************** * Read the internal record which immediately follows the internal * record being resized. If it is a UIR make it the starting UIR. * ---------------------------- DANGER --------------------------------- * Don't try to read an entire UIR. First read only the record type * field and check if it is UIR_. Then read the entire UIR. This is * because the next internal record could be smaller than a UIR (or * larger but not entirely written yet [eg. a VVR]). **********************************************************************/ sOffset = curOffset + curSize; if (!sX(ReadIrType(CDF->fp,sOffset,&irType),&pStatus)) return pStatus; if (irType != UIR_) { ASSIGNnotNULL (success, FALSE) return pStatus; } if (!sX(ReadUIR(CDF->fp,sOffset, UIR_RECORD,&sUIR, UIR_NULL),&pStatus)) return pStatus; tSize = curSize + sUIR.RecordSize; eOffset = sOffset; eUIR = sUIR; for (;;) { /******************************************************************* * Check if the exact amount of available space has been found. *******************************************************************/ if (newSize == tSize) { if (!sX(RemoveUIRs(CDF,sOffset,eOffset),&pStatus)) return pStatus; if (!sX(WriteIrSize(CDF->fp, curOffset, &newSize),&pStatus)) return pStatus; ASSIGNnotNULL (newOffset, curOffset) ASSIGNnotNULL (success, TRUE) return pStatus; } /******************************************************************* * Check if enough available space has been found to increase the * internal record and then create a new UIR in the remaining space. *******************************************************************/ if (newSize + UIR_BASE_SIZE <= tSize) { if (!sX(RemoveUIRs(CDF,sOffset,eOffset),&pStatus)) return pStatus; if (!sX(WasteIR(CDF,curOffset+newSize,tSize-newSize),&pStatus)) { return pStatus; } if (!sX(WriteIrSize(CDF->fp, curOffset, &newSize),&pStatus)) return pStatus; ASSIGNnotNULL (newOffset, curOffset) ASSIGNnotNULL (success, TRUE) return pStatus; } /******************************************************************* * Check if the end of the UIRs has been reached. *******************************************************************/ if (eUIR.NextUIR == 0) { /***************************************************************** * If the ending UIR is at the EOF, then the internal record can * be extended beyond the EOF or up to it with the creation of a * new UIR at the very end. *****************************************************************/ if (eOffset + eUIR.RecordSize == eof) { if (!sX(RemoveUIRs(CDF,sOffset,eOffset),&pStatus)) return pStatus; if (newSize < tSize) { if (!sX(WasteIR(CDF,curOffset+newSize, UIR_BASE_SIZE),&pStatus)) return pStatus; eof = curOffset + newSize + UIR_BASE_SIZE; } else eof = curOffset + newSize; if (!sX(WriteGDR(CDF->fp,CDF->GDRoffset, GDR_EOF,&eof, GDR_NULL),&pStatus)) return pStatus; if (!sX(WriteIrSize(CDF->fp, curOffset, &newSize),&pStatus)) return pStatus; ASSIGNnotNULL (newOffset, curOffset) ASSIGNnotNULL (success, TRUE) return pStatus; } else { ASSIGNnotNULL (success, FALSE) return pStatus; } } /******************************************************************* * If the next UIR is contiguous with the ending UIR, make it the * ending UIR. *******************************************************************/ if (eOffset + eUIR.RecordSize == eUIR.NextUIR) { eOffset = eUIR.NextUIR; if (!sX(ReadUIR(CDF->fp,eOffset, UIR_RECORD,&eUIR, UIR_NULL),&pStatus)) return pStatus; tSize += eUIR.RecordSize; } else { ASSIGNnotNULL (success, FALSE) return pStatus; } } } } } else { /************************************************************************** * The internal record is shrinking. Check if it can be shrunk in place * and a UIR created to occupy the extra space. If not, waste it and then * allocate a new internal record (if moving it is allowed). **************************************************************************/ if (newSize <= (curSize - UIR_BASE_SIZE)) { if (!sX(WasteIR(CDF,curOffset + newSize, curSize - newSize),&pStatus)) return pStatus; if (!sX(WriteIrSize(CDF->fp, curOffset, &newSize),&pStatus)) return pStatus; ASSIGNnotNULL (newOffset, curOffset) ASSIGNnotNULL (success, TRUE) } else { if (move) { if (!sX(WasteIR(CDF,curOffset,curSize),&pStatus)) return pStatus; if (!sX(AllocateIR(CDF,newSize,newOffset),&pStatus)) return pStatus; ASSIGNnotNULL (success, TRUE) } else { ASSIGNnotNULL (success, FALSE) } } return pStatus; } } /****************************************************************************** * RemoveUIRs. ******************************************************************************/ STATICforIDL CDFstatus RemoveUIRs (CDF, sOffset, eOffset) struct CDFstruct *CDF; /* In: Pointer to CDF. */ Int32 sOffset; /* In: Offset of starting UIR. */ Int32 eOffset; /* In: Offset of ending UIR. */ { CDFstatus pStatus = CDF_OK; struct UIRstruct sUIR, eUIR; Int32 UIRhead; if (!sX(ReadGDR(CDF->fp,CDF->GDRoffset, GDR_UIRHEAD,&UIRhead, GDR_NULL),&pStatus)) return pStatus; if (!sX(ReadUIR(CDF->fp,sOffset, UIR_RECORD,&sUIR, UIR_NULL),&pStatus)) return pStatus; if (!sX(ReadUIR(CDF->fp,eOffset, UIR_RECORD,&eUIR, UIR_NULL),&pStatus)) return pStatus; if (UIRhead == sOffset) { UIRhead = eUIR.NextUIR; if (!sX(WriteGDR(CDF->fp,CDF->GDRoffset, GDR_UIRHEAD,&UIRhead, GDR_NULL),&pStatus)) return pStatus; } else { struct UIRstruct prevUIR; if (!sX(ReadUIR(CDF->fp,sUIR.PrevUIR, UIR_RECORD,&prevUIR, UIR_NULL),&pStatus)) return pStatus; prevUIR.NextUIR = eUIR.NextUIR; if (!sX(WriteUIR(CDF->fp,sUIR.PrevUIR, UIR_RECORD,&prevUIR, UIR_NULL),&pStatus)) return pStatus; } if (eUIR.NextUIR != 0) { struct UIRstruct nextUIR; if (!sX(ReadUIR(CDF->fp,eUIR.NextUIR, UIR_RECORD,&nextUIR, UIR_NULL),&pStatus)) return pStatus; nextUIR.PrevUIR = sUIR.PrevUIR; if (!sX(WriteUIR(CDF->fp,eUIR.NextUIR, UIR_RECORD,&nextUIR, UIR_NULL),&pStatus)) return pStatus; } return pStatus; } /****************************************************************************** * PriorTo. ******************************************************************************/ VISIBLE_PREFIX Logical PriorTo (spec, version, release, increment) char *spec; Int32 version; Int32 release; Int32 increment; { int ver, rel, incr; switch (sscanf(spec,"%d.%d.%d",&ver,&rel,&incr)) { case 1: if (version < ver) return TRUE; break; case 2: if (version < ver) return TRUE; if (version == ver && release < rel) return TRUE; break; case 3: if (version < ver) return TRUE; if (version == ver && release < rel) return TRUE; if (version == ver && release == rel && increment < incr) return TRUE; break; } return FALSE; } /****************************************************************************** * ShortenCDR. ******************************************************************************/ STATICforIDL CDFstatus ShortenCDR (CDF) struct CDFstruct *CDF; { CDFstatus pStatus = CDF_OK; Int32 offset, oldRecordSize, newRecordSize, nBytes; if (!sX(ReadCDR(CDF->fp,CDF->CDRoffset, CDR_RECORDSIZE,&oldRecordSize, CDR_NULL),&pStatus)) return pStatus; newRecordSize = CDR_BASE_SIZE + CDF_COPYRIGHT_LEN; if (!sX(WriteCDR(CDF->fp,V2_CDR_OFFSET, CDR_RECORDSIZE,&newRecordSize, CDR_NULL),&pStatus)) return pStatus; offset = CDF->CDRoffset + newRecordSize; nBytes = oldRecordSize - newRecordSize; if (!sX(WasteIR(CDF,offset,nBytes),&pStatus)) return pStatus; return pStatus; } /****************************************************************************** * CorrectScopes. * It is assumed that the last ADR offset has already been fixed. ******************************************************************************/ STATICforIDL CDFstatus CorrectScopes (CDF) struct CDFstruct *CDF; { Int32 tOffset, attrScope; CDFstatus pStatus = CDF_OK; /**************************************************************************** * Read the offset of the first ADR from the GDR. ****************************************************************************/ if (!sX(ReadGDR(CDF->fp,CDF->GDRoffset, GDR_ADRHEAD,&tOffset, GDR_NULL),&pStatus)) return pStatus; /**************************************************************************** * Read the ADRs correcting each assumed scope. ****************************************************************************/ while (tOffset != 0) { if (!sX(ReadADR(CDF->fp,tOffset, ADR_SCOPE,&attrScope, ADR_NULL),&pStatus)) return pStatus; switch (attrScope) { case GLOBALscopeASSUMED: attrScope = GLOBAL_SCOPE; if (!sX(WriteADR(CDF->fp,tOffset, ADR_SCOPE,&attrScope, ADR_NULL),&pStatus)) return pStatus; break; case VARIABLEscopeASSUMED: attrScope = VARIABLE_SCOPE; if (!sX(WriteADR(CDF->fp,tOffset, ADR_SCOPE,&attrScope, ADR_NULL),&pStatus)) return pStatus; break; } if (!sX(ReadADR(CDF->fp,tOffset, ADR_ADRNEXT,&tOffset, ADR_NULL),&pStatus)) return pStatus; } return pStatus; } /****************************************************************************** * ShortenVDRs. * It is assumed that the last rVDR offset has already been fixed. ******************************************************************************/ STATICforIDL CDFstatus ShortenVDRs (CDF) struct CDFstruct *CDF; { Int32 vOffset, nextOffset, recordSize, nTailBytes; void *tBuffer; Int32 tOffset; CDFstatus pStatus = CDF_OK; int i; for (i = 0; i < 2; i++) { Logical zVar = (i == 0); /************************************************************************* * Read the offset of the first rVDR from the GDR. *************************************************************************/ if (!sX(ReadGDR(CDF->fp,CDF->GDRoffset, BOO(zVar,GDR_zVDRHEAD,GDR_rVDRHEAD),&vOffset, GDR_NULL),&pStatus)) return pStatus; /************************************************************************* * Read the rVDRs shortening each. *************************************************************************/ while (vOffset != ZERO_OFFSET) { if (!sX(ReadVDR(CDF,CDF->fp,vOffset,zVar, VDR_VDRNEXT,&nextOffset, VDR_RECORDSIZE,&recordSize, VDR_NULL),&pStatus)) return pStatus; nTailBytes = recordSize - VDR_WASTED_OFFSET - VDR_WASTED_SIZE; recordSize -= VDR_WASTED_SIZE; if (!sX(WriteVDR(CDF,CDF->fp,vOffset,zVar, VDR_RECORDSIZE,&recordSize, VDR_NULL),&pStatus)) return pStatus; tBuffer = cdf_AllocateMemory ((size_t) nTailBytes, NULL); if (tBuffer != NULL) { tOffset = vOffset + VDR_WASTED_OFFSET + VDR_WASTED_SIZE; if (!SEEKv(CDF->fp,tOffset,vSEEK_SET)) return CDF_READ_ERROR; if (!READv(tBuffer,(size_t)nTailBytes,1,CDF->fp)) return CDF_READ_ERROR; tOffset = vOffset + VDR_WASTED_OFFSET; if (!SEEKv(CDF->fp,tOffset,vSEEK_SET)) return CDF_WRITE_ERROR; if (!WRITEv(tBuffer,(size_t)nTailBytes,1,CDF->fp)) return CDF_WRITE_ERROR; cdf_FreeMemory (tBuffer, NULL); } else { Int32 oldOffset = vOffset + VDR_WASTED_OFFSET + VDR_WASTED_SIZE, newOffset = vOffset + VDR_WASTED_OFFSET, byteX; Byte tByte; for (byteX = 0; byteX < nTailBytes; byteX++) { if (!SEEKv(CDF->fp,oldOffset,vSEEK_SET)) return CDF_READ_ERROR; if (!READv(&tByte,1,1,CDF->fp)) return CDF_READ_ERROR; if (!SEEKv(CDF->fp,newOffset,vSEEK_SET)) return CDF_WRITE_ERROR; if (!WRITEv(&tByte,1,1,CDF->fp)) return CDF_WRITE_ERROR; oldOffset++; newOffset++; } } if (!sX(WasteIR(CDF,vOffset+recordSize,VDR_WASTED_SIZE),&pStatus)) { return pStatus; } vOffset = nextOffset; } } return pStatus; } /****************************************************************************** * CorrectBlockingFactors. * It is assumed that the last rVDR offset has already been fixed. ******************************************************************************/ STATICforIDL CDFstatus CorrectBlockingFactors (CDF) struct CDFstruct *CDF; { CDFstatus pStatus = CDF_OK; Int32 nVars, vdrOffset; int varN; Logical zVar; struct VDRstruct VDR; struct VarStruct **Vars, *Var; for (zVar = 0; zVar <= 1; zVar++) { Vars = BOO(zVar,CDF->zVars,CDF->rVars); nVars = BOO(zVar,CDF->NzVars,CDF->NrVars); for (varN = 0; varN < nVars; varN++) { Var = Vars[varN]; if (Var == NULL) { if (!sX(FindVarByNumber(CDF,(Int32)varN, zVar,&vdrOffset),&pStatus)) return pStatus; } else vdrOffset = Var->VDRoffset; if (!sX(ReadVDR(CDF,CDF->fp,vdrOffset,zVar, VDR_RECORD,&VDR,NULL, VDR_NULL),&pStatus)) return pStatus; if (!RECvaryBITset(VDR.Flags) && VDR.blockingFactor > 1) { VDR.blockingFactor = 1; if (!sX(WriteVDR(CDF,CDF->fp,vdrOffset,zVar, VDR_RECORD,&VDR,NULL, VDR_NULL),&pStatus)) return pStatus; if (Var != NULL) { if (!sX(CalcBF(CDF,Var),&pStatus)) return pStatus; } } } } return pStatus; } /****************************************************************************** * CorrectEPOCH. ******************************************************************************/ STATICforIDL CDFstatus CorrectEPOCH (CDF) struct CDFstruct *CDF; { CDFstatus tStatus, pStatus = CDF_OK; Int32 dataType, vNum, vOffset, aOffset, eOffset; Logical zVar; int i; /**************************************************************************** * Search for EPOCH rVariable. ****************************************************************************/ tStatus = FindVarByName (CDF, "EPOCH", &vOffset, &zVar, NULL); switch (tStatus) { case CDF_OK: if (!sX(ReadVDR(CDF,CDF->fp,vOffset,zVar, VDR_NUM,&vNum, VDR_DATATYPE,&dataType, VDR_NULL),&pStatus)) return pStatus; if (FLOAT8dataType(dataType)) dataType = CDF_EPOCH; if (!sX(WriteVDR(CDF,CDF->fp,vOffset,zVar, VDR_DATATYPE,&dataType, VDR_NULL),&pStatus)) return pStatus; /************************************************************************ * Search for associated VALIDMIN/VALIDMAX/SCALEMIN/SCALEMAX rEntries. ************************************************************************/ for (i = 0; i < 4; i++) { char aName[8+1]; switch (i) { case 0: strcpy (aName, "VALIDMIN"); break; case 1: strcpy (aName, "VALIDMAX"); break; case 2: strcpy (aName, "SCALEMIN"); break; case 3: strcpy (aName, "SCALEMAX"); break; } tStatus = FindAttrByName (CDF,aName,&aOffset); switch (tStatus) { case CDF_OK: tStatus = FindEntryByNumber (CDF, aOffset, zVar, vNum, &eOffset); /* We can do this since only rVariables will exist. */ switch (tStatus) { case CDF_OK: if (!sX(ReadAEDR(CDF->fp,eOffset, AEDR_DATATYPE,&dataType, AEDR_NULL),&pStatus)) return pStatus; if (FLOAT8dataType(dataType)) dataType = CDF_EPOCH; if (!sX(WriteAEDR(CDF,CDF->fp,eOffset, AEDR_DATATYPE,&dataType, AEDR_NULL),&pStatus)) return pStatus; break; case NO_SUCH_ENTRY: break; default: return tStatus; } break; case NO_SUCH_ATTR: break; default: return tStatus; } } break; case NO_SUCH_VAR: break; default: return tStatus; } return pStatus; } /****************************************************************************** * DeleteFile. ******************************************************************************/ STATICforIDL Logical DeleteFile (path) char *path; { #if defined(vms) char tPath[DU_MAX_PATH_LEN+1]; strcpyX (tPath, path, DU_MAX_PATH_LEN); strcatX (tPath, ";0", DU_MAX_PATH_LEN); /* Only most recent is deleted. */ return (delete(tPath) == 0); #endif #if defined(unix) || defined(dos) return (unlink(path) == 0); #endif #if defined(mac) || defined(posixSHELL) || defined(win32) return (remove(path) == 0); #endif } /****************************************************************************** * KillAbortedCDF. ******************************************************************************/ STATICforIDL void KillAbortedCDF (CDF, Cur) struct CDFstruct *CDF; struct CurStruct *Cur; { CDF->magic = KILLEDid_MAGIC_NUMBER; cdf_FreeMemory (CDF, NULL); Cur->cdf = NULL; return; } /****************************************************************************** * AbortAccess. ******************************************************************************/ STATICforIDL void AbortAccess (CDF, updateCDF, deleteCDF) struct CDFstruct *CDF; Logical updateCDF; /* Update "working" dotCDF file (if read/write access has been obtained)? */ Logical deleteCDF; /* Delete CDF file(s)? */ { /**************************************************************************** * If the CDF is to be deleted do that first and then skip the updating and/or * closing of the CDF files. ****************************************************************************/ if (deleteCDF) { DeleteCDFfiles (CDF); if (CDF->uDotFp != NULL) V_delete (CDF->uDotFp, NULL); } else { /************************************************************************** * Update the dotCDF file if requested, if the current access is read/write, * and if the "working" dotCDF file has not already been closed or deleted. **************************************************************************/ if (CDF->status == READ_WRITE && updateCDF && (CDF->fp == CDF->dotFp || CDF->fp == CDF->uDotFp)) UpdateDotCDF (CDF); /************************************************************************** * Close all of the CDF files if they are not already closed (or deleted). **************************************************************************/ if (CDF->dotFp != NULL) V_close (CDF->dotFp, CDF, NULL); if (CDF->uDotFp != NULL) V_close (CDF->uDotFp, CDF, NULL); CloseVarFiles (CDF); } /**************************************************************************** * Delete the scratch files that still exist. ****************************************************************************/ if (CDF->stage.fp != NULL) V_delete (CDF->stage.fp, NULL); if (CDF->compressFp != NULL) V_delete (CDF->compressFp, NULL); /**************************************************************************** * Free the memory used by the CDF. ****************************************************************************/ FreeCDFid (CDF, TRUE); return; } /****************************************************************************** * DeleteCDFfiles. * The files may be open or closed. This routine does not delete the * uncompressed dotCDF file (if one exists). ******************************************************************************/ STATICforIDL CDFstatus DeleteCDFfiles (CDF) struct CDFstruct *CDF; { char tmpFile[DU_MAX_PATH_LEN+1]; CDFstatus pStatus = CDF_OK; /************************************************************************** * Delete dotCDF file. **************************************************************************/ if (CDF->dotFp == NULL) { BuildFilePath (CDFt, CDF->CDFname, CDF->no_append, CDF->upper_case_ext, CDF->version_numbers, INT32_ZERO, tmpFile); if (!DeleteFile(tmpFile)) sX (CDF_DELETE_ERROR, &pStatus); } else { if (!DELETEv(CDF->dotFp,NULL)) sX (CDF_DELETE_ERROR, &pStatus); CDF->dotFp = NULL; } /************************************************************************** * Delete the variable files (if multi-file). Both rVariable and zVariable * files are deleted. **************************************************************************/ if (!CDF->singleFile) { int varN; for (varN = 0; varN < CDF->NrVars; varN++) { struct VarStruct *Var = CDF->rVars[varN]; if (Var != NULL) { if (Var->fp != NULL) { if (!DELETEv(Var->fp,NULL)) sX (VAR_DELETE_ERROR, &pStatus); Var->fp = NULL; continue; } } BuildFilePath (Vt, CDF->CDFname, CDF->no_append, CDF->upper_case_ext, CDF->version_numbers, varN, tmpFile); if (!DeleteFile(tmpFile)) sX (VAR_DELETE_ERROR, &pStatus); } for (varN = 0; varN < CDF->NzVars; varN++) { struct VarStruct *Var = CDF->zVars[varN]; if (Var != NULL) { if (Var->fp != NULL) { if (!DELETEv(Var->fp,NULL)) sX (VAR_DELETE_ERROR, &pStatus); Var->fp = NULL; continue; } } BuildFilePath (Zt, CDF->CDFname, CDF->no_append, CDF->upper_case_ext, CDF->version_numbers, varN, tmpFile); if (!DeleteFile(tmpFile)) sX (VAR_DELETE_ERROR, &pStatus); } } return pStatus; } /****************************************************************************** * DeleteEntry. ******************************************************************************/ STATICforIDL CDFstatus DeleteEntry (CDF, aOffset, eOffset) struct CDFstruct *CDF; Int32 aOffset; Int32 eOffset; { CDFstatus pStatus = CDF_OK; struct ADRstruct ADR; struct AEDRstruct AEDR, AEDRt; Int32 prevEntryOffset; Logical zEntry; /**************************************************************************** * Read the ADR and the AEDR being deleted. ****************************************************************************/ if (!sX(ReadADR(CDF->fp,aOffset, ADR_RECORD,&ADR, ADR_NULL),&pStatus)) return pStatus; if (!sX(ReadAEDR(CDF->fp,eOffset, AEDR_RECORD,&AEDR,NULL, AEDR_NULL),&pStatus)) return pStatus; zEntry = (AEDR.RecordType == AzEDR_); /**************************************************************************** * Remove the AEDR from the list of entries. ****************************************************************************/ if (!sX(FindPrevEntry(CDF,aOffset,eOffset, zEntry,&prevEntryOffset),&pStatus)) return pStatus; if (prevEntryOffset == 0) { /************************************************************************** * The first entry on the linked list is being deleted. Point the ADR to * the entry being pointed to by the entry being deleted. **************************************************************************/ if (zEntry) ADR.AzEDRhead = AEDR.AEDRnext; else ADR.AgrEDRhead = AEDR.AEDRnext; } else { /************************************************************************** * The entry being deleted is not the first entry on the linked list. Point * the previous entry to the entry pointed to by the entry being deleted. **************************************************************************/ if (!sX(ReadAEDR(CDF->fp,prevEntryOffset, AEDR_RECORD,&AEDRt,NULL, AEDR_NULL),&pStatus)) return pStatus; AEDRt.AEDRnext = AEDR.AEDRnext; if (!sX(WriteAEDR(CDF,CDF->fp,prevEntryOffset, AEDR_RECORD,&AEDRt,NULL, AEDR_NULL),&pStatus)) return pStatus; } /**************************************************************************** * Decrement the number of entries and recalculate the maximum entry (if * necessary). ****************************************************************************/ if (zEntry) ADR.NzEntries--; else ADR.NgrEntries--; if (BOO(zEntry,ADR.MAXzEntry,ADR.MAXgrEntry) == AEDR.Num) { Int32 maxEntry = NO_ENTRY; Int32 tOffset = BOO(zEntry,ADR.AzEDRhead,ADR.AgrEDRhead); while (tOffset != 0) { if (!sX(ReadAEDR(CDF->fp,tOffset, AEDR_RECORD,&AEDRt,NULL, AEDR_NULL),&pStatus)) return pStatus; maxEntry = MaxInt32 (maxEntry, AEDRt.Num); tOffset = AEDRt.AEDRnext; } if (zEntry) ADR.MAXzEntry = maxEntry; else ADR.MAXgrEntry = maxEntry; } /**************************************************************************** * Rewrite the ADR and waste the AEDR (of the entry being deleted). ****************************************************************************/ if (!sX(WriteADR(CDF->fp,aOffset, ADR_RECORD,&ADR, ADR_NULL),&pStatus)) return pStatus; if (!sX(WasteIR(CDF,eOffset,AEDR.RecordSize),&pStatus)) return pStatus; return pStatus; } /****************************************************************************** * CtoPstr/PtoCstr. ******************************************************************************/ #if defined(MPW_C) STATICforIDL unsigned char *CtoPstr (string) char *string; { size_t length = MINIMUM(strlen(string),255); if (length > 0) memmove (&string[1], string, length); string[0] = (char) length; return ((unsigned char *) string); } #endif #if defined(MPW_C) STATICforIDL char *PtoCstr (string) unsigned char *string; { size_t length = (size_t) string[0]; if (length > 0) memmove (string, &string[1], length); string[length] = (unsigned char) NUL; return ((char *) string); } #endif /****************************************************************************** * PadUnRecords. * Pad all allocated records within the first/last record range. Note that * in the case of sparse records some of the records may not be allocated (and * should not be padded of course). ******************************************************************************/ STATICforIDL CDFstatus PadUnRecords (CDF, Var, firstRec, lastRec) struct CDFstruct *CDF; struct VarStruct *Var; Int32 firstRec; Int32 lastRec; { CDFstatus pStatus = CDF_OK; Int32 offset; int how; void *buffer; Int32 recNum, nRecords, toRec, lastRecInVVR; Logical found; /**************************************************************************** * Pad the records. * NOTE: Padding in a single-file CDF could be made more efficient by not * allocating/freeing the pad buffer over and over... ****************************************************************************/ if (CDF->singleFile) { /************************************************************************** * Single-file...first determine the first allocated record to be padded. **************************************************************************/ if (!sX(NextRecord(CDF,Var->VDRoffset,Var->zVar, firstRec,&recNum,&found),&pStatus)) return pStatus; if (!found) return pStatus; /************************************************************************** * While the first record to be padded is within the range... **************************************************************************/ while (recNum <= lastRec) { if (!sX(RecordByteOffset(CDF,Var,recNum, &offset),&pStatus)) return pStatus; if (!sX(SearchForRecord(CDF,Var->VDRoffset, Var->zVar,recNum, NULL,&lastRecInVVR, NULL,NULL),&pStatus)) return pStatus; toRec = MINIMUM(lastRec,lastRecInVVR); nRecords = toRec - recNum + 1; if (!sX(BuildPadBuffer(CDF,Var,nRecords, &how,&buffer,TRUE),&pStatus)) return pStatus; if (!sX(WritePadValues(Var,CDF->fp,offset, nRecords,how,buffer),&pStatus)) { cdf_FreeMemory (buffer, NULL); return pStatus; } cdf_FreeMemory (buffer, NULL); recNum += nRecords; /************************************************************************ * Determine the next `first' record to be padded. ************************************************************************/ if (!sX(NextRecord(CDF,Var->VDRoffset,Var->zVar, recNum,&recNum,&found),&pStatus)) return pStatus; if (!found) return pStatus; } } else { /************************************************************************** * Multi-file... **************************************************************************/ if (!sX(RecordByteOffset(CDF,Var, firstRec, &offset),&pStatus)) return pStatus; nRecords = lastRec - firstRec + 1; if (!sX(BuildPadBuffer(CDF,Var,nRecords, &how,&buffer,TRUE),&pStatus)) return pStatus; if (!sX(WritePadValues(Var,Var->fp,offset,nRecords,how,buffer),&pStatus)) { cdf_FreeMemory (buffer, NULL); return pStatus; } cdf_FreeMemory (buffer, NULL); } return pStatus; } /****************************************************************************** * WritePadValues. * NOTE: It is assumed that the records are contiguous (in a single-file CDF) * and that on a DOS machine the buffer does not exceed 64K bytes. It is also * assumed that the values have already been encoded for the CDF. ******************************************************************************/ STATICforIDL CDFstatus WritePadValues (Var, fp, offset, nRecords, how, buffer) struct VarStruct *Var; vFILE *fp; Int32 offset; Int32 nRecords; int how; void *buffer; { Int32 nBytes, nValues, recX, valueX; /**************************************************************************** * Seek to desired offset. ****************************************************************************/ if (!SEEKv(fp,(long)offset,vSEEK_SET)) return VAR_WRITE_ERROR; /**************************************************************************** * Write records... ****************************************************************************/ switch (how) { case ALLrecordsATonce: nBytes = nRecords * Var->NphyRecBytes; if (!WRITEv(buffer,(size_t)nBytes,1,fp)) return VAR_WRITE_ERROR; break; case ONErecordATaTIME: for (recX = 0; recX < nRecords; recX++) { if (!WRITEv(buffer,(size_t)Var->NphyRecBytes,1,fp)) { return VAR_WRITE_ERROR; } } break; case ONEvalueATaTIME: nValues = nRecords * Var->NphyRecValues; for (valueX = 0; valueX < nValues; valueX++) { if (!WRITEv(buffer,(size_t)Var->NvalueBytes,1,fp)) { return VAR_WRITE_ERROR; } } break; } return CDF_OK; } /****************************************************************************** * MinInt/Int32/Long. * These are used to avoid double evaluation in macro expansions (eg. MINIMUM). ******************************************************************************/ VISIBLE_PREFIX int MinInt (a, b) int a; int b; { return MINIMUM(a,b); } VISIBLE_PREFIX Int32 MinInt32 (a, b) Int32 a; Int32 b; { return MINIMUM(a,b); } VISIBLE_PREFIX long MinLong (a, b) long a; long b; { return MINIMUM(a,b); } /****************************************************************************** * MaxInt/Int32/Long. * These are used to avoid double evaluation in macro expansions (eg. MAXIMUM). ******************************************************************************/ VISIBLE_PREFIX int MaxInt (a, b) int a; int b; { return MAXIMUM(a,b); } VISIBLE_PREFIX Int32 MaxInt32 (a, b) Int32 a; Int32 b; { return MAXIMUM(a,b); } VISIBLE_PREFIX long MaxLong (a, b) long a; long b; { return MAXIMUM(a,b); } /****************************************************************************** * AddTOvStats. ******************************************************************************/ STATICforIDL void AddTOvStats (vStatsTO, vStats) vSTATS *vStatsTO; /* If NULL, do nothing. */ vSTATS *vStats; /* If NULL, initialize (to zero). */ { if (vStatsTO != NULL) { if (vStats == NULL) { vStatsTO->nBuffers = 0; vStatsTO->maxBuffers = 0; vStatsTO->nV_reads = 0; vStatsTO->nV_writes = 0; vStatsTO->nPageIns = 0; vStatsTO->nPageOuts = 0; vStatsTO->nBlockReads = 0; vStatsTO->nBlockWrites = 0; } else { vStatsTO->nBuffers = MAXIMUM(vStatsTO->nBuffers,vStats->nBuffers); vStatsTO->maxBuffers = MAXIMUM(vStatsTO->maxBuffers,vStats->maxBuffers); vStatsTO->nV_reads += vStats->nV_reads; vStatsTO->nV_writes += vStats->nV_writes; vStatsTO->nPageIns += vStats->nPageIns; vStatsTO->nPageOuts += vStats->nPageOuts; vStatsTO->nBlockReads += vStats->nBlockReads; vStatsTO->nBlockWrites += vStats->nBlockWrites; } } return; } /****************************************************************************** * DisplayVs. ******************************************************************************/ #if defined(DEBUG) STATICforIDL void DisplayVs (toWhere, label, vStats) char *toWhere; char *label; vSTATS *vStats; { if (toWhere != NULL) { FILE *fp = BOO(strcmp(toWhere,"STDOUT"),FOPEN(toWhere,"a"),stdout); if (fp == NULL) return; fprintf (fp, "%s", label); fprintf (fp, "..BUF:%03ldu/%03ldx", vStats->nBuffers, vStats->maxBuffers); fprintf (fp, " V_:%06ldr/%06ldw", vStats->nV_reads, vStats->nV_writes); fprintf (fp, " PAGE:%05ldi/%05ldo", vStats->nPageIns, vStats->nPageOuts); fprintf (fp, " BLK:%05ldr/%05ldw", vStats->nBlockReads, vStats->nBlockWrites); fprintf (fp, "\n"); if (fp != stdout) fclose (fp); } return; } #endif