1 /******************************************************************************
2 *
3 *  NSSDC/CDF                   Toolbox of routines for CDF Toolkit (General).
4 *
5 *  Version 1.5d, 23-Nov-97, Hughes STX.
6 *
7 *  Modification history:
8 *
9 *   V1.0  25-Jan-94, J Love     Original version.
10 *   V1.0a  6-Feb-94, J Love     DEC Alpha/OpenVMS port.
11 *   V1.1  10-Mar-94, J Love     Modified `ParseOptionList' to make the
12 *                               enclosing parentheses optional (on any
13 *                               operating system).
14 *   V1.2  15-Dec-94, J Love     CDF V2.5.
15 *   V1.2a 13-Jan-95, J Love     Allow mixed-case in tokens.  Changed
16 *                               `CDFdirList' to allow all possible extensions
17 *                               on Macintosh machines also.
18 *   V1.2b  6-Mar-95, J Love     Added macro definition checking to catch
19 *                               bug in directory listing system calls.  Pass
20 *                               `char' as `int'.
21 *   V1.3  21-Mar-95, J Love     POSIX.
22 *   V1.3a 18-Apr-95, J Love     More POSIX.
23 *   V1.3b 24-Apr-95, J Love     Fixed `EncodeString' to not overflow the
24 *                               maximum length if the string won't fit.
25 *   V1.4  25-May-95, J Love     Added `GetCdataType'.  EPOCH styles.
26 *                               SOLARISbsdDIRUTILSbug.
27 *   V1.4a 12-Jun-95, J Love     EPOCH custom format.  catchrX.
28 *   V1.4b  5-Sep-95, J Love     Allow NULL for output fields not needed.
29 *                               NUL-terminate decoded string in `DecodeValues'.
30 *   V1.4c 19-Sep-95, J Love     Macintosh event handling.
31 *   V1.4d 27-Sep-95, J Love     Reduced TextEdit text size for Think C.
32 *   V1.5  27-Aug-96, J Love     CDF V2.6.
33 *   V1.5a  2-Nov-96, J Love	Changed `DisplayIdentification' to not print
34 *				a `blank' sub-increment.
35 *   V1.5b 21-Feb-97, J Love	Removed RICE.
36 *   V1.5c  3-Mar-97, J Love	Windows NT for MS Visual C/C++ on an IBM PC.
37 *   V1.5d 23-Nov-97, J Love	More Windows NT.
38 *   V1.6  10-May-01, M Liu      New port for Cygwin
39 *   V1.7  11-Jul-05, M Liu      Added MingW port for PC.
40 *   V1.8  13-Oct-06, M Liu      Changed to allow upper and lower case CDF
41 *                               name to be used on win32.
42 *
43 ******************************************************************************/
44 
45 #define TOOLBOX1
46 #include "cdftools.h"
47 
48 /******************************************************************************
49 * Local macros.
50 ******************************************************************************/
51 
52 #define MAX_cFORMAT_LEN 10
53 
54 /******************************************************************************
55 * Local enumerators.
56 ******************************************************************************/
57 
58 #if (defined(unix) && !defined(__MINGW32__)) || defined(mac) || \
59      defined(posixSHELL)
60 enum typeENUM {TBD, STR, WILD1, WILDn};
61 #endif
62 
63 /******************************************************************************
64 * Local structures.
65 ******************************************************************************/
66 
67 struct FILEstruct {
68   char *name;
69   struct FILEstruct *next;
70 };
71 
72 /******************************************************************************
73 * Local function prototypes.
74 ******************************************************************************/
75 
76 static Logical FtoCformat PROTOARGs((long, char *, long *, char *));
77 static int UseCformat PROTOARGs((long, long, char *, void *, char *));
78 static long GetCdataType PROTOARGs((char *, long *));
79 static void AddToList PROTOARGs((struct FILEstruct **FILEhead,
80 				 struct FILEstruct *FILEptr));
81 #if (defined(unix) && !defined(__MINGW32__)) || defined(mac) || \
82      defined(posixSHELL)
83 static int PatternMatch PROTOARGs((char *pattern, char *name));
84 static int CheckPattern PROTOARGs((int nTypes, enum typeENUM types[],
85 				   char *strings[], char *name));
86 #endif
87 
88 /******************************************************************************
89 * FatalError.
90 ******************************************************************************/
91 
FatalError(message)92 void FatalError (message)
93 char *message;
94 {
95 #if defined(mac)
96   MacMessageDialog ("FATAL ERROR!", message);
97 #else
98 #if defined(win32) && !defined(ALONE)
99   WinMessageDialog ("FATAL ERROR!", message);
100 #else
101   WriteOut (stdout, "FATAL ERROR!  ");
102   WriteOut (stdout, message);
103   WriteOut (stdout, "\n");
104 #endif
105 #endif
106   ExitBAD;
107 }
108 
109 /******************************************************************************
110 * DisplayError.
111 ******************************************************************************/
112 
DisplayError(message)113 void DisplayError (message)
114 char *message;
115 {
116 #if defined(mac)
117   MacMessageDialog ("Error!", message);
118 #else
119 #if defined(win32) && !defined(ALONE)
120   WinMessageDialog ("Error!", message);
121 #else
122   WriteOut (stdout, "Error!  ");
123   WriteOut (stdout, message);
124   WriteOut (stdout, "\n");
125 #endif
126 #endif
127   return;
128 }
129 
130 /******************************************************************************
131 * DisplayWarning.
132 *    It is assumed that the message contains at least one character.
133 ******************************************************************************/
134 
DisplayWarning(message)135 void DisplayWarning (message)
136 char *message;
137 {
138 #if defined(mac)
139   MacMessageDialog ("Warning...", message);
140 #else
141   WriteOut (stdout, "Warning: ");
142   WriteOut (stdout, message);
143   WriteOut (stdout, "\n");
144 #endif
145   return;
146 }
147 
148 /******************************************************************************
149 * DisplayInfo.
150 ******************************************************************************/
151 
DisplayInfo(message)152 void DisplayInfo (message)
153 char *message;
154 {
155 #if defined(mac)
156   MacMessageDialog ("", message);
157 #else
158   WriteOut (stdout, message);
159   WriteOut (stdout, "\n");
160 #endif
161   return;
162 }
163 
164 /******************************************************************************
165 * DecodeVariances.
166 ******************************************************************************/
167 
DecodeVariances(mask,numDims,recVary,dimVarys)168 Logical DecodeVariances (mask, numDims, recVary, dimVarys)
169 char *mask;
170 long numDims;
171 long *recVary;
172 long dimVarys[];
173 {
174   int dimN, charN;
175 
176   switch (mask[0]) {
177     case 'T':
178     case 't':
179       *recVary = VARY;
180       break;
181     case 'F':
182     case 'f':
183       *recVary = NOVARY;
184       break;
185     default:
186       return FALSE;
187   }
188 
189   for (dimN = 0, charN = 2; dimN < numDims; dimN++, charN++) {
190      switch (mask[charN]) {
191        case 'T':
192        case 't':
193 	 dimVarys[dimN] = VARY;
194 	 break;
195        case 'F':
196        case 'f':
197 	 dimVarys[dimN] = NOVARY;
198 	 break;
199        default:
200 	 return FALSE;
201    }
202   }
203 
204   return TRUE;
205 }
206 
207 /******************************************************************************
208 * DecodeDelimitedString.
209 ******************************************************************************/
210 
DecodeDelimitedString(dString,pString)211 Logical DecodeDelimitedString (dString, pString)
212 char *dString;          /* Delimited string. */
213 char *pString;          /* Parsed (decoded) string. */
214 {
215   char *d1 = dString;           /* First delimiter. */
216   char *d2;                     /* Second delimiter. */
217   size_t len;                   /* Size of decoded string. */
218 
219   while (*d1 != NUL && Spacing(*d1)) d1++;
220   if (*d1 == NUL) return FALSE;
221 
222   d2 = d1 + 1;
223   while (*d2 != NUL && *d2 != *d1) d2++;
224   if (*d2 == NUL) return FALSE;
225 
226   len = (size_t) (d2 - d1 - 1);
227   memmove (pString, d1 + 1, len);
228   pString[len] = NUL;
229 
230   return TRUE;
231 }
232 
233 /******************************************************************************
234 * DecodeDimensionality.
235 ******************************************************************************/
236 
DecodeDimensionality(string,numDims,dimSizes)237 Logical DecodeDimensionality (string, numDims, dimSizes)
238 char *string;
239 long *numDims;
240 long *dimSizes;
241 {
242   char *cp;
243   /****************************************************************************
244   * The number of dimensions should be first.
245   ****************************************************************************/
246   cp = NextNonSpace (string);
247   if (sscanf(cp,"%ld",numDims) != 1) return FALSE;
248   if (*numDims < 0) return FALSE;
249   cp = NextNonDigit (cp);
250   /****************************************************************************
251   * Skip past the `:' and `['.
252   ****************************************************************************/
253   cp = NextNonSpace (cp);
254   if (*cp != ':') return FALSE;
255   cp = NextNonSpace (cp+1);
256   if (*cp != '[') return FALSE;
257   cp = NextNonSpace (cp+1);
258   /****************************************************************************
259   * Decode each dimension size.
260   ****************************************************************************/
261   if (*numDims > 0) {
262     int dimN, lastDim = (int) (*numDims - 1);
263     for (dimN = 0; dimN <= lastDim; dimN++) {
264        if (sscanf(cp,"%ld",&dimSizes[dimN]) != 1) return FALSE;
265        cp = NextNonDigit (cp);
266        cp = NextNonSpace (cp);
267        if (dimN != lastDim) {
268 	 if (*cp != ',') return FALSE;
269 	 cp = NextNonSpace (cp+1);
270        }
271     }
272   }
273   /****************************************************************************
274   * Check for a trailing `]'.
275   ****************************************************************************/
276   if (*cp != ']') return FALSE;
277   /****************************************************************************
278   * Everything went Ok, return TRUE;
279   ****************************************************************************/
280   return TRUE;
281 }
282 
283 /******************************************************************************
284 * DecodeRecordAndIndices.
285 ******************************************************************************/
286 
DecodeRecordAndIndices(string,recN,nIndices,indices)287 Logical DecodeRecordAndIndices (string, recN, nIndices, indices)
288 char *string;
289 long *recN;                     /* Can be NULL if not needed. */
290 long *nIndices;
291 long indices[CDF_MAX_DIMS];
292 {
293   char *cp; long recNt;
294   /****************************************************************************
295   * The record number will be first if it exists;
296   ****************************************************************************/
297   cp = NextNonSpace (string);
298   if (*cp == '[') {
299     recNt = 0;
300   }
301   else {
302     if (sscanf(cp,"%ld",&recNt) != 1) return FALSE;
303     recNt -= 1;
304     if (recNt < 0) return FALSE;
305     cp = NextNonDigit (cp);
306     cp = NextNonSpace (cp);
307     if (*cp != ':') return FALSE;
308     cp = NextNonSpace (cp+1);
309     if (*cp != '[') return FALSE;
310   }
311   ASSIGNnotNULL (recN, recNt)
312   cp = NextNonSpace (cp+1);
313   /****************************************************************************
314   * Decode each index while counting how many there are.
315   ****************************************************************************/
316   *nIndices = 0;
317   if (*cp == ']') return TRUE;
318   for (;;) {
319      if (*nIndices == CDF_MAX_DIMS) return FALSE;       /* Too many indices. */
320      if (sscanf(cp,"%ld",&indices[(int)(*nIndices)]) != 1) return FALSE;
321      indices[(int)(*nIndices)] -= 1;
322      if (indices[(int)(*nIndices)] < 0) return FALSE;
323      *nIndices += 1;
324      cp = NextNonDigit (cp);    /* Skip to space, comma, or `]'. */
325      cp = NextNonSpace (cp);    /* Skip past spaces. */
326      switch (*cp) {
327        case ']':
328 	 return TRUE;
329        case ',':
330 	 cp = NextNonSpace (cp + 1);
331 	 break;
332        default:
333 	 return FALSE;
334      }
335   }
336 }
337 
338 /******************************************************************************
339 * NextNonSpace.
340 ******************************************************************************/
341 
NextNonSpace(cp)342 char *NextNonSpace (cp)
343 char *cp;
344 {
345   while (Spacing(*cp)) cp++;
346   return cp;
347 }
348 
349 /******************************************************************************
350 * NextNonDigit.
351 ******************************************************************************/
352 
NextNonDigit(cp)353 char *NextNonDigit (cp)
354 char *cp;
355 {
356   while (Decimal(*cp)) cp++;
357   return cp;
358 }
359 
360 /******************************************************************************
361 * FormatWidth.
362 *    Returns width of a format specifier [or zero if the width is unknown or
363 * illegal].
364 ******************************************************************************/
365 
FormatWidth(format)366 int FormatWidth (format)
367 char *format;
368 {
369   int width; char *ptr = format;
370   /****************************************************************************
371   * Skip past Fortran repeat count (eg. the `20' in `20I8' or `20(I8)').
372   * Note that this won't skip past a C `%'.
373   ****************************************************************************/
374   while (*ptr != NUL && (*ptr == '(' ||
375 			 Spacing(*ptr) ||
376 			 Decimal(*ptr))) ptr++;
377   if (*ptr == NUL) return 0;
378   /****************************************************************************
379   * Skip past Fortran format type (eg. the `F' in `F4.1') or C `%' and/or
380   * flags (one of which might be a `0').
381   ****************************************************************************/
382   while (*ptr != NUL && (!Decimal(*ptr) || *ptr == '0')) ptr++;
383   if (*ptr == NUL) return 0;
384   /****************************************************************************
385   * Decode format width.
386   ****************************************************************************/
387   if (sscanf(ptr,"%d",&width) != 1) width = 0;
388   return width;
389 }
390 
391 /******************************************************************************
392 * FormatPrecision.
393 *   Returns precision of a format specifier [or zero if the precision doesn't
394 * exist [eg. integer format]).
395 ******************************************************************************/
396 
FormatPrecision(format)397 int FormatPrecision (format)
398 char *format;
399 {
400   int precision;
401   char *ptr = strchr (format, '.');
402   if (ptr == NULL)
403     precision = 0;
404   else
405     if (sscanf(ptr+1,"%d",&precision) != 1) precision = 0;
406   return precision;
407 }
408 
409 /******************************************************************************
410 * EncodeValuesFormat.  Returns width of encoded values.
411 ******************************************************************************/
412 
EncodeValuesFormat(dataType,numElems,binary,text,format,minWidth,maxWidth,style)413 int EncodeValuesFormat (dataType, numElems, binary, text, format, minWidth,
414 			maxWidth, style)
415 long dataType;          /* Data type of values. */
416 long numElems;          /* Number of elements (values). */
417 void *binary;           /* In: Values in binary. */
418 char *text;             /* Out: Encoded values. */
419 char *format;           /* If NULL, use default formats.  Not applicable if
420 			   a string data type. */
421 int minWidth;           /* Minimum width (including delimeters if a string
422 			   data type.  If zero, no minimum width (no blank
423 			   padding).  If positive, right justified (padding
424 			   on left side).  If negative, left justified
425 			   (padding on right side). */
426 int maxWidth;           /* Maximum width (including delimeters if a string
427 			   data type.  If zero, no maximum width (no
428 			   truncating). */
429 int style;              /* EPOCH style. */
430 {
431   /****************************************************************************
432   * Encode value(s).
433   ****************************************************************************/
434   if (STRINGdataType(dataType))
435     EncodeString (numElems, binary, text, minWidth, maxWidth);
436   else {
437     long elemN;
438     char tText[MAX_nonSTRING_VALUE_LEN+1];
439     strcpyX (text, "", maxWidth);
440     for (elemN = 0; elemN < numElems; elemN++) {
441        /***********************************************************************
442        * Encode each value (if it fits).
443        ***********************************************************************/
444        EncodeValueFormat (dataType, (Byte *) binary +
445 				    (size_t) (elemN*CDFelemSize(dataType)),
446 			  tText, format, 0, 0, style);
447        if (maxWidth > 0) {
448 	 int n = strlen(tText);
449 	 if (strlen(text) + (elemN > 0 ? 2 : 0) + n > (size_t) maxWidth) {
450 	   /*******************************************************************
451 	   * This value won't fit.  Find a comma after which to put the
452 	   * truncation symbol (`...').  `i' starts at the NUL just in case
453 	   * this is the first value (`text' is a null-string).
454 	   *******************************************************************/
455 	   int i;
456 	   for (i = strlen(text); i != 0; i--) {
457 	      if (text[i] == ',' &&
458 		  (i + strlen(" ...") < (size_t) maxWidth)) break;
459 	   }
460 	   if (i != 0)
461 	     strcpyX (&text[i+1], " ...", maxWidth);
462 	   else {
463 	     switch (elemN) {
464 	       case 0:
465 		 CpyNcharacters (text, maxWidth, (int) '*');
466 		 break;
467 	       case 1:
468 		 if (strlen(text) + strlen(", ...") <= (size_t) maxWidth)
469 		   strcatX (text, ", ...", maxWidth);
470 		 else {
471 		   CpyNcharacters (text, maxWidth, (int) '*');
472 		 }
473 		 break;
474 	       default:
475 		 CpyNcharacters (text, maxWidth, (int) '*');
476 		 break;
477 	     }
478 	   }
479 	   break;
480 	 }
481 	 else
482 	   sprintf (&text[strlen(text)], "%s%s", (elemN > 0 ? ", " : ""),
483 		    tText);
484        }
485        else
486 	 sprintf (&text[strlen(text)], "%s%s", (elemN > 0 ? ", " : ""), tText);
487     }
488     /**************************************************************************
489     * Blank pad to `minWidth' if necessary.
490     **************************************************************************/
491     if (minWidth != 0) {
492       int n = strlen(text);
493       if (minWidth > 0) {               /* Right justify. */
494 	if (n < minWidth) {
495 	  int i, pad = minWidth - n;
496 	  memmove (&text[pad], text, n + 1);
497 	  for (i = 0; i < pad; i++) text[i] = ' ';
498 	}
499       }
500       else {                    /* Left justify. */
501 	int min = -minWidth;
502 	if (n < min) {
503 	  int pad = min - n;
504 	  CatNcharacters (text, pad, (int) ' ');
505 	}
506       }
507     }
508   }
509   /****************************************************************************
510   * Return length of encoded value(s).
511   ****************************************************************************/
512   return strlen(text);
513 }
514 
515 /******************************************************************************
516 * EncodeValueFormat.
517 *    Returns width of encoded value.  Not for use with character string data
518 * types (CDF_CHAR or CDF_UCHAR).
519 ******************************************************************************/
520 
EncodeValueFormat(dataType,binary,text,format,minWidth,maxWidth,style)521 int EncodeValueFormat (dataType, binary, text, format, minWidth, maxWidth,
522 		       style)
523 long dataType;          /* Data type of value being encoded. */
524 void *binary;           /* In: Value in binary. */
525 char *text;             /* Out: Encoded value. */
526 char *format;           /* Format string to be used. */
527 int minWidth;           /* Minimum width (including delimeters if a string
528 			   data type.  If zero, no minimum width (no blank
529 			   padding).  If positive, right justified (padding
530 			   on left side).  If negative, left justified
531 			   (padding on right side). */
532 int maxWidth;           /* Maximum width.  If zero, no maximum width (no
533 			   asteriks if too big). */
534 int style;              /* EPOCH style. */
535 {
536   long CdataType;
537   char Cformat[MAX_cFORMAT_LEN+1];
538   char tText[MAX_nonSTRING_VALUE_LEN+1];
539   /****************************************************************************
540   * Encode value.
541   ****************************************************************************/
542   if (EPOCHdataType(dataType)) {
543     switch (style) {
544       case EPOCHf_STYLE:
545 	return EncodeValueFormat(CDF_DOUBLE,binary,text,
546 				 format,minWidth,maxWidth,0);
547       case EPOCHx_STYLE:
548 	encodeEPOCHx (*((double *) binary), format, tText);
549 	break;
550       default:
551 	EncodeValue (CDF_EPOCH, binary, tText, style);
552 	break;
553     }
554   } else if (EPOCH16dataType(dataType)) {
555     switch (style) {
556       case EPOCHf_STYLE:
557         return EncodeValueFormat(CDF_DOUBLE,binary,text,
558                                  format,minWidth,maxWidth,0);
559       case EPOCHx_STYLE:
560         encodeEPOCHx (*((double *) binary), format, tText);
561         break;
562       default:
563         EncodeValue (CDF_EPOCH16, binary, tText, style);
564         break;
565     }
566   }
567   else
568     if (format == NULL)
569       EncodeValue (dataType, binary, tText, 0);
570     else
571       if (strchr(format,'%') != NULL)
572 	if (GetCdataType(format,&CdataType))
573 	  UseCformat (dataType, CdataType, format, binary, tText);
574 	else
575 	  EncodeValue (dataType, binary, tText, 0);
576       else
577 	if (FtoCformat(dataType,format,&CdataType,Cformat))
578 	  UseCformat (dataType, CdataType, Cformat, binary, tText);
579 	else
580 	  EncodeValue (dataType, binary, tText, 0);
581   /****************************************************************************
582   * Fill in asteriks if encoded value is too big.  Otherwise, copy encoded
583   * value.
584   ****************************************************************************/
585   if (maxWidth > 0) {
586     int n = strlen(tText);
587     if (n > maxWidth)
588       CpyNcharacters (text, maxWidth, (int) '*');
589     else
590       strcpyX (text, tText, maxWidth);
591   }
592   else
593     strcpyX (text, tText, maxWidth);
594   /****************************************************************************
595   * Blank pad to `minWidth' if necessary.
596   ****************************************************************************/
597   if (minWidth != 0) {
598     int n = strlen(text);
599     if (minWidth > 0) {         /* Right justify. */
600       if (n < minWidth) {
601 	int i, pad = minWidth - n;
602 	memmove (&text[pad], text, n + 1);
603 	for (i = 0; i < pad; i++) text[i] = ' ';
604       }
605     }
606     else {                      /* Left justify. */
607       int min = -minWidth;
608       if (n < min) {
609 	int pad = min - n;
610 	CatNcharacters (text, pad, (int) ' ');
611       }
612     }
613   }
614   /****************************************************************************
615   * Return length of encoded value.
616   ****************************************************************************/
617   return strlen(text);
618 }
619 
620 /******************************************************************************
621 * EncodeValue.
622 * Returns width of encoded value.
623 ******************************************************************************/
624 
EncodeValue(dataType,binary,text,style)625 int EncodeValue (dataType, binary, text, style)
626 long dataType;          /* CDF data type. */
627 void *binary;           /* In: Value to encode. */
628 char *text;             /* Out: Encoded value. */
629 int style;              /* In: EPOCH style. */
630 {
631   MakeNUL (text);
632   switch (dataType) {
633     case CDF_BYTE:
634     case CDF_INT1:
635       sprintf (text, "%d", (int) *((sChar *) binary));
636       break;
637     case CDF_INT2:
638       sprintf (text, "%d", (int) *((Int16 *) binary));
639       break;
640     case CDF_INT4:
641       sprintf (text, Int32FORMAT, *((Int32 *) binary));
642       break;
643     case CDF_UINT1:
644       sprintf (text, "%u", (uInt) *((uChar *) binary));
645       break;
646     case CDF_UINT2:
647       sprintf (text, "%u", (uInt) *((uInt16 *) binary));
648       break;
649     case CDF_UINT4:
650       sprintf (text, Int32uFORMAT, *((uInt32 *) binary));
651       break;
652     case CDF_REAL4:
653     case CDF_FLOAT: {
654       if (NegativeZeroReal4((float *) binary))
655 	strcpyX (text, NEGATIVEzeroSYMBOL, 0);
656       else {
657 	size_t len;
658 	char *ePtr, tText[80+1];
659 	sprintf (text, "%g", *((float *) binary));
660 	if ((ePtr = strchr(text,'e')) == NULL) {  /* eg., 0 */
661 	  if (strchr(text,'.') == NULL) strcatX (text,".0", 0);
662 	}
663 	else {
664 	  if (strchr(text,'.') == NULL) {  /* eg., 1e+07 */
665 	    len = (size_t) (ePtr - text);
666 	    strcpyX (tText, text, MINIMUM(len,80));
667 	    strcatX (tText, ".0", 0);
668 	    strcatX (tText, ePtr, 0);
669 	    strcpyX (text, tText, 0);
670 	  }
671 	}
672       }
673       break;
674     }
675     case CDF_REAL8:
676     case CDF_DOUBLE: {
677       if (NegativeZeroReal8((double *) binary))
678 	strcpyX (text, NEGATIVEzeroSYMBOL, 0);
679       else {
680 	size_t len;
681 	char *ePtr, tText[80+1];
682 	sprintf (text, "%g", *((double *) binary));
683 	if ((ePtr = strchr(text,'e')) == NULL) {  /* eg., 0 */
684 	  if (strchr(text,'.') == NULL) strcatX (text,".0", 0);
685 	}
686 	else {
687 	  if (strchr(text,'.') == NULL) {  /* eg., 1e+07 */
688 	    len = (size_t) (ePtr - text);
689 	    strcpyX (tText, text, MINIMUM(len,80));
690 	    strcatX (tText, ".0", 0);
691 	    strcatX (tText, ePtr, 0);
692 	    strcpyX (text, tText, 0);
693 	  }
694 	}
695       }
696       break;
697     }
698     case CDF_CHAR:
699       sprintf (text, "%c", *((sChar *) binary));
700       break;
701     case CDF_UCHAR:
702       sprintf (text, "%c", *((uChar *) binary));
703       break;
704     case CDF_EPOCH:
705       switch (style) {
706 	case EPOCH0_STYLE:
707 	  encodeEPOCH (*((double *) binary), text);
708 	  break;
709 	case EPOCH1_STYLE:
710 	  encodeEPOCH1 (*((double *) binary), text);
711 	  break;
712 	case EPOCH2_STYLE:
713 	  encodeEPOCH2 (*((double *) binary), text);
714 	  break;
715 	case EPOCH3_STYLE:
716 	  encodeEPOCH3 (*((double *) binary), text);
717 	  break;
718 	case EPOCHf_STYLE:
719 	  return EncodeValue(CDF_DOUBLE,binary,text,0);
720 	case EPOCHx_STYLE:
721 	  /* Unsupported (a format specification is needed). */
722 	  break;
723       }
724       break;
725     case CDF_EPOCH16:
726       switch (style) {
727         case EPOCH0_STYLE:
728           encodeEPOCH16 ((double *) binary, text);
729           break;
730         case EPOCH1_STYLE:
731           encodeEPOCH16_1 ((double *) binary, text);
732           break;
733         case EPOCH2_STYLE:
734           encodeEPOCH16_2 ((double *) binary, text);
735           break;
736         case EPOCH3_STYLE:
737           encodeEPOCH16_3 ((double *) binary, text);
738           break;
739         case EPOCHf_STYLE:
740           return EncodeValue(CDF_DOUBLE,binary,text,0);
741         case EPOCHx_STYLE:
742           /* Unsupported (a format specification is needed). */
743           break;
744       }
745       break;
746   }
747   return strlen(text);
748 }
749 
750 /******************************************************************************
751 * EncodeString.  Returns width of encoded string (including delimeters).
752 ******************************************************************************/
753 
EncodeString(nChars,iString,oString,minWidth,maxWidth)754 int EncodeString (nChars, iString, oString, minWidth, maxWidth)
755 long nChars;            /* Number of characters (elements). */
756 char *iString;          /* String to encode (input). */
757 char *oString;          /* Encoded string (output). */
758 int minWidth;           /* Minimum width (including delimeters if a string
759 			   data type.  If zero, no minimum width (no blank
760 			   padding).  If positive, right justified (padding
761 			   on left side).  If negative, left justified
762 			   (padding on right side). */
763 int maxWidth;           /* Maximum width (including delimeters).  If zero,
764 			   no maximum width (no truncating). */
765 {
766   char delim = PickDelimiter (iString, (size_t) nChars); int i;
767   /****************************************************************************
768   * Encode string.
769   ****************************************************************************/
770   if (nChars + 2 > BOO(maxWidth == 0,(int)(nChars + 2),maxWidth)) {
771     /**************************************************************************
772     * Won't fit.  Should at least encode `"a..."'.  If not enough room, fill
773     * in with astericks.
774     **************************************************************************/
775     if (maxWidth < 6) {
776       CpyNcharacters (oString, maxWidth, (int) '*');
777     }
778     else {
779       oString[0] = delim;
780       for (i = 0; i < maxWidth - 5; i++) {
781 	 oString[i+1] = BOO(Printable(iString[i]),iString[i],'.');
782       }
783       oString[i+1] = '.';
784       oString[i+2] = '.';
785       oString[i+3] = '.';
786       oString[i+4] = delim;
787       oString[i+5] = NUL;
788     }
789   }
790   else {
791     /**************************************************************************
792     * Fits.
793     **************************************************************************/
794     oString[0] = delim;
795     for (i = 0; i < nChars; i++) {
796        oString[i+1] = BOO(Printable(iString[i]),iString[i],'.');
797     }
798     oString[i+1] = delim;
799     oString[i+2] = NUL;
800   }
801   /****************************************************************************
802   * Blank pad to `minWidth' if necessary.
803   ****************************************************************************/
804   if (minWidth != 0) {
805     int n = strlen(oString);
806     if (minWidth > 0) {         /* Right justify. */
807       if (n < minWidth) {
808 	int i, pad = minWidth - n;
809 	memmove (&oString[pad], oString, n + 1);
810 	for (i = 0; i < pad; i++) oString[i] = ' ';
811       }
812     }
813     else {                      /* Left justify. */
814       int min = -minWidth;
815       if (n < min) {
816 	int pad = min - n;
817 	CatNcharacters (oString, pad, (int) ' ');
818       }
819     }
820   }
821   /****************************************************************************
822   * Return length of encoded string.
823   ****************************************************************************/
824   return strlen(oString);
825 }
826 
827 /******************************************************************************
828 * EncodeNegativeZero.
829 ******************************************************************************/
830 
EncodeNegativeZero(string,format)831 void EncodeNegativeZero (string, format)
832 char *string;
833 char *format;
834 {
835   char *ptr;
836   /****************************************************************************
837   * Encode 0.0 using format then check if the value was successfully encoded.
838   ****************************************************************************/
839   string[0] = NUL;
840   sprintf(string, format, 0.0);
841   if (NULstring(string)) {
842     strcpyX (string, "-0.0(bad FORMAT)", 0);
843     return;
844   }
845   /****************************************************************************
846   * 0.0 was successfully encoded - put a negative sign at the beginning
847   * (increasing the length of the string if necessary).
848   ****************************************************************************/
849   ptr = string;
850   while (*ptr == ' ') ptr++;
851   if (ptr == string) {
852     memmove (&string[1], string, strlen(string) + 1);
853     string[0] = '-';
854   }
855   else
856     *(ptr - 1) = '-';
857   return;
858 }
859 
860 /******************************************************************************
861 * UseCformat.
862 * Returns width of encoded value.  Not for use with CDF_EPOCH or CDF_(U)CHAR
863 * values.
864 ******************************************************************************/
865 
UseCformat(dataType,CdataType,Cformat,binary,text)866 static int UseCformat (dataType, CdataType, Cformat, binary, text)
867 long dataType;          /* Value's actual data type.  This should never be
868 			   CDF_EPOCH. */
869 long CdataType;         /* Data type corresponding to C format.  This should
870 			   never be CDF_EPOCH. */
871 char *Cformat;          /* C format specification. */
872 void *binary;           /* Value to be encoded. */
873 char *text;             /* String into which to encode the value. */
874 {
875   switch (dataType) {
876     case CDF_BYTE:
877     case CDF_INT1:
878       switch (CdataType) {
879 	case CDF_BYTE:
880 	case CDF_INT1:
881 	  sprintf (text, Cformat, (sChar) *((sChar *) binary));
882 	  break;
883 	case CDF_UINT1:
884 	  sprintf (text, Cformat, (uChar) *((sChar *) binary));
885 	  break;
886 	case CDF_INT2:
887 	  sprintf (text, Cformat, (Int16) *((sChar *) binary));
888 	  break;
889 	case CDF_UINT2:
890 	  sprintf (text, Cformat, (uInt16) *((sChar *) binary));
891 	  break;
892 	case CDF_INT4:
893 	  sprintf (text, Cformat, (Int32) *((sChar *) binary));
894 	  break;
895 	case CDF_UINT4:
896 	  sprintf (text, Cformat, (uInt32) *((sChar *) binary));
897 	  break;
898 	case CDF_REAL4:
899 	case CDF_FLOAT:
900 	  sprintf (text, Cformat, (float) *((sChar *) binary));
901 	  break;
902 	case CDF_REAL8:
903 	case CDF_DOUBLE:
904 	  sprintf (text, Cformat, (double) *((sChar *) binary));
905 	  break;
906       }
907       break;
908     case CDF_UINT1:
909       switch (CdataType) {
910 	case CDF_BYTE:
911 	case CDF_INT1:
912 	  sprintf (text, Cformat, (sChar) *((uChar *) binary));
913 	  break;
914 	case CDF_UINT1:
915 	  sprintf (text, Cformat, (uChar) *((uChar *) binary));
916 	  break;
917 	case CDF_INT2:
918 	  sprintf (text, Cformat, (Int16) *((uChar *) binary));
919 	  break;
920 	case CDF_UINT2:
921 	  sprintf (text, Cformat, (uInt16) *((uChar *) binary));
922 	  break;
923 	case CDF_INT4:
924 	  sprintf (text, Cformat, (Int32) *((uChar *) binary));
925 	  break;
926 	case CDF_UINT4:
927 	  sprintf (text, Cformat, (uInt32) *((uChar *) binary));
928 	  break;
929 	case CDF_REAL4:
930 	case CDF_FLOAT:
931 	  sprintf (text, Cformat, (float) *((uChar *) binary));
932 	  break;
933 	case CDF_REAL8:
934 	case CDF_DOUBLE:
935 	  sprintf (text, Cformat, (double) *((uChar *) binary));
936 	  break;
937       }
938       break;
939     case CDF_INT2:
940       switch (CdataType) {
941 	case CDF_BYTE:
942 	case CDF_INT1:
943 	  sprintf (text, Cformat, (sChar) *((Int16 *) binary));
944 	  break;
945 	case CDF_UINT1:
946 	  sprintf (text, Cformat, (uChar) *((Int16 *) binary));
947 	  break;
948 	case CDF_INT2:
949 	  sprintf (text, Cformat, (Int16) *((Int16 *) binary));
950 	  break;
951 	case CDF_UINT2:
952 	  sprintf (text, Cformat, (uInt16) *((Int16 *) binary));
953 	  break;
954 	case CDF_INT4:
955 	  sprintf (text, Cformat, (Int32) *((Int16 *) binary));
956 	  break;
957 	case CDF_UINT4:
958 	  sprintf (text, Cformat, (uInt32) *((Int16 *) binary));
959 	  break;
960 	case CDF_REAL4:
961 	case CDF_FLOAT:
962 	  sprintf (text, Cformat, (float) *((Int16 *) binary));
963 	  break;
964 	case CDF_REAL8:
965 	case CDF_DOUBLE:
966 	  sprintf (text, Cformat, (double) *((Int16 *) binary));
967 	  break;
968       }
969       break;
970     case CDF_UINT2:
971       switch (CdataType) {
972 	case CDF_BYTE:
973 	case CDF_INT1:
974 	  sprintf (text, Cformat, (sChar) *((uInt16 *) binary));
975 	  break;
976 	case CDF_UINT1:
977 	  sprintf (text, Cformat, (uChar) *((uInt16 *) binary));
978 	  break;
979 	case CDF_INT2:
980 	  sprintf (text, Cformat, (Int16) *((uInt16 *) binary));
981 	  break;
982 	case CDF_UINT2:
983 	  sprintf (text, Cformat, (uInt16) *((uInt16 *) binary));
984 	  break;
985 	case CDF_INT4:
986 	  sprintf (text, Cformat, (Int32) *((uInt16 *) binary));
987 	  break;
988 	case CDF_UINT4:
989 	  sprintf (text, Cformat, (uInt32) *((uInt16 *) binary));
990 	  break;
991 	case CDF_REAL4:
992 	case CDF_FLOAT:
993 	  sprintf (text, Cformat, (float) *((uInt16 *) binary));
994 	  break;
995 	case CDF_REAL8:
996 	case CDF_DOUBLE:
997 	  sprintf (text, Cformat, (double) *((uInt16 *) binary));
998 	  break;
999       }
1000       break;
1001     case CDF_INT4:
1002       switch (CdataType) {
1003 	case CDF_BYTE:
1004 	case CDF_INT1:
1005 	  sprintf (text, Cformat, (sChar) *((Int32 *) binary));
1006 	  break;
1007 	case CDF_UINT1:
1008 	  sprintf (text, Cformat, (uChar) *((Int32 *) binary));
1009 	  break;
1010 	case CDF_INT2:
1011 	  sprintf (text, Cformat, (Int16) *((Int32 *) binary));
1012 	  break;
1013 	case CDF_UINT2:
1014 	  sprintf (text, Cformat, (uInt16) *((Int32 *) binary));
1015 	  break;
1016 	case CDF_INT4:
1017 	  sprintf (text, Cformat, (Int32) *((Int32 *) binary));
1018 	  break;
1019 	case CDF_UINT4:
1020 	  sprintf (text, Cformat, (uInt32) *((Int32 *) binary));
1021 	  break;
1022 	case CDF_REAL4:
1023 	case CDF_FLOAT:
1024 	  sprintf (text, Cformat, (float) *((Int32 *) binary));
1025 	  break;
1026 	case CDF_REAL8:
1027 	case CDF_DOUBLE:
1028 	  sprintf (text, Cformat, (double) *((Int32 *) binary));
1029 	  break;
1030       }
1031       break;
1032     case CDF_UINT4:
1033       switch (CdataType) {
1034 	case CDF_BYTE:
1035 	case CDF_INT1:
1036 	  sprintf (text, Cformat, (sChar) *((uInt32 *) binary));
1037 	  break;
1038 	case CDF_UINT1:
1039 	  sprintf (text, Cformat, (uChar) *((uInt32 *) binary));
1040 	  break;
1041 	case CDF_INT2:
1042 	  sprintf (text, Cformat, (Int16) *((uInt32 *) binary));
1043 	  break;
1044 	case CDF_UINT2:
1045 	  sprintf (text, Cformat, (uInt16) *((uInt32 *) binary));
1046 	  break;
1047 	case CDF_INT4:
1048 	  sprintf (text, Cformat, (Int32) *((uInt32 *) binary));
1049 	  break;
1050 	case CDF_UINT4:
1051 	  sprintf (text, Cformat, (uInt32) *((uInt32 *) binary));
1052 	  break;
1053 	case CDF_REAL4:
1054 	case CDF_FLOAT:
1055 	  sprintf (text, Cformat, (float) *((uInt32 *) binary));
1056 	  break;
1057 	case CDF_REAL8:
1058 	case CDF_DOUBLE:
1059 	  sprintf (text, Cformat, (double) *((uInt32 *) binary));
1060 	  break;
1061       }
1062       break;
1063     case CDF_REAL4:
1064     case CDF_FLOAT:
1065       switch (CdataType) {
1066 	case CDF_BYTE:
1067 	case CDF_INT1:
1068 	  sprintf (text, Cformat, (sChar) *((float *) binary));
1069 	  break;
1070 	case CDF_UINT1:
1071 	  sprintf (text, Cformat, (uChar) *((float *) binary));
1072 	  break;
1073 	case CDF_INT2:
1074 	  sprintf (text, Cformat, (Int16) *((float *) binary));
1075 	  break;
1076 	case CDF_UINT2:
1077 	  sprintf (text, Cformat, (uInt16) *((float *) binary));
1078 	  break;
1079 	case CDF_INT4:
1080 	  sprintf (text, Cformat, (Int32) *((float *) binary));
1081 	  break;
1082 	case CDF_UINT4:
1083 	  sprintf (text, Cformat, (uInt32) *((float *) binary));
1084 	  break;
1085 	case CDF_REAL4:
1086 	case CDF_FLOAT:
1087 	  if (NegativeZeroReal4((float *) binary))
1088 	    EncodeNegativeZero (text, Cformat);
1089 	  else
1090 	    sprintf (text, Cformat, (float) *((float *) binary));
1091 	  break;
1092 	case CDF_REAL8:
1093 	case CDF_DOUBLE:
1094 	  if (NegativeZeroReal4((float *) binary))
1095 	    EncodeNegativeZero (text, Cformat);
1096 	  else
1097 	    sprintf (text, Cformat, (double) *((float *) binary));
1098 	  break;
1099       }
1100       break;
1101     case CDF_REAL8:
1102     case CDF_DOUBLE:
1103       switch (CdataType) {
1104 	case CDF_BYTE:
1105 	case CDF_INT1:
1106 	  sprintf (text, Cformat, (sChar) *((double *) binary));
1107 	  break;
1108 	case CDF_UINT1:
1109 	  sprintf (text, Cformat, (uChar) *((double *) binary));
1110 	  break;
1111 	case CDF_INT2:
1112 	  sprintf (text, Cformat, (Int16) *((double *) binary));
1113 	  break;
1114 	case CDF_UINT2:
1115 	  sprintf (text, Cformat, (uInt16) *((double *) binary));
1116 	  break;
1117 	case CDF_INT4:
1118 	  sprintf (text, Cformat, (Int32) *((double *) binary));
1119 	  break;
1120 	case CDF_UINT4:
1121 	  sprintf (text, Cformat, (uInt32) *((double *) binary));
1122 	  break;
1123 	case CDF_REAL4:
1124 	case CDF_FLOAT:
1125 	  if (NegativeZeroReal8((double *) binary))
1126 	    EncodeNegativeZero (text, Cformat);
1127 	  else
1128 	    sprintf (text, Cformat, (float) *((double *) binary));
1129 	  break;
1130 	case CDF_REAL8:
1131 	case CDF_DOUBLE:
1132 	  if (NegativeZeroReal8((double *) binary))
1133 	    EncodeNegativeZero (text, Cformat);
1134 	  else
1135 	    sprintf (text, Cformat, (double) *((double *) binary));
1136 	  break;
1137       }
1138       break;
1139   }
1140 
1141 /* Change ...e+0.. (3 numbers after +/-) from win32 to ...e+.. (2 numbers
1142    after +/-) just like other systems */
1143 #if defined(win32)
1144   if (strchr(text, 'e') != NULL || strchr(text, 'E') != NULL) {
1145       int ilen = strlen(text);
1146       char *ie;
1147       char *to0;
1148       ie = strchr(text, 'e');
1149       if (ie == NULL) ie = strchr(text, 'E');
1150       to0 = strstr(ie, "+0");
1151       if (to0 == NULL) to0 = strstr(ie, "-0");
1152       if (to0 != NULL) {
1153         if (strlen(ie) == 5) {
1154           char *newText;
1155           int itrail;
1156           newText = (char *) malloc(ilen-1);
1157           itrail = strlen(ie);
1158           memmove(newText, text, ilen-itrail+2);
1159           memmove(newText+ilen-itrail+2, text+ilen-itrail+3,
1160                   itrail-3);
1161           newText[ilen-1] = NUL;
1162           strcpy(text, newText);
1163         }
1164       }
1165   }
1166 #endif
1167 
1168   return strlen(text);
1169 }
1170 
1171 /******************************************************************************
1172 * FtoCformat.
1173 * Returns TRUE if valid FORTRAN format specification.
1174 ******************************************************************************/
1175 
FtoCformat(dataType,Fformat,CdataType,Cformat)1176 static Logical FtoCformat (dataType, Fformat, CdataType, Cformat)
1177 long dataType;          /* Value's actual data type.  This should never be
1178 			   CDF_EPOCH. */
1179 char *Fformat;          /* FORTRAN format specification. */
1180 long *CdataType;        /* Data type implied by C format specification. */
1181 char *Cformat;          /* C format specification. */
1182 {
1183   int nFound;
1184   int w, m, d;
1185   /****************************************************************************
1186   * Change `Fformat' to point to first non-blank, non-digit, non-`('
1187   * character.  This will skip over a Fortran repeat count (eg. the `20' in
1188   * `20F8.4' or `20(F8.4)').
1189   ****************************************************************************/
1190   while (*Fformat != NUL && (*Fformat == '(' ||
1191 			     Spacing(*Fformat) ||
1192 			     Decimal(*Fformat))) Fformat++;
1193   if (*Fformat == NUL) return FALSE;
1194   /****************************************************************************
1195   * Encode C format specification.
1196   ****************************************************************************/
1197   switch (Fformat[0]) {
1198     /**************************************************************************
1199     * Integer/decimal.
1200     **************************************************************************/
1201     case 'I':
1202     case 'i':
1203       nFound = sscanf (&Fformat[1], "%d.%d", &w, &m);
1204       switch (nFound) {
1205 	case 0:
1206 	  return FALSE;
1207 	case 1:
1208 	  switch (dataType) {
1209 	    case CDF_BYTE:
1210 	    case CDF_INT1:
1211 	      sprintf (Cformat, "%%%dd", w);
1212 	      *CdataType = CDF_INT1;
1213 	      return TRUE;
1214 	    case CDF_UINT1:
1215 	      sprintf (Cformat, "%%%du", w);
1216 	      *CdataType = CDF_UINT1;
1217 	      return TRUE;
1218 	    case CDF_INT2:
1219 	      sprintf (Cformat, "%%%dd", w);
1220 	      *CdataType = CDF_INT2;
1221 	      return TRUE;
1222 	    case CDF_UINT2:
1223 	      sprintf (Cformat, "%%%du", w);
1224 	      *CdataType = CDF_UINT2;
1225 	      return TRUE;
1226 	    case CDF_INT4:
1227 	      sprintf (Cformat, "%%%d%sd", w, Int32FORMATmod);
1228 	      *CdataType = CDF_INT4;
1229 	      return TRUE;
1230 	    case CDF_UINT4:
1231 	      sprintf (Cformat, "%%%d%su", w, Int32FORMATmod);
1232 	      *CdataType = CDF_UINT4;
1233 	      return TRUE;
1234 	    case CDF_REAL4:
1235 	    case CDF_FLOAT:
1236 	    case CDF_REAL8:
1237 	    case CDF_DOUBLE:
1238 	      sprintf (Cformat, "%%%d%sd", w, Int32FORMATmod);
1239 	      *CdataType = CDF_INT4;
1240 	      return TRUE;
1241 	  }
1242 	  return FALSE;
1243 	case 2:
1244 	  switch (dataType) {
1245 	    case CDF_BYTE:
1246 	    case CDF_INT1:
1247 	      sprintf (Cformat, "%%%d.%dd", w, m);
1248 	      *CdataType = CDF_INT1;
1249 	      return TRUE;
1250 	    case CDF_UINT1:
1251 	      sprintf (Cformat, "%%%d.%du", w, m);
1252 	      *CdataType = CDF_UINT1;
1253 	      return TRUE;
1254 	    case CDF_INT2:
1255 	      sprintf (Cformat, "%%%d.%dd", w, m);
1256 	      *CdataType = CDF_INT2;
1257 	      return TRUE;
1258 	    case CDF_UINT2:
1259 	      sprintf (Cformat, "%%%d.%du", w, m);
1260 	      *CdataType = CDF_UINT2;
1261 	      return TRUE;
1262 	    case CDF_INT4:
1263 	      sprintf (Cformat, "%%%d.%d%sd", w, m, Int32FORMATmod);
1264 	      *CdataType = CDF_INT4;
1265 	      return TRUE;
1266 	    case CDF_UINT4:
1267 	      sprintf (Cformat, "%%%d.%d%su", w, m, Int32FORMATmod);
1268 	      *CdataType = CDF_UINT4;
1269 	      return TRUE;
1270 	    case CDF_REAL4:
1271 	    case CDF_FLOAT:
1272 	    case CDF_REAL8:
1273 	    case CDF_DOUBLE:
1274 	      sprintf (Cformat, "%%%d.%d%sd", w, m, Int32FORMATmod);
1275 	      *CdataType = CDF_INT4;
1276 	      return TRUE;
1277 	  }
1278 	  return FALSE;
1279       }
1280       return FALSE;
1281     /**************************************************************************
1282     * Integer/octal.
1283     **************************************************************************/
1284     case 'O':
1285     case 'o':
1286       nFound = sscanf (&Fformat[1], "%d.%d", &w, &m);
1287       switch (nFound) {
1288 	case 0:
1289 	  return FALSE;
1290 	case 1:
1291 	  switch (dataType) {
1292 	    case CDF_BYTE:
1293 	    case CDF_INT1:
1294 	      sprintf (Cformat, "%%%do", w);
1295 	      *CdataType = CDF_UINT1;
1296 	      return TRUE;
1297 	    case CDF_UINT1:
1298 	      sprintf (Cformat, "%%%do", w);
1299 	      *CdataType = CDF_UINT1;
1300 	      return TRUE;
1301 	    case CDF_INT2:
1302 	      sprintf (Cformat, "%%%do", w);
1303 	      *CdataType = CDF_UINT2;
1304 	      return TRUE;
1305 	    case CDF_UINT2:
1306 	      sprintf (Cformat, "%%%do", w);
1307 	      *CdataType = CDF_UINT2;
1308 	      return TRUE;
1309 	    case CDF_INT4:
1310 	      sprintf (Cformat, "%%%d%so", w, Int32FORMATmod);
1311 	      *CdataType = CDF_UINT4;
1312 	      return TRUE;
1313 	    case CDF_UINT4:
1314 	      sprintf (Cformat, "%%%d%so", w, Int32FORMATmod);
1315 	      *CdataType = CDF_UINT4;
1316 	      return TRUE;
1317 	    case CDF_REAL4:
1318 	    case CDF_FLOAT:
1319 	    case CDF_REAL8:
1320 	    case CDF_DOUBLE:
1321 	      sprintf (Cformat, "%%%d%so", w, Int32FORMATmod);
1322 	      *CdataType = CDF_UINT4;
1323 	      return TRUE;
1324 	  }
1325 	  return FALSE;
1326 	case 2:
1327 	  switch (dataType) {
1328 	    case CDF_BYTE:
1329 	    case CDF_INT1:
1330 	      sprintf (Cformat, "%%%d.%do", w, m);
1331 	      *CdataType = CDF_UINT1;
1332 	      return TRUE;
1333 	    case CDF_UINT1:
1334 	      sprintf (Cformat, "%%%d.%do", w, m);
1335 	      *CdataType = CDF_UINT1;
1336 	      return TRUE;
1337 	    case CDF_INT2:
1338 	      sprintf (Cformat, "%%%d.%do", w, m);
1339 	      *CdataType = CDF_UINT2;
1340 	      return TRUE;
1341 	    case CDF_UINT2:
1342 	      sprintf (Cformat, "%%%d.%do", w, m);
1343 	      *CdataType = CDF_UINT2;
1344 	      return TRUE;
1345 	    case CDF_INT4:
1346 	      sprintf (Cformat, "%%%d.%d%so", w, m, Int32FORMATmod);
1347 	      *CdataType = CDF_UINT4;
1348 	      return TRUE;
1349 	    case CDF_UINT4:
1350 	      sprintf (Cformat, "%%%d.%d%so", w, m, Int32FORMATmod);
1351 	      *CdataType = CDF_UINT4;
1352 	      return TRUE;
1353 	    case CDF_REAL4:
1354 	    case CDF_FLOAT:
1355 	    case CDF_REAL8:
1356 	    case CDF_DOUBLE:
1357 	      sprintf (Cformat, "%%%d.%d%so", w, m, Int32FORMATmod);
1358 	      *CdataType = CDF_UINT4;
1359 	      return TRUE;
1360 	  }
1361 	  return FALSE;
1362       }
1363       return FALSE;
1364     /**************************************************************************
1365     * Integer/hexadecimal.
1366     **************************************************************************/
1367     case 'Z':
1368     case 'z':
1369       nFound = sscanf (&Fformat[1], "%d.%d", &w, &m);
1370       switch (nFound) {
1371 	case 0:
1372 	  return FALSE;
1373 	case 1:
1374 	  switch (dataType) {
1375 	    case CDF_BYTE:
1376 	    case CDF_INT1:
1377 	      sprintf (Cformat, "%%%dX", w);
1378 	      *CdataType = CDF_UINT1;
1379 	      return TRUE;
1380 	    case CDF_UINT1:
1381 	      sprintf (Cformat, "%%%dX", w);
1382 	      *CdataType = CDF_UINT1;
1383 	      return TRUE;
1384 	    case CDF_INT2:
1385 	      sprintf (Cformat, "%%%dX", w);
1386 	      *CdataType = CDF_UINT2;
1387 	      return TRUE;
1388 	    case CDF_UINT2:
1389 	      sprintf (Cformat, "%%%dX", w);
1390 	      *CdataType = CDF_UINT2;
1391 	      return TRUE;
1392 	    case CDF_INT4:
1393 	      sprintf (Cformat, "%%%d%sX", w, Int32FORMATmod);
1394 	      *CdataType = CDF_UINT4;
1395 	      return TRUE;
1396 	    case CDF_UINT4:
1397 	      sprintf (Cformat, "%%%d%sX", w, Int32FORMATmod);
1398 	      *CdataType = CDF_UINT4;
1399 	      return TRUE;
1400 	    case CDF_REAL4:
1401 	    case CDF_FLOAT:
1402 	    case CDF_REAL8:
1403 	    case CDF_DOUBLE:
1404 	      sprintf (Cformat, "%%%d%sX", w, Int32FORMATmod);
1405 	      *CdataType = CDF_UINT4;
1406 	      return TRUE;
1407 	  }
1408 	  return FALSE;
1409 	case 2:
1410 	  switch (dataType) {
1411 	    case CDF_BYTE:
1412 	    case CDF_INT1:
1413 	      sprintf (Cformat, "%%%d.%dX", w, m);
1414 	      *CdataType = CDF_UINT1;
1415 	      return TRUE;
1416 	    case CDF_UINT1:
1417 	      sprintf (Cformat, "%%%d.%dX", w, m);
1418 	      *CdataType = CDF_UINT1;
1419 	      return TRUE;
1420 	    case CDF_INT2:
1421 	      sprintf (Cformat, "%%%d.%dX", w, m);
1422 	      *CdataType = CDF_UINT2;
1423 	      return TRUE;
1424 	    case CDF_UINT2:
1425 	      sprintf (Cformat, "%%%d.%dX", w, m);
1426 	      *CdataType = CDF_UINT2;
1427 	      return TRUE;
1428 	    case CDF_INT4:
1429 	      sprintf (Cformat, "%%%d.%d%sX", w, m, Int32FORMATmod);
1430 	      *CdataType = CDF_UINT4;
1431 	      return TRUE;
1432 	    case CDF_UINT4:
1433 	      sprintf (Cformat, "%%%d.%d%sX", w, m, Int32FORMATmod);
1434 	      *CdataType = CDF_UINT4;
1435 	      return TRUE;
1436 	    case CDF_REAL4:
1437 	    case CDF_FLOAT:
1438 	    case CDF_REAL8:
1439 	    case CDF_DOUBLE:
1440 	      sprintf (Cformat, "%%%d.%d%sX", w, m, Int32FORMATmod);
1441 	      *CdataType = CDF_UINT4;
1442 	      return TRUE;
1443 	  }
1444 	  return FALSE;
1445       }
1446       return FALSE;
1447     /**************************************************************************
1448     * Floating-point/non-scientific notation (which is called...
1449     **************************************************************************/
1450     case 'F':
1451     case 'f':
1452       nFound = sscanf (&Fformat[1], "%d.%d", &w, &d);
1453       switch (nFound) {
1454 	case 2:
1455 	  sprintf (Cformat, "%%%d.%df", w, d);
1456 	  *CdataType = CDF_DOUBLE;
1457 	  return TRUE;
1458       }
1459       return FALSE;
1460     /**************************************************************************
1461     * Floating-point/scientific notation.
1462     **************************************************************************/
1463     case 'E':
1464     case 'e':
1465     case 'D':
1466     case 'd':
1467       nFound = sscanf (&Fformat[1], "%d.%d", &w, &d);
1468       switch (nFound) {
1469 	case 2:
1470 	  sprintf (Cformat, "%%%d.%de", w, d);
1471 	  *CdataType = CDF_DOUBLE;
1472 	  return TRUE;
1473       }
1474       return FALSE;
1475     /**************************************************************************
1476     * Floating-point/notation depends on value.
1477     **************************************************************************/
1478     case 'G':
1479     case 'g':
1480       nFound = sscanf (&Fformat[1], "%d.%d", &w, &d);
1481       switch (nFound) {
1482 	case 2:
1483 	  sprintf (Cformat, "%%%d.%dg", w, d);
1484 	  *CdataType = CDF_DOUBLE;
1485 	  return TRUE;
1486       }
1487       return FALSE;
1488     /**************************************************************************
1489     * Character.
1490     **************************************************************************/
1491     case 'A':
1492     case 'a':
1493       nFound = sscanf (&Fformat[1], "%d", &w);
1494       switch (nFound) {
1495 	case 1:
1496 	  sprintf (Cformat, "%%%d.%ds", w, w);
1497 	  *CdataType = CDF_CHAR;
1498 	  return TRUE;
1499       }
1500       return FALSE;
1501   }
1502   return FALSE;                         /* Unknown FORTRAN format character. */
1503 }
1504 
1505 /******************************************************************************
1506 * GetCdataType.
1507 *   Given a C format specification, returns the corresponding C data type.
1508 ******************************************************************************/
1509 
GetCdataType(Cformat,CdataType)1510 static long GetCdataType (Cformat, CdataType)
1511 char *Cformat;          /* C format specification. */
1512 long *CdataType;        /* Corresponding C data type. */
1513 {
1514   char *ptrB;           /* Beginning of specification. */
1515   char *ptrE;           /* End of specification. */
1516   /****************************************************************************
1517   * Find beginning of specification.
1518   ****************************************************************************/
1519   ptrB = Cformat;
1520   while (*ptrB != NUL && Spacing(*ptrB)) ptrB++;
1521   if (*ptrB != '%') return FALSE;
1522   /****************************************************************************
1523   * Find end of specification.
1524   ****************************************************************************/
1525   ptrE = Cformat + strlen(Cformat) - 1;
1526   while (ptrE != ptrB && Spacing(*ptrE)) ptrE--;
1527   if (ptrE == ptrB) return FALSE;
1528   /****************************************************************************
1529   * Choose a data type based on the conversion character and possible modifier.
1530   ****************************************************************************/
1531   switch (*ptrE) {
1532     case 'd':
1533     case 'i':
1534       switch (*(ptrE-1)) {
1535 	case 'l':
1536 	  *CdataType = CDF_INT4;
1537 	  break;
1538 	case 'h':
1539 	  *CdataType = CDF_INT2;
1540 	  break;
1541 	default:
1542 #if defined(dos)
1543 	  *CdataType = CDF_INT2;
1544 #else
1545 	  *CdataType = CDF_INT4;
1546 #endif
1547 	  break;
1548       }
1549       break;
1550     case 'x':
1551     case 'X':
1552     case 'o':
1553     case 'u':
1554       switch (*(ptrE-1)) {
1555 	case 'l':
1556 	  *CdataType = CDF_UINT4;
1557 	  break;
1558 	case 'h':
1559 	  *CdataType = CDF_UINT2;
1560 	  break;
1561 	default:
1562 #if defined(dos)
1563 	  *CdataType = CDF_UINT2;
1564 #else
1565 	  *CdataType = CDF_UINT4;
1566 #endif
1567 	  break;
1568       }
1569       break;
1570     case 'c':
1571     case 's':
1572       *CdataType = CDF_CHAR;
1573       break;
1574     case 'f':
1575     case 'e':
1576     case 'E':
1577     case 'g':
1578     case 'G':
1579       *CdataType = CDF_DOUBLE;
1580       break;
1581     default:
1582       return FALSE;     /* Unknown C format description. */
1583   }
1584   return TRUE;
1585 }
1586 
1587 /******************************************************************************
1588 * EncodeDimensionality.  Returns width of encoded dimensionality
1589 ******************************************************************************/
1590 
EncodeDimensionality(string,numDims,dimSizes)1591 int EncodeDimensionality (string, numDims, dimSizes)
1592 char *string;
1593 long numDims;
1594 long *dimSizes;
1595 {
1596   int dimN;
1597   sprintf (string, "%ld:[", numDims);
1598   for (dimN = 0; dimN < numDims; dimN++)
1599      sprintf (&(string[strlen(string)]), "%s%ld", (dimN > 0 ? "," : ""),
1600 	      dimSizes[dimN]);
1601   strcatX (string, "]", 0);
1602   return strlen(string);
1603 }
1604 
1605 /******************************************************************************
1606 * EncodeVariances.  Returns width of encoded variances.
1607 ******************************************************************************/
1608 
EncodeVariances(string,recVary,numDims,dimVarys)1609 int EncodeVariances (string, recVary, numDims, dimVarys)
1610 char *string;
1611 long recVary;
1612 long numDims;
1613 long *dimVarys;
1614 {
1615   int dimN;
1616   strcpyX (string, TFvarianceToken(recVary), 0);
1617   strcatX (string, "/", 0);
1618   for (dimN = 0; dimN < numDims; dimN++)
1619      strcatX (string, TFvarianceToken(dimVarys[dimN]), 0);
1620   return strlen(string);
1621 }
1622 
1623 /******************************************************************************
1624 * EncodeRecordIndices.
1625 * Uses `*' for record/dimension variances of NOVARY.  Returns width of
1626 * record/indices.
1627 ******************************************************************************/
1628 
EncodeRecordIndices(string,recNum,recVary,numDims,indices,dimVarys)1629 int EncodeRecordIndices (string, recNum, recVary, numDims, indices, dimVarys)
1630 char *string;
1631 long recNum;
1632 long recVary;
1633 long numDims;
1634 long indices[];
1635 long dimVarys[];
1636 {
1637   int dimN;
1638   if (recVary)
1639     sprintf (string, "%ld", recNum + 1);
1640   else
1641     strcpyX (string, "*", 0);
1642   strcatX (string, ":[", 0);
1643   for (dimN = 0; dimN < numDims; dimN++) {
1644      if (dimN != 0) strcatX (string, ",", 0);
1645      if (dimVarys[dimN])
1646        sprintf (&string[strlen(string)], "%ld", indices[dimN] + 1);
1647      else
1648        strcatX (string, "*", 0);
1649   }
1650   strcatX (string, "]", 0);
1651   return strlen(string);
1652 }
1653 
1654 /******************************************************************************
1655 * EncodeRecordIndicesVARY.  Force record/dimension variances to VARY.
1656 ******************************************************************************/
1657 
EncodeRecordIndicesVARY(string,recNum,numDims,indices)1658 int EncodeRecordIndicesVARY (string, recNum, numDims, indices)
1659 char *string;
1660 long recNum;
1661 long numDims;
1662 long indices[];
1663 {
1664   static long recVary = VARY;
1665   static long dimVarys[CDF_MAX_DIMS] = { VARY, VARY, VARY, VARY, VARY,
1666 					 VARY, VARY, VARY, VARY, VARY };
1667   EncodeRecordIndices (string, recNum, recVary, numDims, indices, dimVarys);
1668   return strlen(string);
1669 }
1670 
1671 /*****************************************************************************
1672 * OnlineHelpFP.
1673 *
1674 *  UNIX: The full pathname of the executable is not passed in via `argv[0]'.
1675 *  The command which was entered on the command line is passed in (aliases
1676 *  are, however, evaluated).
1677 *
1678 ******************************************************************************/
1679 
OnlineHelpFP(filename,execpath)1680 FILE *OnlineHelpFP (filename, execpath)
1681 char *filename;                         /* Name of help file. */
1682 char *execpath;                         /* Pathname of executable (argv[0]). */
1683 {
1684   FILE *fp;
1685   char pathname[DU_MAX_PATH_LEN+1];
1686 #if !defined(mac)
1687   char execname[DU_MAX_NAME_LEN+1];
1688   char *envPtr;
1689 #endif
1690 #if defined(mac)
1691   execpath;                     /* Quites the MPW C compiler. */
1692 #endif
1693   /****************************************************************************
1694   * Try to use logical name (VMS) or environment variable (UNIX/POSIXshell,
1695   * DOS, & Windows).
1696   ****************************************************************************/
1697 #if defined(vms)
1698   strcpyX (pathname, "CDF$HELP:", DU_MAX_PATH_LEN);
1699   AppendToDir (pathname, filename);
1700   fp = fopen (pathname, "r");
1701   if (fp != NULL) return fp;
1702 #endif
1703 #if (defined(unix) && !defined(__MINGW32__)) || defined(dos) || \
1704      defined(posixSHELL) || defined(win32)
1705   envPtr = getenv ("CDF_HELP");
1706   if (envPtr != NULL) {
1707     strcpyX (pathname, envPtr, DU_MAX_PATH_LEN);
1708     AppendToDir (pathname, filename);
1709 #if defined(__CYGWIN__) || defined(__MINGW32__)
1710     fp = fopen (pathname, "rt");
1711 #else
1712     fp = fopen (pathname, "r");
1713 #endif
1714     if (fp != NULL) return fp;
1715   }
1716 #endif
1717   /***************************************************************************
1718   * If not on a Macintosh...
1719   * Try relative paths from location of executable in the following order...
1720   *  1. From standard executable/binary directory.
1721   *  2. From source directory.
1722   *  3. Same directory as that containing the executable.
1723   ***************************************************************************/
1724 #if !defined(mac)
1725   if (execpath != NULL) {
1726     if (execpath[0] != NUL) {
1727       ParsePath (execpath, pathname, execname);
1728 #if defined(vms)
1729       pathname[strlen(pathname)-1] = NUL;   /* Wipes out trailing `]'. */
1730       strcatX (pathname, "-.HELP]", DU_MAX_PATH_LEN);
1731 #endif
1732 #if (defined(unix) && !defined(__CYGWIN__) && !defined(__MINGW32__)) || \
1733      defined(posixSHELL)
1734       AppendToDir (pathname, "../lib/cdf/help");
1735 #endif
1736 #if defined(dos) || defined(win32) || defined(__CYGWIN__) || \
1737     defined(__MINGW32__)
1738       AppendToDir (pathname, "..\\help");
1739 #endif
1740       AppendToDir (pathname, filename);
1741 #if defined(__CYGWIN__) || defined(__MINGW32__)
1742       fp = fopen (pathname, "rt");
1743 #else
1744       fp = fopen (pathname, "r");
1745 #endif
1746       if (fp != NULL) return fp;
1747       ParsePath (execpath, pathname, execname);
1748 #if defined(vms)
1749       pathname[strlen(pathname)-1] = NUL;   /* Wipes out trailing `]'. */
1750       strcatX (pathname, "-.-.HELP]", DU_MAX_PATH_LEN);
1751 #endif
1752 #if (defined(unix) && !defined(__CYGWIN__) && !defined(__MINGW32__)) || \
1753      defined(posixSHELL)
1754       AppendToDir (pathname, "../help");
1755 #endif
1756 #if defined(dos) || defined(win32) || defined(__CYGWIN__) || \
1757     defined(__MINGW32__)
1758       AppendToDir (pathname, "..\\..\\help");
1759 #endif
1760       AppendToDir (pathname, filename);
1761 #if defined(__CYGWIN__) || defined(__MINGW32__)
1762       fp = fopen (pathname, "rt");
1763 #else
1764       fp = fopen (pathname, "r");
1765 #endif
1766       if (fp != NULL) return fp;
1767       ParsePath (execpath, pathname, execname);
1768       AppendToDir (pathname, filename);
1769       fp = fopen (pathname, "r");
1770       if (fp != NULL) return fp;
1771     }
1772   }
1773 #endif
1774   /***************************************************************************
1775   * If on a Macintosh...try relative (partial) paths to the `help' file.
1776   ***************************************************************************/
1777 #if defined(mac)
1778   strcpyX (pathname, "::help", DU_MAX_PATH_LEN);
1779   AppendToDir (pathname, filename);
1780   fp = fopen (pathname, "r");
1781   if (fp != NULL) return fp;
1782   strcpyX (pathname, ":::help", DU_MAX_PATH_LEN);
1783   AppendToDir (pathname, filename);
1784   fp = fopen (pathname, "r");
1785   if (fp != NULL) return fp;
1786 #endif
1787   /***************************************************************************
1788   * If on a UNIX/POSIXshell or DOS/Windows system, assume that the `bin'
1789   * directory has been added to the `path' and try a relative path from each
1790   * `path' entry.
1791   ***************************************************************************/
1792 #if (defined(unix) && !defined(__MINGW32__)) || defined(posixSHELL) || \
1793      defined(dos) || defined(win32)
1794 #if (defined(unix) && !defined(__MINGW32__)) || defined(posixSHELL)
1795 #define SEP_CHAR ':'
1796 #else
1797 #define SEP_CHAR ';'
1798 #endif
1799   envPtr = getenv ("PATH");
1800   if (envPtr != NULL) {
1801     char *path = (char *) cdf_AllocateMemory (strlen(envPtr) + 1, FatalError);
1802     char *p1 = path;
1803     strcpyX (path, envPtr, 0);
1804     for (;;) {
1805        char *sepPtr = strchr (p1, SEP_CHAR);
1806        if (sepPtr != NULL) *sepPtr = NUL;
1807        strcpyX (pathname, p1, DU_MAX_PATH_LEN);
1808 #if (defined(unix) && !defined(__CYGWIN__) && !defined(__MINGW32__)) || \
1809      defined(posixSHELL)
1810        AppendToDir (pathname, "../lib/cdf/help");
1811 #else
1812        AppendToDir (pathname, "..\\help");
1813 #endif
1814        AppendToDir (pathname, filename);
1815 #if defined(__CYGWIN__) || defined(__MINGW32__)
1816        fp = fopen (pathname, "rt");
1817 #else
1818        fp = fopen (pathname, "r");
1819 #endif
1820        if (fp != NULL) {
1821 	 cdf_FreeMemory (path, FatalError);
1822 	 return fp;
1823        }
1824        if (sepPtr == NULL) break;
1825        p1 = sepPtr + 1;
1826     }
1827     cdf_FreeMemory (path, FatalError);
1828   }
1829 #endif
1830   /***************************************************************************
1831   * Try pathes from the current directory.
1832   ***************************************************************************/
1833 #if defined(vms)
1834   strcpyX (pathname, "[-.HELP]", DU_MAX_PATH_LEN);
1835 #endif
1836 #if (defined(unix) && !defined(__CYGWIN__) && !defined(__MINGW32__)) || \
1837      defined(posixSHELL)
1838   strcpyX (pathname, "../help", DU_MAX_PATH_LEN);
1839 #endif
1840 #if defined(dos) || defined(win32) || defined(__CYGWIN__) || \
1841     defined(__MINGW32__)
1842   strcpyX (pathname, "..\\help", DU_MAX_PATH_LEN);
1843 #endif
1844   AppendToDir (pathname, filename);
1845 #if defined(__CYGWIN__) || defined(__MINGW32__)
1846   fp = fopen (pathname, "rt");
1847 #else
1848   fp = fopen (pathname, "r");
1849 #endif
1850   if (fp != NULL) return fp;
1851 #if defined(vms)
1852   strcpyX (pathname, "[-.-.HELP]", DU_MAX_PATH_LEN);
1853 #endif
1854 #if (defined(unix) && !defined(__CYGWIN__) && !defined(__MINGW32__)) || \
1855      defined(posixSHELL)
1856   strcpyX (pathname, "../../help", DU_MAX_PATH_LEN);
1857 #endif
1858 #if defined(dos) || defined(win32) || defined(__CYGWIN__) || \
1859     defined(__MINGW32__)
1860   strcpyX (pathname, "..\\..\\help", DU_MAX_PATH_LEN);
1861 #endif
1862   AppendToDir (pathname, filename);
1863 #if defined(__CYGWIN__) || defined(__MINGW32__)
1864   fp = fopen (pathname, "rt");
1865 #else
1866   fp = fopen (pathname, "r");
1867 #endif
1868   if (fp != NULL) return fp;
1869 #if defined(vms)
1870   strcpyX (pathname, "[-.-.-.HELP]", DU_MAX_PATH_LEN);
1871 #endif
1872 #if (defined(unix) && !defined(__CYGWIN__) && !defined(__MINGW32__)) || \
1873      defined(posixSHELL)
1874   strcpyX (pathname, "../../../help", DU_MAX_PATH_LEN);
1875 #endif
1876 #if defined(dos) || defined(win32) || defined(__CYGWIN__) || \
1877     defined(__MINGW32__)
1878   strcpyX (pathname, "..\\..\\..\\help", DU_MAX_PATH_LEN);
1879 #endif
1880   AppendToDir (pathname, filename);
1881 #if defined(__CYGWIN__) || defined(__MINGW32__)
1882   fp = fopen (pathname, "rt");
1883 #else
1884   fp = fopen (pathname, "r");
1885 #endif
1886   if (fp != NULL) return fp;
1887 #if defined(win32) || defined(__CYGWIN__) || defined(__MINGW32__)
1888   strcpyX (pathname, "help", DU_MAX_PATH_LEN);
1889 #endif
1890   AppendToDir (pathname, filename);
1891 #if defined(__CYGWIN__) || defined(__MINGW32__)
1892   fp = fopen (pathname, "rt");
1893 #else
1894   fp = fopen (pathname, "r");
1895 #endif
1896   if (fp != NULL) return fp;
1897   /***************************************************************************
1898   * Try current directory.
1899   ***************************************************************************/
1900 #if defined(__CYGWIN__) || defined(__MINGW32__)
1901   fp = fopen (pathname, "rt");
1902 #else
1903   fp = fopen (pathname, "r");
1904 #endif
1905   if (fp != NULL) return fp;
1906   /***************************************************************************
1907   * Give up.
1908   ***************************************************************************/
1909   return NULL;
1910 }
1911 
1912 /*****************************************************************************
1913 * PageOLH.
1914 *****************************************************************************/
1915 
PageOLH(olhFile,argv0)1916 void PageOLH (olhFile, argv0)
1917 char *olhFile;
1918 char *argv0;
1919 {
1920   FILE *fp;
1921   char line[MAX_SCREENLINE_LEN+1+1];
1922   int nestLevel = 0;                    /* Depth into `#ifos's. */
1923   int osMask = 0;                       /* When 0, display line.  Note that bit
1924 					   0 is not used (eg. nesting depth of
1925 					   1 uses bit 1, etc.). */
1926 #if defined(vms)
1927   static char thisOS[] = "vms";
1928 #endif
1929 #if (defined(unix) && !defined(__CYGWIN__) && !defined(__MINGW32__)) || \
1930      defined(posixSHELL)
1931   static char thisOS[] = "unix";
1932 #endif
1933 #if defined(dos) || defined(__CYGWIN__)  || defined(__MINGW32__) || \
1934     (defined(win32) && defined(ALONE))
1935   static char thisOS[] = "dos";
1936 #endif
1937 #if defined(mac)
1938   static char thisOS[] = "mac";
1939 #endif
1940 #if defined(win32) && !defined(ALONE)
1941   static char thisOS[] = "win";
1942 #endif
1943   static char *openErrorMsg = {
1944     "Error opening online help file - contact CDFsupport.\n"
1945   };
1946   static char *syntaxErrorMsg = {
1947     "Syntax error in online help file - contact CDFsupport.\n"
1948   };
1949   /****************************************************************************
1950   * Open online help file.
1951   ****************************************************************************/
1952   fp = OnlineHelpFP (olhFile, argv0);
1953   if (fp == NULL) {
1954     WriteOut (stdout, openErrorMsg);
1955     return;
1956   }
1957   /****************************************************************************
1958   * Read online help file - passing appropriate lines through for display.
1959   ****************************************************************************/
1960   while (fgets(line,MAX_SCREENLINE_LEN+1+1,fp) != NULL) {
1961     /**************************************************************************
1962     * Check if an operating system directive.  If not, display the line if
1963     * all of the bits in the operating system mask are clear.
1964     **************************************************************************/
1965     if (line[0] == '#') {
1966       line[strlen(line)-1] = NUL;
1967       /************************************************************************
1968       * Check for a `#ifos' directive.  If this operating system is not
1969       * specified, then set the bit in the operating system mask for this
1970       * nesting level.
1971       ************************************************************************/
1972       if (!strncmp(line,"#ifos",5)) {
1973 	nestLevel++;
1974 	if (strstr(line,thisOS) == NULL) SETBIT (osMask, nestLevel);
1975 	continue;
1976       }
1977       /************************************************************************
1978       * Check for a `#else' directive.  Simply flip the bit in the operating
1979       * system mask for this nesting level.
1980       ************************************************************************/
1981       if (!strcmp(line,"#else")) {
1982 	if (nestLevel < 1) {
1983 	  WriteOut (stdout, syntaxErrorMsg);
1984 	  break;
1985 	}
1986 	FLPBIT (osMask, nestLevel);
1987 	continue;
1988       }
1989       /************************************************************************
1990       * Check for a `#endos' directive.  Clear the bit in the operating system
1991       * mask for this nesting level and decrement the nesting level.
1992       ************************************************************************/
1993       if (!strcmp(line,"#endos")) {
1994 	if (nestLevel < 1) {
1995 	  WriteOut (stdout, syntaxErrorMsg);
1996 	  break;
1997 	}
1998 	CLRBIT (osMask, nestLevel);
1999 	nestLevel--;
2000 	continue;
2001       }
2002       /************************************************************************
2003       * An unknown directive has been encountered - assume it to be a comment.
2004       ************************************************************************/
2005       continue;
2006     }
2007     else {
2008       if (osMask == 0) WriteOut (stdout, line);
2009     }
2010   }
2011   if (nestLevel != 0) WriteOut (stdout, syntaxErrorMsg);
2012   fclose (fp);
2013   return;
2014 }
2015 
2016 /******************************************************************************
2017 * OutputWithMargin.
2018 *   Outputs a long text string to multiple lines of a file (or stdout)
2019 * breaking the lines at blanks if possible.
2020 ******************************************************************************/
2021 
OutputWithMargin(fp,text,maxLen,marginLen)2022 void OutputWithMargin (fp, text, maxLen, marginLen)
2023 FILE *fp;
2024 char *text;
2025 int maxLen;     /* Maximum length of line (including margin). */
2026 int marginLen;  /* Length of margin preceeding text on each line. */
2027 {
2028   char *ptr = text, *ptrT;
2029   int maxLenT = maxLen - marginLen;     /* Maximum number of characters per
2030 					   line (excluding the margin). */
2031   for (;;) {
2032      /*************************************************************************
2033      * If the remaining characters will fit on a line, print them and return.
2034      * This also covers the case where the entire text will fit on one line.
2035      *************************************************************************/
2036      if (strlen(ptr) <= (size_t) maxLenT) {
2037        if (marginLen > 0) Ncharacters (fp, marginLen, (int) ' ');
2038        WriteOut (fp, ptr);
2039        WriteOut (fp, "\n");
2040        return;
2041      }
2042      /*************************************************************************
2043      * Otherwise, find a blank character at which to break the characters.  The
2044      * blank is not printed on either line.
2045      *************************************************************************/
2046      for (ptrT = ptr + maxLenT; ptrT != ptr; ptrT--) {
2047 	if (*ptrT == ' ') {
2048 	  char *string = NULedString (ptr, (int) (ptrT - ptr));
2049 	  if (marginLen > 0) Ncharacters (fp, marginLen, (int) ' ');
2050 	  WriteOut (fp, string);
2051 	  WriteOut (fp, "\n");
2052 	  ptr = ptrT + 1;
2053 	  cdf_FreeMemory (string, FatalError);
2054 	  break;
2055 	}
2056      }
2057      /*************************************************************************
2058      * If a blank could not be found, break the characters at the end of the
2059      * maximum number per line.
2060      *************************************************************************/
2061      if (ptrT == ptr) {
2062        char *string = NULedString (ptr, maxLenT);
2063        if (marginLen > 0) Ncharacters (fp, marginLen, (int) ' ');
2064        WriteOut (fp, string);
2065        WriteOut (fp, "\n");
2066        ptr += maxLenT;
2067        cdf_FreeMemory (string, FatalError);
2068      }
2069   }
2070 }
2071 
2072 /******************************************************************************
2073 * InitPctLog.
2074 ******************************************************************************/
2075 
InitPctLog(lastPct,pctOn)2076 void InitPctLog (lastPct, pctOn)
2077 int *lastPct;
2078 Logical *pctOn;
2079 {
2080   WriteOut (stdout, "..0%");
2081   *lastPct = 0;
2082   *pctOn = TRUE;
2083   return;
2084 }
2085 
2086 /******************************************************************************
2087 * UpdatePctLog.
2088 ******************************************************************************/
2089 
UpdatePctLog(pct,lastPct)2090 void UpdatePctLog (pct, lastPct)
2091 int pct;
2092 int *lastPct;
2093 {
2094   if (pct != *lastPct) {
2095     char string[10+1];
2096     sprintf (string, "\b\b\b\b%s%d%%",
2097 	     (pct < 10 ? ".." : (pct < 100 ? "." : "")), pct);
2098     WriteOut (stdout, string);
2099     *lastPct = pct;
2100   }
2101   return;
2102 }
2103 
2104 /******************************************************************************
2105 * RefreshPctLog.
2106 ******************************************************************************/
2107 
RefreshPctLog(lastPct)2108 void RefreshPctLog (lastPct)
2109 int lastPct;
2110 {
2111   char string[6+1];
2112   sprintf (string, "%s%d%%",
2113 	   (lastPct < 10 ? ".." : (lastPct < 100 ? "." : "")), lastPct);
2114   WriteOut (stdout, string);
2115   return;
2116 }
2117 
2118 /******************************************************************************
2119 * CleanupPctLog.
2120 *   100% is output in case there were no values (in which case 0% would be
2121 * currently displayed).
2122 ******************************************************************************/
2123 
CleanupPctLog(pctOn)2124 void CleanupPctLog (pctOn)
2125 Logical *pctOn;
2126 {
2127   WriteOut (stdout, "\b\b\b\b100%\n");
2128   *pctOn = FALSE;
2129   return;
2130 }
2131 
2132 /******************************************************************************
2133 * Ncharacters.
2134 *   Outputs a specified number of a selected character to a file pointer.
2135 ******************************************************************************/
2136 
Ncharacters(fp,nChars,chr)2137 void Ncharacters (fp, nChars, chr)
2138 FILE *fp;
2139 int nChars;
2140 int chr;
2141 {
2142   int i; char string[1+1];
2143   string[0] = (char) chr;
2144   string[1] = NUL;
2145   for (i = 0; i < nChars; i++) WriteOut (fp, string);
2146   return;
2147 }
2148 
2149 /******************************************************************************
2150 * CatNcharacters.
2151 *   Concatenates some number of a specified character to a string.
2152 ******************************************************************************/
2153 
CatNcharacters(string,nChars,chr)2154 void CatNcharacters (string, nChars, chr)
2155 char *string;
2156 int nChars;
2157 int chr;
2158 {
2159   int i;
2160   for (i = 0; i < nChars; i++) catchrX (string, chr, 0);
2161   return;
2162 }
2163 
2164 /******************************************************************************
2165 * CpyNcharacters.
2166 *   Copies some number of a specified character to a string.
2167 ******************************************************************************/
2168 
CpyNcharacters(string,nChars,chr)2169 void CpyNcharacters (string, nChars, chr)
2170 char *string;
2171 int nChars;
2172 int chr;
2173 {
2174   int i;
2175   for (i = 0; i < nChars; i++) string[i] = (char) chr;
2176   string[nChars] = NUL;
2177   return;
2178 }
2179 
2180 /******************************************************************************
2181 * TFqualifier.
2182 ******************************************************************************/
2183 
TFqualifier(qop,variable,Tx,Fx,defaultTF,conflictText)2184 Logical TFqualifier (qop, variable, Tx, Fx, defaultTF, conflictText)
2185 QOP *qop;
2186 Logical *variable;
2187 int Tx;
2188 int Fx;
2189 Logical defaultTF;
2190 char *conflictText;
2191 {
2192   int count = 0;
2193   if (qop->qualEntered[Tx]) count++;
2194   if (qop->qualEntered[Fx]) count++;
2195   switch (count) {
2196     case 0:
2197       *variable = defaultTF;
2198       return TRUE;
2199     case 1:
2200       *variable = (qop->qualEntered[Tx] ? TRUE : FALSE);
2201       return TRUE;
2202     default: {
2203       char tempS[MAX_MESSAGE_TEXT_LEN+1];
2204       sprintf (tempS, "Conflicting qualifiers (%s & no%s).",
2205 	       conflictText, conflictText);
2206       DisplayError (tempS);
2207       return FALSE;
2208     }
2209   }
2210 }
2211 
2212 /******************************************************************************
2213 * S2qualifierLong.
2214 ******************************************************************************/
2215 
S2qualifierLong(qop,variable,S1x,S1,S2x,S2,defaultS,conflictText)2216 Logical S2qualifierLong (qop, variable, S1x, S1, S2x, S2, defaultS,
2217 			 conflictText)
2218 QOP *qop;
2219 long *variable;
2220 int S1x;
2221 long S1;
2222 int S2x;
2223 long S2;
2224 long defaultS;
2225 char *conflictText;
2226 {
2227   int count = 0;
2228   if (qop->qualEntered[S1x]) count++;
2229   if (qop->qualEntered[S2x]) count++;
2230   switch (count) {
2231     case 0:
2232       *variable = defaultS;
2233       return TRUE;
2234     case 1:
2235       *variable = (qop->qualEntered[S1x] ? S1 : S2);
2236       return TRUE;
2237     default: {
2238       char tempS[MAX_MESSAGE_TEXT_LEN+1];
2239       sprintf (tempS, "Conflicting qualifiers (%s).", conflictText);
2240       DisplayError (tempS);
2241       return FALSE;
2242     }
2243   }
2244 }
2245 
2246 /******************************************************************************
2247 * S3qualifierLong.
2248 ******************************************************************************/
2249 
S3qualifierLong(qop,variable,S1x,S1,S2x,S2,S3x,S3,defaultS,conflictText)2250 Logical S3qualifierLong (qop, variable, S1x, S1, S2x, S2, S3x, S3, defaultS,
2251 			 conflictText)
2252 QOP *qop;
2253 long *variable;
2254 int S1x;
2255 long S1;
2256 int S2x;
2257 long S2;
2258 int S3x;
2259 long S3;
2260 long defaultS;
2261 char *conflictText;
2262 {
2263   int count = 0;
2264   if (qop->qualEntered[S1x]) count++;
2265   if (qop->qualEntered[S2x]) count++;
2266   if (qop->qualEntered[S3x]) count++;
2267   switch (count) {
2268     case 0:
2269       *variable = defaultS;
2270       return TRUE;
2271     case 1:
2272       *variable = BOO(qop->qualEntered[S1x],S1,
2273 		      BOO(qop->qualEntered[S2x],S2,S3));
2274       return TRUE;
2275     default: {
2276       char tempS[MAX_MESSAGE_TEXT_LEN+1];
2277       sprintf (tempS, "Conflicting qualifiers (%s).", conflictText);
2278       DisplayError (tempS);
2279       return FALSE;
2280     }
2281   }
2282 }
2283 
2284 /******************************************************************************
2285 * BlankPadRight.
2286 *   Concatenate blanks to the right end of a string.
2287 ******************************************************************************/
2288 
BlankPadRight(string,count)2289 void BlankPadRight (string, count)
2290 char *string;
2291 int count;
2292 {
2293   int i;
2294   for (i = 0; i < count; i++) catchrX (string, (int) ' ', 0);
2295   return;
2296 }
2297 
2298 /******************************************************************************
2299 * GetFormatEntry.
2300 * It is assumed that the current CDF has been selected.
2301 ******************************************************************************/
2302 
GetFormatEntry(Z,varNum,format)2303 CDFstatus GetFormatEntry (Z, varNum, format)
2304 Logical Z;
2305 long varNum;
2306 char **format;
2307 {
2308   CDFstatus pStatus = CDF_OK, status; long dataType, numElems;
2309   status = CDFlib (SELECT_, ATTR_NAME_, "FORMAT",
2310 			    BOO(Z,zENTRY_,rENTRY_), varNum,
2311 		   GET_, BOO(Z,zENTRY_DATATYPE_,rENTRY_DATATYPE_), &dataType,
2312 			 BOO(Z,zENTRY_NUMELEMS_,rENTRY_NUMELEMS_), &numElems,
2313 		   NULL_);
2314   switch (status) {
2315     case NO_SUCH_ATTR:
2316     case NO_SUCH_ENTRY:
2317       *format = NULL;
2318       return pStatus;
2319     default:
2320       if (!sX(status,&pStatus)) {
2321 	*format = NULL;
2322 	return pStatus;
2323       }
2324   }
2325   if (!STRINGdataType(dataType)) {
2326     *format = NULL;
2327     return pStatus;
2328   }
2329   *format = (char *) cdf_AllocateMemory ((size_t) (numElems + 1),
2330 				     FatalError);
2331   status = CDFlib (GET_, BOO(Z,zENTRY_DATA_,rENTRY_DATA_), *format,
2332 		   NULL_);
2333   if (!sX(status,&pStatus)) {
2334     cdf_FreeMemory (*format, FatalError);
2335     *format = NULL;
2336     return pStatus;
2337   }
2338   (*format)[(int)numElems] = NUL;
2339   return pStatus;
2340 }
2341 
2342 /******************************************************************************
2343 * ParseOptionList.
2344 ******************************************************************************/
2345 
ParseOptionList(nTokens,tokens,list,present)2346 Logical ParseOptionList (nTokens, tokens, list, present)
2347 int nTokens;
2348 char *tokens[];
2349 char *list;
2350 Logical present[];
2351 {
2352   int tokenN, matchN; size_t tokenLen;
2353   char token[MAX_TOKEN_LEN+1], *ptr1, *ptr2, terminator;
2354   /****************************************************************************
2355   * Assume initially that none of the tokens were found.
2356   ****************************************************************************/
2357   for (tokenN = 0; tokenN < nTokens; tokenN++) present[tokenN] = FALSE;
2358   /****************************************************************************
2359   * Check that the entered list of tokens is not a NUL string, that there are
2360   * some possible tokens to match, etc.
2361   ****************************************************************************/
2362   if (NULstring(list)) return TRUE;     /* Obviously, no tokens were found. */
2363   if (nTokens < 1) return FALSE;        /* Probably a logic error. */
2364   /****************************************************************************
2365   * Scan the entered list of tokens searching for matches with the list of
2366   * possible tokens.  First determine the starting character position and the
2367   * ending delimiter.
2368   ****************************************************************************/
2369   switch (list[0]) {
2370     case '(':           /* VMS-style. */
2371       terminator = ')';
2372       ptr1 = list + 1;
2373       break;
2374     case '"':		/* UNIX-style on a Mac (double quotes not stripped). */
2375       terminator = '"';
2376       ptr1 = list + 1;
2377       break;
2378     default:            /* UNIX-style on a UNIX machine or IBM PC. */
2379       terminator = NUL;
2380       ptr1 = list;
2381       break;
2382   }
2383   for (;;) {
2384      /*************************************************************************
2385      * Find beginning of the next token in list (skipping past any leading
2386      * blanks).  If the end of the list is reached instead, then there are
2387      * no more tokens.
2388      *************************************************************************/
2389      while (*ptr1 == ' ') ptr1++;
2390      if (*ptr1 == terminator) return TRUE;
2391      /*************************************************************************
2392      * Find the end of the token and copy.  The token is ended by either a
2393      * blank, comma, or the terminator.
2394      *************************************************************************/
2395      ptr2 = ptr1 + 1;
2396      while (*ptr2 != ' ' && *ptr2 != ',' && *ptr2 != terminator) ptr2++;
2397      tokenLen = (size_t) (ptr2 - ptr1);
2398      strcpyX (token, ptr1, MINIMUM(tokenLen,MAX_TOKEN_LEN));
2399      /*************************************************************************
2400      * Search possible tokens for a match.  If more than one match is found,
2401      * return an error.
2402      *************************************************************************/
2403      for (matchN = -1, tokenN = 0; tokenN < nTokens; tokenN++)
2404 	if (strncmpIgCasePattern(token,tokens[tokenN],strlen(token)) == 0)
2405 	  if (matchN == -1)
2406 	    matchN = tokenN;
2407 	  else
2408 	    return FALSE;
2409      if (matchN == -1)
2410        return FALSE;
2411      else
2412        present[matchN] = TRUE;
2413      /*************************************************************************
2414      * Setup to search for next token in list.
2415      *************************************************************************/
2416      switch (*ptr2) {
2417        case ' ':
2418 	 /*********************************************************************
2419 	 * The last token was ended by a blank.  Check to see if a comma is
2420 	 * the next non-blank character.  If so, the next token begins one
2421 	 * character beyond the comma (leading blanks will be skipped when
2422 	 * the beginning of that token is located).  Otherwise, the next token
2423 	 * begins at the non-blank character.
2424 	 *********************************************************************/
2425 	 ptr1 = ptr2 + 1;
2426 	 while (*ptr1 == ' ') ptr1++;
2427 	 if (*ptr1 == ',') ptr1++;
2428 	 break;
2429        case ',':
2430 	 /*********************************************************************
2431 	 * The last token was ended by a comma.  The next token begins one
2432 	 * character beyond the comma.
2433 	 *********************************************************************/
2434 	 ptr1 = ptr2 + 1;
2435 	 break;
2436        default:
2437 	 /*********************************************************************
2438 	 * The terminator must have ended the last token.
2439 	 *********************************************************************/
2440 	 return TRUE;
2441      }
2442   }
2443 }
2444 
2445 /******************************************************************************
2446 * NULedString.
2447 *    Returns a pointer to a NUL-terminated string that was allocated here but
2448 * not freed.  The caller must free the string when no longer needed.  Also,
2449 * `len'+1 characters will be allocated for the new string (and copied to from
2450 * the existing string) regardless of whether or not a NUL appears in the first
2451 * `len' characters.
2452 ******************************************************************************/
2453 
NULedString(ptr,len)2454 char *NULedString (ptr, len)
2455 char *ptr;                      /* Pointer to the string from which to extract
2456 				   the first `len' characters. */
2457 size_t len;                     /* Number of characters to extract.  This does
2458 				   not include the terminating NUL that will
2459 				   be appended to the string being returned. */
2460 {
2461   char *string;
2462   string = (char *) cdf_AllocateMemory (len + 1, FatalError);
2463   memmove (string, ptr, len);
2464   string[len] = NUL;
2465   return string;
2466 }
2467 
2468 /******************************************************************************
2469 * WriteOutSO.
2470 ******************************************************************************/
2471 
2472 #if defined(STDARG)
WriteOutSO(char * format,...)2473 int WriteOutSO (char *format, ...)
2474 #else
2475 int WriteOutSO (va_alist)
2476 va_dcl
2477 #endif
2478 {
2479 #if !defined(STDARG)
2480   char *format;
2481 #endif
2482   int n;
2483   char text[MAX_oTEXT_LEN];
2484   va_list ap;
2485 #if defined(STDARG)
2486   va_start (ap, format);
2487 #else
2488   VA_START (ap);
2489   format = va_arg (ap, char *);
2490 #endif
2491   vsprintf (text, format, ap);
2492   n = WriteOut (stdout, text);
2493   va_end (ap);
2494   return n;
2495 }
2496 
2497 /******************************************************************************
2498 * WriteOutFP.
2499 ******************************************************************************/
2500 
2501 #if defined(STDARG)
WriteOutFP(FILE * fp,char * format,...)2502 int WriteOutFP (FILE *fp, char *format, ...)
2503 #else
2504 int WriteOutFP (va_alist)
2505 va_dcl
2506 #endif
2507 {
2508 #if !defined(STDARG)
2509   FILE *fp;
2510   char *format;
2511 #endif
2512   int n;
2513   char text[MAX_oTEXT_LEN];
2514   va_list ap;
2515 #if defined(STDARG)
2516   va_start (ap, format);
2517 #else
2518   VA_START (ap);
2519   fp = va_arg (ap, FILE *);
2520   format = va_arg (ap, char *);
2521 #endif
2522   vsprintf (text, format, ap);
2523   n = WriteOut (fp, text);
2524   va_end (ap);
2525   return n;
2526 }
2527 
2528 /******************************************************************************
2529 * WriteOut.
2530 * Returns number of characters output.
2531 ******************************************************************************/
2532 
WriteOut(fp,text)2533 int WriteOut (fp, text)
2534 FILE *fp;
2535 char *text;
2536 {
2537   /****************************************************************************
2538   * If the output is not going to `stdout', then assume it is going to a file
2539   * (and ignore paging if requested).
2540   ****************************************************************************/
2541   if (fp != stdout)
2542     fprintf (fp, "%s", text);
2543   else {
2544     /**************************************************************************
2545     * The output is going to `stdout'.  Assume that `stdout' has not been
2546     * redirected away from the user's terminal (to a file).  If `stdout' has
2547     * been redirected to a file, then hopefully the user had enough sense not
2548     * to request paging.
2549     **************************************************************************/
2550 #if defined(mac) || (defined(win32) && !defined(ALONE))
2551 #if defined(mac)
2552     WriteOutMacSO (text);
2553 #else
2554 #if defined(SO)
2555     WriteOutWin32 (text);
2556 #endif
2557 #endif
2558 #else
2559     char *ptr = text, *ptrNL; size_t len;
2560     /**************************************************************************
2561     * If paging is on, first prompt for `more...' if the end of the standard
2562     * output screen has been reached.
2563     **************************************************************************/
2564     for (;;) {
2565        /***********************************************************************
2566        * If paging on, check if the maximum number of lines have been written.
2567        ***********************************************************************/
2568        if (pagingOn) {
2569 	 if (soLineCount == MAX_LINES_WHEN_PAGING) {
2570 	   char key = NUL; static char prompt[] = "\nEnter RETURN for more...";
2571 	   WriteStringStdOut (prompt, strlen(prompt));
2572 	   ReadCharStdIn (&key);
2573 	   if (key != '\n') pagingOn = FALSE;
2574 	   WriteStringStdOut ("\n\n", 2);
2575 	   soLineCount = 0;
2576 	 }
2577        }
2578        /***********************************************************************
2579        * Write the string up to the next newline character.  If there aren't
2580        * any(more) newline characters, write the rest of the string.
2581        ***********************************************************************/
2582        ptrNL = strchr (ptr, Nl);
2583        if (ptrNL == NULL) {
2584 	 len = strlen (ptr);
2585 	 WriteStringStdOut (ptr, len);
2586 	 break;
2587        }
2588        else {
2589 	 len = (int) (ptrNL - ptr + 1);
2590 	 WriteStringStdOut (ptr, len);
2591 	 if (pagingOn) soLineCount++;
2592 	 ptr = ptrNL + 1;
2593 	 if (*ptr == NUL) break;
2594        }
2595     }
2596     fflush (stdout);
2597 #endif
2598   }
2599   return strlen(text);
2600 }
2601 
2602 /******************************************************************************
2603 * DirList.
2604 * If an error occurs (or no files found), zero (0) is returned.
2605 ******************************************************************************/
2606 
DirList(dir,patternC,patternS,dirS,nameS)2607 int DirList (dir, patternC, patternS, dirS, nameS)
2608 char *dir;              /* In: Directory to search. */
2609 int patternC;           /* In: Pattern count. */
2610 char **patternS;        /* In: Patterns to search for. */
2611 char ***dirS;           /* Out: Directories. */
2612 char ***nameS;          /* Out: File names. */
2613 {
2614 int i;
2615 int nFiles = 0;
2616 int tNameChars = 0;
2617 struct FILEstruct *FILEhead = NULL;
2618 struct FILEstruct *FILEptr;
2619 struct FILEstruct *FILEptrT;
2620 char *dirP, *nameP;
2621 size_t nNameChars;
2622 
2623 #if defined(BORLANDC)
2624 char pathX[DU_MAX_PATH_LEN + 1];
2625 struct ffblk ffblk;
2626 int done;
2627 #endif
2628 
2629 #if defined(MICROSOFTC)
2630 char pathX[DU_MAX_PATH_LEN + 1];
2631 struct find_t fileinfo;
2632 int done;
2633 #endif
2634 
2635 #if (defined(unix) && !defined(__MINGW32__)) || defined(posixSHELL)
2636 DIR *dirp;
2637 char dirX[DU_MAX_PATH_LEN + 1];
2638 char pattern[DU_MAX_NAME_LEN+1];
2639 #if defined(Mach)
2640 struct direct *dp;
2641 #else
2642 struct dirent *dp;
2643 #endif
2644 #endif
2645 
2646 #if defined(vms)
2647 char pathX[DU_MAX_PATH_LEN + 1];
2648 char pathFound[DU_MAX_PATH_LEN + 1];
2649 struct dsc$descriptor_s pathDESCR;
2650 struct dsc$descriptor_s pathFoundDESCR;
2651 uLong context = 0;
2652 char name[DU_MAX_NAME_LEN + 1];
2653 uLong status;
2654 #endif
2655 
2656 #if defined(mac)
2657 short vRefNum;
2658 long dirID;
2659 OSErr rCode;
2660 CInfoPBRec cParms;
2661 Str255 tempS;
2662 char *name;
2663 char pattern[DU_MAX_NAME_LEN+1];
2664 #endif
2665 
2666 #if defined(win32)
2667 char pathX[DU_MAX_PATH_LEN + 1];
2668 long handle;
2669 struct _finddata_t fdata;
2670 int done;
2671 #endif
2672 
2673 #if defined(win32)
2674   /****************************************************************************
2675   * Find files on Windows machine.  Note that only one directory is possible
2676   * per path on Windows systems.
2677   ****************************************************************************/
2678   for (i = 0; i < patternC; i++) {
2679      ExpandPath (dir, pathX);
2680      AppendToDir (pathX, patternS[i]);
2681      handle = _findfirst (pathX, &fdata);
2682      if (handle != -1) {
2683 	done = FALSE;
2684         while (!done) {
2685           /***********************************************************************
2686           * Allocate/setup file structure.
2687           ***********************************************************************/
2688           FILEptr = (struct FILEstruct *) cdf_AllocateMemory (sizeof(struct FILEstruct), FatalError);
2689           nNameChars = strlen (fdata.name);
2690           FILEptr->name = (char *) cdf_AllocateMemory (nNameChars + 1, FatalError);
2691           strcpyX (FILEptr->name, fdata.name, nNameChars);
2692           tNameChars += nNameChars + 1;
2693           nFiles++;
2694           FILEptr->next = NULL;
2695           AddToList (&FILEhead, FILEptr);
2696           /***********************************************************************
2697           * Get next matching file.
2698           ***********************************************************************/
2699           done = _findnext (handle, &fdata);
2700         }
2701 	_findclose (handle);
2702      }
2703    }
2704 #endif
2705 
2706 #if defined(dos)
2707   /****************************************************************************
2708   * Find files on MS-DOS machine.  Note that only one directory is possible
2709   * per path on MS-DOS systems.
2710   ****************************************************************************/
2711   for (i = 0; i < patternC; i++) {
2712      ExpandPath (dir, pathX);
2713      AppendToDir (pathX, patternS[i]);
2714 #if defined(BORLANDC)
2715      done = findfirst (pathX, &ffblk, 0);
2716 #endif
2717 #if defined(MICROSOFTC)
2718      done = _dos_findfirst (pathX, 0, &fileinfo);
2719 #endif
2720      while (!done) {
2721        /***********************************************************************
2722        * Allocate/setup file structure.
2723        ***********************************************************************/
2724        FILEptr = (struct FILEstruct *)
2725 		 cdf_AllocateMemory (sizeof(struct FILEstruct),
2726 				 FatalError);
2727 #if defined(BORLANDC)
2728        nNameChars = strlen (ffblk.ff_name);
2729        FILEptr->name = (char *) cdf_AllocateMemory (nNameChars + 1, FatalError);
2730        strcpyX (FILEptr->name, ffblk.ff_name, nNameChars);
2731 #endif
2732 #if defined(MICROSOFTC)
2733        nNameChars = strlen (fileinfo.name);
2734        FILEptr->name = (char *) cdf_AllocateMemory (nNameChars + 1, FatalError);
2735        strcpyX (FILEptr->name, fileinfo.name, nNameChars);
2736 #endif
2737        tNameChars += nNameChars + 1;
2738        nFiles++;
2739        FILEptr->next = NULL;
2740        AddToList (&FILEhead, FILEptr);
2741        /***********************************************************************
2742        * Get next matching file.
2743        ***********************************************************************/
2744 #if defined(BORLANDC)
2745        done = findnext (&ffblk);
2746 #endif
2747 #if defined(MICROSOFTC)
2748        done = _dos_findnext (&fileinfo);
2749 #endif
2750      }
2751    }
2752 #endif
2753 
2754 #if (defined(unix) && !defined(__MINGW32__)) || defined(posixSHELL)
2755   /****************************************************************************
2756   * Find files on UNIX machine.  Note that only one directory is possible per
2757   * path on UNIX systems.
2758   ****************************************************************************/
2759   ExpandPath (dir, dirX);
2760   if (NULstring(dirX)) strcpyX (dirX, ".", DU_MAX_PATH_LEN);
2761 						  /* Default to current dir. */
2762   dirp = opendir (dirX);
2763   if (dirp == NULL) return 0;
2764   dp = readdir (dirp);
2765   while (dp != NULL) {
2766     char *name = dp->d_name;
2767 #if SOLARISbsdDIRUTILSbug
2768     name -= 2;
2769 #endif
2770     for (i = 0; i < patternC; i++) {
2771        strcpyX (pattern, patternS[i], DU_MAX_NAME_LEN);
2772        if (NULstring(pattern)) strcpyX (pattern, "*", DU_MAX_NAME_LEN);
2773 						  /* Default to all files. */
2774        if (PatternMatch (pattern, name)) {
2775 	 /*********************************************************************
2776 	 * Allocate/setup file structure.
2777 	 *********************************************************************/
2778 	 FILEptr = (struct FILEstruct *)
2779 		   cdf_AllocateMemory (sizeof(struct FILEstruct),
2780 				   FatalError);
2781 	 nNameChars = strlen (name);
2782 	 FILEptr->name = (char *) cdf_AllocateMemory (nNameChars + 1, FatalError);
2783 	 strcpyX (FILEptr->name, name, nNameChars);
2784 	 tNameChars += nNameChars + 1;
2785 	 nFiles++;
2786 	 FILEptr->next = NULL;
2787 	 AddToList (&FILEhead, FILEptr);
2788 	 break;
2789        }
2790     }
2791     /**************************************************************************
2792     * Get next file.
2793     **************************************************************************/
2794     dp = readdir (dirp);
2795   }
2796   closedir (dirp);
2797 #endif
2798 
2799 #if defined(vms)
2800   /****************************************************************************
2801   * Find files on VMS machine.  Note that a logical name defined to be a set of
2802   * two or more directories may result in files from more than one directory
2803   * being found.  In that case, the logical name would be returned as the name
2804   * of the directory (the VMS file system handles this when opening a file).
2805   * The actual directories are ignored.
2806   ****************************************************************************/
2807   pathFoundDESCR.dsc$w_length = sizeof(pathFound) - 1; /* Pass full string. */
2808   pathFoundDESCR.dsc$b_dtype = DSC$K_DTYPE_T;
2809   pathFoundDESCR.dsc$b_class = DSC$K_CLASS_S;
2810   pathFoundDESCR.dsc$a_pointer = pathFound;
2811   for (i = 0; i < patternC; i++) {
2812      ExpandPath (dir, pathX);
2813      AppendToDir (pathX, patternS[i]);
2814      pathDESCR.dsc$w_length = strlen(pathX);            /* Pass part used. */
2815      pathDESCR.dsc$b_dtype = DSC$K_DTYPE_T;
2816      pathDESCR.dsc$b_class = DSC$K_CLASS_S;
2817      pathDESCR.dsc$a_pointer = pathX;
2818      while ((status = lib$find_file (&pathDESCR, &pathFoundDESCR, &context,
2819 				     NULL, NULL, NULL, NULL)) == RMS$_NORMAL) {
2820        /***********************************************************************
2821        * A file was found, NUL terminate and remove trailing blanks (version
2822        * number is left on).
2823        ***********************************************************************/
2824        pathFound[pathFoundDESCR.dsc$w_length] = NUL;    /* NUL-terminate. */
2825        for (i = strlen(pathFound) - 1; i >= 0 && pathFound[i] == ' '; i--) {
2826 	  pathFound[i] = NUL;
2827        }
2828        ParsePath (pathFound, NULL, name);
2829        /***********************************************************************
2830        * Allocate/setup file structure.
2831        ***********************************************************************/
2832        FILEptr = (struct FILEstruct *)
2833 		 cdf_AllocateMemory (sizeof(struct FILEstruct),
2834 				 FatalError);
2835        nNameChars = strlen (name);
2836        FILEptr->name = (char *) cdf_AllocateMemory (nNameChars + 1,
2837 						FatalError);
2838        strcpyX (FILEptr->name, name, nNameChars);
2839        tNameChars += nNameChars + 1;
2840        nFiles++;
2841        FILEptr->next = NULL;
2842        AddToList (&FILEhead, FILEptr);
2843      }
2844      status = lib$find_file_end (&context);
2845   }
2846 #endif
2847 
2848 #if defined(mac)
2849   /****************************************************************************
2850   * Find files on a Macintosh.  Note that only one directory is possible per
2851   * path on Macintosh systems.
2852   ****************************************************************************/
2853   if (!MacDirSpecified(dir,&vRefNum,&dirID)) {
2854     *nameS = NULL;
2855     *dirS = NULL;
2856     return 0;
2857   }
2858   cParms.hFileInfo.ioNamePtr = tempS;
2859   cParms.hFileInfo.ioVRefNum = vRefNum;
2860   cParms.hFileInfo.ioFDirIndex = 1;
2861   cParms.hFileInfo.ioDirID = dirID;
2862   rCode = PBGetCatInfo (&cParms, FALSE);
2863   while (rCode == noErr) {
2864     /**************************************************************************
2865     * Check if a file (rather than a directory).
2866     **************************************************************************/
2867     if (BITCLR(cParms.hFileInfo.ioFlAttrib,4)) {
2868       name = PtoCstr (cParms.hFileInfo.ioNamePtr);
2869       for (i = 0; i < patternC; i++) {
2870 	 strcpyX (pattern, patternS[i], DU_MAX_NAME_LEN);
2871 	 if (NULstring(pattern)) strcpyX (pattern, "*", DU_MAX_NAME_LEN);
2872 	 if (PatternMatch(pattern,name)) {
2873 	   /*******************************************************************
2874 	   * Allocate/setup file structure.
2875 	   *******************************************************************/
2876 	   FILEptr = (struct FILEstruct *)
2877 		     cdf_AllocateMemory (sizeof(struct FILEstruct),
2878 				     FatalError);
2879 	   nNameChars = strlen (name);
2880 	   FILEptr->name = (char *) cdf_AllocateMemory (nNameChars+1,
2881 						    FatalError);
2882 	   strcpyX (FILEptr->name, name, nNameChars);
2883 	   tNameChars += nNameChars + 1;
2884 	   nFiles++;
2885 	   FILEptr->next = NULL;
2886 	   AddToList (&FILEhead, FILEptr);
2887 	   break;
2888 	 }
2889       }
2890     }
2891     /**************************************************************************
2892     * Get next file.
2893     **************************************************************************/
2894     cParms.hFileInfo.ioDirID = dirID;    /* This must be reset each time. */
2895     cParms.hFileInfo.ioFDirIndex++;         /* Increment to next file. */
2896     rCode = PBGetCatInfo (&cParms, FALSE);
2897   }
2898 #endif
2899 
2900   /****************************************************************************
2901   * Build directory/file arrays.
2902   ****************************************************************************/
2903   if (nFiles > 0) {
2904     /**************************************************************************
2905     * Setup to traverse linked list.
2906     **************************************************************************/
2907     *dirS = (char **) cdf_AllocateMemory ((nFiles*sizeof(char *))+strlen(dir)+1,
2908 				      FatalError);
2909     *nameS = (char **) cdf_AllocateMemory ((nFiles*sizeof(char *)) + tNameChars,
2910 				       FatalError);
2911     dirP = (char *) (*dirS) + nFiles*sizeof(char *);
2912     nameP = (char *) (*nameS) + nFiles*sizeof(char *);
2913     /**************************************************************************
2914     * Traverse linked list of file structures.  Note that the second through
2915     * last directory strings actually point to the first directory string.
2916     **************************************************************************/
2917     for (FILEptr=FILEhead, i=0; FILEptr != NULL; FILEptr=FILEptr->next, i++) {
2918        if (i == 0) {
2919 	 strcpyX (dirP, dir, 0);
2920 	 (*dirS)[i] = dirP;
2921        }
2922        else
2923 	 (*dirS)[i] = (*dirS)[i-1];
2924        strcpyX (nameP, FILEptr->name, 0);
2925        (*nameS)[i] = nameP;
2926        nameP += strlen(FILEptr->name) + 1;
2927     }
2928     /**************************************************************************
2929     * Free linked list of file structures.
2930     **************************************************************************/
2931     FILEptr = FILEhead;
2932     while (FILEptr != NULL) {
2933       FILEptrT = FILEptr;
2934       FILEptr = FILEptr->next;
2935       cdf_FreeMemory (FILEptrT->name, FatalError);
2936       cdf_FreeMemory (FILEptrT, FatalError);
2937     }
2938   }
2939   else {
2940     /**************************************************************************
2941     * No files found.
2942     **************************************************************************/
2943     *nameS = NULL;
2944     *dirS = NULL;
2945   }
2946   return nFiles;
2947 }
2948 
2949 /******************************************************************************
2950 * AddToList.
2951 ******************************************************************************/
2952 
AddToList(FILEhead,FILEptr)2953 static void AddToList (FILEhead, FILEptr)
2954 struct FILEstruct **FILEhead;
2955 struct FILEstruct *FILEptr;
2956 {
2957   if (*FILEhead == NULL)
2958     *FILEhead = FILEptr;
2959   else
2960     if (strcmp(FILEptr->name,(*FILEhead)->name) < 0) {
2961       FILEptr->next = *FILEhead;
2962       *FILEhead = FILEptr;
2963     }
2964     else {
2965       struct FILEstruct *FILEptrT = *FILEhead;
2966       for (;;) {
2967 	 if (FILEptrT->next == NULL) {
2968 	   FILEptrT->next = FILEptr;
2969 	   break;
2970 	 }
2971 	 else
2972 	   if (strcmp(FILEptr->name,FILEptrT->next->name) < 0) {
2973 	     FILEptr->next = FILEptrT->next;
2974 	     FILEptrT->next = FILEptr;
2975 	     break;
2976 	   }
2977 	 FILEptrT = FILEptrT->next;
2978       }
2979     }
2980   return;
2981 }
2982 
2983 /******************************************************************************
2984 * PatternMatch. (Only used on UNIX/POSIXshell and Macintosh systems).
2985 ******************************************************************************/
2986 
2987 #if (defined(unix) && !defined(__MINGW32__)) || defined(mac) || \
2988      defined(posixSHELL)
PatternMatch(pattern,name)2989 static int PatternMatch (pattern, name)
2990 char *pattern;
2991 char *name;
2992 {
2993 enum typeENUM types[DU_MAX_PATTERNS];
2994 char *strings[DU_MAX_PATTERNS];
2995 int nTypes = 0;
2996 int len, i, result;
2997 
2998 for (i = 0; i < DU_MAX_PATTERNS; i++) types[i] = TBD;
2999 
3000 for (i = 0; pattern[i] != NUL; i++)
3001    switch (pattern[i]) {
3002      case '?':
3003        types[nTypes++] = WILD1;
3004        break;
3005      case '*':
3006        if (nTypes == 0 || types[nTypes] != WILDn) types[nTypes++] = WILDn;
3007        break;
3008      default:
3009        if (types[nTypes] == TBD) {
3010 	 types[nTypes] = STR;
3011 	 strings[nTypes] = (char *) cdf_AllocateMemory (DU_MAX_NAME_LEN + 1,
3012 						    FatalError);
3013 	 strings[nTypes][0] = pattern[i];
3014 	 strings[nTypes][1] = NUL;
3015 	 nTypes++;
3016        }
3017        else {
3018 	 len = strlen (strings[nTypes-1]);
3019 	 strings[nTypes-1][len] = pattern[i];
3020 	 strings[nTypes-1][len+1] = NUL;
3021        }
3022    }
3023 
3024 result = CheckPattern (nTypes, types, strings, name);
3025 
3026 for (i = 0; i < DU_MAX_PATTERNS; i++) {
3027    if (types[i] == STR) cdf_FreeMemory (strings[i], FatalError);
3028 }
3029 
3030 return result;
3031 }
3032 #endif
3033 
3034 /******************************************************************************
3035 * CheckPattern. (Only used on UNIX/POSIXshell and Macintosh systems).
3036 ******************************************************************************/
3037 
3038 #if (defined(unix) && !defined(__MINGW32__)) || defined(mac) || \
3039      defined(posixSHELL)
CheckPattern(nTypes,types,strings,name)3040 static int CheckPattern (nTypes, types, strings, name)
3041 int nTypes;
3042 enum typeENUM types[];
3043 char *strings[];
3044 char *name;
3045 {
3046 int sp = 0;
3047 int i, j;
3048 
3049 for (i = 0; i < nTypes; i++) {
3050    switch (types[i]) {
3051      case TBD:
3052        /* Do nothing? */
3053        break;
3054      case STR:
3055        if (strncmp(&name[sp],strings[i],strlen(strings[i])) != 0)
3056 	 return FALSE;
3057        else
3058 	 sp += strlen(strings[i]);
3059        break;
3060      case WILD1:
3061        if (name[sp] == NUL)
3062 	 return FALSE;
3063        else
3064 	 sp++;
3065        break;
3066      case WILDn:
3067        if (i == nTypes-1)       /* At last type to check? */
3068 	 return TRUE;
3069        else {
3070 	 for (j = i; name[j] != NUL; j++)
3071 	    if (CheckPattern (nTypes-i-1, &types[i+1],
3072 			      &strings[i+1], &name[j])) return TRUE;
3073 	 return FALSE;
3074        }
3075    }
3076 }
3077 
3078 if (name[sp] == NUL)
3079   return TRUE;
3080 else
3081   return FALSE;
3082 }
3083 #endif
3084 
3085 /******************************************************************************
3086 * CDFdirList.
3087 *    Does a `DirList' using the possible CDF extensions (`.cdf' on all
3088 * platforms and also `.CDF', `.cdf;1', and `.CDF;1' on UNIX/POSIXshell and
3089 * Macintosh platforms because of CD-ROM inconsistencies
3090 ******************************************************************************/
3091 
CDFdirList(path,dirS,nameS)3092 int CDFdirList (path, dirS, nameS)
3093 char *path;
3094 char ***dirS;
3095 char ***nameS;
3096 {
3097 #if (defined(unix) && !defined(__MINGW32__)) || defined(mac) || \
3098      defined(posixSHELL)
3099   /****************************************************************************
3100   * UNIX/POSIXshell and Macintosh.
3101   ****************************************************************************/
3102   char dir[DU_MAX_DIR_LEN+1];
3103   char pattern[DU_MAX_NAME_LEN+1];
3104   static char pattern1[DU_MAX_NAME_LEN+1];
3105   static char pattern2[DU_MAX_NAME_LEN+1];
3106   static char pattern3[DU_MAX_NAME_LEN+1];
3107   static char pattern4[DU_MAX_NAME_LEN+1];
3108   static char *patternS[4] = { pattern1, pattern2, pattern3, pattern4 };
3109   int nCDFs;
3110 
3111   ParsePath (path, dir, pattern);
3112 
3113   strcpyX (pattern1, pattern, DU_MAX_NAME_LEN);
3114   if (NULstring(pattern1)) strcatX (pattern1, "*", DU_MAX_NAME_LEN);
3115   strcatX (pattern1, ".cdf", DU_MAX_NAME_LEN);
3116 
3117   strcpyX (pattern2, pattern, DU_MAX_NAME_LEN);
3118   if (NULstring(pattern2)) strcatX (pattern2, "*", DU_MAX_NAME_LEN);
3119   strcatX (pattern2, ".CDF", DU_MAX_NAME_LEN);
3120 
3121   strcpyX (pattern3, pattern, DU_MAX_NAME_LEN);
3122   if (NULstring(pattern3)) strcatX (pattern3, "*", DU_MAX_NAME_LEN);
3123   strcatX (pattern3, ".cdf;1", DU_MAX_NAME_LEN);
3124 
3125   strcpyX (pattern4, pattern, DU_MAX_NAME_LEN);
3126   if (NULstring(pattern4)) strcatX (pattern4, "*", DU_MAX_NAME_LEN);
3127   strcatX (pattern4, ".CDF;1", DU_MAX_NAME_LEN);
3128 
3129   nCDFs = DirList (dir, 4, patternS, dirS, nameS);
3130   RemoveExtensions (nCDFs, *nameS);
3131 
3132   return nCDFs;
3133 #endif
3134 #if defined(vms) || defined(dos) || defined(win32)
3135   /****************************************************************************
3136   * VMS, Windows, and MS-DOS.
3137   ****************************************************************************/
3138   char dir[DU_MAX_DIR_LEN+1];
3139   static char pattern[DU_MAX_NAME_LEN+1];
3140   static char *patternS[1] = { pattern };
3141   int nCDFs;
3142 
3143   ParsePath (path, dir, pattern);
3144 
3145   if (NULstring(pattern)) strcatX (pattern, "*", DU_MAX_NAME_LEN);
3146   strcatX (pattern, ".cdf", DU_MAX_NAME_LEN);
3147 
3148   nCDFs = DirList (dir, 1, patternS, dirS, nameS);
3149   RemoveExtensions (nCDFs, *nameS);
3150 
3151   return nCDFs;
3152 #endif
3153 }
3154 
3155 /******************************************************************************
3156 * RemoveExtensions.  Locates the last '.' in a file name and replaces it with
3157 *                    a NUL.  This effectively removes the file extension.  If
3158 *                    the file name does not have an extension and has a '.' in
3159 *                    its name, this could have undesired effects.
3160 ******************************************************************************/
3161 
RemoveExtensions(nFiles,files)3162 void RemoveExtensions (nFiles, files)
3163 int nFiles;
3164 char *files[];
3165 {
3166   int i;
3167   char *ptr;
3168   for (i = 0; i < nFiles; i++)
3169      if ((ptr = strrchr(files[i],'.')) != NULL) *ptr = NUL;
3170   return;
3171 }
3172 
3173 /******************************************************************************
3174 * WriteStringStdOut.
3175 ******************************************************************************/
3176 
WriteStringStdOut(string,length)3177 void WriteStringStdOut (string, length)
3178 char *string;
3179 size_t length;
3180 {
3181   fprintf (stdout, "%*.*s", (int) length, (int) length, string);
3182   return;
3183 }
3184 
3185 /******************************************************************************
3186 * ReadCharStdIn.
3187 ******************************************************************************/
3188 
3189 #if !defined(mac)
ReadCharStdIn(key)3190 void ReadCharStdIn (key)
3191 char *key;
3192 {
3193   *key = (char) fgetc (stdin);
3194   return;
3195 }
3196 #endif
3197 
3198 /******************************************************************************
3199 * DisplayStatistics.
3200 ******************************************************************************/
3201 
DisplayStatistics(label,vStatsDotCDF,vStatsStage,vStatsCompress)3202 void DisplayStatistics (label, vStatsDotCDF, vStatsStage, vStatsCompress)
3203 char *label;
3204 vSTATS *vStatsDotCDF;
3205 vSTATS *vStatsStage;
3206 vSTATS *vStatsCompress;
3207 {
3208   char temp1[MAX_SCREENLINE_LEN+1], temp2[MAX_SCREENLINE_LEN+1],
3209        temp3[MAX_SCREENLINE_LEN+1], labelX[MAX_SCREENLINE_LEN+1];
3210   if (vStatsDotCDF->maxBuffers > 0) {
3211     strcpyX (labelX, label, MAX_SCREENLINE_LEN);
3212     strcatX (labelX, " DotCDF file", MAX_SCREENLINE_LEN);
3213     BuildStatistics (labelX, vStatsDotCDF, temp1, temp2, temp3);
3214     WriteOut (stdout, temp1);
3215     WriteOut (stdout, "\n");
3216     WriteOut (stdout, temp2);
3217     WriteOut (stdout, "\n");
3218     WriteOut (stdout, temp3);
3219     WriteOut (stdout, "\n");
3220   }
3221   if (vStatsStage->maxBuffers > 0) {
3222     strcpyX (labelX, label, MAX_SCREENLINE_LEN);
3223     strcatX (labelX, " staging file", MAX_SCREENLINE_LEN);
3224     BuildStatistics (labelX, vStatsStage, temp1, temp2, temp3);
3225     WriteOut (stdout, temp1);
3226     WriteOut (stdout, "\n");
3227     WriteOut (stdout, temp2);
3228     WriteOut (stdout, "\n");
3229     WriteOut (stdout, temp3);
3230     WriteOut (stdout, "\n");
3231   }
3232   if (vStatsCompress->maxBuffers > 0) {
3233     strcpyX (labelX, label, MAX_SCREENLINE_LEN);
3234     strcatX (labelX, " compression scratch file", MAX_SCREENLINE_LEN);
3235     BuildStatistics (labelX, vStatsCompress, temp1, temp2, temp3);
3236     WriteOut (stdout, temp1);
3237     WriteOut (stdout, "\n");
3238     WriteOut (stdout, temp2);
3239     WriteOut (stdout, "\n");
3240     WriteOut (stdout, temp3);
3241     WriteOut (stdout, "\n");
3242   }
3243   return;
3244 }
3245 
3246 /******************************************************************************
3247 * BuildStatistics.
3248 ******************************************************************************/
3249 
BuildStatistics(label,vStats,temp1,temp2,temp3)3250 void BuildStatistics (label, vStats, temp1, temp2, temp3)
3251 char *label;
3252 vSTATS *vStats;
3253 char temp1[MAX_SCREENLINE_LEN+1];
3254 char temp2[MAX_SCREENLINE_LEN+1];
3255 char temp3[MAX_SCREENLINE_LEN+1];
3256 {
3257   strcpyX (temp1, "  Statistics", MAX_SCREENLINE_LEN);
3258   if (label != NULL) {
3259     strcatX (temp1, " for ", MAX_SCREENLINE_LEN);
3260     strcatX (temp1, label, MAX_SCREENLINE_LEN);
3261   }
3262   strcatX (temp1, ":", MAX_SCREENLINE_LEN);
3263   sprintf (temp2, "    %d buffer%s used of the %d allowed, ", vStats->nBuffers,
3264 	   BOO(vStats->nBuffers == 1,"","s"), vStats->maxBuffers);
3265   sprintf (EofS(temp2), "[%ld reads, %ld writes]  ", vStats->nV_reads,
3266 	   vStats->nV_writes);
3267   sprintf (temp3, "    %ld page in%s, %ld page out%s, ",
3268 	   vStats->nPageIns, BOO(vStats->nPageIns==1,"","s"),
3269 	   vStats->nPageOuts, BOO(vStats->nPageOuts==1,"","s"));
3270   sprintf (EofS(temp3), "%ld block read%s, %ld block write%s  ",
3271 	   vStats->nBlockReads, BOO(vStats->nBlockReads==1,"","s"),
3272 	   vStats->nBlockWrites, BOO(vStats->nBlockWrites==1,"","s"));
3273   return;
3274 }
3275 
3276 /******************************************************************************
3277 * StatusCodeReportOptions.
3278 ******************************************************************************/
3279 
StatusCodeReportOptions(e,w,i)3280 char *StatusCodeReportOptions (e,w,i)
3281 Logical e;
3282 Logical w;
3283 Logical i;
3284 {
3285   static char mask[MAX_REPORTMASK_LEN+1];
3286 #if defined(vms)
3287   strcpyX (mask, "(", MAX_REPORTMASK_LEN);
3288 #else
3289   strcpyX (mask, "\"", MAX_REPORTMASK_LEN);
3290 #endif
3291   strcatX (mask, (e ? "errors" : ""), MAX_REPORTMASK_LEN);
3292   strcatX (mask, (w ? (e ? ",warnings" : "warnings") : ""),
3293 	   MAX_REPORTMASK_LEN);
3294   strcatX (mask, (i ? (e || w ? ",informationals" : "informationals") : ""),
3295 	   MAX_REPORTMASK_LEN);
3296 #if defined(vms)
3297   strcatX (mask, ")", MAX_REPORTMASK_LEN);
3298 #else
3299   strcatX (mask, "\"", MAX_REPORTMASK_LEN);
3300 #endif
3301 #if defined(vms) || defined(dos)
3302   MakeUpperString (mask);
3303 #endif
3304   return mask;
3305 }
3306 
3307 /******************************************************************************
3308 * DisplayIdentification.
3309 ******************************************************************************/
3310 
DisplayIdentification(name)3311 void DisplayIdentification (name)
3312 char *name;
3313 {
3314   long version, release, increment; char subIncrement;
3315   char text[MAX_MESSAGE_TEXT_LEN+1]; CDFstatus status;
3316   status = CDFlib (GET_, LIB_VERSION_, &version,
3317 			 LIB_RELEASE_, &release,
3318 			 LIB_INCREMENT_, &increment,
3319 			 LIB_subINCREMENT_, &subIncrement,
3320 		   NULL_);
3321   if (StatusBAD(status))
3322     sprintf (text, "Error inquiring CDF library.");
3323   else {
3324     sprintf (text, "%s from the CDF V%ld.%ld.%ld",
3325 	     name, version, release, increment);
3326     if (subIncrement != ' ') sprintf (EofS(text), "%c", subIncrement);
3327     sprintf (EofS(text), " distribution.");
3328   }
3329   DisplayInfo (text);
3330   return;
3331 }
3332 
3333 /******************************************************************************
3334 * FindUniqueMatch.
3335 * Returns: NOMATCH if a match was not found,
3336 *	   MATCHES if more than one match,
3337 *	   `index' if only one match.
3338 ******************************************************************************/
3339 
FindUniqueMatch(target,strings)3340 int FindUniqueMatch (target, strings)
3341 char *target;		/* Searching for this string. */
3342 char *strings[];	/* Terminated by a NULL pointer. */
3343 {
3344   int match, beyond; size_t targetL = strlen(target);
3345   for (match = 0; strings[match] != NULL; match++) {
3346      if (strncmpIgCasePattern(target,strings[match],targetL) == 0) {
3347        for (beyond = match + 1; strings[beyond] != NULL; beyond++) {
3348 	  if (strncmpIgCasePattern(target,strings[beyond],targetL) == 0)
3349 	    return MATCHES;
3350        }
3351        return match;
3352      }
3353   }
3354   return NOMATCH;
3355 }
3356 
3357