1 /******************************************************************************
2 *
3 *  NSSDC/CDF                     CDF library miscellaneous functions, part 1.
4 *
5 *  Version 1.3e, 18-Nov-97, Hughes STX.
6 *
7 *  Modification history:
8 *
9 *   V1.0  19-Dec-94, J Love     Original version.
10 *   V1.0a 29-Dec-94, J Love     WriteBuffer: increment buffer pointer in the
11 *                               case where the memory allocation failed.
12 *   V1.1  13-Jan-95, J Love     Encode/decode changes.  More cache-residency.
13 *                               Allow all possible extensions on all machines.
14 *   V1.1a 19-Jan-95, J Love     IRIX 6.x (64-bit).
15 *   V1.1b 24-Feb-95, J Love     Solaris 2.3 IDL i/f.
16 *   V1.2  21-Mar-95, J Love     POSIX.
17 *   V1.2a 18-Apr-95, J Love     More POSIX.  MEMLOG_.
18 *   V1.2b 19-Apr-95, J Love     Memory functions moved to `cdfmem.c'.
19 *   V1.2c  7-Sep-95, J Love     Corrected status codes being returned.  Try
20 *                               progressively smaller temporary buffers in
21 *                               `WriteVarElems'.
22 *   V1.3  10-Sep-96, J Love     CDF V2.6.
23 *   V1.3a 21-Feb-97, J Love	Removed RICE.
24 *   V1.3b 28-Feb-97, J Love	Windows NT for MS Visual C/C++ on an IBM PC.
25 *   V1.3c 11-Sep-97, J Love	Magic numbers are now uInt32.
26 *   V1.3d 20-Oct-97, J Love	Properly cast the uInt32 magic numbers.  More
27 *				Windows NT.
28 *   V1.3e 18-Nov-97, J Love	Even more Windows NT.
29 *   V2.0  08/Apr-04, M liu      Replaced VSTREAM.STATS with VSTREAM_STATS.
30 *   V2.1  13-Oct-06, M Liu      Changed to allow upper and lower case CDF
31 *                               name to be used on win32.
32 *
33 ******************************************************************************/
34 
35 #include "cdflib.h"
36 #include "cdflib64.h"
37 #include "cdfrev.h"
38 
39 /******************************************************************************
40 * CorrectV20eof.
41 ******************************************************************************/
42 
CorrectV20eof(CDF)43 STATICforIDL CDFstatus CorrectV20eof (CDF)
44 struct CDFstruct *CDF;
45 {
46   CDFstatus pStatus = CDF_OK;
47   Int32 eof = 0, size, vOffset, aOffset, eOffset, nAttrs, nEntries;
48   int varX, attrX, entryX;
49   /****************************************************************************
50   * Check if CDR is last internal record.
51   ****************************************************************************/
52   if (!sX(ReadCDR(CDF->fp,CDF->CDRoffset,
53 		  CDR_RECORDSIZE,&size,
54 		  CDR_NULL),&pStatus)) return pStatus;
55   eof = MaxInt32 (eof, CDF->CDRoffset + size);
56   /****************************************************************************
57   * Check if GDR is last internal record.
58   ****************************************************************************/
59   if (!sX(ReadGDR(CDF->fp,CDF->GDRoffset,
60 		  GDR_RECORDSIZE,&size,
61 		  GDR_NULL),&pStatus)) return pStatus;
62   eof = MaxInt32 (eof, CDF->GDRoffset + size);
63   /****************************************************************************
64   * Scan through rVDRs checking if each is the last internal record.  Note
65   * that V2.0 CDFs won't have zVDRs, VXRs, or VVRs.
66   ****************************************************************************/
67   if (!sX(ReadGDR(CDF->fp,CDF->GDRoffset,
68 		  GDR_rVDRHEAD,&vOffset,
69 		  GDR_NULL),&pStatus)) return pStatus;
70   for (varX = 0; varX < CDF->NrVars; varX++) {
71      if (!sX(ReadVDR(CDF,CDF->fp,vOffset,FALSE,
72 		     VDR_RECORDSIZE,&size,
73 		     VDR_NULL),&pStatus)) return pStatus;
74      eof = MaxInt32 (eof, vOffset + size);
75      if (!sX(ReadVDR(CDF,CDF->fp,vOffset,FALSE,
76 		     VDR_VDRNEXT,&vOffset,
77 		     VDR_NULL),&pStatus)) return pStatus;
78   }
79   /****************************************************************************
80   * Scan through the ADRs checking if each is the last internal record.
81   ****************************************************************************/
82   if (!sX(ReadGDR(CDF->fp,CDF->GDRoffset,
83 		  GDR_NUMATTR,&nAttrs,
84 		  GDR_ADRHEAD,&aOffset,
85 		  GDR_NULL),&pStatus)) return pStatus;
86   for (attrX = 0; attrX < nAttrs; attrX++) {
87      if (!sX(ReadADR(CDF->fp,aOffset,
88 		     ADR_RECORDSIZE,&size,
89 		     ADR_NULL),&pStatus)) return pStatus;
90      eof = MaxInt32 (eof, aOffset + size);
91      /*************************************************************************
92      * Scan through the ArEDRs checking if each is the last internal record.
93      * Note that V2.0 CDFs won't have AzEDRs.
94      *************************************************************************/
95      if (!sX(ReadADR(CDF->fp,aOffset,
96 		     ADR_AgrEDRHEAD,&eOffset,
97 		     ADR_NgrENTRIES,&nEntries,
98 		     ADR_NULL),&pStatus)) return pStatus;
99      for (entryX = 0; entryX < nEntries; entryX++) {
100 	if (!sX(ReadAEDR(CDF->fp,eOffset,
101 			 AEDR_RECORDSIZE,&size,
102 			 AEDR_NULL),&pStatus)) return pStatus;
103 	eof = MaxInt32 (eof, eOffset + size);
104 	if (!sX(ReadAEDR(CDF->fp,eOffset,
105 			 AEDR_AEDRNEXT,&eOffset,
106 			 AEDR_NULL),&pStatus)) return pStatus;
107      }
108      if (!sX(ReadADR(CDF->fp,aOffset,
109 		     ADR_ADRNEXT,&aOffset,
110 		     ADR_NULL),&pStatus)) return pStatus;
111   }
112   /****************************************************************************
113   * Save correct EOF and return.
114   ****************************************************************************/
115   if (!sX(WriteGDR(CDF->fp,CDF->GDRoffset,
116 		   GDR_EOF,&eof,
117 		   GDR_NULL),&pStatus)) return pStatus;
118   return pStatus;
119 }
120 
121 /******************************************************************************
122 * CorrectV20offsets.
123 ******************************************************************************/
124 
CorrectV20offsets(CDF)125 STATICforIDL CDFstatus CorrectV20offsets (CDF)
126 struct CDFstruct *CDF;
127 {
128   CDFstatus pStatus = CDF_OK;
129   Int32 zero = 0, size, vOffset, aOffset, eOffset, nAttrs, nEntries;
130   int varX, attrX, entryX;
131   /****************************************************************************
132   * Scan through rVDRs fixing the next VDR field of the last one (setting it
133   * to an offset of zero).  Note that V2.0 CDFs won't have zVDRs, VXRs, or
134   * VVRs.
135   ****************************************************************************/
136   if (!sX(ReadGDR(CDF->fp,CDF->GDRoffset,
137 		  GDR_rVDRHEAD,&vOffset,
138 		  GDR_NULL),&pStatus)) return pStatus;
139   for (varX = 0; varX < CDF->NrVars; varX++) {
140      if (!sX(ReadVDR(CDF,CDF->fp,vOffset,FALSE,
141 		     VDR_RECORDSIZE,&size,
142 		     VDR_NULL),&pStatus)) return pStatus;
143      if (varX == CDF->NrVars - 1) {
144        if (!sX(WriteVDR(CDF,CDF->fp,vOffset,FALSE,
145 			VDR_VDRNEXT,&zero,
146 			VDR_NULL),&pStatus)) return pStatus;
147      }
148      else {
149        if (!sX(ReadVDR(CDF,CDF->fp,vOffset,FALSE,
150 		       VDR_VDRNEXT,&vOffset,
151 		       VDR_NULL),&pStatus)) return pStatus;
152      }
153   }
154   /****************************************************************************
155   * Scan through the ADRs fixing the next ADR field of the last one (setting
156   * it to an offset of zero).
157   ****************************************************************************/
158   if (!sX(ReadGDR(CDF->fp,CDF->GDRoffset,
159 		  GDR_NUMATTR,&nAttrs,
160 		  GDR_ADRHEAD,&aOffset,
161 		  GDR_NULL),&pStatus)) return pStatus;
162   for (attrX = 0; attrX < nAttrs; attrX++) {
163      if (!sX(ReadADR(CDF->fp,aOffset,
164 		     ADR_RECORDSIZE,&size,
165 		     ADR_NULL),&pStatus)) return pStatus;
166      /*************************************************************************
167      * Scan through the ArEDRs fixing the next ArEDR field of the last one
168      * (setting it to an offset of zero).  Note that V2.0 CDFs won't have
169      * AzEDRs.
170      *************************************************************************/
171      if (!sX(ReadADR(CDF->fp,aOffset,
172 		     ADR_AgrEDRHEAD,&eOffset,
173 		     ADR_NgrENTRIES,&nEntries,
174 		     ADR_NULL),&pStatus)) return pStatus;
175      for (entryX = 0; entryX < nEntries; entryX++) {
176 	if (!sX(ReadAEDR(CDF->fp,eOffset,
177 			 AEDR_RECORDSIZE,&size,
178 			 AEDR_NULL),&pStatus)) return pStatus;
179 	if (entryX == nEntries - 1) {
180 	  if (!sX(WriteAEDR(CDF,CDF->fp,eOffset,
181 			    AEDR_AEDRNEXT,&zero,
182 			    AEDR_NULL),&pStatus)) return pStatus;
183 	}
184 	else {
185 	  if (!sX(ReadAEDR(CDF->fp,eOffset,
186 			   AEDR_AEDRNEXT,&eOffset,
187 			   AEDR_NULL),&pStatus)) return pStatus;
188 	}
189      }
190      if (attrX == nAttrs - 1) {
191        if (!sX(WriteADR(CDF->fp,aOffset,
192 			ADR_ADRNEXT,&zero,
193 			ADR_NULL),&pStatus)) return pStatus;
194      }
195      else {
196        if (!sX(ReadADR(CDF->fp,aOffset,
197 		       ADR_ADRNEXT,&aOffset,
198 		       ADR_NULL),&pStatus)) return pStatus;
199      }
200   }
201   return pStatus;
202 }
203 
204 /******************************************************************************
205 * UpdateDotCDF.
206 * If this routine is called when aborting a CDF, we cannot assume that
207 * the CDF structure is complete - it may have been only partially initialized
208 * when the CDF was aborted. If it is called to save the CDF without closing
209 * it, the data will be properly preserved.
210 ******************************************************************************/
211 
UpdateDotCDF(CDF)212 STATICforIDL CDFstatus UpdateDotCDF (CDF)
213 struct CDFstruct *CDF;
214 {
215   CDFstatus pStatus = CDF_OK; int varN; struct VarStruct *Var; Logical zVar;
216   /**************************************************************************
217   * Update r/zVariables depending on the variable type...
218   **************************************************************************/
219   for (zVar = 0; zVar <= 1; zVar++) {
220     if (BOO(zVar,CDF->zVars,CDF->rVars) != NULL) {
221       Int32 nVars = BOO(zVar,CDF->NzVars,CDF->NrVars);
222       for (varN = 0; varN < nVars; varN++) {
223 	 Var = BOO(zVar,CDF->zVars[varN],CDF->rVars[varN]);
224 	 if (Var != NULL) {
225 	   switch (Var->vType) {
226 	     case SPARSE_RECORDS_: {
227 	       if (!sX(FlushStage(CDF,Var),&pStatus)) break;
228 	       /* No `break' is intentional. */
229 	     case STANDARD_:
230 	       if (Var->maxWritten < Var->maxAllocated) {
231 		 Int32 padFrom = Var->maxWritten + 1;
232 		 if (!sX(PadUnRecords(CDF,Var,padFrom,
233 				      Var->maxAllocated),&pStatus)) break;
234 		 Var->maxWritten = Var->maxAllocated;
235 	       }
236 	       break;
237 	     }
238 	     case COMPRESSED_:
239 	     case SPARSE_COMPRESSED_RECORDS_:
240 	       if (!sX(FlushStage(CDF,Var),&pStatus)) break;
241 	       break;
242 	     case SPARSE_ARRAYS_:
243 	     case SPARSE_RECORDS_AND_ARRAYS_:
244 	       sX (UNKNOWN_SPARSENESS, &pStatus);
245 	       break;
246 	     case IN_MULTI_:
247 	       break;
248 	     default:
249 	       sX (CDF_INTERNAL_ERROR, &pStatus);
250 	       break;
251 	   }
252 	 }
253       }
254     }
255   }
256   return pStatus;
257 }
258 
259 /******************************************************************************
260 * CloseVarFiles.
261 *
262 * Close the open variable files of the specified CDF.  This routine closes all
263 * of the open variable files regardless of the number of errors detected.
264 *
265 * Because this routine is called when aborting a CDF, we cannot assume
266 * that the CDF structure is complete.  Eg., it may have been only partially
267 * initialized when the CDF was aborted.
268 ******************************************************************************/
269 
CloseVarFiles(CDF)270 STATICforIDL CDFstatus CloseVarFiles (CDF)
271 struct CDFstruct *CDF;
272 {
273   CDFstatus pStatus = CDF_OK; struct VarStruct *Var; int varN;
274   /****************************************************************************
275   * If a multi-file CDF, close the variable files.
276   ****************************************************************************/
277   if (!CDF->singleFile) {
278     /**************************************************************************
279     * Close rVariable files.  If the pointer to the rVariable is NULL, then
280     * the rVariable has yet to be initialized (and is obviously closed).
281     **************************************************************************/
282     if (CDF->rVars != NULL) {
283       for (varN = 0; varN < CDF->NrVars; varN++) {
284 	 Var = CDF->rVars[varN];
285 	 if (Var != NULL) {
286 	   if (Var->fp != NULL) {
287 	     if (!CLOSEv(Var->fp,NULL,NULL)) sX (VAR_CLOSE_ERROR, &pStatus);
288 	     Var->fp = NULL;
289 	   }
290 	 }
291       }
292     }
293     /**************************************************************************
294     * Close zVariable files.  If the pointer to the zVariable is NULL, then
295     * the zVariable has yet to be initialized (and is obviously closed).
296     **************************************************************************/
297     if (CDF->zVars != NULL) {
298       for (varN = 0; varN < CDF->NzVars; varN++) {
299 	 Var = CDF->zVars[varN];
300 	 if (Var != NULL) {
301 	   if (Var->fp != NULL) {
302 	     if (!CLOSEv(Var->fp,NULL,NULL)) sX (VAR_CLOSE_ERROR, &pStatus);
303 	     Var->fp = NULL;
304 	   }
305 	 }
306       }
307     }
308   }
309   return pStatus;
310 }
311 
312 /******************************************************************************
313 * WriteAccess.
314 * Close and then reopen a CDF for read/write access (it was opened with
315 * read-only access initially).  If the CDF is earlier than CDF V2.5, then
316 * some of the fields will have to be fixed and the CDR will be truncated for
317 * a shorter copyright length (unless the CDF is being deleted in which case
318 * it would be a waste of time to do these things).
319 ******************************************************************************/
320 
WriteAccess(CDF,forDelete,pStatus)321 STATICforIDL Logical WriteAccess (CDF, forDelete, pStatus)
322 struct CDFstruct *CDF;
323 Logical forDelete;      /* Is the write access is needed to delete the CDF? */
324 CDFstatus *pStatus;	/* Returned status. */
325 {
326 #if BUILD_READ_ONLY_DISTRIBUTION
327    *pStatus = READ_ONLY_DISTRIBUTION;
328    return FALSE;
329 #else
330    char pathName[DU_MAX_PATH_LEN+1]; vSTATS vStats;
331    /***************************************************************************
332    * Check if write access already.
333    ***************************************************************************/
334    if (CDF->status == READ_WRITE) return TRUE;
335    /***************************************************************************
336    * Check if this CDF is in read-only mode.
337    ***************************************************************************/
338    if (CDF->readOnly) {
339      *pStatus = READ_ONLY_MODE;
340      return FALSE;
341    }
342    /***************************************************************************
343    * Close (the possibly compressed) dotCDF file and the variable files (if
344    * a multi-file CDF).  An uncompressed dotCDF file and any scratch files
345    * stay open.
346    ***************************************************************************/
347    if (!CLOSEv(CDF->dotFp,NULL,&vStats)) {
348      CDF->dotFp = NULL;
349      AbortAccess (CDF, noUPDATE, noDELETE);
350      return FALSE;
351    }
352    CDF->dotFp = NULL;
353    AddTOvStats (&CDF->dotCDFvStats, &vStats);
354 #if defined(DEBUG)
355    DisplayVs (getenv("VSTREAM_STATS"), "DotCDF..", &vStats);
356 #endif
357    if (!sX(CloseVarFiles(CDF),pStatus)) {
358      AbortAccess (CDF, noUPDATE, noDELETE);
359      return FALSE;
360    }
361    /***************************************************************************
362    * Open dotCDF file with read-write access.  If read-write access is not
363    * allowed, try to return to read-only access.  If reopening with read-only
364    * access fails, free CDF structures as if CDF had been closed.
365    ***************************************************************************/
366    BuildFilePath (CDFt, CDF->CDFname, CDF->no_append, CDF->upper_case_ext,
367 		  CDF->version_numbers, 0L, pathName);
368    CDF->dotFp = V_open (pathName, READ_PLUS_a_mode);
369    if (CDF->dotFp == NULL) {
370      CDF->dotFp = V_open (pathName, READ_ONLY_a_mode);
371      if (CDF->dotFp == NULL) {
372        AbortAccess (CDF, noUPDATE, noDELETE);
373        *pStatus = CDF_OPEN_ERROR;
374        return FALSE;
375      }
376      else {
377        CDF->status = READ_ONLY;
378        *pStatus = NO_WRITE_ACCESS;                      /* Don't return yet. */
379      }
380    }
381    else
382      CDF->status = READ_WRITE;
383    /***************************************************************************
384    * If the CDF is not compressed, reassign the "working" file pointer and
385    * reset the cache size (unless deleting).  If the CDF is compressed, the
386    * cache size of the "working" file pointer does not have to be reset.
387    ***************************************************************************/
388    if (CDF->uDotFp == NULL) {
389      CDF->fp = CDF->dotFp;
390      if (!forDelete) {
391        if (!CACHEv(CDF->fp,CDF->workingCacheSize)) {
392          *pStatus = BAD_CACHE_SIZE;
393          AbortAccess (CDF, noUPDATE, noDELETE);
394          return FALSE;
395        }
396      }
397    }
398    /***************************************************************************
399    * Fix various fields (if write access was obtained) unless write access
400    * was needed to delete the CDF.
401    ***************************************************************************/
402    if (CDF->status == READ_WRITE && !forDelete) {
403      Int32 versionNew = CDF_LIBRARY_VERSION,
404 	   releaseNew = CDF_LIBRARY_RELEASE,
405 	   incrementNew = CDF_LIBRARY_INCREMENT;
406      uInt32 magicNumber1 = V2magicNUMBER_1,
407 	    magicNumber2 = V2magicNUMBER_2u;
408      char copyRight[CDF_COPYRIGHT_LEN+1];
409      /*************************************************************************
410      * Update magic numbers.
411      *************************************************************************/
412      if (!SEEKv(CDF->fp,(long)V2_MAGIC_OFFSET_1,vSEEK_SET)) {
413        AbortAccess (CDF, noUPDATE, noDELETE);
414        *pStatus = CDF_WRITE_ERROR;
415        return FALSE;
416      }
417      if (!Write32(CDF->fp,(Int32 *)&magicNumber1)) {
418        AbortAccess (CDF, noUPDATE, noDELETE);
419        *pStatus = CDF_WRITE_ERROR;
420        return FALSE;
421      }
422      if (!Write32(CDF->fp,(Int32 *)&magicNumber2)) {
423        AbortAccess (CDF, noUPDATE, noDELETE);
424        *pStatus = CDF_WRITE_ERROR;
425        return FALSE;
426      }
427      /*************************************************************************
428      * If a V2.0 CDF, correct the EOF field.
429      *************************************************************************/
430      if (CDF->badEOF) {
431        if (!sX(CorrectV20eof(CDF),pStatus)) {
432 	 AbortAccess (CDF, noUPDATE, noDELETE);
433 	 return FALSE;
434        }
435        CDF->badEOF = FALSE;
436      }
437      /*************************************************************************
438      * If a V2.0 CDF, correct the terminating offset fields.  NOTE: Fix these
439      * fields before the other "fixing" routines (which may depend on these
440      * fields).
441      *************************************************************************/
442      if (CDF->badTerminatingOffsets) {
443        if (!sX(CorrectV20offsets(CDF),pStatus)) {
444 	 AbortAccess (CDF, noUPDATE, noDELETE);
445 	 return FALSE;
446        }
447        CDF->badTerminatingOffsets = FALSE;
448      }
449      /*************************************************************************
450      * If prior to CDF V2.1.1, then change the data type associated with the
451      * "EPOCH" rVariable/rEntries to CDF_EPOCH.
452      *************************************************************************/
453      if (CDF->fakeEPOCH) {
454        if (!sX(CorrectEPOCH(CDF),pStatus)) {
455 	 AbortAccess (CDF, noUPDATE, noDELETE);
456 	 return FALSE;
457        }
458        CDF->fakeEPOCH = FALSE;
459      }
460      /*************************************************************************
461      * If prior to CDF V2.5, then truncate the CDR for a shorter copyright
462      * field and shorten each VDR to reclaim the wasted space.
463      *************************************************************************/
464      if (CDF->wastedSpace) {
465        if (!sX(ShortenCDR(CDF),pStatus)) {
466 	 AbortAccess (CDF, noUPDATE, noDELETE);
467 	 return FALSE;
468        }
469        if (!sX(ShortenVDRs(CDF),pStatus)) {
470 	 AbortAccess (CDF, noUPDATE, noDELETE);
471 	 return FALSE;
472        }
473        CDF->wastedSpace = FALSE;
474      }
475      /*************************************************************************
476      * If prior to CDF V2.5, then convert all assumed scopes to definite
477      * scopes.
478      *************************************************************************/
479      if (CDF->assumedScopes) {
480        if (!sX(CorrectScopes(CDF),pStatus)) {
481 	 AbortAccess (CDF, noUPDATE, noDELETE);
482 	 return FALSE;
483        }
484        CDF->assumedScopes = FALSE;
485      }
486      /*************************************************************************
487      * Fix blocking factors for variables having a recVary of NOVARY.
488      *************************************************************************/
489      if (!sX(CorrectBlockingFactors(CDF),pStatus)) {
490        AbortAccess (CDF, noUPDATE, noDELETE);
491        return FALSE;
492      }
493      /*************************************************************************
494      * Update version/release/increment - should never happen as for older
495      * versioned (V2.7 and older) CDFs, we want to keep its original data
496      * structure.
497      *************************************************************************/
498      if (isLFS(CDF)) { /* It should be false all the time. */
499        if (!sX(WriteCDR(CDF->fp,V2_CDR_OFFSET,
500 		        CDR_VERSION,&versionNew,
501 		        CDR_RELEASE,&releaseNew,
502 		        CDR_INCREMENT,&incrementNew,
503 		        CDR_NULL),pStatus)) {
504          AbortAccess (CDF, noUPDATE, noDELETE);
505          return FALSE;
506        }
507      }
508      /*************************************************************************
509      * Update copyright.
510      *************************************************************************/
511      CDFcopyRight (copyRight);
512      NulPad (copyRight, CDF_COPYRIGHT_LEN);
513      if (!sX(WriteCDR(CDF->fp,V2_CDR_OFFSET,
514 		      CDR_COPYRIGHT,copyRight,
515 		      CDR_NULL),pStatus)) {
516        AbortAccess (CDF, noUPDATE, noDELETE);
517        return FALSE;
518      }
519    }
520    /***************************************************************************
521    * Return based on whether or not write access was obtained.
522    ***************************************************************************/
523    return (CDF->status == READ_WRITE);
524 #endif
525 }
526 
527 /******************************************************************************
528 * WriteBuffer.
529 *    Write occurs at current offset (assumed to have been set before this
530 * routine is called).  On IBM PCs, it is assumed that `nBytes' will not
531 * exceed 65535.
532 ******************************************************************************/
533 
WriteBuffer(CDF,fp,dataType,numElems,buffer)534 STATICforIDL CDFstatus WriteBuffer (CDF, fp, dataType, numElems, buffer)
535 struct CDFstruct *CDF;
536 vFILE *fp;
537 Int32 dataType;
538 Int32 numElems;
539 void *buffer;
540 {
541   CDFstatus pStatus = CDF_OK;
542   size_t nElemBytes = CDFelemSize(dataType);
543   size_t nBytes = (size_t) (numElems * nElemBytes);
544   double eValue; Int32 elemN; Byte *ptr; void *tBuffer;
545   /****************************************************************************
546   * Try to encode/write entire buffer.
547   ****************************************************************************/
548   tBuffer = cdf_AllocateMemory (nBytes, NULL);
549   if (tBuffer != NULL) {
550     if (!sX(ConvertBuffer(HostEncoding(),CDF->encoding,CDF->negToPosFp0,
551 			  dataType,numElems,buffer,tBuffer),&pStatus)) {
552       cdf_FreeMemory (tBuffer, NULL);
553       return pStatus;
554     }
555     if (!WRITEv(tBuffer,1,nBytes,fp)) {
556       cdf_FreeMemory (tBuffer, NULL);
557       return CDF_WRITE_ERROR;
558     }
559     cdf_FreeMemory (tBuffer, NULL);
560     return pStatus;
561   }
562   /****************************************************************************
563   * If that failed, encode/write one element at a time.
564   ****************************************************************************/
565   for (elemN = 0, ptr = buffer; elemN < numElems; elemN++, ptr += nElemBytes) {
566      if (!sX(ConvertBuffer(HostEncoding(),CDF->encoding,
567 			   CDF->negToPosFp0,dataType,1L,ptr,
568 			   &eValue),&pStatus)) return pStatus;
569      if (!WRITEv(&eValue,1,nElemBytes,fp)) return CDF_WRITE_ERROR;
570   }
571   return pStatus;
572 }
573 
574 /******************************************************************************
575 * NegativeZeroReal4.
576 * Checks for -0.0 (on any type computer).  Assumed to be in host encoding.
577 ******************************************************************************/
578 
NegativeZeroReal4(value)579 VISIBLE_PREFIX Logical NegativeZeroReal4 (value)
580 float *value;
581 {
582 #if defined(FP1cpu) || defined(FP2cpu)
583   return (*((uInt32 *) value) == (uInt32) 0x80000000);
584 #endif
585 #if defined(FP3cpu) || defined(FP4cpu)
586   /****************************************************************************
587   * On VAXes and DEC Alphas running OpenVMS/POSIXshell we're only interested
588   * in the sign bit and exponent.
589   ****************************************************************************/
590   return ((*((uInt32 *) value) & (uInt32) 0x0000FF80) == (uInt32) 0x00008000);
591 #endif
592 }
593 
594 /******************************************************************************
595 * NegativeZeroReal8.
596 * Checks for -0.0 (on any type computer).  Assumed to be in host encoding.
597 ******************************************************************************/
598 
NegativeZeroReal8(value)599 VISIBLE_PREFIX Logical NegativeZeroReal8 (value)
600 double *value;
601 {
602 #if defined(FP1cpu)
603   return ((*((uInt32 *) value) == (uInt32) 0x80000000) &&
604 	  (*((uInt32 *) value+1) == (uInt32) 0x00000000));
605 #endif
606 #if defined(FP2cpu)
607   return ((*((uInt32 *) value) == (uInt32) 0x00000000) &&
608 	  (*((uInt32 *) value+1) == (uInt32) 0x80000000));
609 #endif
610 #if defined(FP3cpu)
611   /****************************************************************************
612   * On VAXes and DEC Alphas running OpenVMS/POSIXshell in D_FLOAT mode we're
613   * only interested in the sign bit and exponent (which are in the first
614   * longword [32-bit]).
615   ****************************************************************************/
616   return ((*((uInt32 *) value) & (uInt32) 0x0000FF80) == (uInt32) 0x00008000);
617 #endif
618 #if defined(FP4cpu)
619   /****************************************************************************
620   * On DEC Alphas running OpenVMS/POSIXshell in G_FLOAT mode we're only
621   * interested in the sign bit and exponent (which are in the first longword
622   * [32-bit]).
623   ****************************************************************************/
624   return ((*((uInt32 *) value) & (uInt32) 0x0000FFF0) == (uInt32) 0x00008000);
625 #endif
626 }
627 
628 /******************************************************************************
629 * StripTrailingBlanks.
630 ******************************************************************************/
631 
StripTrailingBlanks(string)632 STATICforIDL void StripTrailingBlanks (string)
633 char *string;
634 {
635   int i;
636   for (i = strlen(string) - 1; i >= 0 && string[i] == ' '; i--) {
637      string[i] = NUL;
638   }
639   return;
640 }
641 
642 /******************************************************************************
643 * MakeUpperString.
644 * Convert string to upper-case.
645 ******************************************************************************/
646 
MakeUpperString(string)647 VISIBLE_PREFIX void MakeUpperString (string)
648 char *string;
649 {
650   int i;
651   for (i = 0; string[i] != NUL; i++) {
652      string[i] = (char) MakeUpper((int)string[i]);
653   }
654   return;
655 }
656 
657 /******************************************************************************
658 * MakeLowerString.
659 * Convert string to lower-case.
660 ******************************************************************************/
661 
MakeLowerString(string)662 VISIBLE_PREFIX void MakeLowerString (string)
663 char *string;
664 {
665   int i;
666   for (i = 0; string[i] != NUL; i++) {
667      string[i] = (char) MakeLower((int)string[i]);
668   }
669   return;
670 }
671 
672 /******************************************************************************
673 * SetBit32.
674 ******************************************************************************/
675 
SetBit32(value,bit)676 STATICforIDL void SetBit32 (value, bit)
677 Int32 *value;
678 int bit;
679 {
680   *value = *value | (1 << bit);
681   return;
682 }
683 
684 /******************************************************************************
685 * ClearBit32.
686 ******************************************************************************/
687 
ClearBit32(value,bit)688 STATICforIDL void ClearBit32 (value, bit)
689 Int32 *value;
690 int bit;
691 {
692   *value = *value & ~(1 << bit);
693   return;
694 }
695 
696 /******************************************************************************
697 * FindCDF.
698 *    Tries various extensions on the specified CDF path to see if the CDF
699 * exists.  The extensions tried are those which should be present on the
700 * various platforms plus the extensions which might be generated by a CD-ROM
701 * driver.  Finally, the pathname is tried without an extension being added
702 * in case the CDF had been renamed with a different extension or no extension.
703 ******************************************************************************/
704 
FindCDF(path,no_append,upper,version)705 STATICforIDL CDFstatus FindCDF (path, no_append, upper, version)
706 char *path;             /* Base pathname. */
707 Logical *no_append;     /* Should extensions/version numbers be appended? */
708 Logical *upper;         /* Should extensions be upper case? */
709 Logical *version;       /* Should a version number of `;1' be appended? */
710 {
711   char pathT[DU_MAX_PATH_LEN+1];
712 
713   strcpyX (pathT, path, DU_MAX_PATH_LEN);
714   strcatX (pathT, ".cdf", DU_MAX_PATH_LEN);
715   if (IsReg(pathT)) {
716     *no_append = FALSE;
717     *upper = FALSE;
718     *version = FALSE;
719     return CDF_OK;
720   }
721 
722   strcpyX (pathT, path, DU_MAX_PATH_LEN);
723   strcatX (pathT, ".CDF", DU_MAX_PATH_LEN);
724   if (IsReg(pathT)) {
725     *no_append = FALSE;
726     *upper = TRUE;
727     *version = FALSE;
728     return CDF_OK;
729   }
730 
731   strcpyX (pathT, path, DU_MAX_PATH_LEN);
732   strcatX (pathT, ".cdf;1", DU_MAX_PATH_LEN);
733   if (IsReg(pathT)) {
734     *no_append = FALSE;
735     *upper = FALSE;
736     *version = TRUE;
737     return CDF_OK;
738   }
739 
740   strcpyX (pathT, path, DU_MAX_PATH_LEN);
741   strcatX (pathT, ".CDF;1", DU_MAX_PATH_LEN);
742   if (IsReg(pathT)) {
743     *no_append = FALSE;
744     *upper = TRUE;
745     *version = TRUE;
746     return CDF_OK;
747   }
748 
749 #if defined(unix) || defined(dos)
750   strcpyX (pathT, path, DU_MAX_PATH_LEN);
751   MakeUpperString (pathT);
752   strcatX (pathT, ".CDF", DU_MAX_PATH_LEN);
753   if (IsReg(pathT)) {
754     *no_append = FALSE;
755     *upper = TRUE;
756     *version = FALSE;
757     return CDF_OK;
758   }
759 
760   strcpyX (pathT, path, DU_MAX_PATH_LEN);
761   MakeUpperString (pathT);
762   if (IsReg(pathT)) {
763     *no_append = TRUE;
764     *upper = TRUE;
765     *version = FALSE;
766     return CDF_OK;
767   }
768 #endif
769 
770   if (IsReg(path)) {
771     *no_append = TRUE;
772     *upper = FALSE;
773     *version = FALSE;
774     return CDF_OK;
775   }
776 
777   return NO_SUCH_CDF;
778 }
779 
780 /******************************************************************************
781 * BuildFilePath.
782 ******************************************************************************/
783 
BuildFilePath(fileType,pathBase,noAppend,upperCase,versionNumber,varN,pathX)784 STATICforIDL void BuildFilePath (fileType, pathBase, noAppend, upperCase,
785 				 versionNumber, varN, pathX)
786 int fileType;           /* Type of file. */
787 char *pathBase;         /* Base pathname. */
788 Logical noAppend;       /* Should extensions/version numbers be appended? */
789 Logical upperCase;      /* Should uppercase extensions be appended? */
790 Logical versionNumber;  /* Should a version number of `;1' be appended? */
791 Int32 varN;              /* Variable number.  N/a if a `cdf' file. */
792 char pathX[DU_MAX_PATH_LEN+1];
793 			/* The expanded path w/ extensions/version numbers. */
794 {
795   ExpandPath (pathBase, pathX);
796   if (!noAppend) {
797     switch (fileType) {
798       case CDFt:
799 	strcatX (pathX, (upperCase ? ".CDF" : ".cdf"), DU_MAX_PATH_LEN);
800 	break;
801       case Vt:
802 	strcatX (pathX, (upperCase ? ".V" : ".v"), DU_MAX_PATH_LEN);
803 	sprintf (EofS(pathX), "%d", varN);
804 	break;
805       case Zt:
806 	strcatX (pathX, (upperCase ? ".Z" : ".z"), DU_MAX_PATH_LEN);
807 	sprintf (EofS(pathX), "%d", varN);
808 	break;
809     }
810     strcatX (pathX, (versionNumber ? ";1" : ""), DU_MAX_PATH_LEN);
811   }
812   return;
813 }
814 
815 /******************************************************************************
816 * NulPad.
817 *    Pads with NUL characters to the length specified.  Also NUL-terminates
818 * the string.
819 ******************************************************************************/
820 
NulPad(string,length)821 STATICforIDL void NulPad (string, length)
822 char *string;
823 int length;
824 {
825   int i;
826   for (i = strlen(string); i < length; i++) string[i] = NUL;
827   string[length] = NUL;
828   return;
829 }
830 
831 /******************************************************************************
832 * UpdateMaxRec.
833 ******************************************************************************/
834 
UpdateMaxRec(CDF,Var,recNum)835 STATICforIDL CDFstatus UpdateMaxRec (CDF, Var, recNum)
836 struct CDFstruct *CDF;          /* In: Pointer to CDF. */
837 struct VarStruct *Var;          /* In: Pointer to variable. */
838 Int32 recNum;                    /* In: Possible new maximum record number. */
839 {
840   CDFstatus pStatus = CDF_OK;
841   if (recNum > Var->maxRec) {
842     Var->maxRec = recNum;
843     if (!sX(WriteVDR(CDF,CDF->fp,Var->VDRoffset,Var->zVar,
844 		     VDR_MAXREC,&recNum,
845 		     VDR_NULL),&pStatus)) return pStatus;
846   }
847   if (!Var->zVar) {
848     if (recNum > CDF->rMaxRec) {
849       CDF->rMaxRec = recNum;
850       if (!sX(WriteGDR(CDF->fp,CDF->GDRoffset,
851 		       GDR_rMAXREC,&recNum,
852 		       GDR_NULL),&pStatus)) return pStatus;
853     }
854   }
855   return pStatus;
856 }
857 
858 /******************************************************************************
859 * CalcDimParms.
860 *    Calculates a variable's number of dimensions, dimension sizes, and
861 * dimension variances depending on the current zMode.
862 ******************************************************************************/
863 
CalcDimParms(CDF,offset,zVar,numDimsP,dimSizesP,dimVarysP)864 STATICforIDL CDFstatus CalcDimParms (CDF, offset, zVar, numDimsP, dimSizesP,
865 				     dimVarysP)
866 struct CDFstruct *CDF;          /* In: Pointer to CDF. */
867 Int32 offset;                   /* In: Offset of VDR. */
868 Logical zVar;                   /* In: TRUE if a true zVariable.  FALSE if a
869 				       true rVariable. */
870 Int32 *numDimsP;		/* Out: Number of dimensions. */
871 Int32 dimSizesP[];              /* Out: Dimension sizes. */
872 Int32 dimVarysP[];		/* Out: Dimension variances. */
873 {
874   CDFstatus pStatus = CDF_OK; int dN;
875   Int32 tNumDims, tDimSizes[CDF_MAX_DIMS], tDimVarys[CDF_MAX_DIMS];
876   Int32 numDims, dimSizes[CDF_MAX_DIMS], dimVarys[CDF_MAX_DIMS];
877   /****************************************************************************
878   * Determine `true' parameters.
879   ****************************************************************************/
880   if (zVar) {
881     if (!sX(ReadVDR(CDF,CDF->fp,offset,TRUE,
882 		    VDR_zNUMDIMS,&tNumDims,
883 		    VDR_zDIMSIZES,tDimSizes,
884 		    VDR_DIMVARYS,tDimVarys,
885 		    VDR_NULL),&pStatus)) return pStatus;
886   }
887   else {
888     if (!sX(ReadGDR(CDF->fp,CDF->GDRoffset,
889 		    GDR_rNUMDIMS,&tNumDims,
890 		    GDR_rDIMSIZES,tDimSizes,
891 		    GDR_NULL),&pStatus)) return pStatus;
892     if (!sX(ReadVDR(CDF,CDF->fp,offset,FALSE,
893 		    VDR_DIMVARYS,tDimVarys,
894 		    VDR_NULL),&pStatus)) return pStatus;
895   }
896   /****************************************************************************
897   * Determine parameters based on zMode and if r/zVariable.
898   ****************************************************************************/
899   if (CDF->zMode == zMODEon2 && !zVar) {
900     for (dN = 0, numDims = 0; dN < tNumDims; dN++) {
901        if (tDimVarys[dN]) {
902 	 dimSizes[(int)numDims] = tDimSizes[dN];
903 	 dimVarys[(int)numDims] = VARY;
904 	 numDims++;
905        }
906     }
907   }
908   else {
909     numDims = tNumDims;
910     for (dN = 0; dN < tNumDims; dN++) {
911        dimSizes[dN] = tDimSizes[dN];
912        dimVarys[dN] = tDimVarys[dN];
913     }
914   }
915   /****************************************************************************
916   * Assign those values requested.
917   ****************************************************************************/
918   ASSIGNnotNULL (numDimsP, numDims)
919   ASSIGNnotNULLarray (dimSizesP, numDims, dimSizes)
920   ASSIGNnotNULLarray (dimVarysP, numDims, dimVarys)
921   return pStatus;
922 }
923 
924 /******************************************************************************
925 * NULterminateMAX.
926 *    NUL-terminate a string but only if a NUL is not found before the maximum
927 * length is reached.
928 ******************************************************************************/
929 
NULterminateMAX(string,maxLen)930 STATICforIDL void NULterminateMAX (string, maxLen)
931 char *string;
932 size_t maxLen;
933 {
934   int i;
935   for (i = 0; i < (int) maxLen; i++)
936      if (string[i] == NUL) return;
937   string[maxLen] = NUL;
938   return;
939 }
940 
941 /******************************************************************************
942 * ClearBytes.
943 ******************************************************************************/
944 
ClearBytes(buffer,firstByte,lastByte)945 VISIBLE_PREFIX void ClearBytes (buffer, firstByte, lastByte)
946 void *buffer;
947 int firstByte;
948 int lastByte;
949 {
950   int i;
951   for (i = firstByte; i <= lastByte; i++) ((Byte *)buffer)[i] = 0;
952   return;
953 }
954 
955 /******************************************************************************
956 * WasteIR.
957 ******************************************************************************/
958 
WasteIR(CDF,wasteOffset,size)959 STATICforIDL CDFstatus WasteIR (CDF, wasteOffset, size)
960 struct CDFstruct *CDF;
961 Int32 wasteOffset;
962 Int32 size;
963 {
964   CDFstatus pStatus = CDF_OK;
965   struct UIRstruct newUIR, firstUIR, tUIR, nextUIR;
966   Int32 tOffset, nextOffset, UIRhead;
967 
968   /****************************************************************************
969   * Begin initializing UIR.
970   ****************************************************************************/
971   newUIR.RecordSize = size;
972   newUIR.RecordType = UIR_;
973   /****************************************************************************
974   * Check that the internal record being wasted is big enough for the `next'
975   * and `previous' fields.  If not, mark it as wasted but don't place it in
976   * the linked list of UIRs.  Note that there will always be enough room for
977   * the `size' and `type' fields.  If not, an internal logic error has occured.
978   ****************************************************************************/
979   if (size < UIR_BASE_SIZE) {
980     if (size < UUIR_BASE_SIZE) return CDF_INTERNAL_ERROR;
981     if (!sX(WriteUIR(CDF->fp,wasteOffset,
982 		     UIR_RECORDSIZE,&(newUIR.RecordSize),
983 		     UIR_RECORDTYPE,&(newUIR.RecordType),
984 		     UIR_NULL),&pStatus)) return pStatus;
985     return pStatus;
986   }
987   /****************************************************************************
988   * Read offset of first UIR.
989   ****************************************************************************/
990   if (!sX(ReadGDR(CDF->fp,CDF->GDRoffset,
991 		  GDR_UIRHEAD,&UIRhead,
992 		  GDR_NULL),&pStatus)) return pStatus;
993   /****************************************************************************
994   * Check if no UIRs exist yet.
995   ****************************************************************************/
996   if (UIRhead == 0) {
997     newUIR.NextUIR = 0;
998     newUIR.PrevUIR = 0;
999     if (!sX(WriteUIR(CDF->fp,wasteOffset,
1000 		     UIR_RECORD,&newUIR,
1001 		     UIR_NULL),&pStatus)) return pStatus;
1002     UIRhead = wasteOffset;
1003     if (!sX(WriteGDR(CDF->fp,CDF->GDRoffset,
1004 		     GDR_UIRHEAD,&UIRhead,
1005 		     GDR_NULL),&pStatus)) return pStatus;
1006     return pStatus;
1007   }
1008   /****************************************************************************
1009   * At least one UIR exists, check if the new UIR is before the first UIR.
1010   ****************************************************************************/
1011   if (wasteOffset < UIRhead) {
1012     if (!sX(ReadUIR(CDF->fp,UIRhead,
1013 		    UIR_RECORD,&firstUIR,
1014 		    UIR_NULL),&pStatus)) return pStatus;
1015     newUIR.NextUIR = UIRhead;
1016     newUIR.PrevUIR = 0;
1017     if (!sX(WriteUIR(CDF->fp,wasteOffset,
1018 		     UIR_RECORD,&newUIR,
1019 		     UIR_NULL),&pStatus)) return pStatus;
1020     firstUIR.PrevUIR = wasteOffset;
1021     if (!sX(WriteUIR(CDF->fp,UIRhead,
1022 		     UIR_RECORD,&firstUIR,
1023 		     UIR_NULL),&pStatus)) return pStatus;
1024     UIRhead = wasteOffset;
1025     if (!sX(WriteGDR(CDF->fp,CDF->GDRoffset,
1026 		     GDR_UIRHEAD,&UIRhead,
1027 		     GDR_NULL),&pStatus)) return pStatus;
1028     return pStatus;
1029   }
1030   /****************************************************************************
1031   * The new UIR is not before the first UIR.  Scan the UIRs to find the point
1032   * at which it should be inserted.
1033   ****************************************************************************/
1034   tOffset = UIRhead;
1035   if (!sX(ReadUIR(CDF->fp,tOffset,
1036 		  UIR_RECORD,&tUIR,
1037 		  UIR_NULL),&pStatus)) return pStatus;
1038   while (tUIR.NextUIR != 0) {
1039     if (wasteOffset < tUIR.NextUIR) {
1040       nextOffset = tUIR.NextUIR;
1041       if (!sX(ReadUIR(CDF->fp,nextOffset,
1042 		      UIR_RECORD,&nextUIR,
1043 		      UIR_NULL),&pStatus)) return pStatus;
1044       newUIR.NextUIR = tUIR.NextUIR;
1045       newUIR.PrevUIR = tOffset;
1046       if (!sX(WriteUIR(CDF->fp,wasteOffset,
1047 		       UIR_RECORD,&newUIR,
1048 		       UIR_NULL),&pStatus)) return pStatus;
1049       tUIR.NextUIR = wasteOffset;
1050       if (!sX(WriteUIR(CDF->fp,tOffset,
1051 		       UIR_RECORD,&tUIR,
1052 		       UIR_NULL),&pStatus)) return pStatus;
1053       nextUIR.PrevUIR = wasteOffset;
1054       if (!sX(WriteUIR(CDF->fp,nextOffset,
1055 		       UIR_RECORD,&nextUIR,
1056 		       UIR_NULL),&pStatus)) return pStatus;
1057       return pStatus;
1058     }
1059     tOffset = tUIR.NextUIR;
1060     if (!sX(ReadUIR(CDF->fp,tOffset,
1061 		    UIR_RECORD,&tUIR,
1062 		    UIR_NULL),&pStatus)) return pStatus;
1063   }
1064   /****************************************************************************
1065   * The new UIR is going to be the last UIR.
1066   ****************************************************************************/
1067   newUIR.NextUIR = 0;
1068   newUIR.PrevUIR = tOffset;
1069   if (!sX(WriteUIR(CDF->fp,wasteOffset,
1070 		   UIR_RECORD,&newUIR,
1071 		   UIR_NULL),&pStatus)) return pStatus;
1072   tUIR.NextUIR = wasteOffset;
1073   if (!sX(WriteUIR(CDF->fp,tOffset,
1074 		   UIR_RECORD,&tUIR,
1075 		   UIR_NULL),&pStatus)) return pStatus;
1076   return pStatus;
1077 }
1078 
1079 /******************************************************************************
1080 * AllocateIR.
1081 ******************************************************************************/
1082 
AllocateIR(CDF,size,offset)1083 STATICforIDL CDFstatus AllocateIR (CDF, size, offset)
1084 struct CDFstruct *CDF;          /* In: Pointer to CDF. */
1085 Int32 size;                     /* In: Size of internal record (bytes). */
1086 Int32 *offset;                  /* Out: Offset of allocated internal record. */
1087 {
1088   CDFstatus pStatus = CDF_OK;
1089   Int32 sOffset, eOffset, tSize, UIRhead, eof, uir_ = UIR_;
1090   struct UIRstruct sUIR, eUIR;
1091   /****************************************************************************
1092   * Read EOF and offset of first UIR from GDR.
1093   ****************************************************************************/
1094   if (!sX(ReadGDR(CDF->fp,CDF->GDRoffset,
1095 		  GDR_UIRHEAD,&UIRhead,
1096 		  GDR_EOF,&eof,
1097 		  GDR_NULL),&pStatus)) return pStatus;
1098   /****************************************************************************
1099   * If UIRs exist, try to use one or more of them (if contiguous) for the new
1100   * internal record.
1101   ****************************************************************************/
1102   if (UIRhead != 0) {
1103     sOffset = UIRhead;
1104     if (!sX(ReadUIR(CDF->fp,sOffset,
1105 		    UIR_RECORD,&sUIR,
1106 		    UIR_NULL),&pStatus)) return pStatus;
1107     eOffset = sOffset;
1108     eUIR = sUIR;
1109     tSize = sUIR.RecordSize;
1110     for (;;) {
1111        /***********************************************************************
1112        * Check if the starting to ending UIRs are the exact size needed.
1113        ***********************************************************************/
1114        if (size == tSize) {
1115 	 if (!sX(RemoveUIRs(CDF,sOffset,eOffset),&pStatus)) return pStatus;
1116 	 if (!sX(WriteIrSize(CDF->fp,sOffset,&size),&pStatus)) return pStatus;
1117 	 if (!sX(WriteIrType(CDF->fp,sOffset,&uir_),&pStatus)) return pStatus;
1118 	 *offset = sOffset;
1119 	 return pStatus;
1120        }
1121        /***********************************************************************
1122        * Check if the starting to ending UIRs are big enough for the new
1123        * internal record and for a new UIR to fill the remaining space.
1124        ***********************************************************************/
1125        if (size + UIR_BASE_SIZE <= tSize) {
1126 	 if (!sX(RemoveUIRs(CDF,sOffset,eOffset),&pStatus)) return pStatus;
1127 	 if (!sX(WasteIR(CDF,sOffset+size,tSize-size),&pStatus)) {
1128 	   return pStatus;
1129 	 }
1130 	 if (!sX(WriteIrSize(CDF->fp,sOffset,&size),&pStatus)) return pStatus;
1131 	 if (!sX(WriteIrType(CDF->fp,sOffset,&uir_),&pStatus)) return pStatus;
1132 	 *offset = sOffset;
1133 	 return pStatus;
1134        }
1135        /***********************************************************************
1136        * Check if the end of the UIRs has been reached.  If so, check if the
1137        * ending UIR is the last IR in the dotCDF file.
1138        ***********************************************************************/
1139        if (eUIR.NextUIR == 0) {
1140 	 if (eOffset + eUIR.RecordSize == eof) {
1141 	   /*******************************************************************
1142 	   * The ending UIR is the last internal record in the CDF.  Check to
1143 	   * see if after allocating the new internal record less than
1144 	   * UIR_BASE_SIZE bytes will remain before the EOF.  If so, waste an
1145 	   * internal record at the location of those bytes so that a UIR is
1146 	   * at the end (rather than stranded bytes).
1147 	   *******************************************************************/
1148 	   if (!sX(RemoveUIRs(CDF,sOffset,eOffset),&pStatus)) return pStatus;
1149 	   if (size < tSize) {
1150 	     if (!sX(WasteIR(CDF,sOffset+size,
1151 			     UIR_BASE_SIZE),&pStatus)) return pStatus;
1152 	     eof = sOffset + size + UIR_BASE_SIZE;
1153 	   }
1154 	   else
1155 	     eof = sOffset + size;
1156 	   if (!sX(WriteGDR(CDF->fp,CDF->GDRoffset,
1157 			    GDR_EOF,&eof,
1158 			    GDR_NULL),&pStatus)) return pStatus;
1159 	   if (!sX(WriteIrSize(CDF->fp,
1160 			       sOffset,
1161 			       &size),&pStatus)) return pStatus;
1162 	   if (!sX(WriteIrType(CDF->fp,
1163 			       sOffset,
1164 			       &uir_),&pStatus)) return pStatus;
1165 	   *offset = sOffset;
1166 	   return pStatus;
1167 	 }
1168 	 else {
1169 	   /*******************************************************************
1170 	   * Non-UIRs follow the ending UIR.  The new internal record will
1171 	   * have to be allocated at the EOF.
1172 	   *******************************************************************/
1173 	   *offset = eof;
1174 	   if (!sX(WriteIrSize(CDF->fp,eof,&size),&pStatus)) return pStatus;
1175 	   if (!sX(WriteIrType(CDF->fp,eof,&uir_),&pStatus)) return pStatus;
1176 	   eof += size;
1177 	   if (!sX(WriteGDR(CDF->fp,CDF->GDRoffset,
1178 			    GDR_EOF,&eof,
1179 			    GDR_NULL),&pStatus)) return pStatus;
1180 	   return pStatus;
1181 	 }
1182        }
1183        /***********************************************************************
1184        * If the next UIR is contiguous with the ending UIR, make it the ending
1185        * UIR.  Otherwise, make the next UIR the starting and ending UIRs.
1186        ***********************************************************************/
1187        if (eOffset + eUIR.RecordSize == eUIR.NextUIR) {
1188 	 eOffset = eUIR.NextUIR;
1189 	 if (!sX(ReadUIR(CDF->fp,eOffset,
1190 			 UIR_RECORD,&eUIR,
1191 			 UIR_NULL),&pStatus)) return pStatus;
1192 	 tSize += eUIR.RecordSize;
1193        }
1194        else {
1195 	 sOffset = eUIR.NextUIR;
1196 	 if (!sX(ReadUIR(CDF->fp,sOffset,
1197 			 UIR_RECORD,&sUIR,
1198 			 UIR_NULL),&pStatus)) return pStatus;
1199 	 eOffset = sOffset;
1200 	 eUIR = sUIR;
1201 	 tSize = sUIR.RecordSize;
1202        }
1203     }
1204   }
1205   /****************************************************************************
1206   * No UIRs exist.  The new internal record will have to be allocated at the
1207   * EOF.
1208   ****************************************************************************/
1209   *offset = eof;
1210   if (!sX(WriteIrSize(CDF->fp,eof,&size),&pStatus)) return pStatus;
1211   if (!sX(WriteIrType(CDF->fp,eof,&uir_),&pStatus)) return pStatus;
1212   eof += size;
1213   if (!sX(WriteGDR(CDF->fp,CDF->GDRoffset,
1214 		   GDR_EOF,&eof,
1215 		   GDR_NULL),&pStatus)) return pStatus;
1216   return pStatus;
1217 }
1218 
1219 /******************************************************************************
1220 * ResizeIR.
1221 ******************************************************************************/
1222 
ResizeIR(CDF,curOffset,newSize,newOffset,move,success)1223 STATICforIDL CDFstatus ResizeIR (CDF, curOffset, newSize, newOffset, move,
1224 				 success)
1225 struct CDFstruct *CDF;
1226 Int32 curOffset;        /* In: Current offset of internal record. */
1227 Int32 newSize;          /* In: New size of internal record.  This may be
1228 			   smaller or larger than the current size. */
1229 Int32 *newOffset;       /* Out: New offset of internal record.  This variable
1230 			   is not modified if an error occurs or the internal
1231 			   record cannot be extended (when `move' is FALSE). */
1232 Logical move;           /* In: TRUE if the internal record can be moved if
1233 			   necessary. */
1234 Logical *success;       /* Out: TRUE if the internal record was successfully
1235 			   extended (whether or not it had to be moved). */
1236 {
1237   CDFstatus pStatus = CDF_OK; Int32 curSize; Int32 eof;
1238   /****************************************************************************
1239   * Determine current size of internal record.
1240   ****************************************************************************/
1241   if (!sX(ReadIrSize(CDF->fp,curOffset,&curSize),&pStatus)) return pStatus;
1242   /****************************************************************************
1243   * Check sizes...
1244   ****************************************************************************/
1245   if (newSize > curSize) {
1246     /**************************************************************************
1247     * The internal record is growing.  First check if it is the last one in
1248     * the CDF.
1249     **************************************************************************/
1250     if (!sX(ReadGDR(CDF->fp,CDF->GDRoffset,
1251 		    GDR_EOF,&eof,
1252 		    GDR_NULL),&pStatus)) return pStatus;
1253     if (curOffset + curSize == eof) {
1254       /************************************************************************
1255       * Last internal record.  Simply extend the CDF.
1256       ************************************************************************/
1257       ASSIGNnotNULL (newOffset, curOffset)
1258       eof += (newSize - curSize);
1259       if (!sX(WriteGDR(CDF->fp,CDF->GDRoffset,
1260 		       GDR_EOF,&eof,
1261 		       GDR_NULL),&pStatus)) return pStatus;
1262       if (!sX(WriteIrSize(CDF->fp,
1263 			  curOffset,
1264 			  &newSize),&pStatus)) return pStatus;
1265       ASSIGNnotNULL (success, TRUE)
1266       return pStatus;
1267     }
1268     else {
1269       /************************************************************************
1270       * Not the last internal record.  If the internal record may be moved,
1271       * first mark it as unused and then allocate a new internal record.
1272       * Marking it unused first allows the possibility that if will be used
1273       * as part of the allocated internal record.  If the internal record can
1274       * not be moved, check if unused records immediately follow.
1275       ************************************************************************/
1276       if (move) {
1277 	if (!sX(WasteIR(CDF,curOffset,curSize),&pStatus)) return pStatus;
1278 	if (!sX(AllocateIR(CDF,newSize,newOffset),&pStatus)) return pStatus;
1279 	ASSIGNnotNULL (success, TRUE)
1280 	return pStatus;
1281       }
1282       else {
1283 	Int32 sOffset, eOffset, tSize, UIRhead, irType;
1284 	struct UIRstruct sUIR, eUIR;
1285 	/**********************************************************************
1286 	* First check if there are any UIRs in the CDF.  This is done because
1287 	* CDF V2.5.0* (alpha/beta) created UIRs without the next and previous
1288 	* UIR fields and didn't use the `UIRhead' field in the GDR.  Because
1289 	* we don't want to use UIRs in those CDFs (because they are not the
1290 	* same as the current UIRs), this will keep us from doing so (because
1291 	* the `UIRhead' fields will always contain zero if a V2.5.0* CDF).
1292 	**********************************************************************/
1293 	if (!sX(ReadGDR(CDF->fp,CDF->GDRoffset,
1294 			GDR_UIRHEAD,&UIRhead,
1295 			GDR_NULL),&pStatus)) return pStatus;
1296 	if (UIRhead == 0) {
1297 	  ASSIGNnotNULL (success, FALSE)
1298 	  return pStatus;
1299 	}
1300 	/**********************************************************************
1301 	* Read the internal record which immediately follows the internal
1302 	* record being resized.  If it is a UIR make it the starting UIR.
1303 	* ---------------------------- DANGER ---------------------------------
1304 	* Don't try to read an entire UIR.  First read only the record type
1305 	* field and check if it is UIR_.  Then read the entire UIR.  This is
1306 	* because the next internal record could be smaller than a UIR (or
1307 	* larger but not entirely written yet [eg. a VVR]).
1308 	**********************************************************************/
1309 	sOffset = curOffset + curSize;
1310 	if (!sX(ReadIrType(CDF->fp,sOffset,&irType),&pStatus)) return pStatus;
1311 	if (irType != UIR_) {
1312 	  ASSIGNnotNULL (success, FALSE)
1313 	  return pStatus;
1314 	}
1315 	if (!sX(ReadUIR(CDF->fp,sOffset,
1316 			UIR_RECORD,&sUIR,
1317 			UIR_NULL),&pStatus)) return pStatus;
1318 	tSize = curSize + sUIR.RecordSize;
1319 	eOffset = sOffset;
1320 	eUIR = sUIR;
1321 	for (;;) {
1322 	   /*******************************************************************
1323 	   * Check if the exact amount of available space has been found.
1324 	   *******************************************************************/
1325 	   if (newSize == tSize) {
1326 	     if (!sX(RemoveUIRs(CDF,sOffset,eOffset),&pStatus)) return pStatus;
1327 	     if (!sX(WriteIrSize(CDF->fp,
1328 				 curOffset,
1329 				 &newSize),&pStatus)) return pStatus;
1330 	     ASSIGNnotNULL (newOffset, curOffset)
1331 	     ASSIGNnotNULL (success, TRUE)
1332 	     return pStatus;
1333 	   }
1334 	   /*******************************************************************
1335 	   * Check if enough available space has been found to increase the
1336 	   * internal record and then create a new UIR in the remaining space.
1337 	   *******************************************************************/
1338 	   if (newSize + UIR_BASE_SIZE <= tSize) {
1339 	     if (!sX(RemoveUIRs(CDF,sOffset,eOffset),&pStatus)) return pStatus;
1340 	     if (!sX(WasteIR(CDF,curOffset+newSize,tSize-newSize),&pStatus)) {
1341 	       return pStatus;
1342 	     }
1343 	     if (!sX(WriteIrSize(CDF->fp,
1344 				 curOffset,
1345 				 &newSize),&pStatus)) return pStatus;
1346 	     ASSIGNnotNULL (newOffset, curOffset)
1347 	     ASSIGNnotNULL (success, TRUE)
1348 	     return pStatus;
1349 	   }
1350 	   /*******************************************************************
1351 	   * Check if the end of the UIRs has been reached.
1352 	   *******************************************************************/
1353 	   if (eUIR.NextUIR == 0) {
1354 	     /*****************************************************************
1355 	     * If the ending UIR is at the EOF, then the internal record can
1356 	     * be extended beyond the EOF or up to it with the creation of a
1357 	     * new UIR at the very end.
1358 	     *****************************************************************/
1359 	     if (eOffset + eUIR.RecordSize == eof) {
1360 	       if (!sX(RemoveUIRs(CDF,sOffset,eOffset),&pStatus)) return
1361 								  pStatus;
1362 	       if (newSize < tSize) {
1363 		 if (!sX(WasteIR(CDF,curOffset+newSize,
1364 				 UIR_BASE_SIZE),&pStatus)) return pStatus;
1365 		 eof = curOffset + newSize + UIR_BASE_SIZE;
1366 	       }
1367 	       else
1368 		 eof = curOffset + newSize;
1369 	       if (!sX(WriteGDR(CDF->fp,CDF->GDRoffset,
1370 				GDR_EOF,&eof,
1371 				GDR_NULL),&pStatus)) return pStatus;
1372 	       if (!sX(WriteIrSize(CDF->fp,
1373 				   curOffset,
1374 				   &newSize),&pStatus)) return pStatus;
1375 	       ASSIGNnotNULL (newOffset, curOffset)
1376 	       ASSIGNnotNULL (success, TRUE)
1377 	       return pStatus;
1378 	     }
1379 	     else {
1380 	       ASSIGNnotNULL (success, FALSE)
1381 	       return pStatus;
1382 	     }
1383 	   }
1384 	   /*******************************************************************
1385 	   * If the next UIR is contiguous with the ending UIR, make it the
1386 	   * ending UIR.
1387 	   *******************************************************************/
1388 	   if (eOffset + eUIR.RecordSize == eUIR.NextUIR) {
1389 	     eOffset = eUIR.NextUIR;
1390 	     if (!sX(ReadUIR(CDF->fp,eOffset,
1391 			     UIR_RECORD,&eUIR,
1392 			     UIR_NULL),&pStatus)) return pStatus;
1393 	     tSize += eUIR.RecordSize;
1394 	   }
1395 	   else {
1396 	     ASSIGNnotNULL (success, FALSE)
1397 	     return pStatus;
1398 	   }
1399 	}
1400       }
1401     }
1402   }
1403   else {
1404     /**************************************************************************
1405     * The internal record is shrinking.  Check if it can be shrunk in place
1406     * and a UIR created to occupy the extra space.  If not, waste it and then
1407     * allocate a new internal record (if moving it is allowed).
1408     **************************************************************************/
1409     if (newSize <= (curSize - UIR_BASE_SIZE)) {
1410       if (!sX(WasteIR(CDF,curOffset + newSize,
1411 		      curSize - newSize),&pStatus)) return pStatus;
1412       if (!sX(WriteIrSize(CDF->fp,
1413 			  curOffset,
1414 			  &newSize),&pStatus)) return pStatus;
1415       ASSIGNnotNULL (newOffset, curOffset)
1416       ASSIGNnotNULL (success, TRUE)
1417     }
1418     else {
1419       if (move) {
1420 	if (!sX(WasteIR(CDF,curOffset,curSize),&pStatus)) return pStatus;
1421 	if (!sX(AllocateIR(CDF,newSize,newOffset),&pStatus)) return pStatus;
1422 	ASSIGNnotNULL (success, TRUE)
1423       }
1424       else {
1425 	ASSIGNnotNULL (success, FALSE)
1426       }
1427     }
1428     return pStatus;
1429   }
1430 }
1431 
1432 /******************************************************************************
1433 * RemoveUIRs.
1434 ******************************************************************************/
1435 
RemoveUIRs(CDF,sOffset,eOffset)1436 STATICforIDL CDFstatus RemoveUIRs (CDF, sOffset, eOffset)
1437 struct CDFstruct *CDF;          /* In: Pointer to CDF. */
1438 Int32 sOffset;                  /* In: Offset of starting UIR. */
1439 Int32 eOffset;                  /* In: Offset of ending UIR. */
1440 {
1441   CDFstatus pStatus = CDF_OK;
1442   struct UIRstruct sUIR, eUIR;
1443   Int32 UIRhead;
1444   if (!sX(ReadGDR(CDF->fp,CDF->GDRoffset,
1445 		  GDR_UIRHEAD,&UIRhead,
1446 		  GDR_NULL),&pStatus)) return pStatus;
1447   if (!sX(ReadUIR(CDF->fp,sOffset,
1448 		  UIR_RECORD,&sUIR,
1449 		  UIR_NULL),&pStatus)) return pStatus;
1450   if (!sX(ReadUIR(CDF->fp,eOffset,
1451 		  UIR_RECORD,&eUIR,
1452 		  UIR_NULL),&pStatus)) return pStatus;
1453   if (UIRhead == sOffset) {
1454     UIRhead = eUIR.NextUIR;
1455     if (!sX(WriteGDR(CDF->fp,CDF->GDRoffset,
1456 		     GDR_UIRHEAD,&UIRhead,
1457 		     GDR_NULL),&pStatus)) return pStatus;
1458   }
1459   else {
1460     struct UIRstruct prevUIR;
1461     if (!sX(ReadUIR(CDF->fp,sUIR.PrevUIR,
1462 		    UIR_RECORD,&prevUIR,
1463 		    UIR_NULL),&pStatus)) return pStatus;
1464     prevUIR.NextUIR = eUIR.NextUIR;
1465     if (!sX(WriteUIR(CDF->fp,sUIR.PrevUIR,
1466 		     UIR_RECORD,&prevUIR,
1467 		     UIR_NULL),&pStatus)) return pStatus;
1468   }
1469   if (eUIR.NextUIR != 0) {
1470     struct UIRstruct nextUIR;
1471     if (!sX(ReadUIR(CDF->fp,eUIR.NextUIR,
1472 		    UIR_RECORD,&nextUIR,
1473 		    UIR_NULL),&pStatus)) return pStatus;
1474     nextUIR.PrevUIR = sUIR.PrevUIR;
1475     if (!sX(WriteUIR(CDF->fp,eUIR.NextUIR,
1476 		     UIR_RECORD,&nextUIR,
1477 		     UIR_NULL),&pStatus)) return pStatus;
1478   }
1479   return pStatus;
1480 }
1481 
1482 /******************************************************************************
1483 * PriorTo.
1484 ******************************************************************************/
1485 
PriorTo(spec,version,release,increment)1486 VISIBLE_PREFIX Logical PriorTo (spec, version, release, increment)
1487 char *spec;
1488 Int32 version;
1489 Int32 release;
1490 Int32 increment;
1491 {
1492   int ver, rel, incr;
1493   switch (sscanf(spec,"%d.%d.%d",&ver,&rel,&incr)) {
1494     case 1:
1495       if (version < ver) return TRUE;
1496       break;
1497     case 2:
1498       if (version < ver) return TRUE;
1499       if (version == ver && release < rel) return TRUE;
1500       break;
1501     case 3:
1502       if (version < ver) return TRUE;
1503       if (version == ver && release < rel) return TRUE;
1504       if (version == ver && release == rel && increment < incr) return TRUE;
1505       break;
1506   }
1507   return FALSE;
1508 }
1509 
1510 /******************************************************************************
1511 * ShortenCDR.
1512 ******************************************************************************/
1513 
ShortenCDR(CDF)1514 STATICforIDL CDFstatus ShortenCDR (CDF)
1515 struct CDFstruct *CDF;
1516 {
1517   CDFstatus pStatus = CDF_OK;
1518   Int32 offset, oldRecordSize, newRecordSize, nBytes;
1519   if (!sX(ReadCDR(CDF->fp,CDF->CDRoffset,
1520 		  CDR_RECORDSIZE,&oldRecordSize,
1521 		  CDR_NULL),&pStatus))
1522     return pStatus;
1523   newRecordSize = CDR_BASE_SIZE + CDF_COPYRIGHT_LEN;
1524   if (!sX(WriteCDR(CDF->fp,V2_CDR_OFFSET,
1525 		   CDR_RECORDSIZE,&newRecordSize,
1526 		   CDR_NULL),&pStatus)) return pStatus;
1527   offset = CDF->CDRoffset + newRecordSize;
1528   nBytes = oldRecordSize - newRecordSize;
1529   if (!sX(WasteIR(CDF,offset,nBytes),&pStatus)) return pStatus;
1530   return pStatus;
1531 }
1532 
1533 /******************************************************************************
1534 * CorrectScopes.
1535 *    It is assumed that the last ADR offset has already been fixed.
1536 ******************************************************************************/
1537 
CorrectScopes(CDF)1538 STATICforIDL CDFstatus CorrectScopes (CDF)
1539 struct CDFstruct *CDF;
1540 {
1541   Int32 tOffset, attrScope;
1542   CDFstatus pStatus = CDF_OK;
1543   /****************************************************************************
1544   * Read the offset of the first ADR from the GDR.
1545   ****************************************************************************/
1546   if (!sX(ReadGDR(CDF->fp,CDF->GDRoffset,
1547 		  GDR_ADRHEAD,&tOffset,
1548 		  GDR_NULL),&pStatus)) return pStatus;
1549   /****************************************************************************
1550   * Read the ADRs correcting each assumed scope.
1551   ****************************************************************************/
1552   while (tOffset != 0) {
1553      if (!sX(ReadADR(CDF->fp,tOffset,
1554 		     ADR_SCOPE,&attrScope,
1555 		     ADR_NULL),&pStatus)) return pStatus;
1556      switch (attrScope) {
1557        case GLOBALscopeASSUMED:
1558 	 attrScope = GLOBAL_SCOPE;
1559 	 if (!sX(WriteADR(CDF->fp,tOffset,
1560 			  ADR_SCOPE,&attrScope,
1561 			  ADR_NULL),&pStatus)) return pStatus;
1562 	 break;
1563        case VARIABLEscopeASSUMED:
1564 	 attrScope = VARIABLE_SCOPE;
1565 	 if (!sX(WriteADR(CDF->fp,tOffset,
1566 			  ADR_SCOPE,&attrScope,
1567 			  ADR_NULL),&pStatus)) return pStatus;
1568 	 break;
1569      }
1570      if (!sX(ReadADR(CDF->fp,tOffset,
1571 		     ADR_ADRNEXT,&tOffset,
1572 		     ADR_NULL),&pStatus)) return pStatus;
1573   }
1574   return pStatus;
1575 }
1576 
1577 /******************************************************************************
1578 * ShortenVDRs.
1579 *    It is assumed that the last rVDR offset has already been fixed.
1580 ******************************************************************************/
1581 
ShortenVDRs(CDF)1582 STATICforIDL CDFstatus ShortenVDRs (CDF)
1583 struct CDFstruct *CDF;
1584 {
1585   Int32 vOffset, nextOffset, recordSize, nTailBytes;
1586   void *tBuffer;
1587   Int32 tOffset;
1588   CDFstatus pStatus = CDF_OK;
1589   int i;
1590   for (i = 0; i < 2; i++) {
1591      Logical zVar = (i == 0);
1592      /*************************************************************************
1593      * Read the offset of the first rVDR from the GDR.
1594      *************************************************************************/
1595      if (!sX(ReadGDR(CDF->fp,CDF->GDRoffset,
1596 		     BOO(zVar,GDR_zVDRHEAD,GDR_rVDRHEAD),&vOffset,
1597 		     GDR_NULL),&pStatus)) return pStatus;
1598      /*************************************************************************
1599      * Read the rVDRs shortening each.
1600      *************************************************************************/
1601      while (vOffset != ZERO_OFFSET) {
1602        if (!sX(ReadVDR(CDF,CDF->fp,vOffset,zVar,
1603 		       VDR_VDRNEXT,&nextOffset,
1604 		       VDR_RECORDSIZE,&recordSize,
1605 		       VDR_NULL),&pStatus)) return pStatus;
1606        nTailBytes = recordSize - VDR_WASTED_OFFSET - VDR_WASTED_SIZE;
1607        recordSize -= VDR_WASTED_SIZE;
1608        if (!sX(WriteVDR(CDF,CDF->fp,vOffset,zVar,
1609 			VDR_RECORDSIZE,&recordSize,
1610 			VDR_NULL),&pStatus)) return pStatus;
1611        tBuffer = cdf_AllocateMemory ((size_t) nTailBytes, NULL);
1612        if (tBuffer != NULL) {
1613 	 tOffset = vOffset + VDR_WASTED_OFFSET + VDR_WASTED_SIZE;
1614 	 if (!SEEKv(CDF->fp,tOffset,vSEEK_SET)) return CDF_READ_ERROR;
1615 	 if (!READv(tBuffer,(size_t)nTailBytes,1,CDF->fp)) return
1616 							   CDF_READ_ERROR;
1617 	 tOffset = vOffset + VDR_WASTED_OFFSET;
1618 	 if (!SEEKv(CDF->fp,tOffset,vSEEK_SET)) return CDF_WRITE_ERROR;
1619 	 if (!WRITEv(tBuffer,(size_t)nTailBytes,1,CDF->fp)) return
1620 							    CDF_WRITE_ERROR;
1621 	 cdf_FreeMemory (tBuffer, NULL);
1622        }
1623        else {
1624 	 Int32 oldOffset = vOffset + VDR_WASTED_OFFSET + VDR_WASTED_SIZE,
1625 	       newOffset = vOffset + VDR_WASTED_OFFSET, byteX;
1626 	 Byte tByte;
1627 	 for (byteX = 0; byteX < nTailBytes; byteX++) {
1628 	    if (!SEEKv(CDF->fp,oldOffset,vSEEK_SET)) return CDF_READ_ERROR;
1629 	    if (!READv(&tByte,1,1,CDF->fp)) return CDF_READ_ERROR;
1630 	    if (!SEEKv(CDF->fp,newOffset,vSEEK_SET)) return CDF_WRITE_ERROR;
1631 	    if (!WRITEv(&tByte,1,1,CDF->fp)) return CDF_WRITE_ERROR;
1632 	    oldOffset++;
1633 	    newOffset++;
1634 	 }
1635        }
1636        if (!sX(WasteIR(CDF,vOffset+recordSize,VDR_WASTED_SIZE),&pStatus)) {
1637 	 return pStatus;
1638        }
1639        vOffset = nextOffset;
1640      }
1641   }
1642   return pStatus;
1643 }
1644 
1645 /******************************************************************************
1646 * CorrectBlockingFactors.
1647 *    It is assumed that the last rVDR offset has already been fixed.
1648 ******************************************************************************/
1649 
CorrectBlockingFactors(CDF)1650 STATICforIDL CDFstatus CorrectBlockingFactors (CDF)
1651 struct CDFstruct *CDF;
1652 {
1653   CDFstatus pStatus = CDF_OK; Int32 nVars, vdrOffset; int varN;
1654   Logical zVar; struct VDRstruct VDR; struct VarStruct **Vars, *Var;
1655   for (zVar = 0; zVar <= 1; zVar++) {
1656      Vars = BOO(zVar,CDF->zVars,CDF->rVars);
1657      nVars = BOO(zVar,CDF->NzVars,CDF->NrVars);
1658      for (varN = 0; varN < nVars; varN++) {
1659 	Var = Vars[varN];
1660 	if (Var == NULL) {
1661 	  if (!sX(FindVarByNumber(CDF,(Int32)varN,
1662 				  zVar,&vdrOffset),&pStatus)) return pStatus;
1663 	}
1664 	else
1665 	  vdrOffset = Var->VDRoffset;
1666 	if (!sX(ReadVDR(CDF,CDF->fp,vdrOffset,zVar,
1667 			VDR_RECORD,&VDR,NULL,
1668 			VDR_NULL),&pStatus)) return pStatus;
1669 	if (!RECvaryBITset(VDR.Flags) && VDR.blockingFactor > 1) {
1670 	  VDR.blockingFactor = 1;
1671 	  if (!sX(WriteVDR(CDF,CDF->fp,vdrOffset,zVar,
1672 			   VDR_RECORD,&VDR,NULL,
1673 			   VDR_NULL),&pStatus)) return pStatus;
1674 	  if (Var != NULL) {
1675 	    if (!sX(CalcBF(CDF,Var),&pStatus)) return pStatus;
1676 	  }
1677 	}
1678      }
1679   }
1680   return pStatus;
1681 }
1682 
1683 /******************************************************************************
1684 * CorrectEPOCH.
1685 ******************************************************************************/
1686 
CorrectEPOCH(CDF)1687 STATICforIDL CDFstatus CorrectEPOCH (CDF)
1688 struct CDFstruct *CDF;
1689 {
1690   CDFstatus tStatus, pStatus = CDF_OK;
1691   Int32 dataType, vNum, vOffset, aOffset, eOffset;
1692   Logical zVar;
1693   int i;
1694   /****************************************************************************
1695   * Search for EPOCH rVariable.
1696   ****************************************************************************/
1697   tStatus = FindVarByName (CDF, "EPOCH", &vOffset, &zVar, NULL);
1698   switch (tStatus) {
1699     case CDF_OK:
1700       if (!sX(ReadVDR(CDF,CDF->fp,vOffset,zVar,
1701 		      VDR_NUM,&vNum,
1702 		      VDR_DATATYPE,&dataType,
1703 		      VDR_NULL),&pStatus)) return pStatus;
1704       if (FLOAT8dataType(dataType)) dataType = CDF_EPOCH;
1705       if (!sX(WriteVDR(CDF,CDF->fp,vOffset,zVar,
1706 		       VDR_DATATYPE,&dataType,
1707 		       VDR_NULL),&pStatus)) return pStatus;
1708       /************************************************************************
1709       * Search for associated VALIDMIN/VALIDMAX/SCALEMIN/SCALEMAX rEntries.
1710       ************************************************************************/
1711       for (i = 0; i < 4; i++) {
1712 	 char aName[8+1];
1713 	 switch (i) {
1714 	   case 0: strcpy (aName, "VALIDMIN"); break;
1715 	   case 1: strcpy (aName, "VALIDMAX"); break;
1716 	   case 2: strcpy (aName, "SCALEMIN"); break;
1717 	   case 3: strcpy (aName, "SCALEMAX"); break;
1718 	 }
1719 	 tStatus = FindAttrByName (CDF,aName,&aOffset);
1720 	 switch (tStatus) {
1721 	   case CDF_OK:
1722 	     tStatus = FindEntryByNumber (CDF, aOffset, zVar, vNum,
1723 					  &eOffset);    /* We can do this since
1724 							   only rVariables will
1725 							   exist. */
1726 	     switch (tStatus) {
1727 	       case CDF_OK:
1728 		 if (!sX(ReadAEDR(CDF->fp,eOffset,
1729 				  AEDR_DATATYPE,&dataType,
1730 				  AEDR_NULL),&pStatus)) return pStatus;
1731 		 if (FLOAT8dataType(dataType)) dataType = CDF_EPOCH;
1732 		 if (!sX(WriteAEDR(CDF,CDF->fp,eOffset,
1733 				   AEDR_DATATYPE,&dataType,
1734 				   AEDR_NULL),&pStatus)) return pStatus;
1735 		 break;
1736 	       case NO_SUCH_ENTRY:
1737 		 break;
1738 	       default:
1739 		 return tStatus;
1740 	     }
1741 	     break;
1742 	   case NO_SUCH_ATTR:
1743 	     break;
1744 	   default:
1745 	     return tStatus;
1746 	 }
1747       }
1748       break;
1749     case NO_SUCH_VAR:
1750       break;
1751     default:
1752       return tStatus;
1753   }
1754   return pStatus;
1755 }
1756 
1757 /******************************************************************************
1758 * DeleteFile.
1759 ******************************************************************************/
1760 
DeleteFile(path)1761 STATICforIDL Logical DeleteFile (path)
1762 char *path;
1763 {
1764 #if defined(vms)
1765   char tPath[DU_MAX_PATH_LEN+1];
1766   strcpyX (tPath, path, DU_MAX_PATH_LEN);
1767   strcatX (tPath, ";0", DU_MAX_PATH_LEN);    /* Only most recent is deleted. */
1768   return (delete(tPath) == 0);
1769 #endif
1770 #if defined(unix) || defined(dos)
1771   return (unlink(path) == 0);
1772 #endif
1773 #if defined(mac) || defined(posixSHELL) || defined(win32)
1774   return (remove(path) == 0);
1775 #endif
1776 }
1777 
1778 /******************************************************************************
1779 * KillAbortedCDF.
1780 ******************************************************************************/
1781 
KillAbortedCDF(CDF,Cur)1782 STATICforIDL void KillAbortedCDF (CDF, Cur)
1783 struct CDFstruct *CDF;
1784 struct CurStruct *Cur;
1785 {
1786   CDF->magic = KILLEDid_MAGIC_NUMBER;
1787   cdf_FreeMemory (CDF, NULL);
1788   Cur->cdf = NULL;
1789   return;
1790 }
1791 
1792 /******************************************************************************
1793 * AbortAccess.
1794 ******************************************************************************/
1795 
AbortAccess(CDF,updateCDF,deleteCDF)1796 STATICforIDL void AbortAccess (CDF, updateCDF, deleteCDF)
1797 struct CDFstruct *CDF;
1798 Logical updateCDF;      /* Update "working" dotCDF file (if read/write
1799 			   access has been obtained)? */
1800 Logical deleteCDF;      /* Delete CDF file(s)? */
1801 {
1802   /****************************************************************************
1803   * If the CDF is to be deleted do that first and then skip the updating and/or
1804   * closing of the CDF files.
1805   ****************************************************************************/
1806   if (deleteCDF) {
1807     DeleteCDFfiles (CDF);
1808     if (CDF->uDotFp != NULL) V_delete (CDF->uDotFp, NULL);
1809   }
1810   else {
1811     /**************************************************************************
1812     * Update the dotCDF file if requested, if the current access is read/write,
1813     * and if the "working" dotCDF file has not already been closed or deleted.
1814     **************************************************************************/
1815     if (CDF->status == READ_WRITE && updateCDF &&
1816 	(CDF->fp == CDF->dotFp || CDF->fp == CDF->uDotFp)) UpdateDotCDF (CDF);
1817     /**************************************************************************
1818     * Close all of the CDF files if they are not already closed (or deleted).
1819     **************************************************************************/
1820     if (CDF->dotFp != NULL) V_close (CDF->dotFp, CDF, NULL);
1821     if (CDF->uDotFp != NULL) V_close (CDF->uDotFp, CDF, NULL);
1822     CloseVarFiles (CDF);
1823   }
1824   /****************************************************************************
1825   * Delete the scratch files that still exist.
1826   ****************************************************************************/
1827   if (CDF->stage.fp != NULL) V_delete (CDF->stage.fp, NULL);
1828   if (CDF->compressFp != NULL) V_delete (CDF->compressFp, NULL);
1829   /****************************************************************************
1830   * Free the memory used by the CDF.
1831   ****************************************************************************/
1832   FreeCDFid (CDF, TRUE);
1833   return;
1834 }
1835 
1836 /******************************************************************************
1837 * DeleteCDFfiles.
1838 * The files may be open or closed.  This routine does not delete the
1839 * uncompressed dotCDF file (if one exists).
1840 ******************************************************************************/
1841 
DeleteCDFfiles(CDF)1842 STATICforIDL CDFstatus DeleteCDFfiles (CDF)
1843 struct CDFstruct *CDF;
1844 {
1845   char tmpFile[DU_MAX_PATH_LEN+1]; CDFstatus pStatus = CDF_OK;
1846   /**************************************************************************
1847   * Delete dotCDF file.
1848   **************************************************************************/
1849   if (CDF->dotFp == NULL) {
1850     BuildFilePath (CDFt, CDF->CDFname, CDF->no_append, CDF->upper_case_ext,
1851 		   CDF->version_numbers, INT32_ZERO, tmpFile);
1852     if (!DeleteFile(tmpFile)) sX (CDF_DELETE_ERROR, &pStatus);
1853   }
1854   else {
1855     if (!DELETEv(CDF->dotFp,NULL)) sX (CDF_DELETE_ERROR, &pStatus);
1856     CDF->dotFp = NULL;
1857   }
1858   /**************************************************************************
1859   * Delete the variable files (if multi-file).  Both rVariable and zVariable
1860   * files are deleted.
1861   **************************************************************************/
1862   if (!CDF->singleFile) {
1863     int varN;
1864     for (varN = 0; varN < CDF->NrVars; varN++) {
1865        struct VarStruct *Var = CDF->rVars[varN];
1866        if (Var != NULL) {
1867 	 if (Var->fp != NULL) {
1868 	   if (!DELETEv(Var->fp,NULL)) sX (VAR_DELETE_ERROR, &pStatus);
1869 	   Var->fp = NULL;
1870 	   continue;
1871 	 }
1872        }
1873        BuildFilePath (Vt, CDF->CDFname, CDF->no_append, CDF->upper_case_ext,
1874 		      CDF->version_numbers, varN, tmpFile);
1875        if (!DeleteFile(tmpFile)) sX (VAR_DELETE_ERROR, &pStatus);
1876     }
1877     for (varN = 0; varN < CDF->NzVars; varN++) {
1878        struct VarStruct *Var = CDF->zVars[varN];
1879        if (Var != NULL) {
1880 	 if (Var->fp != NULL) {
1881 	   if (!DELETEv(Var->fp,NULL)) sX (VAR_DELETE_ERROR, &pStatus);
1882 	   Var->fp = NULL;
1883 	   continue;
1884 	 }
1885        }
1886        BuildFilePath (Zt, CDF->CDFname, CDF->no_append, CDF->upper_case_ext,
1887 		      CDF->version_numbers, varN, tmpFile);
1888        if (!DeleteFile(tmpFile)) sX (VAR_DELETE_ERROR, &pStatus);
1889     }
1890   }
1891   return pStatus;
1892 }
1893 
1894 /******************************************************************************
1895 * DeleteEntry.
1896 ******************************************************************************/
1897 
DeleteEntry(CDF,aOffset,eOffset)1898 STATICforIDL CDFstatus DeleteEntry (CDF, aOffset, eOffset)
1899 struct CDFstruct *CDF;
1900 Int32 aOffset;
1901 Int32 eOffset;
1902 {
1903   CDFstatus pStatus = CDF_OK;
1904   struct ADRstruct ADR;
1905   struct AEDRstruct AEDR, AEDRt;
1906   Int32 prevEntryOffset;
1907   Logical zEntry;
1908   /****************************************************************************
1909   * Read the ADR and the AEDR being deleted.
1910   ****************************************************************************/
1911   if (!sX(ReadADR(CDF->fp,aOffset,
1912 		  ADR_RECORD,&ADR,
1913 		  ADR_NULL),&pStatus)) return pStatus;
1914   if (!sX(ReadAEDR(CDF->fp,eOffset,
1915 		   AEDR_RECORD,&AEDR,NULL,
1916 		   AEDR_NULL),&pStatus)) return pStatus;
1917   zEntry = (AEDR.RecordType == AzEDR_);
1918   /****************************************************************************
1919   * Remove the AEDR from the list of entries.
1920   ****************************************************************************/
1921   if (!sX(FindPrevEntry(CDF,aOffset,eOffset,
1922 			zEntry,&prevEntryOffset),&pStatus)) return pStatus;
1923   if (prevEntryOffset == 0) {
1924     /**************************************************************************
1925     * The first entry on the linked list is being deleted.  Point the ADR to
1926     * the entry being pointed to by the entry being deleted.
1927     **************************************************************************/
1928     if (zEntry)
1929       ADR.AzEDRhead = AEDR.AEDRnext;
1930     else
1931       ADR.AgrEDRhead = AEDR.AEDRnext;
1932   }
1933   else {
1934     /**************************************************************************
1935     * The entry being deleted is not the first entry on the linked list.  Point
1936     * the previous entry to the entry pointed to by the entry being deleted.
1937     **************************************************************************/
1938     if (!sX(ReadAEDR(CDF->fp,prevEntryOffset,
1939 		     AEDR_RECORD,&AEDRt,NULL,
1940 		     AEDR_NULL),&pStatus)) return pStatus;
1941     AEDRt.AEDRnext = AEDR.AEDRnext;
1942     if (!sX(WriteAEDR(CDF,CDF->fp,prevEntryOffset,
1943 		      AEDR_RECORD,&AEDRt,NULL,
1944 		      AEDR_NULL),&pStatus)) return pStatus;
1945   }
1946   /****************************************************************************
1947   * Decrement the number of entries and recalculate the maximum entry (if
1948   * necessary).
1949   ****************************************************************************/
1950   if (zEntry)
1951     ADR.NzEntries--;
1952   else
1953     ADR.NgrEntries--;
1954   if (BOO(zEntry,ADR.MAXzEntry,ADR.MAXgrEntry) == AEDR.Num) {
1955     Int32 maxEntry = NO_ENTRY;
1956     Int32 tOffset = BOO(zEntry,ADR.AzEDRhead,ADR.AgrEDRhead);
1957     while (tOffset != 0) {
1958       if (!sX(ReadAEDR(CDF->fp,tOffset,
1959 		       AEDR_RECORD,&AEDRt,NULL,
1960 		       AEDR_NULL),&pStatus)) return pStatus;
1961       maxEntry = MaxInt32 (maxEntry, AEDRt.Num);
1962       tOffset = AEDRt.AEDRnext;
1963     }
1964     if (zEntry)
1965       ADR.MAXzEntry = maxEntry;
1966     else
1967       ADR.MAXgrEntry = maxEntry;
1968   }
1969   /****************************************************************************
1970   * Rewrite the ADR and waste the AEDR (of the entry being deleted).
1971   ****************************************************************************/
1972   if (!sX(WriteADR(CDF->fp,aOffset,
1973 		   ADR_RECORD,&ADR,
1974 		   ADR_NULL),&pStatus)) return pStatus;
1975   if (!sX(WasteIR(CDF,eOffset,AEDR.RecordSize),&pStatus)) return pStatus;
1976   return pStatus;
1977 }
1978 
1979 /******************************************************************************
1980 * CtoPstr/PtoCstr.
1981 ******************************************************************************/
1982 
1983 #if defined(MPW_C)
CtoPstr(string)1984 STATICforIDL unsigned char *CtoPstr (string)
1985 char *string;
1986 {
1987   size_t length = MINIMUM(strlen(string),255);
1988   if (length > 0) memmove (&string[1], string, length);
1989   string[0] = (char) length;
1990   return ((unsigned char *) string);
1991 }
1992 #endif
1993 
1994 #if defined(MPW_C)
PtoCstr(string)1995 STATICforIDL char *PtoCstr (string)
1996 unsigned char *string;
1997 {
1998   size_t length = (size_t) string[0];
1999   if (length > 0) memmove (string, &string[1], length);
2000   string[length] = (unsigned char) NUL;
2001   return ((char *) string);
2002 }
2003 #endif
2004 
2005 /******************************************************************************
2006 * PadUnRecords.
2007 *   Pad all allocated records within the first/last record range.  Note that
2008 * in the case of sparse records some of the records may not be allocated (and
2009 * should not be padded of course).
2010 ******************************************************************************/
2011 
PadUnRecords(CDF,Var,firstRec,lastRec)2012 STATICforIDL CDFstatus PadUnRecords (CDF, Var, firstRec, lastRec)
2013 struct CDFstruct *CDF;
2014 struct VarStruct *Var;
2015 Int32 firstRec;
2016 Int32 lastRec;
2017 {
2018   CDFstatus pStatus = CDF_OK; Int32 offset; int how; void *buffer;
2019   Int32 recNum, nRecords, toRec, lastRecInVVR; Logical found;
2020   /****************************************************************************
2021   * Pad the records.
2022   * NOTE: Padding in a single-file CDF could be made more efficient by not
2023   * allocating/freeing the pad buffer over and over...
2024   ****************************************************************************/
2025   if (CDF->singleFile) {
2026     /**************************************************************************
2027     * Single-file...first determine the first allocated record to be padded.
2028     **************************************************************************/
2029     if (!sX(NextRecord(CDF,Var->VDRoffset,Var->zVar,
2030 		       firstRec,&recNum,&found),&pStatus)) return pStatus;
2031     if (!found) return pStatus;
2032     /**************************************************************************
2033     * While the first record to be padded is within the range...
2034     **************************************************************************/
2035     while (recNum <= lastRec) {
2036       if (!sX(RecordByteOffset(CDF,Var,recNum,
2037 			       &offset),&pStatus)) return pStatus;
2038       if (!sX(SearchForRecord(CDF,Var->VDRoffset,
2039 			      Var->zVar,recNum,
2040 			      NULL,&lastRecInVVR,
2041 			      NULL,NULL),&pStatus)) return pStatus;
2042       toRec = MINIMUM(lastRec,lastRecInVVR);
2043       nRecords = toRec - recNum + 1;
2044       if (!sX(BuildPadBuffer(CDF,Var,nRecords,
2045 			     &how,&buffer,TRUE),&pStatus)) return pStatus;
2046       if (!sX(WritePadValues(Var,CDF->fp,offset,
2047 			     nRecords,how,buffer),&pStatus)) {
2048 	cdf_FreeMemory (buffer, NULL);
2049 	return pStatus;
2050       }
2051       cdf_FreeMemory (buffer, NULL);
2052       recNum += nRecords;
2053       /************************************************************************
2054       * Determine the next `first' record to be padded.
2055       ************************************************************************/
2056       if (!sX(NextRecord(CDF,Var->VDRoffset,Var->zVar,
2057 			 recNum,&recNum,&found),&pStatus)) return pStatus;
2058       if (!found) return pStatus;
2059     }
2060   }
2061   else {
2062     /**************************************************************************
2063     * Multi-file...
2064     **************************************************************************/
2065     if (!sX(RecordByteOffset(CDF,Var,
2066 			     firstRec,
2067 			     &offset),&pStatus)) return pStatus;
2068     nRecords = lastRec - firstRec + 1;
2069     if (!sX(BuildPadBuffer(CDF,Var,nRecords,
2070 			   &how,&buffer,TRUE),&pStatus)) return pStatus;
2071     if (!sX(WritePadValues(Var,Var->fp,offset,nRecords,how,buffer),&pStatus)) {
2072       cdf_FreeMemory (buffer, NULL);
2073       return pStatus;
2074     }
2075     cdf_FreeMemory (buffer, NULL);
2076   }
2077   return pStatus;
2078 }
2079 
2080 /******************************************************************************
2081 * WritePadValues.
2082 *   NOTE: It is assumed that the records are contiguous (in a single-file CDF)
2083 * and that on a DOS machine the buffer does not exceed 64K bytes.  It is also
2084 * assumed that the values have already been encoded for the CDF.
2085 ******************************************************************************/
2086 
WritePadValues(Var,fp,offset,nRecords,how,buffer)2087 STATICforIDL CDFstatus WritePadValues (Var, fp, offset, nRecords, how, buffer)
2088 struct VarStruct *Var;
2089 vFILE *fp;
2090 Int32 offset;
2091 Int32 nRecords;
2092 int how;
2093 void *buffer;
2094 {
2095   Int32 nBytes, nValues, recX, valueX;
2096   /****************************************************************************
2097   * Seek to desired offset.
2098   ****************************************************************************/
2099   if (!SEEKv(fp,(long)offset,vSEEK_SET)) return VAR_WRITE_ERROR;
2100   /****************************************************************************
2101   * Write records...
2102   ****************************************************************************/
2103   switch (how) {
2104     case ALLrecordsATonce:
2105       nBytes = nRecords * Var->NphyRecBytes;
2106       if (!WRITEv(buffer,(size_t)nBytes,1,fp)) return VAR_WRITE_ERROR;
2107       break;
2108     case ONErecordATaTIME:
2109       for (recX = 0; recX < nRecords; recX++) {
2110 	 if (!WRITEv(buffer,(size_t)Var->NphyRecBytes,1,fp)) {
2111 	   return VAR_WRITE_ERROR;
2112 	 }
2113       }
2114       break;
2115     case ONEvalueATaTIME:
2116       nValues = nRecords * Var->NphyRecValues;
2117       for (valueX = 0; valueX < nValues; valueX++) {
2118 	 if (!WRITEv(buffer,(size_t)Var->NvalueBytes,1,fp)) {
2119 	   return VAR_WRITE_ERROR;
2120 	 }
2121       }
2122       break;
2123   }
2124   return CDF_OK;
2125 }
2126 
2127 /******************************************************************************
2128 * MinInt/Int32/Long.
2129 * These are used to avoid double evaluation in macro expansions (eg. MINIMUM).
2130 ******************************************************************************/
2131 
MinInt(a,b)2132 VISIBLE_PREFIX int MinInt (a, b)
2133 int a;
2134 int b;
2135 {
2136   return MINIMUM(a,b);
2137 }
2138 
MinInt32(a,b)2139 VISIBLE_PREFIX Int32 MinInt32 (a, b)
2140 Int32 a;
2141 Int32 b;
2142 {
2143   return MINIMUM(a,b);
2144 }
2145 
MinLong(a,b)2146 VISIBLE_PREFIX long MinLong (a, b)
2147 long a;
2148 long b;
2149 {
2150   return MINIMUM(a,b);
2151 }
2152 
2153 /******************************************************************************
2154 * MaxInt/Int32/Long.
2155 * These are used to avoid double evaluation in macro expansions (eg. MAXIMUM).
2156 ******************************************************************************/
2157 
MaxInt(a,b)2158 VISIBLE_PREFIX int MaxInt (a, b)
2159 int a;
2160 int b;
2161 {
2162   return MAXIMUM(a,b);
2163 }
2164 
MaxInt32(a,b)2165 VISIBLE_PREFIX Int32 MaxInt32 (a, b)
2166 Int32 a;
2167 Int32 b;
2168 {
2169   return MAXIMUM(a,b);
2170 }
2171 
MaxLong(a,b)2172 VISIBLE_PREFIX long MaxLong (a, b)
2173 long a;
2174 long b;
2175 {
2176   return MAXIMUM(a,b);
2177 }
2178 
2179 /******************************************************************************
2180 * AddTOvStats.
2181 ******************************************************************************/
2182 
AddTOvStats(vStatsTO,vStats)2183 STATICforIDL void AddTOvStats (vStatsTO, vStats)
2184 vSTATS *vStatsTO;	/* If NULL, do nothing. */
2185 vSTATS *vStats;		/* If NULL, initialize (to zero). */
2186 {
2187   if (vStatsTO != NULL) {
2188     if (vStats == NULL) {
2189       vStatsTO->nBuffers = 0;
2190       vStatsTO->maxBuffers = 0;
2191       vStatsTO->nV_reads = 0;
2192       vStatsTO->nV_writes = 0;
2193       vStatsTO->nPageIns = 0;
2194       vStatsTO->nPageOuts = 0;
2195       vStatsTO->nBlockReads = 0;
2196       vStatsTO->nBlockWrites = 0;
2197     }
2198     else {
2199       vStatsTO->nBuffers = MAXIMUM(vStatsTO->nBuffers,vStats->nBuffers);
2200       vStatsTO->maxBuffers = MAXIMUM(vStatsTO->maxBuffers,vStats->maxBuffers);
2201       vStatsTO->nV_reads += vStats->nV_reads;
2202       vStatsTO->nV_writes += vStats->nV_writes;
2203       vStatsTO->nPageIns += vStats->nPageIns;
2204       vStatsTO->nPageOuts += vStats->nPageOuts;
2205       vStatsTO->nBlockReads += vStats->nBlockReads;
2206       vStatsTO->nBlockWrites += vStats->nBlockWrites;
2207     }
2208   }
2209   return;
2210 }
2211 
2212 /******************************************************************************
2213 * DisplayVs.
2214 ******************************************************************************/
2215 
2216 #if defined(DEBUG)
DisplayVs(toWhere,label,vStats)2217 STATICforIDL void DisplayVs (toWhere, label, vStats)
2218 char *toWhere;
2219 char *label;
2220 vSTATS *vStats;
2221 {
2222   if (toWhere != NULL) {
2223     FILE *fp = BOO(strcmp(toWhere,"STDOUT"),FOPEN(toWhere,"a"),stdout);
2224     if (fp == NULL) return;
2225     fprintf (fp, "%s", label);
2226     fprintf (fp, "..BUF:%03ldu/%03ldx", vStats->nBuffers, vStats->maxBuffers);
2227     fprintf (fp, " V_:%06ldr/%06ldw", vStats->nV_reads, vStats->nV_writes);
2228     fprintf (fp, " PAGE:%05ldi/%05ldo", vStats->nPageIns, vStats->nPageOuts);
2229     fprintf (fp, " BLK:%05ldr/%05ldw",
2230 	     vStats->nBlockReads, vStats->nBlockWrites);
2231     fprintf (fp, "\n");
2232     if (fp != stdout) fclose (fp);
2233   }
2234   return;
2235 }
2236 #endif
2237