1 /******************************************************************************
2 *
3 *  NSSDC/CDF                                       CDF `get' operations.
4 *
5 *  Version 1.4, 9-Sep-96, Hughes STX.
6 *
7 *  Modification history:
8 *
9 *   V1.0  20-May-92, J Love     Original version (was part of `cdflib.c').
10 *   V1.1  16-Sep-92, J Love     CDF V2.3 (shareable/NeXT/zVar).
11 *   V1.2  13-Dec-93, J Love     CDF V2.4.
12 *   V1.3  15-Dec-94, J Love     CDF V2.5.
13 *   V1.3a  9-Jan-95, J Love     Encode/decode changes.  More cache-residency.
14 *   V1.3b 24-Feb-95, J Love     Solaris 2.3 IDL i/f.
15 *   V1.3c  4-Aug-95, J Love     CDFexport-related changes.
16 *   V1.4   9-Sep-96, J Love     CDF V2.6.
17 *   V2.0  08-Apr-04, M Liu      Removed call to LocateCurrentVar function as
18 *                               its offset becomes avilable when it is
19 *                               selected.
20 *   V2.1  21-Jun-04, M Liu      Modified the error message for NOT_A_CDF.
21 *   V3.2  16-Oct-07, D Han      The length of the pad value for a CDF_CHAR
22 *                               variable is the length of the variable (i.e.
23 *                               CHAR/162, etc.).  If the length of the pad
24 *                               value is greater than 16, it causes
25 *                               segmentation fault for the IDL CDF interface
26 *                               routine.
27 ******************************************************************************/
28 
29 #include "cdflib.h"
30 #include "cdfrev.h"
31 
32 /******************************************************************************
33 * CDFget.
34 ******************************************************************************/
35 
CDFget(Va,Cur)36 STATICforIDL CDFstatus CDFget (Va, Cur)
37 struct VAstruct *Va;
38 struct CurStruct *Cur;
39 {
40 CDFstatus tStatus, pStatus = CDF_OK;
41 
42 switch (Va->item) {
43   /****************************************************************************
44   * CDF_INFO_
45   ****************************************************************************/
46   case CDF_INFO_: {
47     char CDFpathX[DU_MAX_PATH_LEN+1], CDFpathT[CDF_PATHNAME_LEN+1], *CDFpathP;
48     vFILE *dotFp; Logical upper_case_ext, version_numbers, no_append;
49     Int32 magicNumber1, magicNumber2; int i;
50     long *cType, *cParms, *cFileSize, *uFileSize;
51     CDFpathP = va_arg (Va->ap, char *);
52     cType = va_arg (Va->ap, long *);
53     cParms = va_arg (Va->ap, long *);
54     cFileSize = va_arg (Va->ap, long *);
55     uFileSize = va_arg (Va->ap, long *);
56     if (strlen(CDFpathP) > (size_t) CDF_PATHNAME_LEN) {
57       if (!sX(CDF_NAME_TRUNC,&pStatus)) return pStatus;
58     }
59     strcpyX (CDFpathT, CDFpathP, CDF_PATHNAME_LEN);
60 #if STRIP_TRAILING_BLANKS_FROM_CDFPATH
61     StripTrailingBlanks (CDFpathT);
62 #endif
63 #if defined(vms) || defined(dos)
64     MakeUpperString (CDFpathT);
65 #endif
66     if (!ValidCDFname(CDFpathT)) return BAD_CDF_NAME;
67     if (!sX(FindCDF(CDFpathT,&no_append,
68 		    &upper_case_ext,
69 		    &version_numbers),&pStatus)) return pStatus;
70     BuildFilePath (CDFt, CDFpathT, no_append, upper_case_ext, version_numbers,
71 		   INT32_ZERO, CDFpathX);
72     dotFp = V_open (CDFpathX, READ_ONLY_a_mode);
73     if (dotFp == NULL) return CDF_OPEN_ERROR;
74     if (!Read32(dotFp,&magicNumber1)) {
75       V_close (dotFp, NULL, NULL);
76       return CDF_READ_ERROR;
77     }
78     if (!Read32(dotFp,&magicNumber2)) {
79       V_close (dotFp, NULL, NULL);
80       return CDF_READ_ERROR;
81     }
82     switch (magicNumber1) {
83       case V1magicNUMBER_flip:
84 	V_close (dotFp, NULL, NULL);
85 	return ILLEGAL_ON_V1_CDF;
86       case V2magicNUMBER_1pre:
87 	*cType = NO_COMPRESSION;
88 	*cFileSize = 0;
89 	if (!SEEKv(dotFp,0L,vSEEK_END)) {
90 	  V_close (dotFp, NULL, NULL);
91 	  return CDF_READ_ERROR;
92 	}
93 	*uFileSize = V_tell (dotFp);
94 	break;
95       case V2magicNUMBER_1:
96 	switch (magicNumber2) {
97 	  case V2magicNUMBER_2u:
98 	    *cType = NO_COMPRESSION;
99 	    *cFileSize = 0;
100 	    if (!SEEKv(dotFp,0L,vSEEK_END)) {
101 	      V_close (dotFp, NULL, NULL);
102 	      return CDF_READ_ERROR;
103 	    }
104 	    *uFileSize = V_tell (dotFp);
105 	    break;
106 	  case V2magicNUMBER_2c: {
107 	    struct CCRstruct CCR; struct CPRstruct CPR;
108 	    if (!sX(ReadCCR(dotFp,V2_CCR_OFFSET,
109 			    CCR_RECORD,&CCR,
110 			    CCR_NULL),&pStatus)) {
111 	      V_close (dotFp, NULL, NULL);
112 	      return pStatus;
113 	    }
114 	    if (CCR.uSize == 0) {
115 	      V_close (dotFp, NULL, NULL);
116 	      return EMPTY_COMPRESSED_CDF;
117 	    }
118 	    if (!sX(ReadCPR(dotFp,CCR.CPRoffset,
119 			    CPR_RECORD,&CPR,
120 			    CPR_NULL),&pStatus)) {
121 	      V_close (dotFp, NULL, NULL);
122 	      return pStatus;
123 	    }
124 	    *cType = (long) CPR.cType;
125 	    if (CPR.pCount > CDF_MAX_PARMS) {
126 	      V_close (dotFp, NULL, NULL);
127 	      return TOO_MANY_PARMS;
128 	    }
129 	    for (i = 0; i < CPR.pCount; i++) cParms[i] = (long) CPR.cParms[i];
130 	    if (!SEEKv(dotFp,0L,vSEEK_END)) {
131 	      V_close (dotFp, NULL, NULL);
132 	      return CDF_READ_ERROR;
133 	    }
134 	    *cFileSize = V_tell (dotFp);
135 	    *uFileSize = (long) CCR.uSize + MAGIC_NUMBERS_SIZE;
136 	    break;
137 	  }
138 	  default:
139 	    V_close (dotFp, NULL, NULL);
140 	    return NOT_A_CDF;
141 	}
142 	break;
143       default:
144 	V_close (dotFp, NULL, NULL);
145 	return NOT_A_CDF_OR_NOT_SUPPORTED;
146     }
147     V_close (dotFp, NULL, NULL);
148     break;
149   }
150   /****************************************************************************
151   * STATUS_TEXT_,
152   ****************************************************************************/
153   case STATUS_TEXT_: {
154     char *textPtr;
155     textPtr = va_arg (Va->ap, char *);
156     CDFstatusText (Cur->status, textPtr);
157     break;
158   }
159   /****************************************************************************
160   * DATATYPE_SIZE_,
161   ****************************************************************************/
162   case DATATYPE_SIZE_: {
163     long dataType = va_arg (Va->ap, long);
164     long *numBytes = va_arg (Va->ap, long *);
165     if (!ValidDataType((Int32)dataType)) return BAD_DATA_TYPE;
166     *numBytes = (long) CDFelemSize (dataType);
167     break;
168   }
169   /****************************************************************************
170   * rVARs_NUMDIMS_/zVAR_NUMDIMS_
171   *    Note that inquiring the number of rVariable dimensions is allowed while
172   * in zMode.
173   ****************************************************************************/
174   case rVARs_NUMDIMS_: {
175     struct CDFstruct *CDF;
176     long *numDims = va_arg (Va->ap, long *);
177     SelectCDF (Cur->cdf, CDF)
178     *numDims = CDF->rNumDims;
179     break;
180   }
181   case zVAR_NUMDIMS_: {
182     struct CDFstruct *CDF;
183     long *numDimsP = va_arg (Va->ap, long *);
184     Logical zVar; Int32 offset, numDims;
185     SelectCDF (Cur->cdf, CDF)
186     if (!CURRENTvarSELECTED(CDF,TRUE)) return NO_VAR_SELECTED;
187 
188     zVar = CurrentVarMode(CDF,TRUE);
189     if (zModeON(CDF) || zVar) offset = CDF->CURzVarOffset;
190     else offset = CDF->CURrVarOffset;
191 
192     if (!sX(CalcDimParms(CDF,offset,zVar,&numDims,NULL,NULL),&pStatus)) {
193       AbortAccess (CDF, UPDATE, noDELETE);
194       return pStatus;
195     }
196     ASSIGNnotNULL (numDimsP, numDims)
197     break;
198   }
199   /****************************************************************************
200   * rVARs_DIMSIZES_/zVAR_DIMSIZES_
201   *    Note that inquiring the rVariable dimension sizes is allowed while in
202   * zMode.
203   ****************************************************************************/
204   case rVARs_DIMSIZES_: {
205     struct CDFstruct *CDF;
206     int dimN;
207     long *dimsize = va_arg (Va->ap, long *);
208     SelectCDF (Cur->cdf, CDF)
209     for (dimN = 0; dimN < CDF->rNumDims; dimN++) {
210        dimsize[dimN] = CDF->rDimSizes[dimN];
211     }
212     break;
213   }
214   case zVAR_DIMSIZES_: {
215     struct CDFstruct *CDF; Logical zVar;
216     Int32 offset, numDims, dimSizes[CDF_MAX_DIMS];
217     long *dimSizesP = va_arg (Va->ap, long *);
218     SelectCDF (Cur->cdf, CDF)
219     if (!CURRENTvarSELECTED(CDF,TRUE)) return NO_VAR_SELECTED;
220 
221     zVar = CurrentVarMode(CDF,TRUE);
222     if (zModeON(CDF) || zVar) offset = CDF->CURzVarOffset;
223     else offset = CDF->CURrVarOffset;
224 
225     if (!sX(CalcDimParms(CDF,offset,zVar,&numDims,dimSizes,NULL),&pStatus)) {
226       AbortAccess (CDF, UPDATE, noDELETE);
227       return pStatus;
228     }
229     ASSIGNnotNULLarray (dimSizesP, numDims, dimSizes)
230     break;
231   }
232   /****************************************************************************
233   * CDF_ENCODING_,
234   ****************************************************************************/
235   case CDF_ENCODING_: {
236     struct CDFstruct *CDF;
237     long *encoding = va_arg (Va->ap, long *);
238     SelectCDF (Cur->cdf, CDF)
239     *encoding = (long) CDF->encoding;
240     break;
241   }
242   /****************************************************************************
243   * CDF_MAJORITY_,
244   ****************************************************************************/
245   case CDF_MAJORITY_: {
246     struct CDFstruct *CDF;
247     long *majority = va_arg (Va->ap, long *);
248     SelectCDF (Cur->cdf, CDF)
249     *majority = BOO(CDF->rowMajor,ROW_MAJOR,COLUMN_MAJOR);
250     break;
251   }
252   /****************************************************************************
253   * CDF_FORMAT_,
254   ****************************************************************************/
255   case CDF_FORMAT_: {
256     struct CDFstruct *CDF;
257     long *format = va_arg (Va->ap, long *);
258     SelectCDF (Cur->cdf, CDF)
259     *format = BOO(CDF->singleFile,SINGLE_FILE,MULTI_FILE);
260     break;
261   }
262   /****************************************************************************
263   * CDF_CHECKSUM_,
264   ****************************************************************************/
265   case CDF_CHECKSUM_: {
266     struct CDFstruct *CDF;
267     long *checksum = va_arg (Va->ap, long *);
268     SelectCDF (Cur->cdf, CDF)
269     *checksum = CDF->checksum;
270     break;
271   }
272   /****************************************************************************
273   * CDF_COMPRESSION_
274   ****************************************************************************/
275   case CDF_COMPRESSION_: {
276     long *cType = va_arg (Va->ap, long *);      /* Compression type. */
277     long *cParms = va_arg (Va->ap, long *);     /* Compression parameters. */
278     long *cPct = va_arg (Va->ap, long *);	/* Compression percentage. */
279     struct CDFstruct *CDF; struct CCRstruct CCR; struct CPRstruct CPR;
280     int i; long cTotal, uTotal;
281     SelectCDF (Cur->cdf, CDF)
282     /**************************************************************************
283     * If multi-file or uncompressed...
284     **************************************************************************/
285     if (!CDF->singleFile || CDF->uDotFp == NULL) {
286       *cType = NO_COMPRESSION;
287       *cPct = 100;
288       break;
289     }
290     /**************************************************************************
291     * ...otherwise, read the CCR and CPR.
292     **************************************************************************/
293     if (!sX(ReadCCR(CDF->dotFp,V2_CCR_OFFSET,
294 		    CCR_RECORD,&CCR,
295 		    CCR_NULL),&pStatus)) return pStatus;
296     if (!sX(ReadCPR(CDF->dotFp,CCR.CPRoffset,
297 		    CPR_RECORD,&CPR,
298 		    CPR_NULL),&pStatus)) return pStatus;
299     *cType = CPR.cType;
300     if (CPR.pCount > CDF_MAX_PARMS) return TOO_MANY_PARMS;
301     for (i = 0; i < CPR.pCount; i++) cParms[i] = CPR.cParms[i];
302     /**************************************************************************
303     * Calculate the percentage.  If the `uSize' field of the CCR is zero,
304     * then the compressed CDF is empty (and the percentage is unknown).
305     **************************************************************************/
306     if (CCR.uSize == 0)
307       *cPct = 0;
308     else {
309       cTotal = MAGIC_NUMBERS_SIZE + CCR.RecordSize + CPR.RecordSize;
310       uTotal = MAGIC_NUMBERS_SIZE + CCR.uSize;
311       *cPct = (100L * cTotal) / uTotal;
312     }
313     break;
314   }
315   /****************************************************************************
316   * CDF_COPYRIGHT_
317   ****************************************************************************/
318   case CDF_COPYRIGHT_: {
319     struct CDFstruct *CDF;
320     char *copyRight = va_arg (Va->ap,  char *);
321     SelectCDF (Cur->cdf, CDF)
322     if (!sX(ReadCDR(CDF->fp,CDF->CDRoffset,
323 		    CDR_COPYRIGHT,copyRight,
324 		    CDR_NULL),&pStatus)) {
325       AbortAccess (CDF, UPDATE, noDELETE);
326       return pStatus;
327     }
328     copyRight[CDF_COPYRIGHT_LEN] = NUL;
329     break;
330   }
331   /****************************************************************************
332   * LIB_COPYRIGHT_
333   ****************************************************************************/
334   case LIB_COPYRIGHT_: {
335     char *copyRight = va_arg (Va->ap, char *);
336     CDFcopyRight (copyRight);
337     break;
338   }
339   /****************************************************************************
340   * CDF_NUMrVARS_/CDF_NUMzVARS_
341   *    Inquire number of r/z variables.  When in zMode, the number of
342   * rVariables is always zero (0).  (Inquiring the number of rVariables
343   * while in zMode is one of the few legal rVariable operations).
344   ****************************************************************************/
345   case CDF_NUMrVARS_:
346   case CDF_NUMzVARS_: {
347     Logical zOp = (Va->item == CDF_NUMzVARS_);
348     struct CDFstruct *CDF;
349     long *numVars = va_arg (Va->ap, long *);
350     SelectCDF (Cur->cdf, CDF)
351     if (zModeON(CDF))
352       *numVars = BOO(zOp,CDF->NrVars + CDF->NzVars,0);
353     else
354       *numVars = BOO(zOp,CDF->NzVars,CDF->NrVars);
355     break;
356   }
357   /****************************************************************************
358   * CDF_NUMATTRS_,
359   ****************************************************************************/
360   case CDF_NUMATTRS_: {
361     struct CDFstruct *CDF;
362     long *numAttrs = va_arg (Va->ap, long *);
363     Int32 tNumAttrs;
364     SelectCDF (Cur->cdf, CDF)
365     if (!sX(ReadGDR(CDF->fp,CDF->GDRoffset,
366 		    GDR_NUMATTR,&tNumAttrs,
367 		    GDR_NULL),&pStatus)) {
368       AbortAccess (CDF, UPDATE, noDELETE);
369       return pStatus;
370     }
371     *numAttrs = tNumAttrs;
372     break;
373   }
374   /****************************************************************************
375   * CDF_NUMgATTRS_/CDF_NUMvATTRS_
376   ****************************************************************************/
377   case CDF_NUMvATTRS_:
378   case CDF_NUMgATTRS_: {
379     Logical gOp = (Va->item == CDF_NUMgATTRS_);
380     struct CDFstruct *CDF;
381     long *numAttrs = va_arg (Va->ap, long *);
382     Int32 totalAttrs, offset, scope;
383     int attrX;
384     SelectCDF (Cur->cdf, CDF)
385     *numAttrs = 0;
386     if (!sX(ReadGDR(CDF->fp,CDF->GDRoffset,
387 		    GDR_NUMATTR,&totalAttrs,
388 		    GDR_ADRHEAD,&offset,
389 		    GDR_NULL),&pStatus)) {
390       AbortAccess (CDF, UPDATE, noDELETE);
391       return pStatus;
392     }
393     for (attrX = 0; attrX < totalAttrs; attrX++) {
394        CDF->fp->CurADRIndex = attrX;
395        if (!sX(ReadADR(CDF->fp,offset,
396 		       ADR_SCOPE,&scope,
397 		       ADR_NULL),&pStatus)) {
398 	 AbortAccess (CDF, UPDATE, noDELETE);
399 	 return pStatus;
400        }
401        if ((gOp && GLOBALscope(scope)) ||
402 	   (!gOp && VARIABLEscope(scope))) (*numAttrs)++;
403        if (!sX(ReadADR(CDF->fp,offset,
404 		       ADR_ADRNEXT,&offset,
405 		       ADR_NULL),&pStatus)) {
406 	 AbortAccess (CDF, UPDATE, noDELETE);
407 	 return pStatus;
408        }
409     }
410     break;
411   }
412   /****************************************************************************
413   * rVARs_MAXREC_/zVARs_MAXREC_
414   *    Maximum record number of all of the rVariables/zVariables.  Note that
415   * inquiring the maximum rVariable record number is allowed while in zMode.
416   ****************************************************************************/
417   case rVARs_MAXREC_: {
418     struct CDFstruct *CDF;
419     long *maxRec = va_arg (Va->ap, long *);
420     SelectCDF (Cur->cdf, CDF)
421     if (zModeON(CDF))
422       *maxRec = NO_RECORD;
423     else
424       *maxRec = CDF->rMaxRec;
425     break;
426   }
427   case zVARs_MAXREC_: {
428     struct CDFstruct *CDF;
429     long *maxRec = va_arg (Va->ap, long *);
430     Int32 offset, tMaxRec;
431     SelectCDF (Cur->cdf, CDF)
432     /**************************************************************************
433     * If zMode is on, consider both rVariables and zVariables.  If zMode is
434     * not on, only consider the zVariables.  Because zVariables did not exist
435     * in CDF V2.0, the problem with the `VDRnext' offset in the last VDR does
436     * not have to be considered here.
437     **************************************************************************/
438     *maxRec = BOO(zModeON(CDF),CDF->rMaxRec,NO_RECORD);
439     if (!sX(ReadGDR(CDF->fp,CDF->GDRoffset,
440 		    GDR_zVDRHEAD,&offset,
441 		    GDR_NULL),&pStatus)) {
442       AbortAccess (CDF, UPDATE, noDELETE);
443       return pStatus;
444     }
445     while (offset != ZERO_OFFSET) {
446       if (!sX(ReadVDR(CDF,CDF->fp,offset,TRUE,
447 		      VDR_MAXREC,&tMaxRec,
448 		      VDR_VDRNEXT,&offset,
449 		      VDR_NULL),&pStatus)) {
450 	AbortAccess (CDF, UPDATE, noDELETE);
451 	return pStatus;
452       }
453       *maxRec = MAXIMUM (*maxRec, tMaxRec);
454     }
455     break;
456   }
457   /****************************************************************************
458   * CDF_VERSION_,
459   ****************************************************************************/
460   case CDF_VERSION_: {
461     struct CDFstruct *CDF;
462     long *version = va_arg (Va->ap, long *);
463     Int32 tVersion;
464     SelectCDF (Cur->cdf, CDF)
465     if (!sX(ReadCDR(CDF->fp,CDF->CDRoffset,
466 		    CDR_VERSION,&tVersion,
467 		    CDR_NULL),&pStatus)) {
468       AbortAccess (CDF, UPDATE, noDELETE);
469       return pStatus;
470     }
471     *version = tVersion;
472     break;
473   }
474   /****************************************************************************
475   * CDF_RELEASE_,
476   ****************************************************************************/
477   case CDF_RELEASE_: {
478     struct CDFstruct *CDF;
479     long *release = va_arg (Va->ap, long *);
480     Int32 tRelease;
481     SelectCDF (Cur->cdf, CDF)
482     if (!sX(ReadCDR(CDF->fp,CDF->CDRoffset,
483 		    CDR_RELEASE,&tRelease,
484 		    CDR_NULL),&pStatus)) {
485       AbortAccess (CDF, UPDATE, noDELETE);
486       return pStatus;
487     }
488     *release = tRelease;
489     break;
490   }
491   /****************************************************************************
492   * CDF_INCREMENT_,
493   ****************************************************************************/
494   case CDF_INCREMENT_: {
495     struct CDFstruct *CDF;
496     long *increment = va_arg (Va->ap, long *);
497     Int32 tIncrement;
498     SelectCDF (Cur->cdf, CDF)
499     if (!sX(ReadCDR(CDF->fp,CDF->CDRoffset,
500 		    CDR_INCREMENT,&tIncrement,
501 		    CDR_NULL),&pStatus)) {
502       AbortAccess (CDF, UPDATE, noDELETE);
503       return pStatus;
504     }
505     *increment = tIncrement;
506     break;
507   }
508   /****************************************************************************
509   * LIB_VERSION_,
510   ****************************************************************************/
511   case LIB_VERSION_: {
512     long *version = va_arg (Va->ap, long *);
513     *version = CDF_LIBRARY_VERSION;
514     break;
515   }
516   /****************************************************************************
517   * LIB_RELEASE_,
518   ****************************************************************************/
519   case LIB_RELEASE_: {
520     long *release = va_arg (Va->ap, long *);
521     *release = CDF_LIBRARY_RELEASE;
522     break;
523   }
524   /****************************************************************************
525   * LIB_INCREMENT_,
526   ****************************************************************************/
527   case LIB_INCREMENT_: {
528     long *increment = va_arg (Va->ap, long *);
529     *increment = CDF_LIBRARY_INCREMENT;
530     break;
531   }
532   /****************************************************************************
533   * LIB_subINCREMENT_,
534   ****************************************************************************/
535   case LIB_subINCREMENT_: {
536     char *subincrement = va_arg (Va->ap, char *);
537     *subincrement = CDF_LIBRARY_subINCREMENT;
538     break;
539   }
540   /****************************************************************************
541   * rVAR_NAME_/zVAR_NAME_
542   *    Note that a temporary variable is used when reading the variable name.
543   * This is because the caller may have only allocated enough memory for the
544   * size name they expect (ie., less than CDF_VAR_NAME_LEN characters).  Since
545   * the variable name is NUL-terminated in the CDF, only the actual characters
546   * of the name will be copied to the caller's buffer.
547   ****************************************************************************/
548   case rVAR_NAME_:
549   case zVAR_NAME_: {
550     Logical zOp = (Va->item == zVAR_NAME_), zVar;
551     struct CDFstruct *CDF;
552     char *varName = va_arg (Va->ap,  char *), tName[CDF_VAR_NAME_LEN+1];
553     Int32 offset;
554     SelectCDF (Cur->cdf, CDF)
555     if (BADzOP(CDF,!zOp)) return ILLEGAL_IN_zMODE;
556     if (!CURRENTvarSELECTED(CDF,zOp)) return NO_VAR_SELECTED;
557 
558     zVar = CurrentVarMode(CDF,zOp);
559     if (zModeON(CDF) || zVar) offset = CDF->CURzVarOffset;
560     else offset = CDF->CURrVarOffset;
561 
562     if (!sX(ReadVDR(CDF,CDF->fp,offset,zVar,
563 		    VDR_NAME,tName,
564 		    VDR_NULL),&pStatus)) {
565       AbortAccess (CDF, UPDATE, noDELETE);
566       return pStatus;
567     }
568     strcpyX (varName, tName, CDF_VAR_NAME_LEN);
569     break;
570   }
571   /****************************************************************************
572   * rVAR_DATATYPE_/zVAR_DATATYPE_
573   *    If this for an rVarible named "EPOCH" in a CDF prior to CDF V2.1.1,
574   * then return the CDF_EPOCH data type if the actual data type is CDF_REAL8
575   * or CDF_DOUBLE.  (The CDF_EPOCH data type was not introduced until CDF
576   * V2.1.1).  Note that only rVariables were supported prior to CDF V2.3.
577   ****************************************************************************/
578   case rVAR_DATATYPE_:
579   case zVAR_DATATYPE_: {
580     Logical zOp = (Va->item == zVAR_DATATYPE_), zVar;
581     struct CDFstruct *CDF;
582     long *dataType = va_arg (Va->ap, long *);
583     Int32 tDataType, offset;
584     SelectCDF (Cur->cdf, CDF)
585     if (BADzOP(CDF,!zOp)) return ILLEGAL_IN_zMODE;
586     if (!CURRENTvarSELECTED(CDF,zOp)) return NO_VAR_SELECTED;
587 
588     zVar = CurrentVarMode(CDF,zOp);
589     if (zModeON(CDF) || zVar) offset = CDF->CURzVarOffset;
590     else offset = CDF->CURrVarOffset;
591 
592     if (!sX(ReadVDR(CDF,CDF->fp,offset,zVar,
593 		    VDR_DATATYPE,&tDataType,
594 		    VDR_NULL),&pStatus)) {
595       AbortAccess (CDF, UPDATE, noDELETE);
596       return pStatus;
597     }
598     if (!zVar && CDF->fakeEPOCH) {
599       char varName[CDF_VAR_NAME_LEN+1];
600       if (!sX(ReadVDR(CDF,CDF->fp,offset,zVar,
601 		      VDR_NAME,varName,
602 		      VDR_NULL),&pStatus)) {
603 	AbortAccess (CDF, UPDATE, noDELETE);
604 	return pStatus;
605       }
606       if (!strcmpITB(varName,"EPOCH") && FLOAT8dataType(tDataType)) {
607 	tDataType = CDF_EPOCH;
608       } else if (!strcmpITB(varName,"EPOCH") && FLOAT16dataType(tDataType)) {
609         tDataType = CDF_EPOCH16;
610       }
611     }
612     *dataType = tDataType;
613     break;
614   }
615   /****************************************************************************
616   * rVAR_NUMELEMS_/zVAR_NUMELEMS_,
617   ****************************************************************************/
618   case rVAR_NUMELEMS_:
619   case zVAR_NUMELEMS_: {
620     Logical zOp = (Va->item == zVAR_NUMELEMS_), zVar;
621     struct CDFstruct *CDF;
622     long *numElements = va_arg (Va->ap, long *);
623     Int32 offset, tNumElems;
624     SelectCDF (Cur->cdf, CDF)
625     if (BADzOP(CDF,!zOp)) return ILLEGAL_IN_zMODE;
626     if (!CURRENTvarSELECTED(CDF,zOp)) return NO_VAR_SELECTED;
627 
628     zVar = CurrentVarMode(CDF,zOp);
629     if (zModeON(CDF) || zVar) offset = CDF->CURzVarOffset;
630     else offset = CDF->CURrVarOffset;
631 
632     if (!sX(ReadVDR(CDF,CDF->fp,offset,zVar,
633 		    VDR_NUMELEMS,&tNumElems,
634 		    VDR_NULL),&pStatus)) {
635       AbortAccess (CDF, UPDATE, noDELETE);
636       return pStatus;
637     }
638     *numElements = tNumElems;
639     break;
640   }
641   /****************************************************************************
642   * rVAR_RECVARY_/zVAR_RECVARY_,
643   ****************************************************************************/
644   case rVAR_RECVARY_:
645   case zVAR_RECVARY_: {
646     Logical zOp = (Va->item == zVAR_RECVARY_), zVar;
647     struct CDFstruct *CDF;
648     long *recVary = va_arg (Va->ap, long *);
649     Int32 flags, offset;
650     SelectCDF (Cur->cdf, CDF)
651     if (BADzOP(CDF,!zOp)) return ILLEGAL_IN_zMODE;
652     if (!CURRENTvarSELECTED(CDF,zOp)) return NO_VAR_SELECTED;
653 
654     zVar = CurrentVarMode(CDF,zOp);
655     if (zModeON(CDF) || zVar) offset = CDF->CURzVarOffset;
656     else offset = CDF->CURrVarOffset;
657 
658     if (!sX(ReadVDR(CDF,CDF->fp,offset,zVar,
659 		    VDR_FLAGS,&flags,
660 		    VDR_NULL),&pStatus)) {
661       AbortAccess (CDF, UPDATE, noDELETE);
662       return pStatus;
663     }
664     *recVary = BOO(RECvaryBITset(flags),VARY,NOVARY);
665     break;
666   }
667   /****************************************************************************
668   * rVAR_DIMVARYS_/zVAR_DIMVARYS_,
669   ****************************************************************************/
670   case rVAR_DIMVARYS_:
671   case zVAR_DIMVARYS_: {
672     Logical zOp = (Va->item == zVAR_DIMVARYS_), zVar;
673     struct CDFstruct *CDF; Int32 offset, numDims, dimVarys[CDF_MAX_DIMS];
674     long *dimVarysP = va_arg (Va->ap, long *);
675     SelectCDF (Cur->cdf, CDF)
676     if (BADzOP(CDF,!zOp)) return ILLEGAL_IN_zMODE;
677     if (!CURRENTvarSELECTED(CDF,zOp)) return NO_VAR_SELECTED;
678 
679     zVar = CurrentVarMode(CDF,zOp);
680     if (zModeON(CDF) || zVar) offset = CDF->CURzVarOffset;
681     else offset = CDF->CURrVarOffset;
682 
683     if (!sX(CalcDimParms(CDF,offset,zVar,&numDims,NULL,dimVarys),&pStatus)) {
684       AbortAccess (CDF, UPDATE, noDELETE);
685       return pStatus;
686     }
687     ASSIGNnotNULLarray (dimVarysP, numDims, dimVarys)
688     break;
689   }
690   /****************************************************************************
691   * rVAR_MAXREC_/zVAR_MAXREC_,
692   ****************************************************************************/
693   case rVAR_MAXREC_:
694   case zVAR_MAXREC_: {
695     Logical zOp = (Va->item == zVAR_MAXREC_), zVar;
696     struct CDFstruct *CDF; Int32 offset, tMaxRec;
697     long *maxRec = va_arg (Va->ap, long *);
698     SelectCDF (Cur->cdf, CDF)
699     if (BADzOP(CDF,!zOp)) return ILLEGAL_IN_zMODE;
700     if (!CURRENTvarSELECTED(CDF,zOp)) return NO_VAR_SELECTED;
701 
702     zVar = CurrentVarMode(CDF,zOp);
703     if (zModeON(CDF) || zVar) offset = CDF->CURzVarOffset;
704     else offset = CDF->CURrVarOffset;
705 
706     if (!sX(ReadVDR(CDF,CDF->fp,offset,zVar,
707 		    VDR_MAXREC,&tMaxRec,
708 		    VDR_NULL),&pStatus)) {
709       AbortAccess (CDF, UPDATE, noDELETE);
710       return pStatus;
711     }
712     *maxRec = (long) tMaxRec;
713     break;
714   }
715   /****************************************************************************
716   * rVAR_MAXallocREC_/zVAR_MAXallocREC_,
717   ****************************************************************************/
718   case rVAR_MAXallocREC_:
719   case zVAR_MAXallocREC_: {
720     Logical zOp = (Va->item == zVAR_MAXallocREC_), zVar;
721     struct CDFstruct *CDF;
722     Int32 offset, maxRec, lastAllocatedRecN;
723     long *maxAllocated = va_arg (Va->ap, long *);
724     SelectCDF (Cur->cdf, CDF)
725     if (BADzOP(CDF,!zOp)) return ILLEGAL_IN_zMODE;
726     if (!CURRENTvarSELECTED(CDF,zOp)) return NO_VAR_SELECTED;
727 
728     zVar = CurrentVarMode(CDF,zOp);
729     if (zModeON(CDF) || zVar) offset = CDF->CURzVarOffset;
730     else offset = CDF->CURrVarOffset;
731 
732     /**************************************************************************
733     * If a single-file CDF, pass back the maximum record number allocated.
734     * If a multi-file CDF, pass back the maximum record number written (which
735     * will always be the maximum record allocated).
736     **************************************************************************/
737     if (CDF->singleFile) {
738       if (!sX(LastRecord(CDF,offset,zVar,&lastAllocatedRecN),&pStatus)) {
739 	AbortAccess (CDF, UPDATE, noDELETE);
740 	return pStatus;
741       }
742       *maxAllocated = lastAllocatedRecN;
743     }
744     else {
745       if (!sX(ReadVDR(CDF,CDF->fp,offset,zVar,
746 		      VDR_MAXREC,&maxRec,
747 		      VDR_NULL),&pStatus)) {
748 	AbortAccess (CDF, UPDATE, noDELETE);
749 	return pStatus;
750       }
751       *maxAllocated = (long) maxRec;
752     }
753     break;
754   }
755   /****************************************************************************
756   * rVAR_NUMRECS_/zVAR_NUMRECS_,
757   ****************************************************************************/
758   case rVAR_NUMRECS_:
759   case zVAR_NUMRECS_: {
760     Logical zOp = (Va->item == zVAR_NUMRECS_), zVar; struct VarStruct *Var;
761     struct CDFstruct *CDF; Int32 vdrOffset, nRecords; int vType;
762     Int32 tMaxRec;
763     long *nRecordsP = va_arg (Va->ap, long *);
764     SelectCDF (Cur->cdf, CDF)
765     if (BADzOP(CDF,!zOp)) return ILLEGAL_IN_zMODE;
766     if (!CURRENTvarSELECTED(CDF,zOp)) return NO_VAR_SELECTED;
767 
768     zVar = CurrentVarMode(CDF,zOp);
769     if (zModeON(CDF) || zVar) vdrOffset = CDF->CURzVarOffset;
770     else vdrOffset = CDF->CURrVarOffset;
771 
772     if (zModeON(CDF))
773       if (CDF->CURzVarNum < CDF->NrVars)
774         Var = CDF->rVars[(int)CDF->CURzVarNum];
775       else
776         Var = CDF->zVars[(int)(CDF->CURzVarNum - CDF->NrVars)];
777     else
778       Var = BOO(zOp,CDF->zVars[(int)CDF->CURzVarNum],
779                     CDF->rVars[(int)CDF->CURrVarNum]);
780 
781     if (!sX(ReadVDR(CDF,CDF->fp,vdrOffset,zVar,
782 		    VDR_MAXREC,&tMaxRec,
783 		    VDR_NULL),&pStatus)) {
784       AbortAccess (CDF, UPDATE, noDELETE);
785       return pStatus;
786     }
787     if (!sX(VariableType(CDF,vdrOffset,zVar,&vType),&pStatus)) {
788       AbortAccess (CDF, UPDATE, noDELETE);
789       return pStatus;
790     }
791     /**************************************************************************
792     * Depending on the variable type...
793     **************************************************************************/
794     switch (vType) {
795       case SPARSE_RECORDS_:
796 	if (!sX(IndexingStatistics(CDF,vdrOffset,zVar,
797 				   NULL,NULL,NULL,
798 				   &nRecords,NULL),&pStatus)) return pStatus;
799 	if (Var != NULL) {
800 	  if (Var->stage.areaOffset != NO_OFFSET &&
801 	      Var->stage.firstRec != NO_RECORD) {
802 	    Int32 tmp = (Var->stage.lastRec > tMaxRec ? tMaxRec : Var->stage.lastRec);
803 	    nRecords += (tmp - Var->stage.firstRec + 1);
804 	  }
805 	}
806 	break;
807       case COMPRESSED_:
808       case SPARSE_COMPRESSED_RECORDS_:
809 	if (!sX(IndexingStatistics(CDF,vdrOffset,zVar,
810 				   NULL,NULL,NULL,
811 				   &nRecords,NULL),&pStatus)) return pStatus;
812 	if (Var != NULL) {
813 	  if (Var->stage.areaOffset != NO_OFFSET &&
814 	      Var->stage.firstRec != NO_RECORD &&
815 	      Var->stage.dotOffset == NO_OFFSET) {
816             Int32 tmp = (Var->stage.lastRec > tMaxRec ? tMaxRec : Var->stage.lastRec);
817 	    nRecords += (tmp - Var->stage.firstRec + 1);
818 	  }
819 	}
820 	break;
821       case SPARSE_ARRAYS_:
822       case SPARSE_RECORDS_AND_ARRAYS_:
823 	return CDF_INTERNAL_ERROR;
824       case STANDARD_:
825       case IN_MULTI_: {
826 	Int32 maxRec;
827 	if (!sX(ReadVDR(CDF,CDF->fp,vdrOffset,zVar,
828 			VDR_MAXREC,&maxRec,
829 			VDR_NULL),&pStatus)) {
830 	  AbortAccess (CDF, UPDATE, noDELETE);
831 	  return pStatus;
832 	}
833 	nRecords = maxRec + 1;
834 	break;
835       }
836     }
837     ASSIGNnotNULL (nRecordsP, nRecords)
838     break;
839   }
840   /****************************************************************************
841   * rVAR_NUMallocRECS_/zVAR_NUMallocRECS_,
842   ****************************************************************************/
843   case rVAR_NUMallocRECS_:
844   case zVAR_NUMallocRECS_: {
845     Logical zOp = (Va->item == zVAR_NUMallocRECS_), zVar;
846     struct CDFstruct *CDF; Int32 offset, nAllocated; int vType;
847     long *nAllocatedP = va_arg (Va->ap, long *);
848     SelectCDF (Cur->cdf, CDF)
849     if (BADzOP(CDF,!zOp)) return ILLEGAL_IN_zMODE;
850     if (!CURRENTvarSELECTED(CDF,zOp)) return NO_VAR_SELECTED;
851 
852     zVar = CurrentVarMode(CDF,zOp);
853     if (zModeON(CDF) || zVar) offset = CDF->CURzVarOffset;
854     else offset = CDF->CURrVarOffset;
855 
856     if (!sX(ReadVDR(CDF,CDF->fp,offset,zVar,
857 		    VDR_NULL),&pStatus)) {
858       AbortAccess (CDF, UPDATE, noDELETE);
859       return pStatus;
860     }
861     if (!sX(VariableType(CDF,offset,zVar,&vType),&pStatus)) {
862       AbortAccess (CDF, UPDATE, noDELETE);
863       return pStatus;
864     }
865     /**************************************************************************
866     * Depending on the variable type...
867     **************************************************************************/
868     switch (vType) {
869       case STANDARD_:
870       case SPARSE_RECORDS_:
871       case COMPRESSED_:
872       case SPARSE_COMPRESSED_RECORDS_:
873       case SPARSE_ARRAYS_:
874       case SPARSE_RECORDS_AND_ARRAYS_:
875 
876 	if (!sX(IndexingStatistics(CDF,offset,
877 				   zVar,NULL,NULL,
878 				   &nAllocated,
879 				   NULL,NULL),&pStatus)) return pStatus;
880 	break;
881       case IN_MULTI_: {
882 	Int32 maxRec;
883 	if (!sX(ReadVDR(CDF,CDF->fp,offset,zVar,
884 			VDR_MAXREC,&maxRec,
885 			VDR_NULL),&pStatus)) {
886 	  AbortAccess (CDF, UPDATE, noDELETE);
887 	  return pStatus;
888 	}
889 	nAllocated = maxRec + 1;
890 	break;
891       }
892     }
893     ASSIGNnotNULL (nAllocatedP, nAllocated)
894     break;
895   }
896   /****************************************************************************
897   * rVAR_ALLOCATEDFROM_/zVAR_ALLOCATEDFROM_
898   * Determines the next allocated record AT or AFTER `startRec' (meaning that
899   * `startRec' could be the record number returned).
900   ****************************************************************************/
901   case rVAR_ALLOCATEDFROM_:
902   case zVAR_ALLOCATEDFROM_: {
903     Logical zOp = (Va->item == zVAR_ALLOCATEDFROM_), zVar, found;
904     struct CDFstruct *CDF; Int32 offset, nextRec;
905     Int32 startRec = (Int32) va_arg (Va->ap, long);
906     long *fromRec = va_arg (Va->ap, long *);
907     SelectCDF (Cur->cdf, CDF)
908     if (BADzOP(CDF,!zOp)) return ILLEGAL_IN_zMODE;
909     if (!CURRENTvarSELECTED(CDF,zOp)) return NO_VAR_SELECTED;
910     if (startRec <= NO_RECORD) return BAD_REC_NUM;
911 
912     zVar = CurrentVarMode(CDF,zOp);
913     if (zModeON(CDF) || zVar) offset = CDF->CURzVarOffset;
914     else offset = CDF->CURrVarOffset;
915 
916     if (!sX(NextRecord(CDF,offset,zVar,startRec,&nextRec,&found),&pStatus)) {
917       AbortAccess (CDF, UPDATE, noDELETE);
918       return pStatus;
919     }
920     if (!found) return NO_SUCH_RECORD;
921     *fromRec = (long) nextRec;
922     break;
923   }
924   /****************************************************************************
925   * rVAR_ALLOCATEDTO_/zVAR_ALLOCATEDTO_
926   * Determines the last record (before the next unallocated record) allocated
927   * AT or AFTER `startRec'.  This can span non-contiguous blocks of records.
928   ****************************************************************************/
929   case rVAR_ALLOCATEDTO_:
930   case zVAR_ALLOCATEDTO_: {
931     Logical zOp = (Va->item == zVAR_ALLOCATEDTO_), zVar, found;
932     struct CDFstruct *CDF; Int32 vdrOffset, lastRec;
933     Int32 startRec = (Int32) va_arg (Va->ap, long);
934     long *toRec = va_arg (Va->ap, long *);
935     SelectCDF (Cur->cdf, CDF)
936     if (BADzOP(CDF,!zOp)) return ILLEGAL_IN_zMODE;
937     if (!CURRENTvarSELECTED(CDF,zOp)) return NO_VAR_SELECTED;
938     if (startRec <= NO_RECORD) return BAD_REC_NUM;
939 
940     zVar = CurrentVarMode(CDF,zOp);
941     if (zModeON(CDF) || zVar) vdrOffset = CDF->CURzVarOffset;
942     else vdrOffset = CDF->CURrVarOffset;
943 
944     /**************************************************************************
945     * Determine the last record in the block containing the starting record.
946     **************************************************************************/
947     if (!sX(SearchForRecord(CDF,vdrOffset,zVar,startRec,
948 			    NULL,&lastRec,NULL,&found),&pStatus)) {
949       AbortAccess (CDF, UPDATE, noDELETE);
950       return pStatus;
951     }
952     if (!found) return NO_SUCH_RECORD;
953     /**************************************************************************
954     * Keep searching until an unallocated record is encountered.
955     **************************************************************************/
956     while (found) {
957       Int32 nextRec = (Int32) (lastRec + 1);
958       if (!sX(SearchForRecord(CDF,vdrOffset,zVar,nextRec,
959 			      NULL,&lastRec,NULL,&found),&pStatus)) {
960         AbortAccess (CDF, UPDATE, noDELETE);
961         return pStatus;
962       }
963     }
964     /**************************************************************************
965     * Return the last allocated record detected.
966     **************************************************************************/
967     *toRec = (long) lastRec;
968     break;
969   }
970   /****************************************************************************
971   * rVAR_COMPRESSION_/zVAR_COMPRESSION_
972   ****************************************************************************/
973   case rVAR_COMPRESSION_:
974   case zVAR_COMPRESSION_: {
975     Logical zOp = (Va->item == zVAR_COMPRESSION_), zVar;
976     struct CDFstruct *CDF; /* struct VarStruct *Var; */ struct CPRstruct CPR;
977     Int32 VDRoffset, PRoffset, flags; int parmN;
978     long *cType = va_arg (Va->ap, long *);      /* Compression type. */
979     long *cParms = va_arg (Va->ap, long *);     /* Compression parameters. */
980     long *cPct = va_arg (Va->ap, long *);	/* Compression percentage. */
981     /**************************************************************************
982     * Select/validate/locate CDF and variable.
983     **************************************************************************/
984     SelectCDF (Cur->cdf, CDF)
985     if (BADzOP(CDF,!zOp)) return ILLEGAL_IN_zMODE;
986     if (!CURRENTvarSELECTED(CDF,zOp)) return NO_VAR_SELECTED;
987 
988     zVar = CurrentVarMode(CDF,zOp);
989     if (zModeON(CDF) || zVar) VDRoffset = CDF->CURzVarOffset;
990     else VDRoffset = CDF->CURrVarOffset;
991 
992     /**************************************************************************
993     * Read fields from VDR.
994     **************************************************************************/
995     if (!sX(ReadVDR(CDF,CDF->fp,VDRoffset,zVar,
996 		    VDR_FLAGS,&flags,
997 		    VDR_CPRorSPR,&PRoffset,
998 		    VDR_NULL),&pStatus)) {
999       AbortAccess (CDF, UPDATE, noDELETE);
1000       return pStatus;
1001     }
1002     /**************************************************************************
1003     * If the compression bit is set, read the CPR.
1004     **************************************************************************/
1005     if (VARcompressionBITset(flags)) {
1006       if (!sX(ReadCPR(CDF->fp,PRoffset,
1007 		      CPR_RECORD,&CPR,
1008 		      CPR_NULL),&pStatus)) {
1009 	AbortAccess (CDF, UPDATE, noDELETE);
1010 	return pStatus;
1011       }
1012       *cType = CPR.cType;
1013       for (parmN = 0; parmN < CPR.pCount; parmN++) {
1014 	 cParms[parmN] = CPR.cParms[parmN];
1015       }
1016       if (!sX(CalcCompressionPct(CDF,VDRoffset,zVar,cPct),&pStatus)) {
1017 	AbortAccess (CDF, UPDATE, noDELETE);
1018 	return pStatus;
1019       }
1020     }
1021     else {
1022       *cType = NO_COMPRESSION;
1023       *cPct = 100;
1024     }
1025     break;
1026   }
1027   /****************************************************************************
1028   * rVAR_SPARSEARRAYS_/zVAR_SPARSEARRAYS_
1029   ****************************************************************************/
1030   case rVAR_SPARSEARRAYS_:
1031   case zVAR_SPARSEARRAYS_: {
1032     Logical zOp = (Va->item == zVAR_SPARSEARRAYS_), zVar;
1033     struct CDFstruct *CDF; /* struct VarStruct *Var; */ struct SPRstruct SPR;
1034     Int32 VDRoffset, PRoffset, flags; int parmN;
1035     long *sArraysType = va_arg (Va->ap, long *);   /* Sparseness type. */
1036     long *sArraysParms = va_arg (Va->ap, long *);  /* Sparseness parameters. */
1037     long *sArraysPct = va_arg (Va->ap, long *);    /* Sparseness percentage. */
1038     /**************************************************************************
1039     * Select/validate/locate CDF and variable.
1040     **************************************************************************/
1041     SelectCDF (Cur->cdf, CDF)
1042     if (BADzOP(CDF,!zOp)) return ILLEGAL_IN_zMODE;
1043     if (!CURRENTvarSELECTED(CDF,zOp)) return NO_VAR_SELECTED;
1044 
1045     zVar = CurrentVarMode(CDF,zOp);
1046     if (zModeON(CDF) || zVar) VDRoffset = CDF->CURzVarOffset;
1047     else VDRoffset = CDF->CURrVarOffset;
1048 
1049     /**************************************************************************
1050     * Read fields from VDR.
1051     **************************************************************************/
1052     if (!sX(ReadVDR(CDF,CDF->fp,VDRoffset,zVar,
1053 		    VDR_FLAGS,&flags,
1054 		    VDR_CPRorSPR,&PRoffset,
1055 		    VDR_NULL),&pStatus)) {
1056       AbortAccess (CDF, UPDATE, noDELETE);
1057       return pStatus;
1058     }
1059     /**************************************************************************
1060     * If the sparse arrays bit is set, read the SPR.
1061     **************************************************************************/
1062     if (SPARSEarraysBITset(flags)) {
1063       if (!sX(ReadSPR(CDF->fp,PRoffset,
1064 		      SPR_RECORD,&SPR,
1065 		      SPR_NULL),&pStatus)) {
1066 	AbortAccess (CDF, UPDATE, noDELETE);
1067 	return pStatus;
1068       }
1069       *sArraysType = SPR.sArraysType;
1070       for (parmN = 0; parmN < SPR.pCount; parmN++) {
1071 	 sArraysParms[parmN] = SPR.sArraysParms[parmN];
1072       }
1073       *sArraysPct = 100;
1074     }
1075     else {
1076       *sArraysType = NO_SPARSEARRAYS;
1077       *sArraysPct = 100;
1078     }
1079     break;
1080   }
1081   /****************************************************************************
1082   * rVAR_SPARSERECORDS_/zVAR_SPARSERECORDS_
1083   ****************************************************************************/
1084   case rVAR_SPARSERECORDS_:
1085   case zVAR_SPARSERECORDS_: {
1086     Logical zOp = (Va->item == zVAR_SPARSERECORDS_), zVar;
1087     struct CDFstruct *CDF; /* struct VarStruct *Var; */
1088     Int32 VDRoffset, sRecords;
1089     long *sRecordsType = va_arg (Va->ap, long *);
1090     /**************************************************************************
1091     * Select/validate/locate CDF and variable.
1092     **************************************************************************/
1093     SelectCDF (Cur->cdf, CDF)
1094     if (BADzOP(CDF,!zOp)) return ILLEGAL_IN_zMODE;
1095     if (!CURRENTvarSELECTED(CDF,zOp)) return NO_VAR_SELECTED;
1096 
1097     zVar = CurrentVarMode(CDF,zOp);
1098     if (zModeON(CDF) || zVar) VDRoffset = CDF->CURzVarOffset;
1099     else VDRoffset = CDF->CURrVarOffset;
1100 
1101     /**************************************************************************
1102     * Read sparse records field from VDR.
1103     **************************************************************************/
1104     if (!sX(ReadVDR(CDF,CDF->fp,VDRoffset,zVar,
1105 		    VDR_sRECORDS,&sRecords,
1106 		    VDR_NULL),&pStatus)) {
1107       AbortAccess (CDF, UPDATE, noDELETE);
1108       return pStatus;
1109     }
1110     *sRecordsType = sRecords;
1111     break;
1112   }
1113   /****************************************************************************
1114   * rVAR_NUMBER_/zVAR_NUMBER_
1115   *    Determines the variable number for a specified variable name.
1116   ****************************************************************************/
1117   case rVAR_NUMBER_:
1118   case zVAR_NUMBER_: {
1119     Logical zOp = (Va->item == zVAR_NUMBER_), zVar;
1120     struct CDFstruct *CDF;
1121     char *varName = va_arg (Va->ap, char *);
1122     long *varNum = va_arg (Va->ap,  long *);
1123     Int32 varN, offset;
1124     SelectCDF (Cur->cdf, CDF)
1125     if (BADzOP(CDF,!zOp)) return ILLEGAL_IN_zMODE;
1126     tStatus = FindVarByName (CDF, varName, &offset, &zVar, NULL);
1127     switch (tStatus) {
1128       case CDF_OK:
1129 	break;
1130       case NO_SUCH_VAR:
1131 	return tStatus;
1132       default:
1133 	if (!sX(tStatus,&pStatus)) {
1134 	  AbortAccess (CDF, UPDATE, noDELETE);
1135 	  return tStatus;
1136 	}
1137     }
1138     if (!sX(ReadVDR(CDF,CDF->fp,offset,zVar,
1139 		    VDR_NUM,&varN,
1140 		    VDR_NULL),&pStatus)) {
1141       AbortAccess (CDF, UPDATE, noDELETE);
1142       return pStatus;
1143     }
1144     if (zModeON(CDF))
1145       *varNum = BOO(zVar,CDF->NrVars,0) + varN;
1146     else
1147       if (zOp)
1148 	if (zVar)
1149 	  *varNum = varN;
1150 	else
1151 	  return NO_SUCH_VAR;                   /* Wrong type of variable. */
1152       else
1153 	if (zVar)
1154 	  return NO_SUCH_VAR;                   /* Wrong type of variable. */
1155 	else
1156 	  *varNum = varN;
1157     break;
1158   }
1159   /****************************************************************************
1160   * rVAR_BLOCKINGFACTOR_/zVAR_BLOCKINGFACTOR_,
1161   ****************************************************************************/
1162   case rVAR_BLOCKINGFACTOR_:
1163   case zVAR_BLOCKINGFACTOR_: {
1164     Logical zOp = (Va->item == zVAR_BLOCKINGFACTOR_), zVar;
1165     struct CDFstruct *CDF;
1166     long *nExtendRecs = va_arg (Va->ap, long *);
1167     Int32 tRecs, offset;
1168     SelectCDF (Cur->cdf, CDF)
1169     if (BADzOP(CDF,!zOp)) return ILLEGAL_IN_zMODE;
1170     if (!CURRENTvarSELECTED(CDF,zOp)) return NO_VAR_SELECTED;
1171 
1172     zVar = CurrentVarMode(CDF,zOp);
1173     if (zModeON(CDF) || zVar) offset = CDF->CURzVarOffset;
1174     else offset = CDF->CURrVarOffset;
1175 
1176     if (!sX(ReadVDR(CDF,CDF->fp,offset,zVar,
1177 		    VDR_BLOCKING,&tRecs,
1178 		    VDR_NULL),&pStatus)) {
1179       AbortAccess (CDF, UPDATE, noDELETE);
1180       return pStatus;
1181     }
1182     *nExtendRecs = tRecs;
1183     break;
1184   }
1185   /****************************************************************************
1186   * rVAR_nINDEXRECORDS_/zVAR_nINDEXRECORDS_,
1187   * rVAR_nINDEXENTRIES_/zVAR_nINDEXENTRIES_,
1188   * rVAR_nINDEXLEVELS_/zVAR_nINDEXLEVELS_,
1189   ****************************************************************************/
1190   case rVAR_nINDEXRECORDS_:
1191   case zVAR_nINDEXRECORDS_:
1192   case rVAR_nINDEXENTRIES_:
1193   case zVAR_nINDEXENTRIES_:
1194   case rVAR_nINDEXLEVELS_:
1195   case zVAR_nINDEXLEVELS_: {
1196     Logical zOp = (Va->item == zVAR_nINDEXRECORDS_ ||
1197 		   Va->item == zVAR_nINDEXENTRIES_ ||
1198 		   Va->item == zVAR_nINDEXLEVELS_), zVar;
1199     struct CDFstruct *CDF; Int32 offset, count;
1200     long *countP = va_arg (Va->ap, long *);
1201     SelectCDF (Cur->cdf, CDF)
1202     if (BADzOP(CDF,!zOp)) return ILLEGAL_IN_zMODE;
1203     if (!CURRENTvarSELECTED(CDF,zOp)) return NO_VAR_SELECTED;
1204 
1205     zVar = CurrentVarMode(CDF,zOp);
1206     if (zModeON(CDF) || zVar) offset = CDF->CURzVarOffset;
1207     else offset = CDF->CURrVarOffset;
1208 
1209     /**************************************************************************
1210     * If a multi-file CDF, pass back a count of zero (0) and an info/warning
1211     * status code.  If a single-file CDF, scan through the linked list of VXRs
1212     * counting the parameter requested.
1213     **************************************************************************/
1214     if (!CDF->singleFile) {
1215       count = 0;
1216       sX (MULTI_FILE_FORMAT, &pStatus);
1217     }
1218     else {
1219       switch (Va->item) {
1220 	case rVAR_nINDEXRECORDS_:
1221 	case zVAR_nINDEXRECORDS_:
1222 	  if (!sX(IndexingStatistics(CDF,offset,zVar,
1223 				     &count,NULL,NULL,
1224 				     NULL,NULL),&pStatus)) return pStatus;
1225 	  break;
1226 	case rVAR_nINDEXENTRIES_:
1227 	case zVAR_nINDEXENTRIES_:
1228 	  if (!sX(IndexingStatistics(CDF,offset,zVar,
1229 				     NULL,&count,NULL,
1230 				     NULL,NULL),&pStatus)) return pStatus;
1231 	  break;
1232 	case rVAR_nINDEXLEVELS_:
1233 	case zVAR_nINDEXLEVELS_:
1234 	  if (!sX(IndexingStatistics(CDF,offset,zVar,
1235 				     NULL,NULL,NULL,
1236 				     NULL,&count),&pStatus)) return pStatus;
1237 	  break;
1238       }
1239     }
1240     ASSIGNnotNULL (countP, count)
1241     break;
1242   }
1243   /****************************************************************************
1244   * rVAR_PADVALUE_/zVAR_PADVALUE_
1245   ****************************************************************************/
1246   case rVAR_PADVALUE_:
1247   case zVAR_PADVALUE_: {
1248     Logical zOp = (Va->item == zVAR_PADVALUE_), zVar;
1249     struct CDFstruct *CDF;
1250     void *padValue = va_arg (Va->ap, void *);
1251     Int32 offset, dataType, numElems, flags;
1252     SelectCDF (Cur->cdf, CDF)
1253     if (BADzOP(CDF,!zOp)) return ILLEGAL_IN_zMODE;
1254     if (!CURRENTvarSELECTED(CDF,zOp)) return NO_VAR_SELECTED;
1255 
1256     zVar = CurrentVarMode(CDF,zOp);
1257     if (zModeON(CDF) || zVar) offset = CDF->CURzVarOffset;
1258     else offset = CDF->CURrVarOffset;
1259 
1260     if (!sX(ReadVDR(CDF,CDF->fp,offset,zVar,
1261 		    VDR_FLAGS,&flags,
1262 		    VDR_DATATYPE,&dataType,
1263 		    VDR_NUMELEMS,&numElems,
1264 		    VDR_NULL),&pStatus)) {
1265       AbortAccess (CDF, UPDATE, noDELETE);
1266       return pStatus;
1267     }
1268 
1269     /**********************************************************************
1270         The length of the pad value for a CDF_CHAR variable is the
1271         length of the variable (i.e. CHAR/162, etc.).  If the length
1272         of the pad value is greater than 16, it causes segmentation fault
1273         for the IDL CDF interface routine.
1274     ***********************************************************************/
1275     if (dataType == CDF_CHAR ||  dataType == CDF_UCHAR)
1276         numElems = 1;
1277 
1278     if (PADvalueBITset(flags)) {
1279       if (!sX(ReadVDR(CDF,CDF->fp,offset,zVar,
1280 	              VDR_PADVALUE,padValue,
1281 		      VDR_NULL),&pStatus)) {
1282 	  AbortAccess (CDF, UPDATE, noDELETE);
1283     	  return pStatus;
1284       }
1285       if (!sX(ConvertBuffer(CDF->encoding,CDF->decoding,
1286 			    CDF->negToPosFp0,dataType,
1287 			    numElems,padValue,padValue),&pStatus)) {
1288 	AbortAccess (CDF, UPDATE, noDELETE);
1289 	return pStatus;
1290       }
1291     }
1292     else {
1293       DefaultPadValue (dataType, numElems, padValue);
1294       if (!sX(ConvertBuffer(HostEncoding(),CDF->decoding,
1295     		            CDF->negToPosFp0,dataType,
1296 			    numElems,padValue,padValue),&pStatus)) {
1297 	    AbortAccess (CDF, UPDATE, noDELETE);
1298 	return pStatus;
1299       }
1300       sX (NO_PADVALUE_SPECIFIED, &pStatus);
1301     }
1302     break;
1303   }
1304   /****************************************************************************
1305   * rVAR_DATA_/zVAR_DATA_,
1306   ****************************************************************************/
1307   case rVAR_DATA_:
1308   case zVAR_DATA_: {
1309     Logical zOp = (Va->item == zVAR_DATA_);
1310     struct CDFstruct *CDF; struct VarStruct *Var;
1311     Int32 phyRecNum, offset; struct rdSTRUCT *rd;
1312     char *value = va_arg (Va->ap, char *);
1313     SelectCDF (Cur->cdf, CDF)
1314     if (BADzOP(CDF,!zOp)) return ILLEGAL_IN_zMODE;
1315     if (!CURRENTvarSELECTED(CDF,zOp)) return NO_VAR_SELECTED;
1316     if (!sX(InitCurrentVar(CDF,zOp,&Var),&pStatus)) {
1317       AbortAccess (CDF, UPDATE, noDELETE);
1318       return pStatus;
1319     }
1320     rd = BOO(zModeON(CDF),&(Var->zRD),BOO(zOp,&(Var->zRD),&(CDF->rRD)));
1321     if (!CDF->singleFile && Var->fp == NULL) {
1322       if (!sX(OpenVar(CDF,Var),&pStatus)) {
1323 	AbortAccess (CDF, UPDATE, noDELETE);
1324 	return pStatus;
1325       }
1326     }
1327     phyRecNum = BOO(Var->recVary,rd->recNumber,0);
1328     offset = IndicesValueOffset(Var->numDims,
1329 				rd->dimIndices,
1330 				Var->dimVarys,
1331 				Var->nPhyDimValues) * Var->NvalueBytes;
1332     if (!sX(ReadVarValues(CDF,Var,phyRecNum,
1333 			  offset,INT32_ONE,value),&pStatus)) {
1334       AbortAccess (CDF, UPDATE, noDELETE);
1335       return pStatus;
1336     }
1337     Var->accessed_at = CDF->pseudo_clock++;
1338     break;
1339   }
1340   /****************************************************************************
1341   * rVAR_HYPERDATA_/zVAR_HYPERDATA_,
1342   ****************************************************************************/
1343   case rVAR_HYPERDATA_:
1344   case zVAR_HYPERDATA_: {
1345     Logical zOp = (Va->item == zVAR_HYPERDATA_);
1346     struct CDFstruct *CDF;
1347     struct VarStruct *Var;
1348     int dimN;
1349     struct rdSTRUCT *rd;
1350 #if LIMITof64K
1351     long Nvalues, Nbytes;
1352 #endif
1353     char *buffer = va_arg (Va->ap, char *);
1354     SelectCDF (Cur->cdf, CDF)
1355     if (BADzOP(CDF,!zOp)) return ILLEGAL_IN_zMODE;
1356     if (!CURRENTvarSELECTED(CDF,zOp)) return NO_VAR_SELECTED;
1357 
1358     if (!sX(InitCurrentVar(CDF,zOp,&Var),&pStatus)) {
1359       AbortAccess (CDF, UPDATE, noDELETE);
1360       return pStatus;
1361     }
1362     rd = BOO(zModeON(CDF),&(Var->zRD),BOO(zOp,&(Var->zRD),&(CDF->rRD)));
1363     for (dimN = 0; dimN < Var->numDims; dimN++) {
1364        long maxIndex = rd->dimIndices[dimN] +
1365 		       ((rd->dimCounts[dimN] - 1) * rd->dimIntervals[dimN]);
1366        if (maxIndex >= Var->dimSizes[dimN]) return BAD_DIM_INDEX;
1367     }
1368 #if LIMITof64K
1369     Nvalues = rd->recCount;
1370     for (dimN = 0; dimN < Var->numDims; dimN++) Nvalues *= rd->dimCounts[dimN];
1371     Nbytes = Nvalues * Var->NvalueBytes;
1372     if (TOObigIBMpc(Nbytes)) return IBM_PC_OVERFLOW;
1373 #endif
1374     if (!CDF->singleFile && Var->fp == NULL) {
1375       if (!sX(OpenVar(CDF,Var),&pStatus)) {
1376 	AbortAccess (CDF, UPDATE, noDELETE);
1377 	return pStatus;
1378       }
1379     }
1380     if (!sX(HyperRead(CDF,Var,rd,buffer),&pStatus)) {
1381       AbortAccess (CDF, UPDATE, noDELETE);
1382       return pStatus;
1383     }
1384     Var->accessed_at = CDF->pseudo_clock++;
1385     break;
1386   }
1387   /****************************************************************************
1388   * rVAR_SEQDATA_/zVAR_SEQDATA_,
1389   ****************************************************************************/
1390   case rVAR_SEQDATA_:
1391   case zVAR_SEQDATA_: {
1392     Logical zOp = (Va->item == zVAR_SEQDATA_);
1393     struct CDFstruct *CDF; struct VarStruct *Var; Int32 recNum, offset;
1394     void *value = va_arg (Va->ap, char *);
1395     SelectCDF (Cur->cdf, CDF)
1396     if (BADzOP(CDF,!zOp)) return ILLEGAL_IN_zMODE;
1397     if (!CURRENTvarSELECTED(CDF,zOp)) return NO_VAR_SELECTED;
1398     if (!sX(InitCurrentVar(CDF,zOp,&Var),&pStatus)) {
1399       AbortAccess (CDF, UPDATE, noDELETE);
1400       return pStatus;
1401     }
1402     if (!CDF->singleFile && Var->fp == NULL) {
1403       if (!sX(OpenVar(CDF,Var),&pStatus)) {
1404 	AbortAccess (CDF, UPDATE, noDELETE);
1405 	return pStatus;
1406       }
1407     }
1408     recNum = Var->seqValueOffset / Var->NphyRecValues;
1409     if (recNum > Var->maxRec) return END_OF_VAR;
1410     offset = (Var->seqValueOffset % Var->NphyRecValues) * Var->NvalueBytes;
1411     if (!sX(ReadVarValues(CDF,Var,recNum,offset,INT32_ONE,value),&pStatus)) {
1412       AbortAccess (CDF, UPDATE, noDELETE);
1413       return pStatus;
1414     }
1415     Var->seqValueOffset++;
1416     Var->accessed_at = CDF->pseudo_clock++;
1417     break;
1418   }
1419   /****************************************************************************
1420   * rVARs_RECDATA_/zVARs_RECDATA_
1421   *    Read data records for up to all of the rVariables/zVariables.
1422   ****************************************************************************/
1423   case rVARs_RECDATA_:
1424   case zVARs_RECDATA_: {
1425     Logical zOp = (Va->item == zVARs_RECDATA_), zVar;
1426     struct VarStruct *Var; struct CDFstruct *CDF;
1427     Int32 recNum, varNt; Byte *tBuffer; int varX;
1428     long nVars = va_arg (Va->ap, long);
1429     long *varNs = va_arg (Va->ap, long *);
1430     void *buffer = va_arg (Va->ap, char *);
1431 #if LIMITof64K
1432     long nBytes;
1433 #endif
1434     SelectCDF (Cur->cdf, CDF)
1435     if (BADzOP(CDF,!zOp)) return ILLEGAL_IN_zMODE;
1436     if (nVars < 1) return BAD_NUM_VARS;
1437     for (varX = 0; varX < nVars; varX++) {
1438        if (!sX(VarIdentity(CDF,(Int32)varNs[varX],
1439 			   zOp,&varNt,&zVar,NULL),&pStatus)) {
1440 	 return pStatus;
1441        }
1442        if (!sX(InitVar(CDF,varNt,zVar,NULL),&pStatus)) {
1443 	 AbortAccess (CDF, UPDATE, noDELETE);
1444 	 return pStatus;
1445        }
1446     }
1447 #if LIMITof64K
1448     for (varX = 0, nBytes = 0; varX < nVars; varX++) {
1449        if (!sX(VarIdentity(CDF,varNs[varX],zOp,NULL,NULL,&Var),&pStatus)) {
1450 	 return pStatus;
1451        }
1452        nBytes += Var->NphyRecBytes;
1453     }
1454     if (TOObigIBMpc(nBytes)) return IBM_PC_OVERFLOW;
1455 #endif
1456     for (varX = 0, tBuffer = buffer; varX < nVars; varX++) {
1457        if (!sX(VarIdentity(CDF,(Int32)varNs[varX],
1458 			   zOp,NULL,NULL,&Var),&pStatus)) {
1459 	 return pStatus;
1460        }
1461        if (!CDF->singleFile && Var->fp == NULL) {
1462 	 if (!sX(OpenVar(CDF,Var),&pStatus)) {
1463 	   AbortAccess (CDF, UPDATE, noDELETE);
1464 	   return pStatus;
1465 	 }
1466        }
1467        recNum = BOO(Var->recVary,BOO(zOp,Var->zRD.recNumber,
1468 					 CDF->rRD.recNumber),0);
1469        if (!sX(ReadVarValues(CDF,Var,recNum,INT32_ZERO,
1470 			     Var->NphyRecValues,tBuffer),&pStatus)) {
1471 	 AbortAccess (CDF, UPDATE, noDELETE);
1472 	 return pStatus;
1473        }
1474        tBuffer += (size_t) Var->NphyRecBytes;
1475        Var->accessed_at = CDF->pseudo_clock++;
1476     }
1477 
1478     break;
1479   }
1480   /****************************************************************************
1481   * ATTR_NAME_,
1482   *    Note that a temporary variable is used when reading the attribute name.
1483   * This is because the caller may have only allocated enough memory for the
1484   * size name they expect (ie., less than CDF_ATTR_NAME_LEN characters).  Since
1485   * the attribute name is NUL-terminated in the CDF, only the actual characters
1486   * of the name will be copied to the caller's buffer.
1487   ****************************************************************************/
1488   case ATTR_NAME_: {
1489     struct CDFstruct *CDF;
1490     char *attrName = va_arg (Va->ap,  char *), tName[CDF_ATTR_NAME_LEN+1];
1491     SelectCDF (Cur->cdf, CDF)
1492     if (!CURRENTattrSELECTED(CDF)) return NO_ATTR_SELECTED;
1493     if (!sX(ReadADR(CDF->fp,CDF->CURattrOffset,
1494 		    ADR_NAME,tName,
1495 		    ADR_NULL),&pStatus)){
1496       AbortAccess (CDF, UPDATE, noDELETE);
1497       return pStatus;
1498     }
1499     strcpyX (attrName, tName, CDF_ATTR_NAME_LEN);
1500     break;
1501   }
1502   /****************************************************************************
1503   * ATTR_NUMBER_,
1504   ****************************************************************************/
1505   case ATTR_NUMBER_: {
1506     struct CDFstruct *CDF;
1507     char *attrName = va_arg (Va->ap, char *);
1508     long *attrNum = va_arg (Va->ap,  long *);
1509     Int32 attrNumT, offset;
1510     SelectCDF (Cur->cdf, CDF)
1511     tStatus = FindAttrByName (CDF, attrName, &offset);
1512     switch (tStatus) {
1513       case CDF_OK:
1514 	break;
1515       case NO_SUCH_ATTR:
1516 	return tStatus;
1517       default:
1518 	if (!sX(tStatus,&pStatus)) {
1519 	  AbortAccess (CDF, UPDATE, noDELETE);
1520 	  return tStatus;
1521 	}
1522     }
1523     if (!sX(ReadADR(CDF->fp,offset,
1524 		    ADR_NUM,&attrNumT,
1525 		    ADR_NULL),&pStatus)) {
1526       AbortAccess (CDF, UPDATE, noDELETE);
1527       return pStatus;
1528     }
1529     *attrNum = attrNumT;
1530     break;
1531   }
1532   /****************************************************************************
1533   * ATTR_SCOPE_,
1534   ****************************************************************************/
1535   case ATTR_SCOPE_: {
1536     struct CDFstruct *CDF;
1537     long *scope = va_arg (Va->ap, long *);
1538     Int32 tScope;
1539     SelectCDF (Cur->cdf, CDF)
1540     if (!CURRENTattrSELECTED(CDF)) return NO_ATTR_SELECTED;
1541     if (!sX(ReadADR(CDF->fp,CDF->CURattrOffset,
1542 		    ADR_SCOPE,&tScope,
1543 		    ADR_NULL),&pStatus)) {
1544       AbortAccess (CDF, UPDATE, noDELETE);
1545       return pStatus;
1546     }
1547     *scope = DEFINITEscope(tScope);
1548     break;
1549   }
1550   /****************************************************************************
1551   * ATTR_MAXgENTRY_/ATTR_MAXrENTRY_/ATTR_MAXzENTRY_
1552   * ATTR_NUMgENTRIES_/ATTR_NUMrENTRIES_/ATTR_NUMzENTRIES_
1553   ****************************************************************************/
1554   case ATTR_MAXgENTRY_:
1555   case ATTR_NUMgENTRIES_:
1556   case ATTR_MAXrENTRY_:
1557   case ATTR_NUMrENTRIES_:
1558   case ATTR_MAXzENTRY_:
1559   case ATTR_NUMzENTRIES_: {
1560     Logical maxOp = ONEof3(Va->item,ATTR_MAXgENTRY_,
1561 				    ATTR_MAXrENTRY_,
1562 				    ATTR_MAXzENTRY_);
1563     int entryType = BOO(maxOp,E3p(Va->item,ATTR_MAXgENTRY_,
1564 					   ATTR_MAXrENTRY_,
1565 					   ATTR_MAXzENTRY_),
1566 			      E3p(Va->item,ATTR_NUMgENTRIES_,
1567 					   ATTR_NUMrENTRIES_,
1568 					   ATTR_NUMzENTRIES_));
1569     struct CDFstruct *CDF;
1570     long *value = va_arg (Va->ap, long *);
1571     Int32 scope, gr, z;
1572     SelectCDF (Cur->cdf, CDF)
1573     if (!CURRENTattrSELECTED(CDF)) return NO_ATTR_SELECTED;
1574     if (!sX(ReadADR(CDF->fp,CDF->CURattrOffset,
1575 		    ADR_SCOPE,&scope,
1576 		    ADR_NULL),&pStatus)) {
1577       AbortAccess (CDF, UPDATE, noDELETE);
1578       return pStatus;
1579     }
1580     if (GLOBALscope(scope)) {
1581       if (entryType != gENTRYt) return ILLEGAL_FOR_SCOPE;
1582     }
1583     else {
1584       if (entryType == gENTRYt) return ILLEGAL_FOR_SCOPE;
1585     }
1586     if (!sX(ReadADR(CDF->fp,CDF->CURattrOffset,
1587 		    BOO(maxOp,ADR_MAXgrENTRY,ADR_NgrENTRIES),&gr,
1588 		    BOO(maxOp,ADR_MAXzENTRY,ADR_NzENTRIES),&z,
1589 		    ADR_NULL),&pStatus)) {
1590       AbortAccess (CDF, UPDATE, noDELETE);
1591       return pStatus;
1592     }
1593     if (GLOBALscope(scope))
1594       *value = (long) gr;
1595     else
1596       if (zModeON(CDF))
1597 	if (entryType == rENTRYt)
1598 	  *value = (long) BOO(maxOp,NO_ENTRY,0);
1599 					/* Never any rEntries in zMode. */
1600 	else
1601 	  *value = (long) BOO(maxOp,BOO(z > NO_ENTRY,CDF->NrVars+z,gr),gr+z);
1602       else
1603 	*value = (long) E3(entryType,BOO(maxOp,NO_ENTRY,0),gr,z);
1604     break;
1605   }
1606   /****************************************************************************
1607   * gENTRY_DATATYPE_/rENTRY_DATATYPE_/zENTRY_DATATYPE_
1608   * gENTRY_NUMELEMS_/rENTRY_NUMELEMS_/zENTRY_NUMELEMS_
1609   *    If this CDF is prior to CDF V2.1.1, the current attribute is named
1610   * "VALIDMIN", "VALIDMAX", "SCALEMIN", or "SCALEMAX", this is a true rEntry,
1611   * and the rEntry corresponds to an rVariable named "EPOCH", then return
1612   * the CDF_EPOCH data type if the actual data type is CDF_REAL8 or CDF_DOUBLE.
1613   * (The CDF_EPOCH data type was not introduced until CDF V2.1.1).  Note that
1614   * only rVariables were supported prior to CDF V2.3.
1615   ****************************************************************************/
1616   case gENTRY_DATATYPE_:
1617   case gENTRY_NUMELEMS_:
1618   case rENTRY_DATATYPE_:
1619   case rENTRY_NUMELEMS_:
1620   case zENTRY_DATATYPE_:
1621   case zENTRY_NUMELEMS_: {
1622     Logical dataOp = ONEof3(Va->item,gENTRY_DATATYPE_,
1623 				     rENTRY_DATATYPE_,
1624 				     zENTRY_DATATYPE_);
1625     int entryType = BOO(dataOp,E3p(Va->item,gENTRY_DATATYPE_,
1626 					    rENTRY_DATATYPE_,
1627 					    zENTRY_DATATYPE_),
1628 			       E3p(Va->item,gENTRY_NUMELEMS_,
1629 					    rENTRY_NUMELEMS_,
1630 					    zENTRY_NUMELEMS_));
1631     struct CDFstruct *CDF;
1632     long *value = va_arg (Va->ap, long *);
1633     Int32 tValue, eOffset;
1634     SelectCDF (Cur->cdf, CDF)
1635     if (!CURRENTattrSELECTED(CDF)) return NO_ATTR_SELECTED;
1636     if (E3(entryType,
1637 	   CDF->CURgrEntryNum,
1638 	   CDF->CURgrEntryNum,
1639 	   CDF->CURzEntryNum) == RESERVED_ENTRYNUM) return NO_ENTRY_SELECTED;
1640     if (!sX(CheckEntryOp(CDF,entryType),&pStatus)) return pStatus;
1641     eOffset = E3(entryType,CDF->CURgrEntryOffset,
1642 			   CDF->CURgrEntryOffset,
1643 			   CDF->CURzEntryOffset);
1644     if (eOffset == RESERVED_ENTRYOFFSET) return NO_SUCH_ENTRY;
1645     if (!sX(ReadAEDR(CDF->fp,eOffset,
1646 		     BOO(dataOp,AEDR_DATATYPE,AEDR_NUMELEMS),&tValue,
1647 		     AEDR_NULL),&pStatus)) {
1648       AbortAccess (CDF, UPDATE, noDELETE);
1649       return pStatus;
1650     }
1651     if (dataOp && CDF->fakeEPOCH) {
1652       char aName[CDF_ATTR_NAME_LEN+1];
1653       if (!sX(ReadADR(CDF->fp,CDF->CURattrOffset,
1654 		      ADR_NAME,aName,
1655 		      ADR_NULL),&pStatus)) {
1656 	AbortAccess (CDF, UPDATE, noDELETE);
1657 	return pStatus;
1658       }
1659       if (!strcmpITB(aName,"VALIDMIN") || !strcmpITB(aName,"VALIDMAX") ||
1660 	  !strcmpITB(aName,"SCALEMIN") || !strcmpITB(aName,"SCALEMAX")) {
1661 	Int32 vOffset; char vName[CDF_VAR_NAME_LEN+1];
1662 	tStatus = FindVarByNumber (CDF, E3(entryType, CDF->CURgrEntryNum,
1663 						      CDF->CURgrEntryNum,
1664 						      CDF->CURzEntryNum),
1665 				   FALSE, &vOffset);
1666 	switch (tStatus) {
1667 	  case NO_SUCH_VAR:
1668 	    break;
1669 	  default:
1670 	    if (!sX(tStatus,&pStatus)) {
1671 	      AbortAccess (CDF, UPDATE, noDELETE);
1672 	      return tStatus;
1673 	    }
1674 	    if (!sX(ReadVDR(CDF,CDF->fp,vOffset,FALSE,
1675 			    VDR_NAME,vName,
1676 			    VDR_NULL),&pStatus)) {
1677 	      AbortAccess (CDF, UPDATE, noDELETE);
1678 	      return pStatus;
1679 	    }
1680 	    if (!strcmpITB(vName,"EPOCH") &&
1681 		FLOAT8dataType(tValue)) tValue = CDF_EPOCH;
1682 	    if (!strcmpITB(vName,"EPOCH") &&
1683                 FLOAT16dataType(tValue)) tValue = CDF_EPOCH16;
1684 	    break;
1685 	}
1686       }
1687     }
1688     *value = tValue;
1689     break;
1690   }
1691   /****************************************************************************
1692   * gENTRY_DATA_/rENTRY_DATA_/zENTRY_DATA_,
1693   ****************************************************************************/
1694   case gENTRY_DATA_:
1695   case rENTRY_DATA_:
1696   case zENTRY_DATA_: {
1697     int entryType = E3p(Va->item,gENTRY_DATA_,rENTRY_DATA_,zENTRY_DATA_);
1698     struct CDFstruct *CDF;
1699     Int32 offset, dataType, numElems;
1700     void *value = va_arg (Va->ap, void *);
1701     SelectCDF (Cur->cdf, CDF)
1702     if (!CURRENTattrSELECTED(CDF)) return NO_ATTR_SELECTED;
1703     if (E3(entryType,
1704 	   CDF->CURgrEntryNum,
1705 	   CDF->CURgrEntryNum,
1706 	   CDF->CURzEntryNum) == RESERVED_ENTRYNUM) return NO_ENTRY_SELECTED;
1707     if (!sX(CheckEntryOp(CDF,entryType),&pStatus)) return pStatus;
1708     offset = E3(entryType,CDF->CURgrEntryOffset,
1709 			  CDF->CURgrEntryOffset,
1710 			  CDF->CURzEntryOffset);
1711     if (offset == RESERVED_ENTRYOFFSET) return NO_SUCH_ENTRY;
1712     if (!sX(ReadAEDR(CDF->fp,offset,
1713 		     AEDR_DATATYPE,&dataType,
1714 		     AEDR_NUMELEMS,&numElems,
1715 		     AEDR_VALUE,value,
1716 		     AEDR_NULL),&pStatus)) {
1717       AbortAccess (CDF, UPDATE, noDELETE);
1718       return pStatus;
1719     }
1720     if (!sX(ConvertBuffer(CDF->encoding,CDF->decoding,
1721 			  CDF->negToPosFp0,dataType,
1722 			  numElems,value,value),&pStatus)) {
1723       AbortAccess (CDF, UPDATE, noDELETE);
1724       return pStatus;
1725     }
1726     break;
1727   }
1728   /****************************************************************************
1729   * Unknown item, must be the next function.
1730   ****************************************************************************/
1731   default: {
1732     Va->fnc = Va->item;
1733     break;
1734   }
1735 }
1736 return pStatus;
1737 }
1738