/******************************************************************************
* Copyright 1996-2014 United States Government as represented by the
* Administrator of the National Aeronautics and Space Administration.
* All Rights Reserved.
******************************************************************************/
/******************************************************************************
*
*  NSSDC/CDF                                                       CDFexport.
*
*  Version 1.2e, 14-Dec-97, Hughes STX.
*
*  Modification history:
*
*   V1.0  13-Sep-95, J Love     Original version.
*   V1.0a 28-Sep-95, J Love     Macintosh dialog filtering.  Outline default
*                               button.
*   V1.1   9-Sep-96, J Love     CDF V2.6.
*   V1.2  15-Nov-96, J Love     Added `simple' environment and batch mode.
*   V1.2a 15-Jan-97, J Love     Added prompts for settings file (when saving
*                               and restoring).  Added `help' qualifier.
*   V1.2b 21-Feb-97, J Love     Removed RICE.
*   V1.2c 30-Mar-97, J Love     Allow FieldWindow fields to exceed their
*                               on-screen width.
*   V1.2d 16-Nov-97, J Love	Windows NT/Visual C++.
*   V1.2e 14-Dec-97, J Love	Added ALPHAVMSi encoding.
*   V1.3  03-May-06, M Liu      Added checksum option for the files.
*   V1.4  13-Oct-06, M Liu      Changed to allow upper and lower case CDF  
*                               name to be used on win32.
*   V3.3  10-Jan-09, M Liu      Validate a file before it is used. Use "PPC"
*                               instead of "MAC" for encoding.
*   V3.3a  1-Aug-09, M Liu      Added new qualifiers of 
*                                 - include | exclude
*                                 - epochrange | recordrange
*                                 - controlsettings
*                               to the batch run. 
*   V3.3b 10-Dec-10, M Liu      Added a new option "ios8601" for epoch output.
*   V3.3c 20-Dec-10, M Liu      Added another option "poundedheading" for
*                               heading.
*   V3.3d 04-Apr-11, M Liu      Modified to handle TT2000 epoch style string.
*   V3.7  10-Jan-18, M Liu      Added ARM and IA64 openVMS.
* 
******************************************************************************/

#define CDFXP
#include "cdfxp.h"

void FreeTemps();

/******************************************************************************
* Increased stack size and overlay buffer for Borland C on IBM PC.
******************************************************************************/

#if defined(BORLANDC)
extern unsigned _stklen = BORLANDC_STACK_SIZE;
extern unsigned _ovrbuffer = BORLANDC_OVERLAY_SIZE;
#endif
#ifdef WIN32
  static unsigned int oldCodePage = 0;
#endif
/******************************************************************************
* Main.
******************************************************************************/

#if !defined(win32)
MAIN {
  Logical success = TRUE;
  strcpyX (pgmName, "CDFexport", MAX_PROGRAM_NAME_LEN);
#if defined(mac)
  MacExecuteFSI (ExportCDFs, ExportQOPs);
#else
  success = ExportCDFs (argc, argv);
  FreeTemps ();
#endif
#ifdef WIN32
  if (oldCodePage != 0) SetConsoleOutputCP(oldCodePage);
#endif
  return BOO(success,EXIT_SUCCESS_,EXIT_FAILURE_);
}
#endif

/******************************************************************************
* ExportCDFs.
******************************************************************************/

Logical ExportCDFs (argC, argV)
int argC;
char *argV[];
{
  static char CDFspec[DU_MAX_PATH_LEN+1] = CURRENTDIRECTORY;
  long zMode = BOO(DEFAULTsimpleEXPORT,DEFAULTzModeSIMPLE,DEFAULTzModeEXPORT);
  Logical negToPosFp0 = DEFAULT_NEGtoPOSfp0;
  Logical prompt = BOO(DEFAULTsimpleEXPORT,DEFAULTpromptSIMPLE,
					   DEFAULTpromptEXPORT);
  /****************************************************************************
  * Set defaults based on simple mode.
  ****************************************************************************/
  OptDefaults ();
  /****************************************************************************
  * Scan parameters/options/qualifiers.
  ****************************************************************************/
  switch (argC) {
    case 1:
      if (!prompt) {
	create_pasteboard ();
	set_cursor_mode (CURSORoff);
	OnlineHelpWindow ("cdfxp.ilh", OLHhelpID);
	delete_pasteboard (ERASE);
	set_cursor_mode (CURSORon);
	return TRUE;
      }
      break;
    default: {
      QOP *qop;
      static char *validQuals[] = {
	"initial", "prompt", "noprompt", "cache", "zmode", "neg2posfp0",
	"noneg2posfp0", "report", "statistics", "nostatistics", "about",
	"simple", "nosimple", "cdf", "text", "settings", "batch", "help",
	"include", "exclude", "sequencetime", "controlsettings", 
        "epochrange", "recordrange", "ziso8601", "novalidate", NULL
      };
      static int optRequired[] = {
	TRUE, FALSE, FALSE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE,
	FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE, FALSE,
        FALSE, TRUE, TRUE, FALSE, FALSE, 0
      };
      static char *reportTokens[] = { "errors", "warnings", "informationals" };
      Logical qopError = FALSE;
      /************************************************************************
      * Parse qualifiers, options, and parameters (QOPs).
      ************************************************************************/
      qop = Qop (argC, argV, validQuals, optRequired);
      if (qop == NULL) return FALSE;
      /************************************************************************
      * Check for `about' qualifier.
      ************************************************************************/
      if (qop->qualEntered[ABOUTqual]) {
	DisplayIdentification (pgmName);
	cdf_FreeMemory (qop, FatalError);
	return TRUE;
      }
      /************************************************************************
      * Check for `help' qualifier.
      ************************************************************************/
      if (qop->qualEntered[HELPqual]) {
	create_pasteboard ();
	set_cursor_mode (CURSORoff);
	OnlineHelpWindow ("cdfxp.ilh", OLHhelpID);
	delete_pasteboard (ERASE);
	set_cursor_mode (CURSORon);
	cdf_FreeMemory (qop, FatalError);
	return TRUE;
      }
      /************************************************************************
      * Check for `simple' qualifier.
      ************************************************************************/
      qopError = qopError | !TFqualifier(qop,&simpleMode,SIMPLEqual,
					 NOSIMPLEqual,DEFAULTsimpleEXPORT,
					 "simple");
      /************************************************************************
      * Set some defaults based on simple mode.  The other defaults will be
      * set as the remaining qualifiers are checked.
      ************************************************************************/
      strcpyX (settingsFile, BOO(simpleMode,"simple.set",
					    "export.set"), DU_MAX_PATH_LEN);
      zMode = BOO(simpleMode,DEFAULTzModeSIMPLE,DEFAULTzModeEXPORT);
      OptDefaults ();
      /************************************************************************
      * Check for the `prompt' qualifier.
      ************************************************************************/
      qopError = qopError | !TFqualifier(qop,&prompt,PROMPTqual,NOPROMPTqual,
					 BOO(simpleMode,
					     DEFAULTpromptSIMPLE,
					     DEFAULTpromptEXPORT),"prompt");
      /************************************************************************
      * Check for `batch' qualifier.
      * Note that the `batch' qualifier will negate the `prompt' qualifier.
      ************************************************************************/
      if (qop->qualEntered[BATCHqual]) {
	static char *batchStrings[] = { "cdf", "text", NULL };
	static int batches[] = { BATCHcdf, BATCHtext };
	int match = FindUniqueMatch (qop->qualOpt[BATCHqual],batchStrings);
	switch (match) {
	  case NOMATCH:
	    DisplayError ("Unknown batch mode.");
	    qopError = TRUE;
	    break;
	  case MATCHES:
	    DisplayError ("Ambiguous batch mode.");
	    qopError = TRUE;
	    break;
	  default:
	    batchMode = batches[match];
	    prompt = FALSE;
	    break;
	}
      }
      else
	batchMode = noBATCH;
      /************************************************************************
      * Check for `neg2posfp0' and `statistics' qualifiers.
      ************************************************************************/
      qopError = qopError | !TFqualifier(qop,&negToPosFp0,NEG2POSFP0qual,
					 NONEG2POSFP0qual,DEFAULT_NEGtoPOSfp0,
					 "neg2posfp0");
      qopError = qopError | !TFqualifier(qop,&dumpStats,STATSqual,NOSTATSqual,
					 DEFAULTstatsEXPORT,"statistics");
      /************************************************************************
      * Check for `cdf', `text', and `settings' qualifiers.
      ************************************************************************/
      if (qop->qualEntered[CDFqual]) {
        if (!ValidateQual(qop->qualOpt[CDFqual], validQuals))
          strcpyX (outputCDF, qop->qualOpt[CDFqual], CDF_PATHNAME_LEN);
        else {
          DisplayError ("Invalid \"cdf\" qualifier.");
          qopError = TRUE;
        }
      }
      if (qop->qualEntered[TEXTqual]) {
        if (!ValidateQual(qop->qualOpt[TEXTqual], validQuals))
          strcpyX (outputText, qop->qualOpt[TEXTqual], DU_MAX_PATH_LEN);
        else {
          DisplayError ("Invalid \"text\" qualifier.");
          qopError = TRUE;
        }
      }
      if (qop->qualEntered[SETTINGSqual]) {
        if (!ValidateQual(qop->qualOpt[SETTINGSqual], validQuals)) {
          strcpyX (settingsFile, qop->qualOpt[SETTINGSqual], DU_MAX_PATH_LEN);
          numVars = 0;
        } else {
          DisplayError ("Invalid \"settings\" qualifier.");
          qopError = TRUE;
        }
      }
      /************************************************************************
      * Check for `cache' qualifier.
      ************************************************************************/
      if (qop->qualEntered[CACHEqual]) {
	if (!ParseCacheSizes(qop->qualOpt[CACHEqual],
			     &workingCache,&stageCache,&compressCache)) {
	  DisplayError ("Illegal cache size/type.");
	  qopError = TRUE;
	}
      }
      /***********************************************************************
      * Check for `epochrange' or 'recordrange' qualifier.
      ***********************************************************************/
      if (!S2qualifierLong(qop,&range,EPOCHRANGEqual,
                           1L,RECORDRANGEqual,2L,
                           0L,"epochrange and recordrange")) {
        qopError = TRUE;
      } else {
        if (range  == 1L) {
          char *epochStrings[2];
          epochStrings[0] = (char *) cdf_AllocateMemory((size_t)36+1, NULL);
          epochStrings[1] = (char *) cdf_AllocateMemory((size_t)36+1, NULL);
          ParseStringForTokens(',', qop->qualOpt[EPOCHRANGEqual],
                               epochStrings);
          if (!ParseEpochRange(epochStrings)) {
            qopError = TRUE;
          }
          cdf_FreeMemory (epochStrings[0], FatalError);
          cdf_FreeMemory (epochStrings[1], FatalError);
        } else if (range == 2L) {
          if (!ParseRecordRange(qop->qualOpt[RECORDRANGEqual], &recordStart,
                                &recordEnd)) {
            DisplayError ("Illegal record range.");
            qopError = TRUE;
          }
          --recordStart;
          --recordEnd;
        }
      }
      /***********************************************************************
      * Check for `report' qualifier.
      ***********************************************************************/
      if (qop->qualEntered[REPORTqual]) {
	if (!ParseOptionList(3,reportTokens,
			     qop->qualOpt[REPORTqual],report)) {
	  DisplayError ("Illegal list of `report' options.");
	  qopError = TRUE;
	}
      }
      /***********************************************************************
      * Check for `include' or 'exclude' qualifier.
      ***********************************************************************/
      if (!S2qualifierLong(qop,&includeVars,INCLUDEqual,
                           1L,EXCLUDEqual,2L,
                           0L,"include and exclude")) {
        qopError = TRUE;
      } else {
        char *tmp = NULL;
        int len = 0;
        if (includeVars > 0 && qop->qualEntered[SETTINGSqual]) {
          DisplayError ("include/exclude and settings file are mutually exclusive.");
          qopError = TRUE;
        } else {
          if (includeVars == 1L) {
            len = strlen(qop->qualOpt[INCLUDEqual]);
            tmp = (char *) cdf_AllocateMemory ((size_t)len+1, NULL);
            strcpyX (tmp, qop->qualOpt[INCLUDEqual], len);
          } else if (includeVars == 2L) {
            len = strlen(qop->qualOpt[EXCLUDEqual]);
            tmp = (char *) cdf_AllocateMemory ((size_t)len+1, NULL);
            strcpyX (tmp, qop->qualOpt[EXCLUDEqual], len);
          }
          if (includeVars > 0) {
            if ((strstrIgCase(tmp, "varsfile=") != NULL) ||
                (strstrIgCase(tmp, "varsfile:") != NULL)) {
              if (!LoadVarsTextFile(tmp+9)) {
                DisplayError ("`include/exclude' file does not exist or is bad.");
                qopError = TRUE;
              }
            } else {
              strcpyX (varsList, tmp, len);
              numVars = GetNumTokens (',', varsList);
              if (numVars > 0) {
                int i;
                vars = (char **) cdf_AllocateMemory ((size_t)sizeof(char *) *
                                                     numVars, FatalError);
                for (i = 0; i < numVars; ++i)
                  vars[i] = (char *) cdf_AllocateMemory (
                                    (size_t)CDF_VAR_NAME_LEN256+1, FatalError);
                ParseStringForTokens (',', varsList, vars);  
              } else {
                DisplayError ("Illegal list of `include' or 'exclude' option.");
                qopError = TRUE;
              }
            }
            cdf_FreeMemory (tmp, FatalError);
          }
        }
      }
      /************************************************************************
      * Check for 'controlsettings' qualifier.
      ************************************************************************/
      if (qop->qualEntered[SETTINGSSEQUENCEqual]) {
        if (!qop->qualEntered[SETTINGSqual]) {
          FILE *fp = fopen (settingsFile, "r");
          if (fp == NULL) {
            DisplayError ("Missing settings file. ");
            qopError = TRUE;
          } else {
            fclose(fp);
            outputVars = 2L;
          }
        } else
          outputVars = 2L;
      } else
        outputVars = 0L;
      /************************************************************************
      * Check for `zMode' qualifier.
      ************************************************************************/
      if (qop->qualEntered[ZMODEqual]) {
	if (!strcmp(qop->qualOpt[ZMODEqual],"0"))
	  zMode = zMODEoff;
	else
	  if (!strcmp(qop->qualOpt[ZMODEqual],"1"))
	    zMode = zMODEon1;
	  else
	    if (!strcmp(qop->qualOpt[ZMODEqual],"2"))
	      zMode = zMODEon2;
	    else {
	      DisplayError ("Illegal zMode.");
	      qopError = TRUE;
	    }
      } else
        if (cdaweb) zMode = zMODEon2;
      /************************************************************************
      * Check for `ziso8601' qualifier.
      ************************************************************************/
      if (qop->qualEntered[ZISO8601qual]) {
	  ziso8601 = TRUE;
      }	else
	  ziso8601 = FALSE;
      if (!ziso8601) opt.epochStyle = DEFAULTstyleEXPORT;
      else opt.epochStyle = EPOCH3_STYLE;
      /************************************************************************
      * Check for `novalidate' qualifier.
      ************************************************************************/
      if (qop->qualEntered[NOVALIDATEqual]) {
	toValidate = FALSE;
      }	else
	toValidate = TRUE;
      /************************************************************************
      * Check for `initial' qualifier.
      ************************************************************************/
      if (qop->qualEntered[INITIALqual]) {
	char *option, *parenPtr, *commaPtr, *nextPtr; int which;
	static char *validOptions[] = {
	  "format", "noformat", "filter", "nofilter", "fillval", "nofillval",
	  "single", "multi", "host", "network", "epoch", "epoch1", "epoch2",
	  "epoch3", "epochf", "epochx", "horizontal", "vertical", "record",
	  "norecord", "indices", "noindices", "row", "column", "validmin",
	  "novalidmin", "monoton", "nomonoton", "validmax", "novalidmax",
	  "fills", "nofills", "exclusive", "noexclusive", "output", "nooutput",
	  "delete", "nodelete", "preallocate", "nopreallocate", "heading",
	  "noheading", "iso8601", "poundedheading", "ziso8601", "novalidate",
          NULL
	};
	/**********************************************************************
	* If VMS-style QOPs, "remove" beginning and ending parenthesis.  Also,
	* remove any white space in the list of options.
	**********************************************************************/
	if (qop->qualOpt[INITIALqual][0] == '(') {
	  option = &(qop->qualOpt[INITIALqual][1]);
	  parenPtr = strchr (option, ')');
	  if (parenPtr != NULL) *parenPtr = NUL;
	}
	else
	  option = qop->qualOpt[INITIALqual];
	RemoveWhiteSpace (option);
	/**********************************************************************
	* Scan comma-separated list of options.
	**********************************************************************/
	while (*option != NUL) {
	  /********************************************************************
	  * Location the end of the current option.  This will be either a
	  * comma or a NUL (if the last option).  Also set the pointer to the
	  * next option.
	  ********************************************************************/
	  commaPtr = strchr (option, ',');
	  if (commaPtr != NULL) {
	    *commaPtr = NUL;
	    nextPtr = commaPtr + 1;
	  }
	  else
	    nextPtr = option + strlen(option);
	  /********************************************************************
	  * Validate/set the current option.
	  ********************************************************************/
	  which = MatchOption (option, validOptions);
	  switch (which) {
	    case UNKNOWNopt: {
	      char msg[MAX_MESSAGE_TEXT_LEN+1];
	      snprintf (msg, (size_t) sizeof(msg),
		        "Unknown `initial' option: \"%s\"", option);
	      DisplayError (msg);
	      qopError = TRUE;
	      break;
	    }
	    case AMBIGUOUSopt: {
	      char msg[MAX_MESSAGE_TEXT_LEN+1];
	      snprintf (msg, (size_t) sizeof(msg),
		        "Ambiguous `initial' option: \"%s\"", option);
	      DisplayError (msg);
	      qopError = TRUE;
	      break;
	    }
	    case FILTERopt:
	    case NOFILTERopt:
	    case FILLSopt:
	    case NOFILLSopt:
	    case FILLVALopt:
	    case NOFILLVALopt:
	    case VALIDMINopt:
	    case NOVALIDMINopt:
	    case VALIDMAXopt:
	    case NOVALIDMAXopt:
	    case MONOTONopt:
	    case NOMONOTONopt:
	    case SINGLEopt:
	    case MULTIopt:
	    case HOSTopt:
	    case NETWORKopt:
	    case EXCLUSIVEopt:
	    case NOEXCLUSIVEopt:
	    case DELETEopt:
	    case NODELETEopt:
	    case PREALLOCATEopt:
	    case NOPREALLOCATEopt:
	      if (simpleMode) {
		char msg[MAX_MESSAGE_TEXT_LEN+1];
		snprintf (msg, (size_t) sizeof(msg),
		         "Illegal `initial' option: \"%s\"", option);
		DisplayError (msg);
		qopError = TRUE;
	      }
	      else {
		switch (which) {
		    case FILTERopt: opt.eachFilter = TRUE; break;
		    case NOFILTERopt: opt.eachFilter = FALSE; break;
		    case FILLSopt: opt.useFills = TRUE; break;
		    case NOFILLSopt: opt.useFills = FALSE; break;
		    case FILLVALopt: opt.useFILLVAL = TRUE; break;
		    case NOFILLVALopt: opt.useFILLVAL = FALSE; break;
		    case VALIDMINopt: opt.useVALIDMIN = TRUE; break;
		    case NOVALIDMINopt: opt.useVALIDMIN = FALSE; break;
		    case VALIDMAXopt: opt.useVALIDMAX = TRUE; break;
		    case NOVALIDMAXopt: opt.useVALIDMAX = FALSE; break;
		    case MONOTONopt: opt.useMONOTON = TRUE; break;
		    case NOMONOTONopt: opt.useMONOTON = FALSE; break;
		    case SINGLEopt: opt.singleFile = TRUE; break;
		    case MULTIopt: opt.singleFile = FALSE; break;
		    case HOSTopt: opt.encoding = HOST_ENCODING; break;
		    case NETWORKopt: opt.encoding = NETWORK_ENCODING; break;
		    case EXCLUSIVEopt: opt.exclusive = TRUE; break;
		    case NOEXCLUSIVEopt: opt.exclusive = FALSE; break;
		    case DELETEopt: opt.deleteExisting = TRUE; break;
		    case NODELETEopt: opt.deleteExisting = FALSE; break;
		    case PREALLOCATEopt: opt.preAllocate = TRUE; break;
		    case NOPREALLOCATEopt: opt.preAllocate = FALSE; break;
		}
	      }
	      break;
	    case FORMATopt: opt.useFORMAT = TRUE; break;
	    case NOFORMATopt: opt.useFORMAT = FALSE; break;
	    case EPOCHopt: opt.epochStyle = EPOCH0_STYLE; break;
	    case EPOCH1opt: opt.epochStyle = EPOCH1_STYLE; break;
	    case EPOCH2opt: opt.epochStyle = EPOCH2_STYLE; break;
	    case EPOCH3opt: opt.epochStyle = EPOCH3_STYLE; break;
	    case ISO8601opt: opt.epochStyle = EPOCH4_STYLE; break;
	    case ZISO8601opt: opt.epochStyle = EPOCH3_STYLE; break;
	    case EPOCHFopt: opt.epochStyle = EPOCHf_STYLE; break;
	    case EPOCHXopt: opt.epochStyle = EPOCHx_STYLE; break;
	    case HORIZONTALopt: opt.horizontalMode = TRUE; break;
	    case VERTICALopt: opt.horizontalMode = FALSE; break;
	    case RECORDopt: opt.showRecord = TRUE; break;
	    case NORECORDopt: opt.showRecord = FALSE; break;
	    case INDICESopt: opt.showIndices = TRUE; break;
	    case NOINDICESopt: opt.showIndices = FALSE; break;
	    case ROWopt: opt.majority = ROW_MAJOR; break;
	    case COLUMNopt: opt.majority = COLUMN_MAJOR; break;
	    case OUTPUTopt: opt.outputItem = TRUE; break;
	    case NOOUTPUTopt: opt.outputItem = FALSE; break;
	    case HEADINGopt: opt.textHeading = TRUE; poundedheading = 0; break;
	    case NOHEADINGopt: opt.textHeading = FALSE; break;
            case POUNDEDHEADINGopt: opt.textHeading = TRUE; poundedheading = 1;
                                    break;
	  }
	  /********************************************************************
	  * Move to the next option.
	  ********************************************************************/
	  option = nextPtr;
	}
      }
      /************************************************************************
      * Check for a parameter (the CDF[s]).
      ************************************************************************/
      switch (qop->Nparms) {
	case 0:
	  if (!prompt) {
	    DisplayError ("Missing parameter [CDF(s) specification].");
	    qopError = TRUE;
	  }
	  break;
	case 1:
	  strcpyX (CDFspec, qop->parms[CDFparm], DU_MAX_PATH_LEN);
	  break;
	default:
	  DisplayError ("Too many parameters.");
	  qopError = TRUE;
      }
      /************************************************************************
      * Free QOP memory and return if an error was detected.
      ************************************************************************/
      cdf_FreeMemory (qop, FatalError);
      if (qopError) return FALSE;
      break;
    }
  }

#ifndef WIN32
  setlocale(LC_CTYPE, "en_us.UTF-8");
#else
  setlocale(LC_CTYPE, ".UTF8");
  oldCodePage = GetConsoleOutputCP();
  SetConsoleOutputCP(65001);
#endif

  /****************************************************************************
  * Depending on batch mode...
  ****************************************************************************/
  if (!BATCH(batchMode)) {
    /**************************************************************************
    * Initialize screen.
    **************************************************************************/
    create_pasteboard ();
    set_cursor_mode (CURSORoff);
    /**************************************************************************
    * Export from CDFs until the cows come home.
    **************************************************************************/
    CDFexportMenu (CDFspec, prompt, zMode, negToPosFp0);
    /**************************************************************************
    * Cleanup screen and return.
    **************************************************************************/
    delete_pasteboard (ERASE);
    set_cursor_mode (CURSORon);
  } else {
    /**************************************************************************
    * Batch mode...
    **************************************************************************/
    CDFid id; CDFstatus status; Logical noMoreAccess = FALSE;
    /**************************************************************************
    * Validate.
    **************************************************************************/
    if (IsDir(CDFspec) || IsWild(CDFspec)) {
      DisplayError ("A single CDF must be specified in batch mode.");
      return FALSE;
    }
    if (!toValidate) CDFsetValidate (VALIDATEFILEoff);
    /**************************************************************************
    * Open the CDF.
    **************************************************************************/
    status = CDFlib (OPEN_, CDF_, CDFspec, &id,
		     NULL_);
    DisplayStatus (status, "opening CDF");
    if (StatusBAD(status)) return FALSE;
    /**************************************************************************
    * Set CDF modes and cache sizes.
    **************************************************************************/
    status = CDFlib (SELECT_, CDF_zMODE_, zMode,
			      CDF_CACHESIZE_, workingCache,
			      STAGE_CACHESIZE_, stageCache,
			      COMPRESS_CACHESIZE_, compressCache,
			      CDF_NEGtoPOSfp0_MODE_, BOO(negToPosFp0,
							 NEGtoPOSfp0on,
							 NEGtoPOSfp0off),
		     NULL_);
    DisplayStatus (status, "setting CDF modes");
    if (StatusBAD(status)) {
      CDFclose (id);
      return FALSE;
    }
    /**************************************************************************
    * Load the CDF.
    **************************************************************************/
    if (!LoadCDF(id)) {
      CDFclose (id);
      FreeItems ();
      return FALSE;
    }
    /**************************************************************************
    * Load settings file.
    **************************************************************************/
    if (includeVars == 0L) RestoreSettings ();
    /**************************************************************************
    * Generate CDF/listing.
    **************************************************************************/
    switch (batchMode) {
      case BATCHcdf:
	if (!ToCDF(id)) noMoreAccess = TRUE;
	break;
      case BATCHtext:
	if (!cdaweb) {
	  if (!BOO(opt.horizontalMode,ToFileHori(),
				      ToFileVert())) noMoreAccess = TRUE;
	} else
	  if (!ToFileCDAweb()) noMoreAccess = TRUE;
	break;
    }
    /**************************************************************************
    * Close CDF.
    **************************************************************************/
    if (dumpStats && !noMoreAccess) {
      vSTATS vStatsDotCDF, vStatsStage, vStatsCompress;
      char temp1[MAX_SCREENLINE_LEN+1],
	   temp2[MAX_SCREENLINE_LEN+1],
	   temp3[MAX_SCREENLINE_LEN+1];
      status = CDFlib (CLOSE_, CDFwithSTATS_, &vStatsDotCDF,
					      &vStatsStage,
					      &vStatsCompress,
		       NULL_);
      DisplayStatus (status, "closing CDF");
      if (vStatsDotCDF.maxBuffers > 0) {
	BuildStatistics ("input CDF DotCDF file", &vStatsDotCDF,
			 temp1, temp2, temp3);
	printf ("%s\n%s\n%s\n", temp1, temp2, temp3);
      }
      if (vStatsStage.maxBuffers > 0) {
	BuildStatistics ("input CDF staging file", &vStatsStage,
			 temp1, temp2, temp3);
	printf ("%s\n%s\n%s\n", temp1, temp2, temp3);
      }
      if (vStatsCompress.maxBuffers > 0) {
	BuildStatistics ("input CDF compression scratch file", &vStatsCompress,
			 temp1, temp2, temp3);
	printf ("%s\n%s\n%s\n", temp1, temp2, temp3);
      }
    }
    else{
      status = CDFlib (CLOSE_, CDF_,
		       NULL_);
      DisplayStatus (status, "closing CDF");
    }
    /**************************************************************************
    * Free memory.
    **************************************************************************/
    FreeItems ();
  }
  return TRUE;
}

/******************************************************************************
* CDFexportMenu.
******************************************************************************/

void CDFexportMenu (iniSpec, prompt, zMode, negToPosFp0)
char *iniSpec;          /* Initial specification. */
Logical prompt;         /* Was the `prompt' qualifier specified? */
long zMode;             /* zMode to use. */
Logical negToPosFp0;    /* TRUE if -0.0 should be converted to 0.0. */
{
  char path[CDFfieldMAX+1]; static Logical first = TRUE;
  /****************************************************************************
  * CDFwindow definitions.
  ****************************************************************************/
  static char *cdfLabel[2] = { " CDFexport ", " CDFexport (SimpleMode) "};
  AOSs2A (cdfLines,
    "CDF(s):                                                                       ",
    BLANKs78)
  AOSs1 (cdfFields, BLANKs255)
  static int cdfLineNs[] = { CDFfieldLINEn };
  static int cdfCols[] = { CDFfieldCOLn };
  static int cdfLens[] = { CDFfieldLEN };
  static int cdfMaxs[] = { CDFfieldMAX };
  static int cdfExits[] = { ENTERkey_FSI, HELPkey_FSI, EXITkey_FSI, NUL };
  static struct FieldWindowStruct FWcdf_ = {
    0, 0, SCREEN_WIDTH, NULL, 0, NULL, 2, cdfLines, cdfFields, 1, cdfLineNs,
    cdfCols, cdfLens, cdfMaxs, 2, 0, NULL, cdfExits, REFRESHkey_FSI, FALSE,
    NUL, NUL, INSERTorOVERkey_FSI
  };
  /****************************************************************************
  * SelectionWindow definitions.
  ****************************************************************************/
  static char *varLabel[2] = {
    " SelectionWindow, part 0 ",
    " SelectionWindow "
  };
  static char *varHeader[] = { "" };
  static struct ItemWindowStruct IWsel_ = {
    4, 0, SCREEN_WIDTH, NULL, 1, varHeader, 0, NULL, 0, NULL, NULL, NULL,
    NULL, 9, 0, NULL, NULL, REFRESHkey_FSI, TRUE, NSkey_FSI, PSkey_FSI
  };
  /****************************************************************************
  * KeyWindow definitions.
  ****************************************************************************/
  static char keyDefsBlank[] = "\n\n";
  static char keyDefsPrompt[] = {
    "Open: ________    Help: ________    Exit: ________\n\n"
  };
  static struct EditWindowStruct EWkey_ = {
    " KeyDefinitions ", 17, 0, SCREEN_WIDTH, 0, NULL, keyDefsBlank, 2,
    0, NULL, FALSE, TRUE, NULL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
    NUL
  };
  /****************************************************************************
  * MessageWindow definitions.
  ****************************************************************************/
  static char msgLines[] = BLANKs78;
  static int msgExits[] = { NUL };
  static struct EditWindowStruct EWmsg_ = {
    " MessageBuffer ", 21, 0, SCREEN_WIDTH, 0, NULL, msgLines, 1, 0, NULL,
    FALSE, TRUE, msgExits, REFRESHkey_FSI, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
    NUL
  };
  /****************************************************************************
  * Initialize global variables.
  ****************************************************************************/
  itemHead = NULL;
  FWcdf = &FWcdf_;
  IWsel = &IWsel_;
  EWkey = &EWkey_;
  EWmsg = &EWmsg_;
  /****************************************************************************
  * Initialize CDFwindow and encode key definitions.
  ****************************************************************************/
  strcpyX (FWcdf->fields[0], iniSpec, CDFfieldMAX);
  if (first) {
    char *p1 = keyDefsPrompt;
    EncodeKeyDefinitions (1, &p1, ENTERkey_FSI, HELPkey_FSI, EXITkey_FSI);
    FWcdf->label = cdfLabel[BOO(simpleMode,1,0)];
    IWsel->label = varLabel[BOO(simpleMode,1,0)];
    first = FALSE;
  }
  /****************************************************************************
  * Display menu widgets.
  ****************************************************************************/
  FieldWindow (NEWfw, FWcdf, 0, LogicalTRUE);
  ItemWindow (NEWiw, IWsel, 0);
  EditWindow (NEWew, EWkey, LogicalTRUE);
  EditWindow (NEWew, EWmsg, LogicalTRUE);
  /****************************************************************************
  * Determine/export CDF.
  ****************************************************************************/
  if (prompt) {
    NEWkeyDEFS (EWkey, keyDefsPrompt, batchMode)
    FieldWindow (READfw, FWcdf);
  }
  else
    FWcdf->key = ENTERkey_FSI;
  for (;;) {
     switch (FWcdf->key) {
       case ENTERkey_FSI:
	 strcpyX (path, FWcdf->fields[0], CDFfieldMAX);
	 if (IsCDF(path)) {
	   ExportCDF (path, zMode, negToPosFp0);
	   MakeNUL (FWcdf->fLines[CDFvarsRecsLINEn]);
	   FieldWindow (UPDATEfw, FWcdf, 0, LogicalTRUE);
	   IWsel->label = varLabel[BOO(simpleMode,1,0)];
	   IWsel->hLines = varHeader;
	   ItemWindow (UPDATEiw, IWsel, 0);
	 }
	 else
	   if (IsDir(path) || IsWild(path))
	     ExportCDFsSpec (path, zMode, negToPosFp0,
			     varLabel[BOO(simpleMode,1,0)], varHeader);
	   else
	     DisplayMessage ("No CDFs found for specification.", BEEPWAIT1);
	 break;
       case HELPkey_FSI:
	 OnlineHelpWindow ("cdfxp.ilh", CDFhelpID);
	 break;
       case EXITkey_FSI:
	 FieldWindow (DELETEfw, FWcdf);
	 ItemWindow (DELETEiw, IWsel);
	 EditWindow (DELETEew, EWkey);
	 EditWindow (DELETEew, EWmsg);
	 return;
     }
     NEWkeyDEFS (EWkey, keyDefsPrompt, batchMode)
     FieldWindow (READfw, FWcdf);
  }
}

/******************************************************************************
* ExportCDFsSpec.
******************************************************************************/

void ExportCDFsSpec (path, zMode, negToPosFp0, varLabel0, varHeader0)
char *path;
long zMode;
Logical negToPosFp0;
char *varLabel0;
char *varHeader0[];
{
  Logical first = TRUE;
  int nCDFs, CDFn;
  char **dirS, **CDFs;
  static int exitCDFs[] = { ENTERkey_FSI, HELPkey_FSI, EXITkey_FSI, NUL };
  static struct ItemWindowStruct IWcdfs = {
    1, 79 - CDFnameLEN - 2, CDFnameLEN + 2, " Select a CDF ", 0, NULL, 0,
    NULL, 0, NULL, NULL, NULL, NULL, 13, 0, NULL, exitCDFs, REFRESHkey_FSI,
    TRUE, NUL, NUL
  };
  static char keyDefs[] = {
    "Open: ________    Help: ________    Exit: ________\n\n"
  };
  /****************************************************************************
  * Encode key definitions first time.
  ****************************************************************************/
  if (first) {
    char *p1 = keyDefs;
    EncodeKeyDefinitions (1, &p1, ENTERkey_FSI, HELPkey_FSI, EXITkey_FSI);
    first = FALSE;
  }
  /****************************************************************************
  * Get directory listing of CDFs.
  ****************************************************************************/
  nCDFs = CDFdirList (path, &dirS, &CDFs);
  if (nCDFs < 1) {
    DisplayMessage ("No CDFs found for specification.", BEEPWAIT1);
    return;
  }
  /****************************************************************************
  * Allocate/load CDFs.
  ****************************************************************************/
  AllocIW (&IWcdfs, nCDFs, nCDFs, IWcdfs.nColsTotal - 2, FatalError);
  for (CDFn = 0; CDFn < nCDFs; CDFn++) {
     strcpyX (IWcdfs.iLines[CDFn], CDFs[CDFn], IWcdfs.nColsTotal - 2);
     IWcdfs.iLineNs[CDFn] = CDFn;
     IWcdfs.iCols[CDFn] = 0;
     IWcdfs.iLens[CDFn] = CDFnameLEN;
  }
  /****************************************************************************
  * Select a CDF.
  ****************************************************************************/
  ItemWindow (NEWiw, &IWcdfs, 0);
  NEWkeyDEFS (EWkey, keyDefs, batchMode)
  for (;;) {
     ItemWindow (READiw, &IWcdfs);
     switch (IWcdfs.key) {
       case ENTERkey_FSI: {
	 char pathX[CDF_PATHNAME_LEN+1];
	 strcpyX (pathX, dirS[IWcdfs.itemN], CDF_PATHNAME_LEN);
	 AppendToDir (pathX, CDFs[IWcdfs.itemN]);
	 ItemWindow (UNDISPLAYiw, &IWcdfs);
	 ExportCDF (pathX, zMode, negToPosFp0);
	 strcpyX (FWcdf->fields[0], path, CDFfieldMAX);
	 MakeNUL (FWcdf->fLines[CDFvarsRecsLINEn]);
	 FieldWindow (UPDATEfw, FWcdf, 0, LogicalTRUE);
	 IWsel->label = varLabel0;
	 IWsel->hLines = varHeader0;
	 ItemWindow (UPDATEiw, IWsel, 0);
	 NEWkeyDEFS (EWkey, keyDefs, batchMode)
	 ItemWindow (REDISPLAYiw, &IWcdfs);
	 break;
       }
       case HELPkey_FSI:
	 OnlineHelpWindow ("cdfxp.ilh", CDFShelpID);
	 break;
       case EXITkey_FSI:
	 ItemWindow (DELETEiw, &IWcdfs);
	 FreeIW (&IWcdfs, FatalError);
	 cdf_FreeMemory (CDFs, FatalError);
	 cdf_FreeMemory (dirS, FatalError);
	 return;
     }
  }
}

/******************************************************************************
* ExportCDF.
******************************************************************************/

void ExportCDF (path, zMode, negToPosFp0)
char *path;
long zMode;
Logical negToPosFp0;
{
  CDFid id; CDFstatus status; Logical noMoreAccess = FALSE;
  static char keyDefsBlank[] = "\n\n";
  /****************************************************************************
  * Erase key definitions while loading.
  ****************************************************************************/
  NEWkeyDEFS (EWkey, keyDefsBlank, batchMode)
  if (!toValidate) CDFsetValidate (VALIDATEFILEoff);
  /****************************************************************************
  * Open CDF.
  ****************************************************************************/
  DisplayMessage ("Opening CDF...", NOWAIT);
  status = CDFlib (OPEN_, CDF_, path, &id,
		   NULL_);
  DisplayStatus (status, "opening CDF");
  if (StatusBAD(status)) return;
  /****************************************************************************
  * Select CDF modes, etc.
  ****************************************************************************/
  status = CDFlib (SELECT_, CDF_zMODE_, zMode,
			    CDF_CACHESIZE_, workingCache,
			    STAGE_CACHESIZE_, stageCache,
			    COMPRESS_CACHESIZE_, compressCache,
			    CDF_NEGtoPOSfp0_MODE_, BOO(negToPosFp0,
						       NEGtoPOSfp0on,
						       NEGtoPOSfp0off),
		   NULL_);
  DisplayStatus (status, "setting CDF modes");
  if (StatusBAD(status)) {
    CDFclose (id);
    return;
  }

  /****************************************************************************
  * Inquire CDF and load/update widgets.
  ****************************************************************************/
  DisplayMessage ("Loading CDF...", NOWAIT);
  if (!LoadCDF(id)) {
    CDFclose (id);
    FreeItems ();
    return;
  }
  LoadCDFwindow (path);
  FieldWindow (UPDATEfw, FWcdf, 0, LogicalTRUE);
  /****************************************************************************
  * Process keystrokes.
  ****************************************************************************/
  DisplayMessage ("", NOWAIT);
  if (simpleMode)
    SelectionWindow (&noMoreAccess);
  else {
    for (;;) {
       if (!SelectionWindow1(&noMoreAccess)) break;
       if (!SelectionWindow2(&noMoreAccess)) break;
       if (!SelectionWindow3(&noMoreAccess)) break;
       if (!SelectionWindow4(&noMoreAccess)) break;
    }
  }
  if (noMoreAccess) {
    NEWkeyDEFS (EWkey, keyDefsBlank, batchMode)
    InfoWindow ("Access to this CDF has been aborted.",
		NULL, NULL, TRUE, TRUE, 1);
  }
  /****************************************************************************
  * Exit this CDF.
  ****************************************************************************/
  FreeItems ();
  FreeIW (IWsel, FatalError);
  if (dumpStats && !noMoreAccess) {
    vSTATS vStatsDotCDF, vStatsStage, vStatsCompress;
    char temp1[MAX_SCREENLINE_LEN+1],
	 temp2[MAX_SCREENLINE_LEN+1],
	 temp3[MAX_SCREENLINE_LEN+1];
    status = CDFlib (CLOSE_, CDFwithSTATS_, &vStatsDotCDF,
					    &vStatsStage,
					    &vStatsCompress,
		     NULL_);
    DisplayStatus (status, "closing CDF");
    if (vStatsDotCDF.maxBuffers > 0) {
      BuildStatistics ("input CDF DotCDF file", &vStatsDotCDF,
		       temp1, temp2, temp3);
      InfoWindow (temp1, temp2, temp3, FALSE, FALSE, 0);
    }
    if (vStatsStage.maxBuffers > 0) {
      BuildStatistics ("input CDF staging file", &vStatsStage,
		       temp1, temp2, temp3);
      InfoWindow (temp1, temp2, temp3, FALSE, FALSE, 0);
    }
    if (vStatsCompress.maxBuffers > 0) {
      BuildStatistics ("input CDF compression scratch file", &vStatsCompress,
		       temp1, temp2, temp3);
      InfoWindow (temp1, temp2, temp3, FALSE, FALSE, 0);
    }
  } else {
    status = CDFlib (CLOSE_, CDF_,
		     NULL_);
    DisplayStatus (status, "closing CDF");
  }
  return;
}

/******************************************************************************
* LoadCDFwindow.
******************************************************************************/

void LoadCDFwindow (path)
char *path;
{
  if (path != NULL) strcpyX (FWcdf->fields[0], path, CDFfieldMAX);
  if (simpleMode)
    snprintf (FWcdf->fLines[CDFvarsRecsLINEn], (size_t) sizeof(BLANKs78),
	      "Variables: %ld, Records: %ld", (long) (NrVars + NzVars),
	      (long) (MAXIMUM(rMaxRec,zMaxRec) + 1));
  else
    snprintf (FWcdf->fLines[CDFvarsRecsLINEn], (size_t) sizeof(BLANKs78),
	      "Variables: %ldr/%ldz, Records: %ldr/%ldz, Compression: %s, Checksum: %s",
	      NrVars, NzVars, (long) (rMaxRec + 1), (long) (zMaxRec + 1),
	      CompressionToken(CDFcType,CDFcParms), ChecksumToken(CDFchecksum));
  return;
}

/******************************************************************************
* LoadCDF.
*
* Some of the values loaded aren't really necessary if `simple' mode has been
* selected.
******************************************************************************/

Logical LoadCDF (CDFid id) {
  CDFstatus status; char varName[CDF_VAR_NAME_LEN256+1];
  long eDataType, eNumElems, cPct, sArraysPct;
  int varX, lineL = SCREEN_WIDTH - 2, nVars, dimN;
  struct ItemStruct *Item, *itemTail = NULL;
  static char readingCDF[] = "reading input CDF";
  int ix;
  /****************************************************************************
  * Initialize.
  ****************************************************************************/
  nItems = 0;
  numEpochs = 0;
  /****************************************************************************
  * Inquire/check number of variables.
  ****************************************************************************/
  status = CDFlib (GET_, CDF_NUMrVARS_, &NrVars,
			 CDF_NUMzVARS_, &NzVars,
		   NULL_);
  DisplayStatus (status, readingCDF);
  if (StatusBAD(status)) return FALSE;
  nVars = (int) (NrVars + NzVars);
  if (includeVars == 2L) numVarsO = nVars;
  if (nVars == 0) {
    DisplayMessage ("Error loading CDF.", BEEPWAIT1);
    DisplayMessage ("CDF contains no variables.", BEEPWAIT1);
    return FALSE;
  }
  if (outputVars == 2L) {
    vars =
     (char **) cdf_AllocateMemory ((size_t)sizeof(char *) * nVars, FatalError);
    for (ix = 0; ix < nVars; ++ix) vars[ix] = NULL;
    numVars = 0;
  }
  /****************************************************************************
  * Inquire/check number of records.
  ****************************************************************************/
  status = CDFlib (GET_, rVARs_MAXREC_, &rMaxRec,
			 zVARs_MAXREC_, &zMaxRec,
		   NULL_);
  DisplayStatus (status, readingCDF);
  if (StatusBAD(status)) return FALSE;
  if (MAXIMUM(rMaxRec,zMaxRec) < 0) {
    DisplayMessage ("Error loading CDF.", BEEPWAIT1);
    DisplayMessage ("CDF contains no records.", BEEPWAIT1);
    return FALSE;
  }
  /****************************************************************************
  * Load CDF compression.
  ****************************************************************************/
  status = CDFlib (GET_, CDF_COMPRESSION_, &CDFcType, CDFcParms, &cPct,
		   NULL_);
  DisplayStatus (status, readingCDF);
  if (StatusBAD(status)) return FALSE;
  /****************************************************************************
  * Load CDF checksum.
  ****************************************************************************/
  status = CDFlib (GET_, CDF_CHECKSUM_, &CDFchecksum, 
                   NULL_);
  DisplayStatus (status, readingCDF);
  if (StatusBAD(status)) return FALSE;
  /****************************************************************************
  * Load records/indices.
  ****************************************************************************/
  if (opt.showRecord) {
    Item = (struct ItemStruct *)
         cdf_AllocateMemory ((size_t)sizeof(struct ItemStruct), FatalError);
    Item->type = RECORDt;
    Item->width = MIN_RECORD_WIDTH;
    Item->outputSetting = opt.outputItem;
    Item->filterSetting = opt.eachFilter;
    Item->inclusive = TRUE;
    Item->nextItem = NULL;
    Item->Record = (struct RecordStruct *)
        cdf_AllocateMemory ((size_t)sizeof(struct RecordStruct), FatalError);
    Item->Record->min = NOminMax;
    Item->Record->max = NOminMax;
    itemHead = Item;
    itemTail = Item;
    nItems++;
  }
  if (opt.showIndices) {
    Item = (struct ItemStruct *)
	   cdf_AllocateMemory ((size_t)sizeof(struct ItemStruct), FatalError);
    Item->type = INDICESt;
    Item->width = MIN_INDICES_WIDTH;
    Item->outputSetting = opt.outputItem;
    Item->filterSetting = opt.eachFilter;
    Item->inclusive = TRUE;
    Item->nextItem = NULL;
    Item->Indices = (struct IndicesStruct *)
        cdf_AllocateMemory ((size_t)sizeof(struct IndicesStruct), FatalError);
    Item->Indices->minNumDims = NOminMax;
    Item->Indices->maxNumDims = NOminMax;
    if (itemHead == NULL)
      itemHead = Item;
    else
      itemTail->nextItem = Item;
    itemTail = Item;
    nItems++;
  }
  /****************************************************************************
  * Load variables.
  ****************************************************************************/
  for (varX = 0; varX < nVars; varX++) {
     /*************************************************************************
     * Allocate a variable structure and an Item structure and place on linked
     * list.
     *************************************************************************/
     Item = (struct ItemStruct *)
	    cdf_AllocateMemory ((size_t)sizeof(struct ItemStruct), FatalError);
     Item->type = VARIABLEt;
     Item->outputSetting = opt.outputItem;
     Item->filterSetting = FALSE;               /* Reset below... */
     Item->inclusive = TRUE;
     Item->Var = (struct VarStructXP *) cdf_AllocateMemory (
                                            (size_t)sizeof(struct VarStructXP),
					    FatalError);
     Item->nextItem = NULL;
     if (itemHead == NULL)
       itemHead = Item;
     else
       itemTail->nextItem = Item;
     itemTail = Item;
     /*************************************************************************
     * Initialize variable structure.
     *************************************************************************/
     Item->Var->zVar = (varX >= NrVars);
     Item->Var->varN = BOO(varX >= NrVars,varX - NrVars,varX);
     Item->Var->min = NULL;
     Item->Var->max = NULL;
     Item->Var->format = NULL;
     Item->Var->fill = NULL;
     Item->Var->pad = NULL;
     Item->Var->value = NULL;
     /*************************************************************************
     * Load variable dimensionality, variances, data type/number of elements,
     * maximum record written, sparseness, compression, and blocking factor.
     *************************************************************************/
     status = CDFlib (SELECT_, BOO(Item->Var->zVar,
				   zVAR_,rVAR_), Item->Var->varN,
                      GET_, BOO(Item->Var->zVar,
				zVAR_NUMDIMS_,
				rVARs_NUMDIMS_), &(Item->Var->numDims),
			    BOO(Item->Var->zVar,
				zVAR_DIMSIZES_,
				rVARs_DIMSIZES_), Item->Var->dimSizes,
			    BOO(Item->Var->zVar,
				zVAR_DATATYPE_,
				rVAR_DATATYPE_), &(Item->Var->dataType),
			    BOO(Item->Var->zVar,
				zVAR_NUMELEMS_,
				rVAR_NUMELEMS_), &(Item->Var->numElems),
			    BOO(Item->Var->zVar,
				zVAR_MAXREC_,
				rVAR_MAXREC_), &(Item->Var->maxRec),
			    BOO(Item->Var->zVar,
				zVAR_RECVARY_,
				rVAR_RECVARY_), &(Item->Var->recVary),
			    BOO(Item->Var->zVar,
				zVAR_DIMVARYS_,
				rVAR_DIMVARYS_), Item->Var->dimVarys,
			    BOO(Item->Var->zVar,
				zVAR_SPARSERECORDS_,
				rVAR_SPARSERECORDS_),
						&(Item->Var->sRecordsType),
			    BOO(Item->Var->zVar,
				zVAR_SPARSEARRAYS_,
				rVAR_SPARSEARRAYS_), &(Item->Var->sArraysType),
						     Item->Var->sArraysParms,
						     &sArraysPct,
			    BOO(Item->Var->zVar,
				zVAR_COMPRESSION_,
				rVAR_COMPRESSION_), &(Item->Var->cType),
						    Item->Var->cParms, &cPct,
			    BOO(Item->Var->zVar,
				zVAR_BLOCKINGFACTOR_,
				rVAR_BLOCKINGFACTOR_), &(Item->Var->blocking),
		      NULL_);
     DisplayStatus (status, readingCDF);
     if (StatusBAD(status)) return FALSE;
     /*************************************************************************
     * Load reserve percentage.
     *************************************************************************/
     if (Item->Var->cType == NO_COMPRESSION)
       Item->Var->reserve = NA_RESERVE;
     else {
       status = CDFlib (CONFIRM_, BOO(Item->Var->zVar,
				      zVAR_RESERVEPERCENT_,
				      rVAR_RESERVEPERCENT_),
							&(Item->Var->reserve),
			NULL_);
       DisplayStatus (status, readingCDF);
       if (StatusBAD(status)) return FALSE;
     }
     /*************************************************************************
     * Calculate the number of values per variable record (conceptual) and
     * the number of bytes per value.
     *************************************************************************/
     Item->Var->nRecordValues = 1;
     for (dimN = 0; dimN < Item->Var->numDims; dimN++) {
	Item->Var->nRecordValues *= Item->Var->dimSizes[dimN];
     }
     Item->Var->nValueBytes =
	    (size_t) (CDFelemSize(Item->Var->dataType) * Item->Var->numElems);
     /*************************************************************************
     * Load variable name.
     *************************************************************************/
     status = CDFlib (GET_, BOO(Item->Var->zVar,
				zVAR_NAME_,rVAR_NAME_), varName,
		      NULL_);
     DisplayStatus (status, readingCDF);
     if (StatusBAD(status)) return FALSE;
     RemoveTrailingBlanks (varName);
     Item->Var->name = (char *) cdf_AllocateMemory ((size_t)strlen(varName) + 1,
						FatalError);
     strcpyX (Item->Var->name, varName, 0);
     if (Item->Var->dataType == CDF_EPOCH ||
         Item->Var->dataType == CDF_EPOCH16 ||
         Item->Var->dataType == CDF_TIME_TT2000) {
       if (strcmpIgCase(Item->Var->name, "epoch") == 1 ||
           strcmpIgCase(Item->Var->name, "range_epoch") == 1) {
           if (IsaVirtualVariable(Item->Var->zVar, Item->Var->name)) 
             ++numEpochs;
       }
     }
     /*************************************************************************
     * Load VALIDMIN entry.
     *************************************************************************/
     if (opt.useVALIDMIN) {
       status = CDFlib (SELECT_, ATTR_NAME_, "VALIDMIN",
				 BOO(Item->Var->zVar,
				     zENTRY_,rENTRY_), Item->Var->varN,
			GET_, BOO(Item->Var->zVar,
				  zENTRY_DATATYPE_,
				  rENTRY_DATATYPE_), &eDataType,
			      BOO(Item->Var->zVar,
				  zENTRY_NUMELEMS_,
				  rENTRY_NUMELEMS_), &eNumElems,
			NULL_);
       switch (status) {
	 case CDF_OK: {
	   size_t nBytesE = (size_t) (CDFelemSize(eDataType) * eNumElems +
				      (STRINGdataType(eDataType)?1:0));
	   void *buffer = cdf_AllocateMemory (nBytesE, FatalError);
	   status = CDFlib (GET_, BOO(Item->Var->zVar,
				      zENTRY_DATA_,rENTRY_DATA_), buffer,
			    NULL_);
	   DisplayStatus (status, readingCDF);
	   if (StatusBAD(status)) {
	     cdf_FreeMemory (buffer, FatalError);
	     return FALSE;
	   }
	   if (STRINGdataType(eDataType)) *((char *)buffer+eNumElems) = '\0';
	   Item->Var->min = cdf_AllocateMemory ((size_t)Item->Var->nValueBytes,
						FatalError);
	   ConvertDataType (eDataType, eNumElems, buffer, Item->Var->dataType,
			    Item->Var->numElems, Item->Var->min);
	   cdf_FreeMemory (buffer, FatalError);
	   Item->filterSetting = opt.eachFilter;
	   break;
	 }
	 case NO_SUCH_ATTR:
	 case NO_SUCH_ENTRY:
	   break;
	 default:
	   DisplayStatus (status, readingCDF);
	   return FALSE;
       }
     }
     /*************************************************************************
     * Load VALIDMAX.
     *************************************************************************/
     if (opt.useVALIDMAX) {
       status = CDFlib (SELECT_, ATTR_NAME_, "VALIDMAX",
				 BOO(Item->Var->zVar,
				     zENTRY_,rENTRY_), Item->Var->varN,
			GET_, BOO(Item->Var->zVar,
				  zENTRY_DATATYPE_,
				  rENTRY_DATATYPE_), &eDataType,
			      BOO(Item->Var->zVar,
				  zENTRY_NUMELEMS_,
				  rENTRY_NUMELEMS_), &eNumElems,
			NULL_);
       switch (status) {
	 case CDF_OK: {
	   size_t nBytesE = (size_t) (CDFelemSize(eDataType) * eNumElems +
				      (STRINGdataType(eDataType)?1:0));
	   void *buffer = cdf_AllocateMemory (nBytesE, FatalError);
	   status = CDFlib (GET_, BOO(Item->Var->zVar,
				      zENTRY_DATA_,rENTRY_DATA_), buffer,
			    NULL_);
	   DisplayStatus (status, readingCDF);
	   if (StatusBAD(status)) {
	     cdf_FreeMemory (buffer, FatalError);
	     return FALSE;
	   }
	   if (STRINGdataType(eDataType)) *((char *)buffer+eNumElems) = '\0';
	   Item->Var->max = cdf_AllocateMemory ((size_t)Item->Var->nValueBytes,
						FatalError);
	   ConvertDataType (eDataType, eNumElems, buffer, Item->Var->dataType,
			    Item->Var->numElems, Item->Var->max);
	   cdf_FreeMemory (buffer, FatalError);
	   Item->filterSetting = opt.eachFilter;
	   break;
	 }
	 case NO_SUCH_ATTR:
	 case NO_SUCH_ENTRY:
	   break;
	 default:
	   DisplayStatus (status, readingCDF);
	   return FALSE;
       }
     }
     /*************************************************************************
     * Validate VALIDMIN/VALIDMAX entries.
     *************************************************************************/
     if (Item->Var->min != NULL && Item->Var->max != NULL) {
       if (GTx(Item->Var->min,Item->Var->max,
	       Item->Var->dataType,Item->Var->numElems)) {
	 static char msg[SCREEN_WIDTH+CDF_VAR_NAME_LEN256+1];
	 snprintf (msg, (size_t) sizeof(msg),
		   "VALIDMIN > VALIDMAX for variable `%s' (both ignored).",
		   Item->Var->name);
	 DisplayMessage (msg, NOBEEPWAIT1);
	 cdf_FreeMemory (Item->Var->min, FatalError);
	 cdf_FreeMemory (Item->Var->max, FatalError);
	 Item->Var->min = NULL;
	 Item->Var->max = NULL;
	 Item->filterSetting = FALSE;
       }
     }
     /*************************************************************************
     * Load FILLVAL.
     *************************************************************************/
     if (opt.useFILLVAL) {
       status = GetFILLVALEntry (id, Item->Var->zVar, Item->Var->varN,
				 &eDataType, &eNumElems, &(Item->Var->fill));
       if (StatusBAD(status)) {
	 if (status == BAD_DATA_TYPE)
	   if (Item->Var->fill != NULL) {
	     cdf_FreeMemory (Item->Var->fill, FatalError);
             Item->Var->fill = NULL;
           }
       }
/*
       status = CDFlib (SELECT_, ATTR_NAME_, "FILLVAL",
				 BOO(Item->Var->zVar,
				     zENTRY_,rENTRY_), Item->Var->varN,
			GET_, BOO(Item->Var->zVar,
				  zENTRY_DATATYPE_,
				  rENTRY_DATATYPE_), &eDataType,
			      BOO(Item->Var->zVar,
				  zENTRY_NUMELEMS_,
				  rENTRY_NUMELEMS_), &eNumElems,
			NULL_);
       switch (status) {
	 case CDF_OK: {
	   size_t nBytesE = (size_t) (CDFelemSize(eDataType) * eNumElems);
	   void *buffer = cdf_AllocateMemory (nBytesE, FatalError);
	   status = CDFlib (GET_, BOO(Item->Var->zVar,
				      zENTRY_DATA_,rENTRY_DATA_), buffer,
			    NULL_);
	   DisplayStatus (status, readingCDF);
	   if (StatusBAD(status)) {
	     cdf_FreeMemory (buffer, FatalError);
	     return FALSE;
	   }
	   Item->Var->fill = cdf_AllocateMemory ((size_t)Item->Var->nValueBytes,
					     FatalError);
	   ConvertDataType (eDataType, eNumElems, buffer, Item->Var->dataType,
			    Item->Var->numElems, Item->Var->fill);
	   cdf_FreeMemory (buffer, FatalError);
	   break;
	 }
	 case NO_SUCH_ATTR:
	 case NO_SUCH_ENTRY:
	   break;
	 default:
	   DisplayStatus (status, readingCDF);
	   return FALSE;
       }
*/
     }
     /*************************************************************************
     * Load FORMAT entry.
     *************************************************************************/
     if (opt.useFORMAT) {
       status = CDFlib (SELECT_, ATTR_NAME_, "FORMAT",
				 BOO(Item->Var->zVar,
				     zENTRY_,rENTRY_), Item->Var->varN,
			GET_, BOO(Item->Var->zVar,
				  zENTRY_DATATYPE_,
				  rENTRY_DATATYPE_), &eDataType,
			      BOO(Item->Var->zVar,
				  zENTRY_NUMELEMS_,
				  rENTRY_NUMELEMS_), &eNumElems,
			NULL_);
       switch (status) {
	 case CDF_OK: {
	   if (STRINGdataType(eDataType)) {
	     char *aFormat = (char *) cdf_AllocateMemory ((size_t) eNumElems+1,
						         FatalError);
/*
	     Item->Var->format = (char *)
				 cdf_AllocateMemory ((size_t) eNumElems + 1,
						     FatalError);
*/	     status = CDFlib (GET_, BOO(Item->Var->zVar,
					zENTRY_DATA_,
					rENTRY_DATA_), aFormat,
			      NULL_);
	     DisplayStatus (status, readingCDF);
	     if (StatusBAD(status)) return FALSE;
             ((char *)aFormat)[(int)eNumElems] = NUL;
             Item->Var->format = (char *)
                                 cdf_AllocateMemory ((size_t) eNumElems + 1,
                                                     FatalError);
	     strcpy (Item->Var->format, aFormat);
             RemoveWhiteSpace (Item->Var->format);
	     cdf_FreeMemory (aFormat, NULL);
	   }
	   break;
	 }
	 case NO_SUCH_ATTR:
	 case NO_SUCH_ENTRY:
	   break;
	 default:
	   DisplayStatus (status, readingCDF);
	   return FALSE;
       }
     }
     Item->width = VariableWidth(Item->Var);
     /*************************************************************************
     * Load monotonicity.
     *************************************************************************/
     if (OneDimensionVaries(Item->Var)) {
       Item->Var->monotonic = UNKNOWNmono;
       if (opt.useMONOTON) {
	 status = CDFlib (SELECT_, ATTR_NAME_, "MONOTON",
				   BOO(Item->Var->zVar,
				       zENTRY_,rENTRY_), Item->Var->varN,
			  GET_, BOO(Item->Var->zVar,
				    zENTRY_DATATYPE_,
				    rENTRY_DATATYPE_), &eDataType,
				BOO(Item->Var->zVar,
				    zENTRY_NUMELEMS_,
				    rENTRY_NUMELEMS_), &eNumElems,
			  NULL_);
	 switch (status) {
	   case CDF_OK: {
	     size_t nBytes = (size_t) (CDFelemSize(eDataType) * eNumElems);
	     char *buffer = (char *) cdf_AllocateMemory (nBytes + 1, FatalError);
	     status = CDFlib (GET_, BOO(Item->Var->zVar,
					zENTRY_DATA_,rENTRY_DATA_), buffer,
			      NULL_);
	     DisplayStatus (status, readingCDF);
	     if (StatusBAD(status)) {
	       cdf_FreeMemory (buffer, FatalError);
	       return FALSE;
	     }
	     if (STRINGdataType(eDataType)) {
	       ((char *)buffer)[(int)eNumElems] = NUL;
	       if (!strcmpITB(buffer,"INCREASE"))
		 Item->Var->monotonic = INCREASEmono;
	       else
		 if (!strcmpITB(buffer,"DECREASE"))
		   Item->Var->monotonic = DECREASEmono;
		 else
		   if (!strcmpITB(buffer,"FALSE")) {
		     Item->Var->monotonic=FALSEmono;
		   }
	     }
	     cdf_FreeMemory (buffer, FatalError);
	     break;
	   }
	   case NO_SUCH_ATTR:
	   case NO_SUCH_ENTRY:
	     break;
	   default:
	     DisplayStatus (status, readingCDF);
	     return FALSE;
	 }
       }
     }
     else
       Item->Var->monotonic = NAmono;
     /*************************************************************************
     * Load pad value.
     *************************************************************************/
     Item->Var->pad = cdf_AllocateMemory ((size_t)Item->Var->nValueBytes,
					  FatalError);
     status = CDFlib (GET_, BOO(Item->Var->zVar,
				zVAR_PADVALUE_,
				rVAR_PADVALUE_), Item->Var->pad,
		      NULL_);
     if (status != NO_PADVALUE_SPECIFIED) DisplayStatus (status, readingCDF);
     if (StatusBAD(status)) return FALSE;
     /*************************************************************************
     * Allocate buffer for value(s) and set miscellaneous flags.
     *************************************************************************/
     Item->Var->value = cdf_AllocateMemory ((size_t)Item->Var->nValueBytes,
					FatalError);
     Item->Var->scalar = ScalarVariable (Item->Var);
     /*************************************************************************
     * Tally another line.
     *************************************************************************/
     nItems++;
  }
  if (includeVars > 0L) {
    Logical found;
    for (varX = 0; varX < numVars; ++varX) {
      found = FALSE;
      for (Item = itemHead; Item != NULL; Item = Item->nextItem) {
        if (Item->type != VARIABLEt) continue;
        if (strcmp(Item->Var->name, vars[varX]) == 0) {
          found = TRUE;
          break;
        }
      }
      if (found == FALSE) {
        char msg[80];
        snprintf(msg, (size_t) sizeof(msg),
		 "Variable: %s not found -- ignored", vars[varX]);
        DisplayMessage (msg, NOBEEPWAIT1);
      } else {
        if (includeVars == 1L) ++numVarsO;
        else --numVarsO;
      }
    }
  }
  if (numEpochs > 0) {
    epochs = (char **) malloc(sizeof(char **)*numEpochs);
    epochTypes = (int *) calloc(1, sizeof(int)*numEpochs);
    for (ix = 0; ix < numEpochs; ++ix)
      epochs[ix] = (char *) malloc(CDF_VAR_NAME_LEN256+1);
    ix = 0;
    for (Item = itemHead; Item != NULL; Item = Item->nextItem) {
      if (Item->type != VARIABLEt) continue;
      if (Item->Var->dataType == CDF_EPOCH || 
          Item->Var->dataType == CDF_EPOCH16 ||
          Item->Var->dataType == CDF_TIME_TT2000) {
        if (strcmpIgCase(Item->Var->name, "epoch") == 1 ||
            strcmpIgCase(Item->Var->name, "range_epoch") == 1) {
          if (IsaVirtualVariable(Item->Var->zVar, Item->Var->name)) {
            strcpyX (epochs[ix], Item->Var->name, 0);
            if (Item->Var->dataType == CDF_EPOCH) 
              epochTypes[ix] = 1;
            else if (Item->Var->dataType == CDF_EPOCH16)
              epochTypes[ix] = 2;
            else 
              epochTypes[ix] = 3;
            ++ix;
          }
        }
      }
    }
  }

  /****************************************************************************
  * Inquire majority.
  ****************************************************************************/
  status = CDFlib (GET_, CDF_MAJORITY_, &inMajority,
		   NULL_);
  DisplayStatus (status, "inquiring CDF majority");
  if (StatusBAD(status)) return FALSE;
  /****************************************************************************
  * Allocate SelectionWindow unless in batch mode.
  ****************************************************************************/
  if (!BATCH(batchMode)) {
    AllocIW (IWsel, nSELWINDOWcolsMAX * nItems, nItems, lineL, FatalError);
  }
  return TRUE;
}

/******************************************************************************
* LoadSelectionWindow.
******************************************************************************/

Logical LoadSelectionWindow (part)
int part;
{
  int itemN = 0, lineN;
  char temp[MAXitemFieldLEN+1];
  struct ItemStruct *Item;
  int style;
  /****************************************************************************
  * Load the requested part.
  ****************************************************************************/
  switch (part) {
    /**************************************************************************
    * `Simple' mode.  Name & output.
    **************************************************************************/
    case PART_:
      for (Item = itemHead, lineN = 0;
	   Item != NULL; Item = Item->nextItem, lineN++) {
	 /*********************************************************************
	 * Load item/variable name.
	 *********************************************************************/
	 switch (Item->type) {
	   case RECORDt:
	     MakeNUL (IWsel->iLines[lineN]);
	     CatToString (IWsel->iLines[lineN], "<Record>", NAMEitemLENsimple,
			  LEFT_JUSTIFY, dots);
	     break;
	   case INDICESt:
	     MakeNUL (IWsel->iLines[lineN]);
	     CatToString (IWsel->iLines[lineN], "<Indices>", NAMEitemLENsimple,
			  LEFT_JUSTIFY, dots);
	     break;
	   case VARIABLEt:
	     EncodeString ((long) strlen(Item->Var->name), Item->Var->name,
			   IWsel->iLines[lineN], -NAMEitemLENsimple,
			   NAMEitemLENsimple);
	     break;
	 }
	 itemN = nSELWINDOWcols_ * lineN;
	 IWsel->iLineNs[itemN] = lineN;
	 IWsel->iCols[itemN] = NAMEitemCOLnSIMPLE;
	 IWsel->iLens[itemN] = NAMEitemLENsimple;
	 /*********************************************************************
	 * Load output.
	 *********************************************************************/
	 strcatX (IWsel->iLines[lineN], " ", 0);
	 CatToString (IWsel->iLines[lineN],
		      BOO(Item->outputSetting,"YES","no"),
		      OUTPUTitemLEN, LEFT_JUSTIFY, dots);
	 itemN++;
	 IWsel->iLineNs[itemN] = lineN;
	 IWsel->iCols[itemN] = OUTPUTitemCOLnSIMPLE;
	 IWsel->iLens[itemN] = OUTPUTitemLENsimple;
      }
      IWsel->nItems = itemN + 1;
      break;
    /**************************************************************************
    * Part 1.  Name, data specification, dimensionality, variances, output.
    **************************************************************************/
    case PART1:
      for (Item = itemHead, lineN = 0;
	   Item != NULL; Item = Item->nextItem, lineN++) {
	 /*********************************************************************
	 * Load item/variable name.
	 *********************************************************************/
	 switch (Item->type) {
	   case RECORDt:
	     MakeNUL (IWsel->iLines[lineN]);
	     CatToString (IWsel->iLines[lineN], "<Record>", NAMEitemLEN,
			  LEFT_JUSTIFY, dots);
	     break;
	   case INDICESt:
	     MakeNUL (IWsel->iLines[lineN]);
	     CatToString (IWsel->iLines[lineN], "<Indices>", NAMEitemLEN,
			  LEFT_JUSTIFY, dots);
	     break;
	   case VARIABLEt:
	     EncodeString ((long) strlen(Item->Var->name), Item->Var->name,
			   IWsel->iLines[lineN], -NAMEitemLEN, NAMEitemLEN);
	     break;
	 }
	 itemN = nSELWINDOWcols1 * lineN;
	 IWsel->iLineNs[itemN] = lineN;
	 IWsel->iCols[itemN] = NAMEitemCOLn;
	 IWsel->iLens[itemN] = NAMEitemLEN;
	 /*********************************************************************
	 * Load data specification.
	 *********************************************************************/
	 strcatX (IWsel->iLines[lineN], " ", 0);
	 switch (Item->type) {
	   case RECORDt:
	   case INDICESt:
	     CatToString (IWsel->iLines[lineN], na, SPECitemLEN, LEFT_JUSTIFY,
			  dots);
	     break;
	   case VARIABLEt:
	     snprintf (temp, (size_t) sizeof(temp),
		       "%s/%ld", DataTypeToken(Item->Var->dataType),
		       Item->Var->numElems);
	     CatToString (IWsel->iLines[lineN], temp, SPECitemLEN,
			  LEFT_JUSTIFY, dots);
	     break;
	 }
	 itemN++;
	 IWsel->iLineNs[itemN] = lineN;
	 IWsel->iCols[itemN] = SPECitemCOLn;
	 IWsel->iLens[itemN] = SPECitemLEN;
	 /*********************************************************************
	 * Load dimensionality.
	 *********************************************************************/
	 strcatX (IWsel->iLines[lineN], " ", 0);
	 switch (Item->type) {
	   case RECORDt:
	   case INDICESt:
	     CatToString (IWsel->iLines[lineN], na, DIMENitemLEN, LEFT_JUSTIFY,
			  dots);
	     break;
	   case VARIABLEt:
	     EncodeDimensionality (temp, Item->Var->numDims,
				   Item->Var->dimSizes, (size_t) sizeof(temp));
	     CatToString (IWsel->iLines[lineN], temp, DIMENitemLEN,
			  LEFT_JUSTIFY, dots);
	     break;
	 }
	 itemN++;
	 IWsel->iLineNs[itemN] = lineN;
	 IWsel->iCols[itemN] = DIMENitemCOLn;
	 IWsel->iLens[itemN] = DIMENitemLEN;
	 /*********************************************************************
	 * Load variances.
	 *********************************************************************/
	 strcatX (IWsel->iLines[lineN], " ", 0);
	 switch (Item->type) {
	   case RECORDt:
	   case INDICESt:
	     CatToString (IWsel->iLines[lineN], na, VARYSitemLEN, LEFT_JUSTIFY,
			  dots);
	     break;
	   case VARIABLEt:
	     EncodeVariances (temp, Item->Var->recVary, Item->Var->numDims,
			      Item->Var->dimVarys);
	     CatToString (IWsel->iLines[lineN], temp, VARYSitemLEN,
			  LEFT_JUSTIFY, dots);
	     break;
	 }
	 itemN++;
	 IWsel->iLineNs[itemN] = lineN;
	 IWsel->iCols[itemN] = VARYSitemCOLn;
	 IWsel->iLens[itemN] = VARYSitemLEN;
	 /*********************************************************************
	 * Load output.
	 *********************************************************************/
	 strcatX (IWsel->iLines[lineN], " ", 0);
	 CatToString (IWsel->iLines[lineN],
		      BOO(Item->outputSetting,"YES","no"),
		      OUTPUTitemLEN, LEFT_JUSTIFY, dots);
	 itemN++;
	 IWsel->iLineNs[itemN] = lineN;
	 IWsel->iCols[itemN] = OUTPUTitemCOLn;
	 IWsel->iLens[itemN] = OUTPUTitemLEN;
      }
      IWsel->nItems = itemN + 1;
      break;
    /**************************************************************************
    * Part 2.  Name, minimum, maximum, filter.
    **************************************************************************/
    case PART2:
      for (Item = itemHead, lineN = 0;
	   Item != NULL; Item = Item->nextItem, lineN++) {
	 /*********************************************************************
	 * Load item/variable name.
	 *********************************************************************/
	 switch (Item->type) {
	   case RECORDt:
	     MakeNUL (IWsel->iLines[lineN]);
	     CatToString (IWsel->iLines[lineN], "<Record>", NAMEitemLEN,
			  LEFT_JUSTIFY, dots);
	     break;
	   case INDICESt:
	     MakeNUL (IWsel->iLines[lineN]);
	     CatToString (IWsel->iLines[lineN], "<Indices>", NAMEitemLEN,
			  LEFT_JUSTIFY, dots);
	     break;
	   case VARIABLEt:
	     EncodeString ((long) strlen(Item->Var->name), Item->Var->name,
			   IWsel->iLines[lineN], -NAMEitemLEN, NAMEitemLEN);
	     break;
	 }
	 itemN = nSELWINDOWcols2 * lineN;
	 IWsel->iLineNs[itemN] = lineN;
	 IWsel->iCols[itemN] = NAMEitemCOLn;
	 IWsel->iLens[itemN] = NAMEitemLEN;
	 /*********************************************************************
	 * Load minimum value.
	 *********************************************************************/
	 strcatX (IWsel->iLines[lineN], " ", 0);
	 switch (Item->type) {
	   case RECORDt:
	     if (Item->Record->min == NOminMax)
	       MakeNUL (temp);
	     else
	       snprintf (temp, (size_t) sizeof(temp),
		         "%ld", Item->Record->min + 1);
	     CatToString (IWsel->iLines[lineN], temp, MINitemLEN,
			  LEFT_JUSTIFY, dots);
	     break;
	   case INDICESt:
	     if (Item->Indices->minNumDims == NOminMax)
	       CatNcharacters (IWsel->iLines[lineN], MINitemLEN, ' ');
	     else {
	       EncodeIndicesJustify (temp, Item->Indices->minNumDims,
				     Item->Indices->minIndices, 0,
				     (size_t) sizeof(temp));
	       CatToString (IWsel->iLines[lineN], temp, MINitemLEN,
			    LEFT_JUSTIFY, dots);
	     }
	     break;
	   case VARIABLEt:
             if (TT2000dataType(Item->Var->dataType)) {
               if (!ziso8601) style = opt.epochStyle;
               else style = TT2000_4_STYLE;
             } else {
               if (!ziso8601) style = opt.epochStyle;
               else style = EPOCH3_STYLE;
             }
	     if (Item->Var->min != NULL)
	       EncodeValuesFormat (Item->Var->dataType, Item->Var->numElems,
				   Item->Var->min, EofS(IWsel->iLines[lineN]),
				   Item->Var->format, -MINitemLEN, MINitemLEN,
				   style,
				   (size_t) SCREEN_WIDTH-2-
					    strlen(IWsel->iLines[lineN]));
	     else
	       CatNcharacters (IWsel->iLines[lineN], MINitemLEN, ' ');
	     break;
	 }
	 itemN++;
	 IWsel->iLineNs[itemN] = lineN;
	 IWsel->iCols[itemN] = MINitemCOLn;
	 IWsel->iLens[itemN] = MINitemLEN;
	 /*********************************************************************
	 * Load maximum value.
	 *********************************************************************/
	 strcatX (IWsel->iLines[lineN], " ", 0);
	 switch (Item->type) {
	   case RECORDt:
	     if (Item->Record->max == NOminMax)
	       MakeNUL (temp);
	     else
	       snprintf (temp, (size_t) sizeof(temp),
		         "%ld", Item->Record->max + 1);
	     CatToString (IWsel->iLines[lineN], temp, MAXitemLEN,
			  LEFT_JUSTIFY, dots);
	     break;
	   case INDICESt:
	     if (Item->Indices->maxNumDims == NOminMax)
	       CatNcharacters (IWsel->iLines[lineN], MAXitemLEN, ' ');
	     else {
	       EncodeIndicesJustify (temp, Item->Indices->maxNumDims,
				     Item->Indices->maxIndices, 0,
				     (size_t) sizeof(temp));
	       CatToString (IWsel->iLines[lineN], temp, MAXitemLEN,
			    LEFT_JUSTIFY, dots);
	     }
	     break;
	   case VARIABLEt:
             if (TT2000dataType(Item->Var->dataType)) {
               if (!ziso8601) style = opt.epochStyle;
               else style = TT2000_4_STYLE;
             } else {
               if (!ziso8601) style = opt.epochStyle;
               else style = EPOCH3_STYLE;
             }
	     if (Item->Var->max != NULL)
	       EncodeValuesFormat (Item->Var->dataType, Item->Var->numElems,
				   Item->Var->max, EofS(IWsel->iLines[lineN]),
				   Item->Var->format, -MAXitemLEN, MAXitemLEN,
				   style,
				   (size_t) SCREEN_WIDTH-2-
					    strlen(IWsel->iLines[lineN]));
	     else
	       CatNcharacters (IWsel->iLines[lineN], MAXitemLEN, ' ');
	     break;
	 }
	 itemN++;
	 IWsel->iLineNs[itemN] = lineN;
	 IWsel->iCols[itemN] = MAXitemCOLn;
	 IWsel->iLens[itemN] = MAXitemLEN;
	 /*********************************************************************
	 * Load filter.
	 *********************************************************************/
	 strcatX (IWsel->iLines[lineN], " ", 0);
	 CatToString (IWsel->iLines[lineN],
		      BOO(Item->filterSetting,
			  BOO(opt.overallFilter,
			      BOO(opt.exclusive,
				  BOO(Item->inclusive,"YeS","yEs"),"YES"),
			      BOO(opt.exclusive,
				  BOO(Item->inclusive,
				      "(YeS)","(yEs)"),"(YES)")),
			  BOO(opt.overallFilter,"no","(no)")),
		      FILTERitemLEN, LEFT_JUSTIFY, dots);
	 itemN++;
	 IWsel->iLineNs[itemN] = lineN;
	 IWsel->iCols[itemN] = FILTERitemCOLn;
	 IWsel->iLens[itemN] = FILTERitemLEN;
      }
      IWsel->nItems = itemN + 1;
      break;
    /**************************************************************************
    * Part 3.  Name, fill value, monotonicity, format, width.
    **************************************************************************/
    case PART3:
      for (Item = itemHead, lineN = 0;
	   Item != NULL; Item = Item->nextItem, lineN++) {
	 /*********************************************************************
	 * Load item/variable name.
	 *********************************************************************/
	 switch (Item->type) {
	   case RECORDt:
	     MakeNUL (IWsel->iLines[lineN]);
	     CatToString (IWsel->iLines[lineN], "<Record>", NAMEitemLEN,
			  LEFT_JUSTIFY, dots);
	     break;
	   case INDICESt:
	     MakeNUL (IWsel->iLines[lineN]);
	     CatToString (IWsel->iLines[lineN], "<Indices>", NAMEitemLEN,
			  LEFT_JUSTIFY, dots);
	     break;
	   case VARIABLEt:
	     EncodeString ((long) strlen(Item->Var->name), Item->Var->name,
			   IWsel->iLines[lineN], -NAMEitemLEN, NAMEitemLEN);
	     break;
	 }
	 itemN = nSELWINDOWcols3 * lineN;
	 IWsel->iLineNs[itemN] = lineN;
	 IWsel->iCols[itemN] = NAMEitemCOLn;
	 IWsel->iLens[itemN] = NAMEitemLEN;
	 /*********************************************************************
	 * Load fill value.
	 *********************************************************************/
	 strcatX (IWsel->iLines[lineN], " ", 0);
	 switch (Item->type) {
	   case RECORDt:
	   case INDICESt:
	     CatToString (IWsel->iLines[lineN], na, FILLitemLEN, LEFT_JUSTIFY,
			  dots);
	     break;
	   case VARIABLEt:
             if (TT2000dataType(Item->Var->dataType)) {
               if (!ziso8601) style = opt.epochStyle;
               else style = TT2000_4_STYLE;
             } else {
               if (!ziso8601) style = opt.epochStyle;
               else style = EPOCH3_STYLE;
             }
	     if (Item->Var->fill != NULL) {
	       char temp[FILLitemLEN+1];
	       MakeNUL (temp);
	       if (!opt.useFills) strcatX (temp, "(", 0);
	       EncodeValuesFormat (Item->Var->dataType, Item->Var->numElems,
				   Item->Var->fill, EofS(temp),
				   Item->Var->format, -MAXitemLEN,
				   FILLitemLEN - 2, style,
				   (size_t)sizeof(temp)-strlen(temp));
	       if (!opt.useFills) strcatX (temp, ")", 0);
	       CatToString (IWsel->iLines[lineN], temp, FILLitemLEN,
			    LEFT_JUSTIFY, dots);
	     }
	     else
	       CatNcharacters (IWsel->iLines[lineN], FILLitemLEN, ' ');
	     break;
	 }
	 itemN++;
	 IWsel->iLineNs[itemN] = lineN;
	 IWsel->iCols[itemN] = FILLitemCOLn;
	 IWsel->iLens[itemN] = FILLitemLEN;
	 /*********************************************************************
	 * Load monotonicity.
	 *********************************************************************/
	 strcatX (IWsel->iLines[lineN], " ", 0);
	 switch (Item->type) {
	   case RECORDt:
	   case INDICESt:
	     CatToString (IWsel->iLines[lineN], na, MONOitemLEN, LEFT_JUSTIFY,
			  dots);
	     break;
	   case VARIABLEt:
	     CatToString (IWsel->iLines[lineN], monos[Item->Var->monotonic+1],
			  MONOitemLEN, LEFT_JUSTIFY, dots);
	     break;
	 }
	 itemN++;
	 IWsel->iLineNs[itemN] = lineN;
	 IWsel->iCols[itemN] = MONOitemCOLn;
	 IWsel->iLens[itemN] = MONOitemLEN;
	 /*********************************************************************
	 * Load format.
	 *********************************************************************/
	 strcatX (IWsel->iLines[lineN], " ", 0);
	 switch (Item->type) {
	   case RECORDt:
	   case INDICESt:
	     CatToString (IWsel->iLines[lineN], na, FORMATitemLEN,
			  LEFT_JUSTIFY, dots);
	     break;
	   case VARIABLEt:
	     if (Item->Var->format != NULL)
	       if (((EPOCHdataType(Item->Var->dataType) ||
                     EPOCH16dataType(Item->Var->dataType) ||
                     TT2000dataType(Item->Var->dataType)) &&
		    (opt.epochStyle == EPOCH0_STYLE ||
		     opt.epochStyle == EPOCH1_STYLE ||
		     opt.epochStyle == EPOCH2_STYLE ||
		     opt.epochStyle == EPOCH3_STYLE ||
		     opt.epochStyle == EPOCH4_STYLE ||
                     opt.epochStyle == TT2000_4_STYLE))
		   || STRINGdataType(Item->Var->dataType)) {
		 size_t nBytes = 1 + strlen(Item->Var->format) + 1;
		 char *temp = (char *) cdf_AllocateMemory (nBytes + 1,
							   FatalError);
		 strcpyX (temp, "(", 0);
		 strcatX (temp, Item->Var->format, 0);
		 strcatX (temp, ")", 0);
		 CatToString (IWsel->iLines[lineN], temp, FORMATitemLEN,
			      LEFT_JUSTIFY, dots);
		 cdf_FreeMemory (temp, FatalError);
	       }
	       else
		 CatToString (IWsel->iLines[lineN], Item->Var->format,
			      FORMATitemLEN, LEFT_JUSTIFY, dots);
	     else
	       CatNcharacters (IWsel->iLines[lineN], FORMATitemLEN, ' ');
	     break;
	 }
	 itemN++;
	 IWsel->iLineNs[itemN] = lineN;
	 IWsel->iCols[itemN] = FORMATitemCOLn;
	 IWsel->iLens[itemN] = FORMATitemLEN;
	 /*********************************************************************
	 * Load width.
	 *********************************************************************/
	 strcatX (IWsel->iLines[lineN], " ", 0);
	 snprintf (temp, (size_t) sizeof(temp), "%d", Item->width);
	 CatToString (IWsel->iLines[lineN], temp, WIDTHitemLEN, LEFT_JUSTIFY,
		      dots);
	 itemN++;
	 IWsel->iLineNs[itemN] = lineN;
	 IWsel->iCols[itemN] = WIDTHitemCOLn;
	 IWsel->iLens[itemN] = WIDTHitemLEN;
      }
      IWsel->nItems = itemN + 1;
      break;
    /**************************************************************************
    * Part 4.  Name, sparseness, compression, blocking factor.
    **************************************************************************/
    case PART4:
      for (Item = itemHead, lineN = 0;
	   Item != NULL; Item = Item->nextItem, lineN++) {
	 /*********************************************************************
	 * Load item/variable name.
	 *********************************************************************/
	 switch (Item->type) {
	   case RECORDt:
	     MakeNUL (IWsel->iLines[lineN]);
	     CatToString (IWsel->iLines[lineN], "<Record>", NAMEitemLEN,
			  LEFT_JUSTIFY, dots);
	     break;
	   case INDICESt:
	     MakeNUL (IWsel->iLines[lineN]);
	     CatToString (IWsel->iLines[lineN], "<Indices>", NAMEitemLEN,
			  LEFT_JUSTIFY, dots);
	     break;
	   case VARIABLEt:
	     EncodeString ((long) strlen(Item->Var->name), Item->Var->name,
			   IWsel->iLines[lineN], -NAMEitemLEN, NAMEitemLEN);
	     break;
	 }
	 itemN = nSELWINDOWcols4 * lineN;
	 IWsel->iLineNs[itemN] = lineN;
	 IWsel->iCols[itemN] = NAMEitemCOLn;
	 IWsel->iLens[itemN] = NAMEitemLEN;
	 /*********************************************************************
	 * Load sparseness.
	 *********************************************************************/
	 strcatX (IWsel->iLines[lineN], " ", 0);
	 switch (Item->type) {
	   case RECORDt:
	   case INDICESt:
	     CatToString (IWsel->iLines[lineN], na, SPARSEitemLEN,
			  LEFT_JUSTIFY, dots);
	     break;
	   case VARIABLEt:
	     CatToString (IWsel->iLines[lineN],
			  SparsenessToken(Item->Var->sRecordsType,
					  Item->Var->sArraysType,
					  Item->Var->sArraysParms),
			  SPARSEitemLEN, LEFT_JUSTIFY, dots);
	     break;
	 }
	 itemN++;
	 IWsel->iLineNs[itemN] = lineN;
	 IWsel->iCols[itemN] = SPARSEitemCOLn;
	 IWsel->iLens[itemN] = SPARSEitemLEN;
	 /*********************************************************************
	 * Load compression.
	 *********************************************************************/
	 strcatX (IWsel->iLines[lineN], " ", 0);
	 switch (Item->type) {
	   case RECORDt:
	   case INDICESt:
	     CatToString (IWsel->iLines[lineN], na, COMPRESSitemLEN,
			  LEFT_JUSTIFY, dots);
	     break;
	   case VARIABLEt:
	     CatToString (IWsel->iLines[lineN],
			  CompressionToken(Item->Var->cType,Item->Var->cParms),
			  COMPRESSitemLEN, LEFT_JUSTIFY, dots);
	     break;
	 }
	 itemN++;
	 IWsel->iLineNs[itemN] = lineN;
	 IWsel->iCols[itemN] = COMPRESSitemCOLn;
	 IWsel->iLens[itemN] = COMPRESSitemLEN;
	 /*********************************************************************
	 * Load reserve percentage.
	 *********************************************************************/
	 strcatX (IWsel->iLines[lineN], " ", 0);
	 switch (Item->type) {
	   case RECORDt:
	   case INDICESt:
	     CatToString (IWsel->iLines[lineN], na, RESERVEitemLEN,
			  LEFT_JUSTIFY, dots);
	     break;
	   case VARIABLEt:
	     if (Item->Var->reserve == NA_RESERVE)
	       CatToString (IWsel->iLines[lineN], na, RESERVEitemLEN,
			    LEFT_JUSTIFY, dots);
	     else {
	       snprintf (temp, (size_t) sizeof(temp),
		         "%ld", Item->Var->reserve);
	       CatToString (IWsel->iLines[lineN], temp, RESERVEitemLEN,
			    LEFT_JUSTIFY, dots);
	     }
	     break;
	 }
	 itemN++;
	 IWsel->iLineNs[itemN] = lineN;
	 IWsel->iCols[itemN] = RESERVEitemCOLn;
	 IWsel->iLens[itemN] = RESERVEitemLEN;
	 /*********************************************************************
	 * Load blocking factor.
	 *********************************************************************/
	 strcatX (IWsel->iLines[lineN], " ", 0);
	 switch (Item->type) {
	   case RECORDt:
	   case INDICESt:
	     CatToString (IWsel->iLines[lineN], na, BLOCKINGitemLEN,
			  LEFT_JUSTIFY, dots);
	     break;
	   case VARIABLEt:
	     snprintf (temp, (size_t) sizeof(temp),
		       "%ld", Item->Var->blocking);
	     CatToString (IWsel->iLines[lineN], temp, BLOCKINGitemLEN,
			  LEFT_JUSTIFY, dots);
	     break;
	 }
	 itemN++;
	 IWsel->iLineNs[itemN] = lineN;
	 IWsel->iCols[itemN] = BLOCKINGitemCOLn;
	 IWsel->iLens[itemN] = BLOCKINGitemLEN;
      }
      IWsel->nItems = itemN + 1;
      break;
  }
  /****************************************************************************
  * Success, return.
  ****************************************************************************/
  return TRUE;
}

/******************************************************************************
* SelectionWindow.
* This is used when `simple' mode has been selected.
******************************************************************************/

void SelectionWindow (noMoreAccess)
Logical *noMoreAccess;  /* Assumed initialized to FALSE by caller. */
{
  static Logical first = TRUE;
  int rX, cX, rXt; struct ItemStruct *Item;
  static char label[] = " SelectionWindow ";
  static char *header[] = {
    "Variable                                                                Output"
  };
  static int exits[] = {
    ENTERkey_FSI, EXITkey_FSI, HELPkey_FSI, SCREENkey_SIMPLE, FILEkey_SIMPLE,
    SAVEkey_SIMPLE, RESTOREkey_SIMPLE, NUL
  };
  static char keyDefs[] = "ToScreen: ________    SaveSettings: ________ Help: ________ YES/no:  ________\n  ToFile: ________ RestoreSettings: ________ Exit: ________";
  /****************************************************************************
  * Encode key definitions first time.
  ****************************************************************************/
  if (first) {
    char *p1 = keyDefs;
    EncodeKeyDefinitions (1, &p1, SCREENkey_SIMPLE, SAVEkey_SIMPLE,
			  HELPkey_FSI, ENTERkey_FSI, FILEkey_SIMPLE,
			  RESTOREkey_SIMPLE, EXITkey_FSI);
    first = FALSE;
  }
  /****************************************************************************
  * Load/update SelectionWindow.
  ****************************************************************************/
  IWsel->label = label;
  IWsel->hLines = header;
  IWsel->exitChars = exits;
  LoadSelectionWindow (PART_);
  ItemWindow (UPDATEiw, IWsel, 1);
  /****************************************************************************
  * Update/load KeyWindow.
  ****************************************************************************/
  NEWkeyDEFS (EWkey, keyDefs, batchMode)
  /****************************************************************************
  * Process keystrokes.
  ****************************************************************************/
  for (;;) {
     ItemWindow (READiw, IWsel);
     rX = IWsel->itemN / nSELWINDOWcols_;
     cX = IWsel->itemN % nSELWINDOWcols_;
     for (Item = itemHead, rXt = 0; rXt < rX; rXt++) Item = Item->nextItem;
     switch (IWsel->key) {
       case ENTERkey_FSI:
	 switch (cX) {
	   case NAMEcxSIMPLE:
	     ItemWindow (BEEPiw, IWsel);
	     break;
	   case OUTPUTcxSIMPLE:
	     Item->outputSetting = BOO(Item->outputSetting,FALSE,TRUE);
	     LoadSelectionWindow (PART_);
	     ItemWindow (UPDATEiw, IWsel, IWsel->itemN);
	     break;
	 }
	 break;
       case SCREENkey_SIMPLE:
	 if (!BOO(opt.horizontalMode,ToScreenHori(),ToScreenVert())) {
	   *noMoreAccess = TRUE;
	   return;
	 }
	 break;
       case FILEkey_SIMPLE:
	 if (!BOO(opt.horizontalMode,ToFileHori(),ToFileVert())) {
	   *noMoreAccess = TRUE;
	   return;
	 }
	 break;
       case SAVEkey_SIMPLE:
	 if (PromptFor(settingsFile,DU_MAX_PATH_LEN,strlen(settingsFile),
		       "Enter path for settings file...",SETFILEhelpID)) {
	   DisplayMessage ("Saving settings...", NOWAIT);
	   SaveSettings ();
	   DisplayMessage ("", NOWAIT);
	 }
	 break;
       case RESTOREkey_SIMPLE:
	 if (PromptFor(settingsFile,DU_MAX_PATH_LEN,strlen(settingsFile),
		       "Enter path for settings file...",SETFILEhelpID)) {
	   DisplayMessage ("Restoring settings...", NOWAIT);
	   RestoreSettings ();
	   LoadSelectionWindow (PART_);
	   ItemWindow (UPDATEiw, IWsel, IWsel->itemN);
	   DisplayMessage ("", NOWAIT);
	 }
	 break;
       case HELPkey_FSI:
	 OnlineHelpWindow ("cdfxp.ilh", VARhelpID);
	 break;
       case EXITkey_FSI:
	 if (ConfirmExit()) return;
	 break;
     }
     /*************************************************************************
     * Update key definitions in case they were changed.
     *************************************************************************/
     NEWkeyDEFS (EWkey, keyDefs, batchMode)
  }
}

/******************************************************************************
* SelectionWindow1.
* Returns FALSE when the CDF is to be exited (either by choice or because of
* a fatal CDF error).
******************************************************************************/

Logical SelectionWindow1 (noMoreAccess)
Logical *noMoreAccess;  /* Assumed initialized to FALSE by caller. */
{
  static Logical first = TRUE;
  int rX, cX, rXt, itemN; struct ItemStruct *Item;
  static char label[] = " SelectionWindow, part 1 ";
  static char *header[] = {
    "Item/Variable         DataSpec  Dimensionality              Variances   Output"
  };
  static int exits[] = {
    PART2key_EXPORT, ENTERkey_FSI, EXITkey_FSI, ACTIONSkey_EXPORT,
    FLIPkey_EXPORT, DELETEkey_FSI, HELPkey_FSI, OPTIONSkey_EXPORT, NUL
  };
  static char keyDefs[] = "Modify: ________    Actions: ________     Reverse: ________     Help: ________\nPart 2: ________    Options: ________     Delete:  ________     Exit: ________\n";
  /****************************************************************************
  * Encode key definitions first time.
  ****************************************************************************/
  if (first) {
    char *p1 = keyDefs;
    EncodeKeyDefinitions (1, &p1, ENTERkey_FSI, ACTIONSkey_EXPORT,
			  FLIPkey_EXPORT, HELPkey_FSI, PART2key_EXPORT,
			  OPTIONSkey_EXPORT, DELETEkey_FSI, EXITkey_FSI);
    first = FALSE;
  }
  /****************************************************************************
  * Load/update SelectionWindow.
  ****************************************************************************/
  IWsel->label = label;
  IWsel->hLines = header;
  IWsel->exitChars = exits;
  LoadSelectionWindow (PART1);
  itemN = (IWsel->itemN / nSELWINDOWcols4) * nSELWINDOWcols1;
  switch (IWsel->itemN % nSELWINDOWcols4) {
    case NAMEcx: break;
    case SPARSEcx: itemN += SPECcx; break;
    case COMPRESScx: itemN += VARYScx; break;
    case BLOCKINGcx: itemN += OUTPUTcx; break;
  }
  ItemWindow (UPDATEiw, IWsel, itemN);
  /****************************************************************************
  * Update/load KeyWindow.
  ****************************************************************************/
  NEWkeyDEFS (EWkey, keyDefs, batchMode)
  /****************************************************************************
  * Process keystrokes.
  ****************************************************************************/
  for (;;) {
     ItemWindow (READiw, IWsel);
     rX = IWsel->itemN / nSELWINDOWcols1;
     cX = IWsel->itemN % nSELWINDOWcols1;
     for (Item = itemHead, rXt = 0; rXt < rX; rXt++) Item = Item->nextItem;
     switch (IWsel->key) {
       case ENTERkey_FSI:
	 switch (cX) {
	   case NAMEcx:
	   case SPECcx:
	   case DIMENcx:
	   case VARYScx:
	     ItemWindow (BEEPiw, IWsel);
	     break;
	   case OUTPUTcx:
	     Item->outputSetting = BOO(Item->outputSetting,FALSE,TRUE);
	     LoadSelectionWindow (PART1);
	     ItemWindow (UPDATEiw, IWsel, IWsel->itemN);
	     break;
	 }
	 break;
       case DELETEkey_FSI:
	 switch (cX) {
	   case NAMEcx:
	     ItemWindow (BEEPiw, IWsel);
	     break;
	   case SPECcx:
	   case DIMENcx:
	   case VARYScx:
	   case OUTPUTcx:
	     ItemWindow (BEEPiw, IWsel);
	     break;
	 }
	 break;
       case FLIPkey_EXPORT:
	 if (FlipItems(rX)) {
	   int itemN = (IWsel->itemN + nSELWINDOWcols1) % IWsel->nItems;
	   LoadSelectionWindow (PART1);
	   ItemWindow (UPDATEiw, IWsel, itemN);
	 }
	 else
	   ItemWindow (BEEPiw, IWsel);
	 break;
       case ACTIONSkey_EXPORT:
	 if (!ActionMenu(PART1)) {
	   *noMoreAccess = TRUE;
	   return FALSE;
	 }
	 break;
       case OPTIONSkey_EXPORT:
	 OptionMenu ();
	 LoadSelectionWindow (PART1);
	 ItemWindow (UPDATEiw, IWsel, IWsel->itemN);
	 break;
       case HELPkey_FSI:
	 OnlineHelpWindow ("cdfxp.ilh", VAR1helpID);
	 break;
       case PART2key_EXPORT:
	 return TRUE;
       case EXITkey_FSI:
	 if (ConfirmExit()) return FALSE;
	 break;
     }
     /*************************************************************************
     * Update key definitions in case they were changed.
     *************************************************************************/
     NEWkeyDEFS (EWkey, keyDefs, batchMode)
  }
}

/******************************************************************************
* SelectionWindow2.
* Returns FALSE when the CDF is to be exited (either by choice or because of
* a fatal CDF error).
******************************************************************************/

Logical SelectionWindow2 (noMoreAccess)
Logical *noMoreAccess;
{
  static Logical first = TRUE;
  int rX, cX, rXt, itemN; struct ItemStruct *Item;
  static char label[] = " SelectionWindow, part 2 ";
  static char *header[] = {
    "Item/Variable         Minimum                  Maximum                  Filter"
  };
  static int exits[] = {
    PART3key_EXPORT, ENTERkey_FSI, EXITkey_FSI, ACTIONSkey_EXPORT,
    FLIPkey_EXPORT, DELETEkey_FSI, HELPkey_FSI, OPTIONSkey_EXPORT, NUL
  };
  static char keyDefs[] = "Modify: ________    Actions: ________     Reverse: ________     Help: ________\nPart 3: ________    Options: ________     Delete:  ________     Exit: ________\n";
  /****************************************************************************
  * Encode key definitions first time.
  ****************************************************************************/
  if (first) {
    char *p1 = keyDefs;
    EncodeKeyDefinitions (1, &p1, ENTERkey_FSI, ACTIONSkey_EXPORT,
			  FLIPkey_EXPORT, HELPkey_FSI, PART2key_EXPORT,
			  OPTIONSkey_EXPORT, DELETEkey_FSI, EXITkey_FSI);
    first = FALSE;
  }
  /****************************************************************************
  * Load/update SelectionWindow.
  ****************************************************************************/
  IWsel->label = label;
  IWsel->hLines = header;
  IWsel->exitChars = exits;
  LoadSelectionWindow (PART2);
  itemN = (IWsel->itemN / nSELWINDOWcols1) * nSELWINDOWcols2;
  switch (IWsel->itemN % nSELWINDOWcols1) {
    case NAMEcx: break;
    case SPECcx: itemN += MINcx; break;
    case DIMENcx: itemN += MINcx; break;
    case VARYScx: itemN += MAXcx; break;
    case OUTPUTcx: itemN += FILTERcx; break;
  }
  ItemWindow (UPDATEiw, IWsel, itemN);
  /****************************************************************************
  * Load/update KeyWindow.
  ****************************************************************************/
  NEWkeyDEFS (EWkey, keyDefs, batchMode)
  /****************************************************************************
  * Process keystrokes.
  ****************************************************************************/
  for (;;) {
     ItemWindow (READiw, IWsel);
     rX = IWsel->itemN / nSELWINDOWcols2;
     cX = IWsel->itemN % nSELWINDOWcols2;
     for (Item = itemHead, rXt = 0; rXt < rX; rXt++) Item = Item->nextItem;
     switch (IWsel->key) {
       case ENTERkey_FSI:
	 switch (cX) {
	   case NAMEcx:
	     ItemWindow (BEEPiw, IWsel);
	     break;
	   case MINcx:
	   case MAXcx: {
	     switch (Item->type) {
	       case RECORDt:
	       case INDICESt:
	       case VARIABLEt:
		 if (PromptForMinMax(Item,(cX == MINcx))) {
		   LoadSelectionWindow (PART2);
		   ItemWindow (UPDATEiw, IWsel, IWsel->itemN);
		 }
		 break;
	     }
	     break;
	   case FILTERcx:
	     if (MINorMAXexists(Item)) {
	       if (opt.exclusive) {
		 if (Item->filterSetting) {
		   if (Item->inclusive)
		     Item->inclusive = FALSE;
		   else
		     Item->filterSetting = FALSE;
		 } else {
		   Item->filterSetting = TRUE;
		   Item->inclusive = TRUE;
		 }
	       }
	       else
		 Item->filterSetting = BOO(Item->filterSetting,FALSE,TRUE);
	       opt.overallFilter = TRUE;
	       LoadSelectionWindow (PART2);
	       ItemWindow (UPDATEiw, IWsel, IWsel->itemN);
	     }
	     else
	       ItemWindow (BEEPiw, IWsel);
	     break;
	   }
	 }
	 break;
       case DELETEkey_FSI:
	 switch (cX) {
	   case NAMEcx:
	     ItemWindow (BEEPiw, IWsel);
	     break;
	   case MINcx:
	     switch (Item->type) {
	       case RECORDt:
		 if (Item->Record->min != NOminMax) {
		   Item->Record->min = NOminMax;
		   if (Item->Record->max == NOminMax) {
		     Item->filterSetting = FALSE;
		   }
		   LoadSelectionWindow (PART2);
		   ItemWindow (UPDATEiw, IWsel, IWsel->itemN);
		 }
		 else
		   ItemWindow (BEEPiw, IWsel);
		 break;
	       case INDICESt:
		 if (Item->Indices->minNumDims != NOminMax) {
		   Item->Indices->minNumDims = NOminMax;
		   if (Item->Indices->maxNumDims == NOminMax) {
		     Item->filterSetting = FALSE;
		   }
		   LoadSelectionWindow (PART2);
		   ItemWindow (UPDATEiw, IWsel, IWsel->itemN);
		 }
		 else
		   ItemWindow (BEEPiw, IWsel);
		 break;
	       case VARIABLEt:
		 if (Item->Var->min != NULL) {
		   cdf_FreeMemory (Item->Var->min, FatalError);
		   Item->Var->min = NULL;
		   if (Item->Var->max == NULL) Item->filterSetting = FALSE;
		   LoadSelectionWindow (PART2);
		   ItemWindow (UPDATEiw, IWsel, IWsel->itemN);
		 }
		 else
		   ItemWindow (BEEPiw, IWsel);
		 break;
	     }
	     break;
	   case MAXcx:
	     switch (Item->type) {
	       case RECORDt:
		 if (Item->Record->max != NOminMax) {
		   Item->Record->max = NOminMax;
		   if (Item->Record->min == NOminMax) {
		     Item->filterSetting = FALSE;
		   }
		   LoadSelectionWindow (PART2);
		   ItemWindow (UPDATEiw, IWsel, IWsel->itemN);
		 }
		 else
		   ItemWindow (BEEPiw, IWsel);
		 break;
	       case INDICESt:
		 if (Item->Indices->maxNumDims != NOminMax) {
		   Item->Indices->maxNumDims = NOminMax;
		   if (Item->Indices->minNumDims == NOminMax) {
		     Item->filterSetting = FALSE;
		   }
		   LoadSelectionWindow (PART2);
		   ItemWindow (UPDATEiw, IWsel, IWsel->itemN);
		 }
		 else
		   ItemWindow (BEEPiw, IWsel);
		 break;
	       case VARIABLEt:
		 if (Item->Var->max != NULL) {
		   cdf_FreeMemory (Item->Var->max, FatalError);
		   Item->Var->max = NULL;
		   if (Item->Var->min == NULL) Item->filterSetting = FALSE;
		   LoadSelectionWindow (PART2);
		   ItemWindow (UPDATEiw, IWsel, IWsel->itemN);
		 }
		 else
		   ItemWindow (BEEPiw, IWsel);
		 break;
	     }
	     break;
	   case FILTERcx:
	     ItemWindow (BEEPiw, IWsel);
	     break;
	 }
	 break;
       case FLIPkey_EXPORT:
	 if (FlipItems(rX)) {
	   int itemN = (IWsel->itemN + nSELWINDOWcols2) % IWsel->nItems;
	   LoadSelectionWindow (PART2);
	   ItemWindow (UPDATEiw, IWsel, itemN);
	 }
	 else
	   ItemWindow (BEEPiw, IWsel);
	 break;
       case ACTIONSkey_EXPORT:
	 if (!ActionMenu(PART2)) {
	   *noMoreAccess = TRUE;
	   return FALSE;
	 }
	 break;
       case OPTIONSkey_EXPORT:
	 OptionMenu ();
	 LoadSelectionWindow (PART2);
	 ItemWindow (UPDATEiw, IWsel, IWsel->itemN);
	 break;
       case HELPkey_FSI:
	 OnlineHelpWindow ("cdfxp.ilh", VAR2helpID);
	 break;
       case PART3key_EXPORT:
	 return TRUE;
       case EXITkey_FSI:
	 if (ConfirmExit()) return FALSE;
	 break;
     }
     /*************************************************************************
     * Update key definitions in case they were changed.
     *************************************************************************/
     NEWkeyDEFS (EWkey, keyDefs, batchMode)
  }
}

/******************************************************************************
* SelectionWindow3.
* Returns FALSE when the CDF is to be exited (either by choice or because of
* a fatal CDF error).
******************************************************************************/

Logical SelectionWindow3 (noMoreAccess)
Logical *noMoreAccess;
{
  static Logical first = TRUE;
  int rX, cX, rXt, itemN; struct ItemStruct *Item;
  static char label[] = " SelectionWindow, part 3 ";
  static char *header[] = {
    "Item/Variable         FillValue                  Monotonicity  Format    Width"
  };
  static int exits[] = {
    PART4key_EXPORT, ENTERkey_FSI, EXITkey_FSI, ACTIONSkey_EXPORT,
    FLIPkey_EXPORT, DELETEkey_FSI, HELPkey_FSI, OPTIONSkey_EXPORT, NUL
  };
  static char keyDefs[] = "Modify: ________    Actions: ________     Reverse: ________     Help: ________\nPart 4: ________    Options: ________     Delete:  ________     Exit: ________\n";
  /****************************************************************************
  * Encode key definitions first time.
  ****************************************************************************/
  if (first) {
    char *p1 = keyDefs;
    EncodeKeyDefinitions (1, &p1, ENTERkey_FSI, ACTIONSkey_EXPORT,
			  FLIPkey_EXPORT, HELPkey_FSI, PART4key_EXPORT,
			  OPTIONSkey_EXPORT, DELETEkey_FSI, EXITkey_FSI);
    first = FALSE;
  }
  /****************************************************************************
  * Load/update SelectionWindow.
  ****************************************************************************/
  IWsel->label = label;
  IWsel->hLines = header;
  IWsel->exitChars = exits;
  LoadSelectionWindow (PART3);
  itemN = (IWsel->itemN / nSELWINDOWcols2) * nSELWINDOWcols3;
  switch (IWsel->itemN % nSELWINDOWcols2) {
    case NAMEcx: break;
    case MINcx: itemN += FILLcx; break;
    case MAXcx: itemN += MONOcx; break;
    case FILTERcx: itemN += WIDTHcx; break;
  }
  ItemWindow (UPDATEiw, IWsel, itemN);
  /****************************************************************************
  * Load/update KeyWindow.
  ****************************************************************************/
  NEWkeyDEFS (EWkey, keyDefs, batchMode)
  /****************************************************************************
  * Process keystrokes.
  ****************************************************************************/
  for (;;) {
     ItemWindow (READiw, IWsel);
     rX = IWsel->itemN / nSELWINDOWcols3;
     cX = IWsel->itemN % nSELWINDOWcols3;
     for (Item = itemHead, rXt = 0; rXt < rX; rXt++) Item = Item->nextItem;
     switch (IWsel->key) {
       case ENTERkey_FSI:
	 switch (cX) {
	   case NAMEcx:
	     ItemWindow (BEEPiw, IWsel);
	     break;
	   case FILLcx:
	     switch (Item->type) {
	       case RECORDt:
	       case INDICESt:
		 ItemWindow (BEEPiw, IWsel);
		 break;
	       case VARIABLEt:
		 if (PromptForFill(Item->Var)) {
		   LoadSelectionWindow (PART3);
		   ItemWindow (UPDATEiw, IWsel, IWsel->itemN);
		 }
		 break;
	     }
	     break;
	   case WIDTHcx: {
	     if (PromptForWidth(Item)) {
	       LoadSelectionWindow (PART3);
	       ItemWindow (UPDATEiw, IWsel, IWsel->itemN);
	     }
	     break;
	   }
	   case MONOcx:
	     switch (Item->type) {
	       case RECORDt:
	       case INDICESt:
		 ItemWindow (BEEPiw, IWsel);
		 break;
	       case VARIABLEt:
		 if (Item->Var->monotonic != NAmono) {
		   Item->Var->monotonic = (Item->Var->monotonic + 1) % 4;
		   LoadSelectionWindow (PART3);
		   ItemWindow (UPDATEiw, IWsel, IWsel->itemN);
		 }
		 else
		   ItemWindow (BEEPiw, IWsel);
		 break;
	     }
	     break;
	   case FORMATcx:
	     switch (Item->type) {
	       case RECORDt:
	       case INDICESt:
		 ItemWindow (BEEPiw, IWsel);
		 break;
	       case VARIABLEt:
		 if (PromptForFormat(Item)) {
		   LoadSelectionWindow (PART3);
		   ItemWindow (UPDATEiw, IWsel, IWsel->itemN);
		 }
		 break;
	     }
	     break;
	 }
	 break;
       case DELETEkey_FSI:
	 switch (cX) {
	   case NAMEcx:
	     ItemWindow (BEEPiw, IWsel);
	     break;
	   case FILLcx:
	     switch (Item->type) {
	       case RECORDt:
	       case INDICESt:
		 ItemWindow (BEEPiw, IWsel);
		 break;
	       case VARIABLEt:
		 if (Item->Var->fill != NULL) {
		   cdf_FreeMemory (Item->Var->fill, FatalError);
		   Item->Var->fill = NULL;
		   LoadSelectionWindow (PART3);
		   ItemWindow (UPDATEiw, IWsel, IWsel->itemN);
		 }
		 else
		   ItemWindow (BEEPiw, IWsel);
		 break;
	     }
	     break;
	   case WIDTHcx:
	   case MONOcx:
	     ItemWindow (BEEPiw, IWsel);
	     break;
	   case FORMATcx:
	     switch (Item->type) {
	       case RECORDt:
	       case INDICESt:
		 ItemWindow (BEEPiw, IWsel);
		 break;
	       case VARIABLEt:
		 if (Item->Var->format != NULL) {
		   cdf_FreeMemory (Item->Var->format, FatalError);
		   Item->Var->format = NULL;
		   LoadSelectionWindow (PART3);
		   ItemWindow (UPDATEiw, IWsel, IWsel->itemN);
		 }
		 else
		   ItemWindow (BEEPiw, IWsel);
		 break;
	     }
	     break;
	 }
	 break;
       case FLIPkey_EXPORT:
	 if (FlipItems(rX)) {
	   int itemN = (IWsel->itemN + nSELWINDOWcols3) % IWsel->nItems;
	   LoadSelectionWindow (PART3);
	   ItemWindow (UPDATEiw, IWsel, itemN);
	 }
	 else
	   ItemWindow (BEEPiw, IWsel);
	 break;
       case ACTIONSkey_EXPORT:
	 if (!ActionMenu(PART3)) {
	   *noMoreAccess = TRUE;
	   return FALSE;
	 }
	 break;
       case OPTIONSkey_EXPORT:
	 OptionMenu ();
	 LoadSelectionWindow (PART3);
	 ItemWindow (UPDATEiw, IWsel, IWsel->itemN);
	 break;
       case HELPkey_FSI:
	 OnlineHelpWindow ("cdfxp.ilh", VAR3helpID);
	 break;
       case PART4key_EXPORT:
	 return TRUE;
       case EXITkey_FSI:
	 if (ConfirmExit()) return FALSE;
	 break;
     }
     /*************************************************************************
     * Update key definitions in case they were changed.
     *************************************************************************/
     NEWkeyDEFS (EWkey, keyDefs, batchMode)
  }
}

/******************************************************************************
* SelectionWindow4.
* Returns FALSE when the CDF is to be exited (either by choice or because of
* a fatal CDF error).
******************************************************************************/

Logical SelectionWindow4 (noMoreAccess)
Logical *noMoreAccess;
{
  static Logical first = TRUE;
  int rX, cX, rXt, itemN; struct ItemStruct *Item;
  static char label[] = " SelectionWindow, part 4 ";
  static char *header[] = {
    "Item/Variable         Sparseness          Compression         Reserve Blocking"
  };
  static int exits[] = {
    PART1key_EXPORT, ENTERkey_FSI, EXITkey_FSI, ACTIONSkey_EXPORT,
    FLIPkey_EXPORT, DELETEkey_FSI, HELPkey_FSI, OPTIONSkey_EXPORT, NUL
  };
  static char keyDefs[] = "Modify: ________    Actions: ________     Reverse: ________     Help: ________\nPart 1: ________    Options: ________     Delete:  ________     Exit: ________\n";
  /****************************************************************************
  * Encode key definitions first time.
  ****************************************************************************/
  if (first) {
    char *p1 = keyDefs;
    EncodeKeyDefinitions (1, &p1, ENTERkey_FSI, ACTIONSkey_EXPORT,
			  FLIPkey_EXPORT, HELPkey_FSI, PART1key_EXPORT,
			  OPTIONSkey_EXPORT, DELETEkey_FSI, EXITkey_FSI);
    first = FALSE;
  }
  /****************************************************************************
  * Load/update SelectionWindow.
  ****************************************************************************/
  IWsel->label = label;
  IWsel->hLines = header;
  IWsel->exitChars = exits;
  LoadSelectionWindow (PART4);
  itemN = (IWsel->itemN / nSELWINDOWcols3) * nSELWINDOWcols4;
  switch (IWsel->itemN % nSELWINDOWcols3) {
    case NAMEcx: break;
    case FILLcx: itemN += SPARSEcx; break;
    case MONOcx: itemN += COMPRESScx; break;
    case FORMATcx: itemN += RESERVEcx; break;
    case WIDTHcx: itemN += BLOCKINGcx; break;
  }
  ItemWindow (UPDATEiw, IWsel, itemN);
  /****************************************************************************
  * Load/update KeyWindow.
  ****************************************************************************/
  NEWkeyDEFS (EWkey, keyDefs, batchMode)
  /****************************************************************************
  * Process keystrokes.
  ****************************************************************************/
  for (;;) {
     ItemWindow (READiw, IWsel);
     rX = IWsel->itemN / nSELWINDOWcols4;
     cX = IWsel->itemN % nSELWINDOWcols4;
     for (Item = itemHead, rXt = 0; rXt < rX; rXt++) Item = Item->nextItem;
     switch (IWsel->key) {
       case ENTERkey_FSI:
	 switch (cX) {
	   case NAMEcx:
	     ItemWindow (BEEPiw, IWsel);
	     break;
	   case SPARSEcx:
	     switch (Item->type) {
	       case RECORDt:
	       case INDICESt:
		 ItemWindow (BEEPiw, IWsel);
		 break;
	       case VARIABLEt:
		 if (PromptForSparseness(Item->Var)) {
		   LoadSelectionWindow (PART4);
		   ItemWindow (UPDATEiw, IWsel, IWsel->itemN);
		 }
		 break;
	     }
	     break;
	   case COMPRESScx:
	     switch (Item->type) {
	       case RECORDt:
	       case INDICESt:
		 ItemWindow (BEEPiw, IWsel);
		 break;
	       case VARIABLEt: {
		 long cType, cParms[CDF_MAX_PARMS]; int parmN;
		 if (PromptForCompression(&cType,cParms)) {
		   Item->Var->cType = cType;
		   for (parmN = 0; parmN < CDF_MAX_PARMS; parmN++) {
		      Item->Var->cParms[parmN] = cParms[parmN];
		   }
		   Item->Var->reserve = BOO(Item->Var->cType == NO_COMPRESSION,
					    NA_RESERVE,0);
		   LoadSelectionWindow (PART4);
		   ItemWindow (UPDATEiw, IWsel, IWsel->itemN);
		 }
		 break;
	       }
	     }
	     break;
	   case RESERVEcx:
	     switch (Item->type) {
	       case RECORDt:
	       case INDICESt:
		 ItemWindow (BEEPiw, IWsel);
		 break;
	       case VARIABLEt:
		 if (Item->Var->reserve != NA_RESERVE) {
		   if (PromptForReserve(Item->Var)) {
		     LoadSelectionWindow (PART4);
		     ItemWindow (UPDATEiw, IWsel, IWsel->itemN);
		   }
		 }
		 else
		   ItemWindow (BEEPiw, IWsel);
		 break;
	     }
	     break;
	   case BLOCKINGcx:
	     switch (Item->type) {
	       case RECORDt:
	       case INDICESt:
		 ItemWindow (BEEPiw, IWsel);
		 break;
	       case VARIABLEt:
		 if (PromptForBlocking(Item->Var)) {
		   LoadSelectionWindow (PART4);
		   ItemWindow (UPDATEiw, IWsel, IWsel->itemN);
		 }
		 break;
	     }
	     break;
	 }
	 break;
       case DELETEkey_FSI:
	 switch (cX) {
	   case NAMEcx:
	   case SPARSEcx:
	   case COMPRESScx:
	   case RESERVEcx:
	   case BLOCKINGcx:
	     ItemWindow (BEEPiw, IWsel);
	     break;
	 }
	 break;
       case FLIPkey_EXPORT:
	 if (FlipItems(rX)) {
	   int itemN = (IWsel->itemN + nSELWINDOWcols4) % IWsel->nItems;
	   LoadSelectionWindow (PART4);
	   ItemWindow (UPDATEiw, IWsel, itemN);
	 }
	 else
	   ItemWindow (BEEPiw, IWsel);
	 break;
       case ACTIONSkey_EXPORT:
	 if (!ActionMenu(PART4)) {
	   *noMoreAccess = TRUE;
	   return FALSE;
	 }
	 break;
       case OPTIONSkey_EXPORT:
	 OptionMenu ();
	 LoadSelectionWindow (PART4);
	 ItemWindow (UPDATEiw, IWsel, IWsel->itemN);
	 break;
       case HELPkey_FSI:
	 OnlineHelpWindow ("cdfxp.ilh", VAR4helpID);
	 break;
       case PART1key_EXPORT:
	 return TRUE;
       case EXITkey_FSI:
	 if (ConfirmExit()) return FALSE;
	 break;
     }
     /*************************************************************************
     * Update key definitions in case they were changed.
     *************************************************************************/
     NEWkeyDEFS (EWkey, keyDefs, batchMode)
  }
}

/******************************************************************************
* ActionMenu.
* Returns FALSE if no more access to the CDF.
******************************************************************************/

Logical ActionMenu (part)
int part;
{
  static Logical first = TRUE;
  static int actExits[] = { ENTERkey_FSI, HELPkey_FSI, EXITkey_FSI, NUL };
  static char *actLines1[] = {
    "List to screen",
    "List to file...",
    "Output to CDF(V2.7)...",
    "Walk on screen",
    "Output all items/variables",
    "Output no items/variables",
    "Filter all items/variables",
    "Filter no items/variables",
    "Set CDF's compression...",
    "Set variable compressions...",
    "Save settings...",
    "Restore settings...",
    "Set monotonicities",
    "Set CDF's checksum..."
  };
  static char *actLines2[] = {
    "List to screen",
    "List to file...",
    "Output to CDF(V3)...",
    "Output to CDF(V2.7)...",
    "Walk on screen",
    "Output all items/variables",
    "Output no items/variables",
    "Filter all items/variables",
    "Filter no items/variables",
    "Set CDF's compression",
    "Set variable compressions...",
    "Save settings...",
    "Restore settings...",
    "Set monotonicities",
    "Set CDF's checksum..."
  };

  static int actLineNs1[] = { 0,1,2,3,4,5,6,7,8,9,10,11,12,13 };
  static int actCols1[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
  static int actLens1[] = { 33,33,33,33,33,33,33,33,33,33,33,33,33,33 };
  static int actbLens1[] = { 33,33,33,33,33,33,33,33,33,33,33,33,33,33 };
  static int actLineNs2[] = { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14 };
  static int actCols2[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
  static int actLens2[] = { 33,33,33,33,33,33,33,33,33,33,33,33,33,33,33 };
  static int actbLens2[] = { 33,33,33,33,33,33,33,33,33,33,33,33,33,33,33 };

  static struct ItemWindowStruct IWact1 = {
    1, 44, 35, " ActionMenu ", 0, NULL, 14, actLines1, 14, actLineNs1,
    actCols1, actLens1, actbLens1, 14, 0, NULL, actExits, REFRESHkey_FSI,
    FALSE, NUL, NUL
  };
  static struct ItemWindowStruct IWact2 = {
    1, 44, 35, " ActionMenu ", 0, NULL, 15, actLines2, 15, actLineNs2,
    actCols2, actLens2, actbLens2, 15, 0, NULL, actExits, REFRESHkey_FSI,
    FALSE, NUL, NUL
  };
  static struct ItemWindowStruct IWact;
  struct ItemStruct *Item;
  static char keyDefs[] = {
    "Select: ________    Help: ________    Exit: ________\n\n"
  };
  int ix = 0, iy;
  /****************************************************************************
  * Create ActionMenu and process keystrokes.
  ****************************************************************************/
  if (first) {
    char *p1 = keyDefs;
    EncodeKeyDefinitions (1, &p1, ENTERkey_FSI, HELPkey_FSI, EXITkey_FSI);
    first = FALSE;
  }
  if (CDFgetFileBackwardEnvVar() == 1) 
    IWact = IWact1;
  else {
    IWact = IWact2;
    ix = 1;
  }
  ItemWindow (NEWiw, &IWact, 0);
  for (;;) {
     NEWkeyDEFS (EWkey, keyDefs, batchMode)
     ItemWindow (READiw, &IWact);
     switch (IWact.key) {
       case ENTERkey_FSI: {
	 iy = IWact.itemN;
	 if (ix == 0) {
	   if (iy == TOCDFact) iy = TOCDFv2act; /* TOCDFv2act */
	 } else {
	   if (iy == (TOCDFact + 1)) iy = TOCDFv2act;
	   else if ((iy > (TOCDFact + 1)) && (iy != SETcdfCHECKSUMact)) iy--;
	 }
	 switch (iy) {
	   case TOSCREENact:
	     ItemWindow (DELETEiw, &IWact);
	     return BOO(opt.horizontalMode,ToScreenHori(),ToScreenVert());
	   case TOFILEact:
	     ItemWindow (DELETEiw, &IWact);
	     return BOO(opt.horizontalMode,ToFileHori(),ToFileVert());
	   case TOCDFact: 
	   case TOCDFv2act: {
	     CDFstatus status; CDFid inID;
	     ItemWindow (DELETEiw, &IWact);
	     status = CDFlib (CONFIRM_, CDF_, &inID,
			      NULL_);
	     DisplayStatus (status, "confirming input CDF");
	     if (StatusBAD(status)) return FALSE;
	     CDFsetFileBackward(BACKWARDFILEoff);
	     if (iy == TOCDFv2act) CDFsetFileBackward(BACKWARDFILEon);
	     return ToCDF(inID);
	   }
	   case WALKact: {
	     ItemWindow (DELETEiw, &IWact);
	     return ToWalk();
	   }
	   case OUTPUTallITEMSact:
	   case OUTPUTnoITEMSact: {
	     Logical state = (iy == OUTPUTallITEMSact);
	     ItemWindow (DELETEiw, &IWact);
	     DisplayMessage (BOO(state,"Setting `outputs' to `YES'.",
					"Setting `outputs' to `no'"), NOWAIT);
	     for (Item = itemHead; Item != NULL; Item = Item->nextItem) {
		Item->outputSetting = state;
	     }
	     LoadSelectionWindow (part);
	     ItemWindow (UPDATEiw, IWsel, IWsel->itemN);
	     DisplayMessage ("", NOWAIT);
	     return TRUE;
	   }
	   case FILTERallITEMSact:
	     ItemWindow (DELETEiw, &IWact);
	     DisplayMessage ("Setting `filters' to `YES'.", NOWAIT);
	     for (Item = itemHead; Item != NULL; Item = Item->nextItem) {
		switch (Item->type) {
		  case RECORDt:
		    if (Item->Record->min != NOminMax ||
			Item->Record->max != NOminMax) {
		      Item->filterSetting = TRUE;
		    }
		    break;
		  case INDICESt:
		    if (Item->Indices->minNumDims != NOminMax ||
			Item->Indices->maxNumDims != NOminMax) {
		      Item->filterSetting = TRUE;
		    }
		    break;
		  case VARIABLEt:
		    if (Item->Var->min != NULL ||
			Item->Var->max != NULL) Item->filterSetting = TRUE;
		    break;
		}
	     }
	     LoadSelectionWindow (part);
	     ItemWindow (UPDATEiw, IWsel, IWsel->itemN);
	     DisplayMessage ("", NOWAIT);
	     return TRUE;
	   case FILTERnoITEMSact:
	     ItemWindow (DELETEiw, &IWact);
	     DisplayMessage ("Setting `filters' to `no'.", NOWAIT);
	     for (Item = itemHead; Item != NULL; Item = Item->nextItem) {
		Item->filterSetting = FALSE;
	     }
	     LoadSelectionWindow (part);
	     ItemWindow (UPDATEiw, IWsel, IWsel->itemN);
	     DisplayMessage ("", NOWAIT);
	     return TRUE;
	   case SETcdfCOMPRESSact: {
	     long cType, cParms[CDF_MAX_PARMS]; int parmN;
	     ItemWindow (DELETEiw, &IWact);
	     if (PromptForCompression(&cType,cParms)) {
	       CDFcType = cType;
	       for (parmN = 0; parmN < CDF_MAX_PARMS; parmN++) {
		  CDFcParms[parmN] = cParms[parmN];
	       }
	       LoadCDFwindow (NULL);
	       FieldWindow (UPDATEfw, FWcdf, 0, LogicalTRUE);
	     }
	     return TRUE;
	   }
	   case SETvarCOMPRESSact: {
	     long cType, cParms[CDF_MAX_PARMS]; int parmN;
	     ItemWindow (DELETEiw, &IWact);
	     if (PromptForCompression(&cType,cParms)) {
	       for (Item = itemHead; Item != NULL; Item = Item->nextItem) {
		  switch (Item->type) {
		    case RECORDt:
		    case INDICESt:
		      break;
		    case VARIABLEt:
		      Item->Var->cType = cType;
		      for (parmN = 0; parmN < CDF_MAX_PARMS; parmN++) {
			 Item->Var->cParms[parmN] = cParms[parmN];
		      }
		      break;
		  }
	       }
	       LoadSelectionWindow (part);
	       ItemWindow (UPDATEiw, IWsel, IWsel->itemN);
	     }
	     return TRUE;
	   }
	   case SAVEact:
	     ItemWindow (DELETEiw, &IWact);
	     if (PromptFor(settingsFile,DU_MAX_PATH_LEN,strlen(settingsFile),
			   "Enter path for settings file...",SETFILEhelpID)) {
	       DisplayMessage ("Saving settings...", NOWAIT);
	       SaveSettings ();
	       DisplayMessage ("", NOWAIT);
	     }
	     return TRUE;
	   case RESTOREact:
	     ItemWindow (DELETEiw, &IWact);
	     if (PromptFor(settingsFile,DU_MAX_PATH_LEN,strlen(settingsFile),
			   "Enter path for settings file...",SETFILEhelpID)) {
	       DisplayMessage ("Restoring settings...", NOWAIT);
	       RestoreSettings ();
	       LoadSelectionWindow (part);
	       ItemWindow (UPDATEiw, IWsel, IWsel->itemN);
	       DisplayMessage ("", NOWAIT);
	     }
	     return TRUE;
	   case SETMONOact:
	     ItemWindow (DELETEiw, &IWact);
	     if (!SetItemMonotonicities()) return FALSE;
	     LoadSelectionWindow (part);
	     ItemWindow (UPDATEiw, IWsel, IWsel->itemN);
	     return TRUE;
           case SETcdfCHECKSUMact: {
             long checksum; 
             ItemWindow (DELETEiw, &IWact);
             if (PromptForChecksum(&checksum)) {
               CDFchecksum = checksum;
               LoadCDFwindow (NULL);
               FieldWindow (UPDATEfw, FWcdf, 0, LogicalTRUE);
             }
             return TRUE;
           }
	 }
	 break;
      }
      case HELPkey_FSI:
	if (CDFgetFileBackwardEnvVar() == 1)
	  OnlineHelpWindow ("cdfxp.ilh", ACTIONhelpID);
	else
	  OnlineHelpWindow ("cdfxp.ilh", ACTIONv32helpID);
	break;
      case EXITkey_FSI:
	ItemWindow (DELETEiw, &IWact);
	return TRUE;
    }
  }
}

/******************************************************************************
* OptionMenu.
******************************************************************************/

void OptionMenu () {
  Logical first = TRUE; struct OptionStruct optSave;
  int style;
  static long nextEncoding[] = {
    0L, SUN_ENCODING, VAX_ENCODING, DECSTATION_ENCODING, SGi_ENCODING,
    IBMPC_ENCODING, IBMRS_ENCODING, HOST_ENCODING, PPC_ENCODING,
    HP_ENCODING, 0L, NeXT_ENCODING, ALPHAOSF1_ENCODING, ALPHAVMSd_ENCODING,
    ALPHAVMSg_ENCODING, ALPHAVMSi_ENCODING, ARM_LITTLE_ENCODING,
    ARM_BIG_ENCODING, IA64VMSi_ENCODING, IA64VMSd_ENCODING,
    IA64VMSg_ENCODING, NETWORK_ENCODING
  };
  static long prevEncoding[] = {
    0L, IA64VMSg_ENCODING, NETWORK_ENCODING, SUN_ENCODING,
        VAX_ENCODING, DECSTATION_ENCODING, SGi_ENCODING, IBMPC_ENCODING,
        IBMRS_ENCODING, HOST_ENCODING, 0L, PPC_ENCODING, HP_ENCODING,
        NeXT_ENCODING, ALPHAOSF1_ENCODING, ALPHAVMSd_ENCODING,
        ALPHAVMSg_ENCODING, ALPHAVMSi_ENCODING, ARM_LITTLE_ENCODING,
        ARM_BIG_ENCODING, IA64VMSi_ENCODING, IA64VMSd_ENCODING 
  };
  static int optExits[] = { ENTERkey_FSI, HELPkey_FSI, EXITkey_FSI,
			    NEXTFIELDkey_EXPORT, PREVFIELDkey_EXPORT, NUL };
  AOSs15 (optLines, BLANKs40, BLANKs40, BLANKs40, BLANKs40, BLANKs40,
	            BLANKs40, BLANKs40, BLANKs40, BLANKs40, BLANKs40,
	            BLANKs40, BLANKs40, BLANKs40, BLANKs40, BLANKs40)
  static int optLineNs[] = { 0,1,2,3,4,5,6,7,8,9,10,11 };
  static int optCols[] = { 0,0,0,0,0,0,0,0,0,0,0,0 };
  static int optLens[] = { 33,33,33,33,33,33,33,33,33,33,33,33 };
  static int optbLens[] = { 33,33,33,33,33,33,33,33,33,33,33,33 };
  static struct ItemWindowStruct IWopt = {
    1, 44, 35, " OptionMenu ", 0, NULL, 12, optLines, 12, optLineNs, optCols,
    optLens, optbLens, 13, 0, NULL, optExits, REFRESHkey_FSI, FALSE, NUL, NUL
  };
  static char keyDefs[] = "Enter: ________    Increment: ____________    Help: ________\nExit:  ________    Decrement: ____________\n";
  /****************************************************************************
  * Display OptionMenu and process keystrokes until exit requested.
  ****************************************************************************/
  for (;;) {
     /*************************************************************************
     * Initialize/update OptionMenu lines.
     *************************************************************************/
     size_t ilen = (size_t) sizeof(BLANKs40);
     snprintf (IWopt.iLines[FILTERrx], ilen, "Use filters: %s",
	       BOO(opt.overallFilter,"YES","no"));
     snprintf (IWopt.iLines[FILLSrx], ilen, "Use fill values: %s",
	       BOO(opt.useFills,"YES","no"));
     snprintf (IWopt.iLines[CDFFORMATrx], ilen, "Create %s-file CDFs",
	       BOO(opt.singleFile,"single","multi"));
     snprintf (IWopt.iLines[ENCODINGrx], ilen, "Create %s-encoded CDFs",
	       encodings[(int)opt.encoding]);
     snprintf (IWopt.iLines[EPOCHrx], ilen, "EPOCH style: %s",
	       epochStyles[opt.epochStyle]);
     snprintf (IWopt.iLines[hvMODErx], ilen, "%s listings",
	       BOO(opt.horizontalMode,"Horizontal","Vertical"));
     snprintf (IWopt.iLines[MAJORrx], ilen, "Majority: %s",
	       majorities[(int)opt.majority]);
     snprintf (IWopt.iLines[SHOWrx], ilen, "Show filtered lines: %s",
	       BOO(opt.showFiltered,"YES","no"));
     snprintf (IWopt.iLines[SPACINGrx], ilen, "Item/variable spacing: %d",
	       opt.spacing);
     snprintf (IWopt.iLines[DELETErx], ilen, "Delete existing CDF: %s",
	       BOO(opt.deleteExisting,"YES, beware!","no"));
     snprintf (IWopt.iLines[PREALLOCrx], ilen, "Preallocate records: %s",
	       BOO(opt.preAllocate,"YES","no"));
     snprintf (IWopt.iLines[HEADINGrx], ilen, "Display heading: %s",
	       BOO(opt.textHeading,BOO(poundedheading==1,"POUNDEDHEADING",
                                       "YES"),"no"));
     /*************************************************************************
     * Create OptionMenu and encode key definitions first time.  Just update
     * the OptionMenu all the following times.
     *************************************************************************/
     if (first) {
       char *p1 = keyDefs;
       EncodeKeyDefinitions (1, &p1, ENTERkey_FSI, NEXTFIELDkey_EXPORT,
			     HELPkey_FSI, EXITkey_FSI, PREVFIELDkey_EXPORT);
       ItemWindow (NEWiw, &IWopt, 0);
       memmove (&optSave, &opt, sizeof(struct OptionStruct));
       first = FALSE;
     }
     else
       ItemWindow (UPDATEiw, &IWopt, IWopt.itemN);
     /*************************************************************************
     * Update key definitions (in case there were changed).
     *************************************************************************/
     NEWkeyDEFS (EWkey, keyDefs, batchMode)
     style = opt.epochStyle;
     /*************************************************************************
     * Process keystroke.
     *************************************************************************/
     ItemWindow (READiw, &IWopt);
     switch (IWopt.key) {
       case ENTERkey_FSI:
	 ItemWindow (DELETEiw, &IWopt);
	 return;
       case NEXTFIELDkey_EXPORT:
	 switch (IWopt.itemN) {
	   case FILTERrx:
	     opt.overallFilter = BOO(opt.overallFilter,FALSE,TRUE);
	     break;
	   case FILLSrx:
	     opt.useFills = BOO(opt.useFills,FALSE,TRUE);
	     break;
	   case CDFFORMATrx:
	     opt.singleFile = BOO(opt.singleFile,FALSE,TRUE);
	     break;
	   case hvMODErx:
	     opt.horizontalMode = BOO(opt.horizontalMode,FALSE,TRUE);
	     break;
	   case SHOWrx:
	     opt.showFiltered = BOO(opt.showFiltered,FALSE,TRUE);
	     break;
	   case DELETErx:
	     opt.deleteExisting = BOO(opt.deleteExisting,FALSE,TRUE);
	     break;
	   case PREALLOCrx:
	     opt.preAllocate = BOO(opt.preAllocate,FALSE,TRUE);
	     break;
	   case HEADINGrx:
             if (opt.textHeading == FALSE) {
               opt.textHeading = TRUE;
               poundedheading = 0;
             } else {
               if (poundedheading == 0)
                 poundedheading = 1;
               else {
                 poundedheading = 0;
                 opt.textHeading = FALSE;
               }
             }
	     break;
	   case MAJORrx:
	     opt.majority = BOO(opt.majority == COLUMN_MAJOR,
				INPUT_MAJOR,opt.majority + 1);
	     break;
	   case ENCODINGrx:
	     opt.encoding = nextEncoding[(int)opt.encoding];
	     break;
	   case EPOCHrx:
	     opt.epochStyle = BOO(opt.epochStyle == EPOCH4_STYLE,
				  EPOCH0_STYLE,opt.epochStyle + 1);
	     if (style != opt.epochStyle) {
	       long dt; int ix; struct ItemStruct *itemx;
	       if (opt.epochStyle == EPOCH3_STYLE) ziso8601 = TRUE;
               else ziso8601 = FALSE;
	       itemx = itemHead;
	       while (itemx != NULL) {
	         if (itemx->type == VARIABLEt) {
	           dt = itemx->Var->dataType;
	           if (dt == CDF_EPOCH || dt == CDF_EPOCH16 ||
		       dt == CDF_TIME_TT2000) {
	             itemx->width = VariableWidth(itemx->Var);
	           }
	         }
	         itemx = itemx->nextItem;
	       }
	     }
	     break;
	   case SPACINGrx:
	     opt.spacing++;
	     break;
	 }
	 break;
       case PREVFIELDkey_EXPORT:
	 switch (IWopt.itemN) {
	   case FILTERrx:
	     opt.overallFilter = BOO(opt.overallFilter,FALSE,TRUE);
	     break;
	   case FILLSrx:
	     opt.useFills = BOO(opt.useFills,FALSE,TRUE);
	     break;
	   case CDFFORMATrx:
	     opt.singleFile = BOO(opt.singleFile,FALSE,TRUE);
	     break;
	   case hvMODErx:
	     opt.horizontalMode = BOO(opt.horizontalMode,FALSE,TRUE);
	     break;
	   case SHOWrx:
	     opt.showFiltered = BOO(opt.showFiltered,FALSE,TRUE);
	     break;
	   case DELETErx:
	     opt.deleteExisting = BOO(opt.deleteExisting,FALSE,TRUE);
	     break;
	   case PREALLOCrx:
	     opt.preAllocate = BOO(opt.preAllocate,FALSE,TRUE);
	     break;
	   case HEADINGrx:
             if (opt.textHeading == FALSE) {
               opt.textHeading = TRUE;
               poundedheading = 1;
             } else {
               if (poundedheading == 1)
                 poundedheading = 0;
               else {
                 poundedheading = 0;
                 opt.textHeading = FALSE;
               }
             }
	     break;
	   case MAJORrx:
	     opt.majority = BOO(opt.majority == INPUT_MAJOR,
				COLUMN_MAJOR,opt.majority - 1);
	     break;
	   case ENCODINGrx:
	     opt.encoding = prevEncoding[(int)opt.encoding];
	     break;
	   case EPOCHrx:
	     opt.epochStyle = BOO(opt.epochStyle == EPOCH0_STYLE,
				  EPOCH4_STYLE,opt.epochStyle - 1);
	     if (style != opt.epochStyle) {
	       long dt; int ix; struct ItemStruct *itemx;
	       if (opt.epochStyle == EPOCH3_STYLE) ziso8601 = TRUE;
               else ziso8601 = FALSE;
	       itemx = itemHead;
	       while (itemx != NULL) {
	         if (itemx->type == VARIABLEt) {
	           dt = itemx->Var->dataType;
	           if (dt == CDF_EPOCH || dt == CDF_EPOCH16 ||
		       dt == CDF_TIME_TT2000) {
	             itemx->width = VariableWidth(itemx->Var);
	           }
	         }
	         itemx = itemx->nextItem;
	       }
	     }
	     break;
	   case SPACINGrx:
	     if (opt.spacing > 0)
	       opt.spacing--;
	     else
	       ItemWindow (BEEPiw, &IWopt);
	     break;
	 }
	 break;
       case HELPkey_FSI:
	 OnlineHelpWindow ("cdfxp.ilh", OPTIONhelpID);
	 break;
       case EXITkey_FSI:
	 ItemWindow (DELETEiw, &IWopt);
	 memmove (&opt, &optSave, sizeof(struct OptionStruct));
	 return;
     }
  }
}

/******************************************************************************
* ConfirmExit.
* Returns TRUE if exit should proceed.  FALSE if exit should be aborted.
******************************************************************************/

Logical ConfirmExit () {
  return TRUE;
}

/******************************************************************************
* DisplayStatus.
******************************************************************************/

void DisplayStatus (status, text)
CDFstatus status;
char *text;
{
  if (status == CDF_OK) return;
  if (StatusINFO(status)) {
    if (report[INFOs]) {
      char explanation[CDF_STATUSTEXT_LEN+1], msg[MAX_MESSAGE_TEXT_LEN+1];
      CDFlib (SELECT_, CDF_STATUS_, status,
	      GET_, STATUS_TEXT_, explanation,
	      NULL_);
      strcpyX (msg, "Informational...while ", MAX_MESSAGE_TEXT_LEN);
      strcatX (msg, text, MAX_MESSAGE_TEXT_LEN);
      strcatX (msg, ".", MAX_MESSAGE_TEXT_LEN);
      DisplayMessage (msg, NOBEEPWAIT1);
      DisplayMessage (explanation, NOBEEPWAIT1);
    }
    return;
  }
  if (StatusWARN(status)) {
    if (report[WARNs]) {
      char explanation[CDF_STATUSTEXT_LEN+1], msg[MAX_MESSAGE_TEXT_LEN+1];
      CDFlib (SELECT_, CDF_STATUS_, status,
	      GET_, STATUS_TEXT_, explanation,
	      NULL_);
      strcpyX (msg, "Warning...while ", MAX_MESSAGE_TEXT_LEN);
      strcatX (msg, text, MAX_MESSAGE_TEXT_LEN);
      strcatX (msg, ".", MAX_MESSAGE_TEXT_LEN);
      DisplayMessage (msg, BEEPWAIT1);
      DisplayMessage (explanation, BEEPWAIT1);
    }
    return;
  }
  if (report[ERRORs]) {
    char explanation[CDF_STATUSTEXT_LEN+1], msg[MAX_MESSAGE_TEXT_LEN+1];
    CDFlib (SELECT_, CDF_STATUS_, status,
	    GET_, STATUS_TEXT_, explanation,
	    NULL_);
    strcpyX (msg, "ERROR...while ", MAX_MESSAGE_TEXT_LEN);
    strcatX (msg, text, MAX_MESSAGE_TEXT_LEN);
    strcatX (msg, ".", MAX_MESSAGE_TEXT_LEN);
    DisplayMessage (msg, BEEPWAIT1);
    DisplayMessage (explanation, BEEPWAIT);
  }
  return;
}

/******************************************************************************
* DisplayMessage.
*   wait = NOWAIT.      Return immediately, do not clear message.  NUL is
*                       returned.
*   wait = NOBEEPWAIT.  Wait for user input then clear message.  The key
*                       entered is returned.
*   wait = NOBEEPWAIT1. Wait one second then clear message.  NUL is returned.
*   wait = NOBEEPWAIT2. Wait two seconds then clear message.  NUL is returned.
*   wait = BEEPWAIT.    Beep, wait for user input then clear message.  The key
*                       entered is returned.
*   wait = BEEPWAIT1.   Beep, wait one second then clear message.  NUL is
*                       returned.
*   wait = BEEPWAIT2.   Beep, wait two seconds then clear message.  NUL is
*                       returned.
******************************************************************************/

int DisplayMessage (message, wait)
char *message;
int wait;
{
  /****************************************************************************
  * If batch mode, just print the message to the standard output.
  ****************************************************************************/
  if (BATCH(batchMode)) {
    printf ("%s\n", message);
    return 0;
  }
  /****************************************************************************
  * Otherwise...
  ****************************************************************************/
  strcpyX (EWmsg->eText, message, EWmsg->nColsTotal - 2);
  switch (wait) {
    case NOWAIT:
      EditWindow (UPDATEew, EWmsg, LogicalTRUE);
      return 0;
    case NOBEEPWAIT:
    case BEEPWAIT: {
      static char newLabel[] = { " Enter any key to acknowledge. " };
      char *saveLabel = EWmsg->label;
      EWmsg->label = newLabel;
      EditWindow (UPDATEew, EWmsg, LogicalTRUE);
      if (wait == BEEPWAIT) EditWindow (BEEPew, EWmsg);
      EditWindow (READew, EWmsg);
      MakeNUL (EWmsg->eText);
      EWmsg->label = saveLabel;
      EditWindow (UPDATEew, EWmsg, LogicalTRUE);
      return EWmsg->key;
    }
    case NOBEEPWAIT1:
    case NOBEEPWAIT2:
    case BEEPWAIT1:
    case BEEPWAIT2: {
      double seconds = BOO((wait == NOBEEPWAIT1 || wait == BEEPWAIT1),1.0,2.0);
      EditWindow (UPDATEew, EWmsg, LogicalTRUE);
      if (wait == BEEPWAIT1 || wait == BEEPWAIT2) EditWindow (BEEPew, EWmsg);
      zzzzz (seconds);
      MakeNUL (EWmsg->eText);
      EditWindow (UPDATEew, EWmsg, LogicalTRUE);
      return 0;
    }
  }
  return 0;
}

/******************************************************************************
* MatchOption.
*   Returns `AMBIGUOUSopt' if ambiguous, `UNKNOWNopt' if not found.
******************************************************************************/

int MatchOption (option, validOptions)
char *option;
char *validOptions[];
{
  int i, j;
  /****************************************************************************
  * First try for an exact match.
  ****************************************************************************/
  for (i = 0; validOptions[i] != NULL; i++) {
     if (strcmpIgCase(option,validOptions[i]) == 1) return i;
  }
  /****************************************************************************
  * Check if the option matches the first part of one of the valid options
  * (ie. it has been abbreviated by truncation).  If so, make sure that it
  * cannot be any of the other valid options (ie. ambiguous).
  ****************************************************************************/
  for (i = 0; validOptions[i] != NULL; i++) {
     if (strncmpIgCasePattern(option,validOptions[i],strlen(option)) == 0) {
       for (j = i + 1; validOptions[j] != NULL; j++) {
	  if (strncmpIgCasePattern(option,validOptions[j],strlen(option)) == 0) 
	    return AMBIGUOUSopt;
       }
       return i;
     }
  }
  /****************************************************************************
  * The option was not found.
  ****************************************************************************/
  return UNKNOWNopt;
}

/******************************************************************************
* FreeItems.
******************************************************************************/

void FreeItems () {
  struct ItemStruct *Item = itemHead, *tItem;
  while (Item != NULL) {
    tItem = Item->nextItem;
    switch (Item->type) {
      case RECORDt:
	cdf_FreeMemory (Item->Record, FatalError);
	break;
      case INDICESt:
	cdf_FreeMemory (Item->Indices, FatalError);
	break;
      case VARIABLEt:
	if (Item->Var->name != NULL)
	  cdf_FreeMemory (Item->Var->name, FatalError);
	if (Item->Var->min != NULL)
	  cdf_FreeMemory (Item->Var->min, FatalError);
	if (Item->Var->max != NULL)
	  cdf_FreeMemory (Item->Var->max, FatalError);
	if (Item->Var->format != NULL)
	  cdf_FreeMemory (Item->Var->format, FatalError);
	if (Item->Var->fill != NULL)
	  cdf_FreeMemory (Item->Var->fill, FatalError);
	if (Item->Var->pad != NULL)
	  cdf_FreeMemory (Item->Var->pad, FatalError);
	if (Item->Var->value != NULL)
	  cdf_FreeMemory (Item->Var->value, FatalError);
	cdf_FreeMemory (Item->Var, FatalError);
	break;
    }
    cdf_FreeMemory (Item, FatalError);
    Item = tItem;
  }
  itemHead = NULL;
  return;
}
/******************************************************************************
* LongValueWidth.
******************************************************************************/

int LongValueWidth (value)
long value;
{
  int width = 1;
  long tmp = value / 10;
  while (tmp != 0) {
    width++;
    tmp = tmp / 10;
  }
  return width;
}

/******************************************************************************
* RecordIndicesWidth.
******************************************************************************/

int RecordIndicesWidth (lastRec, numDims, dimSizes, type)
long lastRec;
long numDims;
long dimSizes[];
int type;
{
  switch (type) {
    case RECORDt:
      return MaxInt(LongValueWidth(lastRec),MIN_RECORD_WIDTH);
    case INDICESt: {
      int n, indicesW = (int) (1 + BOO(numDims > 1,numDims - 1,0) + 1);
      for (n = 0; n < numDims; n++) indicesW += LongValueWidth(dimSizes[n]);
      return MAXIMUM(indicesW,MIN_INDICES_WIDTH);
    }
  }
  return 0;
}

/******************************************************************************
* FreeToScreen.
******************************************************************************/

void FreeToScreen (header, scrLines, trailer)
char *header[];
char *scrLines[];
char *trailer[];
{
  int lineN;
  cdf_FreeMemory (header[0], FatalError);
  for (lineN = 0; lineN < NUMscreenLINES; lineN++) {
     cdf_FreeMemory (scrLines[lineN], FatalError);
  }
  cdf_FreeMemory (trailer[0], FatalError);
  return;
}

/******************************************************************************
* PromptFor.
******************************************************************************/

Logical PromptFor (value, valueL, cursorAt, label, helpID)
char *value;
int valueL;
int cursorAt;
char *label;
int helpID;
{
  static Logical first = TRUE;
  static int exits[] = { ENTERkey_FSI, HELPkey_FSI, EXITkey_FSI, NUL };
  static struct PromptWindowStruct PW = {
    NULL, 21, 0, SCREEN_WIDTH, 0, NULL, 0, NULL, 0, NULL, exits,
    REFRESHkey_FSI, SOLkey_FSI, EOLkey_FSI, INSERTorOVERkey_FSI
  };
  static char keyDefsBlank[] = "\n\n";
  static char keyDefsPrompt[] = {
    "Enter: ________    Help: ________    Exit: ________\n\n"
  };
  if (first) {
    char *p1 = keyDefsPrompt;
    EncodeKeyDefinitions (1, &p1, ENTERkey_FSI, HELPkey_FSI, EXITkey_FSI);
    first = FALSE;
  }
  PW.label = label;
  PW.maxChars = valueL;
  PW.value = value;
  PromptWindow (NEWpw, &PW, cursorAt, LogicalTRUE);
  NEWkeyDEFS (EWkey, keyDefsPrompt, batchMode)
  for (;;) {
     PromptWindow (READpw, &PW);
     switch (PW.key) {
       case ENTERkey_FSI:
	 PromptWindow (DELETEpw, &PW);
	 NEWkeyDEFS (EWkey, keyDefsBlank, batchMode)
	 return TRUE;
       case HELPkey_FSI:
	 OnlineHelpWindow ("cdfxp.ilh", helpID);
	 break;
       case EXITkey_FSI:
	 PromptWindow (DELETEpw, &PW);
	 NEWkeyDEFS (EWkey, keyDefsBlank, batchMode)
	 return FALSE;
     }
  }
}

/******************************************************************************
* PromptForMinMax.
******************************************************************************/

Logical PromptForMinMax (Item, min)
struct ItemStruct *Item;
Logical min;
{
  static char value[MAXminMaxLEN+1];
  static char minGTmaxMsg[] = {
    "That minimum would be greater than the current maximum."
  };
  static char maxLTminMsg[] = {
    "That maximum would be less than the current minimum."
  };
  switch (Item->type) {
    /**************************************************************************
    * Record.
    **************************************************************************/
    case RECORDt: {
      long *mmPtr = BOO(min,&(Item->Record->min),&(Item->Record->max));
      long *mmPtrX = BOO(min,&(Item->Record->max),&(Item->Record->min));
      long newValue;
      /************************************************************************
      * Set initial value.
      ************************************************************************/
      if (*mmPtr == NOminMax)
	MakeNUL (value);
      else
	snprintf (value, (size_t) sizeof(value), "%ld", *mmPtr + 1);
      /************************************************************************
      * Prompt for new value.
      ************************************************************************/
      if (!PromptFor(value,MAXminMaxLEN,strlen(value),
		     BOO(min,"Enter new minimum record...",
			     "Enter new maximum record..."),
		     MINmaxRECORDhelpID)) {
	return FALSE;
      }
      /************************************************************************
      * Entering nothing erases the current value.
      ************************************************************************/
      if (NULstring(value)) {
	if (*mmPtr != NOminMax) {
	  *mmPtr = NOminMax;
	  if (*mmPtrX == NOminMax) Item->filterSetting = FALSE;
	  return TRUE;
	}
	else
	  return FALSE;
      }
      /************************************************************************
      * Decode the value entered.
      ************************************************************************/
      if (sscanf(value,"%ld",&newValue) != 1) {
	DisplayMessage ("Error decoding value.", BEEPWAIT1);
	return FALSE;
      }
      else
	newValue--;
      /************************************************************************
      * Validate the value entered.
      ************************************************************************/
      if (newValue < 0) {
	DisplayMessage ("Illegal value.", BEEPWAIT1);
	return FALSE;
      }
      /************************************************************************
      * Make sure the new minimum is not greater than the current maximum.
      ************************************************************************/
      if (min && Item->Record->max != NOminMax) {
	if (newValue > Item->Record->max) {
	  DisplayMessage (minGTmaxMsg, BEEPWAIT1);
	  return FALSE;
	}
      }
      /************************************************************************
      * Make sure the new maximum is not less than the current minimum.
      ************************************************************************/
      if (!min && Item->Record->min != NOminMax) {
	if (newValue < Item->Record->min) {
	  DisplayMessage (maxLTminMsg, BEEPWAIT1);
	  return FALSE;
	}
      }
      /************************************************************************
      * Everything's OK, save the new value entered.
      ************************************************************************/
      *mmPtr = newValue;
      Item->filterSetting = TRUE;
      opt.overallFilter = TRUE;
      break;
    }
    /**************************************************************************
    * Indices.
    **************************************************************************/
    case INDICESt: {
      long *mmNumDims = BOO(min,&(Item->Indices->minNumDims),
				&(Item->Indices->maxNumDims)),
	   *mmNumDimsX = BOO(min,&(Item->Indices->maxNumDims),
				 &(Item->Indices->minNumDims)),
	   *mmIndices = BOO(min,Item->Indices->minIndices,
				Item->Indices->maxIndices),
	   newNumDims, newIndices[CDF_MAX_DIMS];
      int dimN;
      /************************************************************************
      * Set initial indices.
      ************************************************************************/
      if (*mmNumDims == NOminMax)
	strcpyX (value, "[]", MAXminMaxLEN);
      else
	EncodeIndicesJustify (value, *mmNumDims, mmIndices, 0,
			      (size_t) sizeof(value));
      /************************************************************************
      * Prompt for new indices.
      ************************************************************************/
      if (!PromptFor(value,MAXminMaxLEN,strlen(value)-1,
		     BOO(min,"Enter new minimum indices...",
			     "Enter new maximum indices..."),
		     MINmaxINDICEShelpID)) {
	return FALSE;
      }
      /************************************************************************
      * Entering nothing erases the current indices.
      ************************************************************************/
      if (NULstring(value)) {
	if (*mmNumDims != NOminMax) {
	  *mmNumDims = NOminMax;
	  if (*mmNumDimsX == NOminMax) Item->filterSetting = FALSE;
	  return TRUE;
	}
	else
	  return FALSE;
      }
      /************************************************************************
      * Decode the indices entered.
      ************************************************************************/
      if (!DecodeRecordAndIndices(value,NULL,&newNumDims,newIndices)) {
	DisplayMessage ("Error decoding indices.", BEEPWAIT1);
	return FALSE;
      }
      /************************************************************************
      * Validate the indices entered.
      ************************************************************************/
      if (newNumDims == 0) {
	DisplayMessage ("Zero dimensions not allowed.", BEEPWAIT1);
	return FALSE;
      }
      for (dimN = 0; dimN < newNumDims; dimN++) {
	 if (newIndices[dimN] < 0) {
	   DisplayMessage ("Illegal indices.", BEEPWAIT1);
	   return FALSE;
	 }
      }
      /************************************************************************
      * Everything's OK, save the new value entered.
      ************************************************************************/
      *mmNumDims = newNumDims;
      for (dimN = 0; dimN < newNumDims; dimN++) {
	 mmIndices[dimN] = newIndices[dimN];
      }
      Item->filterSetting = TRUE;
      opt.overallFilter = TRUE;
      break;
    }
    /**************************************************************************
    * Variable.
    **************************************************************************/
    case VARIABLEt: {
      void *newValue; long numElems;
      void **mmPtr = BOO(min,&(Item->Var->min),&(Item->Var->max));
      void **mmPtrX = BOO(min,&(Item->Var->max),&(Item->Var->min));
      int style;
      if (TT2000dataType(Item->Var->dataType)) {
        if (!ziso8601) style = opt.epochStyle;
        else style = TT2000_4_STYLE;
      } else { 
        if (!ziso8601) style = opt.epochStyle;
        else style = EPOCH3_STYLE;
      }      
      /************************************************************************
      * Set initial value.
      ************************************************************************/
      if (*mmPtr == NULL)
	strcpyX (value, BOO(STRINGdataType(Item->Var->dataType),"\"\"",""), 0);
      else
	EncodeValuesFormat (Item->Var->dataType, Item->Var->numElems, *mmPtr,
			    value, Item->Var->format, 0, MAXminMaxLEN, style,
			    (size_t) sizeof(value));
      /************************************************************************
      * Prompt for new value.
      ************************************************************************/
      if (!PromptFor(value,MAXminMaxLEN,
		     strlen(value) -
		      BOO(STRINGdataType(Item->Var->dataType),1,0),
		     BOO(min,"Enter new minimum value...",
			     "Enter new maximum value..."),
		     MINmaxVALUEhelpID)) {
	return FALSE;
      }
      /************************************************************************
      * Entering nothing erases the current value.
      ************************************************************************/
      if (NULstring(value)) {
	if (*mmPtr != NULL) {
	  cdf_FreeMemory (*mmPtr, FatalError);
	  *mmPtr = NULL;
	  if (*mmPtrX == NULL) Item->filterSetting = FALSE;
	  return TRUE;
	}
	else
	  return FALSE;
      }
      /************************************************************************
      * Decode/validate the value entered.
      ************************************************************************/
      if (!DecodeValues(value,Item->Var->dataType,
			&numElems,&newValue,opt.epochStyle)) {
	DisplayMessage ("Error decoding value.", BEEPWAIT1);
	return FALSE;
      }
      if (numElems != Item->Var->numElems) {
	DisplayMessage ("Wrong number of elements.", BEEPWAIT1);
	cdf_FreeMemory (newValue, FatalError);
	return FALSE;
      }
      /************************************************************************
      * Make sure the new minimum is not greater than the current maximum.
      ************************************************************************/
      if (min && Item->Var->max != NULL) {
	if (GTx(newValue,Item->Var->max,
		Item->Var->dataType,Item->Var->numElems)) {
	  DisplayMessage (minGTmaxMsg, BEEPWAIT1);
	  cdf_FreeMemory (newValue, FatalError);
	  return FALSE;
	}
      }
      /************************************************************************
      * Make sure the new maximum is not less than the current minimum.
      ************************************************************************/
      if (!min && Item->Var->min != NULL) {
	if (LTx(newValue,Item->Var->min,
		Item->Var->dataType,Item->Var->numElems)) {
	  DisplayMessage (maxLTminMsg, BEEPWAIT1);
	  cdf_FreeMemory (newValue, FatalError);
	  return FALSE;
	}
      }
      /************************************************************************
      * Everything's OK, save the new value entered.
      ************************************************************************/
      if (*mmPtr == NULL)
	*mmPtr = cdf_AllocateMemory ((size_t)Item->Var->nValueBytes,
				     FatalError);
      memmove (*mmPtr, newValue, Item->Var->nValueBytes);
      cdf_FreeMemory (newValue, FatalError);
      Item->filterSetting = TRUE;
      opt.overallFilter = TRUE;
      break;
    }
  }
  return TRUE;
}

/******************************************************************************
* PromptForFill.
******************************************************************************/

Logical PromptForFill (Var)
struct VarStructXP *Var;
{
  static char value[MAXfillLEN+1];
  void *newValue; long numElems; int style;
  if (TT2000dataType(Var->dataType)) {
    if (!ziso8601) style = opt.epochStyle;
    else style = TT2000_4_STYLE;
  } else {
    if (!ziso8601) style = opt.epochStyle;
    else style = EPOCH3_STYLE;
  }
  /****************************************************************************
  * Set initial value.
  ****************************************************************************/
  if (Var->fill == NULL)
    strcpyX (value, BOO(STRINGdataType(Var->dataType),"\"\"",""), 0);
  else
    EncodeValuesFormat (Var->dataType, Var->numElems, Var->fill, value,
			Var->format, 0, MAXfillLEN, style,
			(size_t) sizeof(value));
  /****************************************************************************
  * Prompt for new value.
  ****************************************************************************/
  if (!PromptFor(value,MAXfillLEN,
		 strlen(value) - BOO(STRINGdataType(Var->dataType),1,0),
		 "Enter new fill value...",FILLhelpID)) {
    return FALSE;
  }
  /****************************************************************************
  * Check if nothing entered.
  ****************************************************************************/
  if (NULstring(value)) {
    if (Var->fill != NULL) {
      cdf_FreeMemory (Var->fill, FatalError);
      Var->fill = NULL;
      return TRUE;
    }
    else
      return FALSE;
  }
  /****************************************************************************
  * Decode/validate value.
  ****************************************************************************/
  if (!DecodeValues(value,Var->dataType,
		    &numElems,&newValue,opt.epochStyle)) {
    DisplayMessage ("Error decoding value.", BEEPWAIT1);
    return FALSE;
  }
  if (numElems != Var->numElems) {
    DisplayMessage ("Illegal number of elements.", BEEPWAIT1);
    cdf_FreeMemory (newValue, FatalError);
    return FALSE;
  }
  /****************************************************************************
  * Save new value.
  ****************************************************************************/
  if (Var->fill == NULL) {
    Var->fill = cdf_AllocateMemory ((size_t)Var->nValueBytes, FatalError);
  }
  memmove (Var->fill, newValue, Var->nValueBytes);
  cdf_FreeMemory (newValue, FatalError);
  opt.useFills = TRUE;
  return TRUE;
}

/******************************************************************************
* PromptForWidth.
******************************************************************************/

Logical PromptForWidth (Item)
struct ItemStruct *Item;
{
  static char value[MAXwidthLEN+1]; int newWidth;
  /****************************************************************************
  * Set initial value.
  ****************************************************************************/
  snprintf (value, (size_t) sizeof(value), "%d", Item->width);
  /****************************************************************************
  * Prompt for new value.
  ****************************************************************************/
  if (!PromptFor(value,MAXwidthLEN,strlen(value),
		 "Enter new width...",WIDTHhelpID)) return FALSE;
  /****************************************************************************
  * Check if nothing entered.
  ****************************************************************************/
  if (NULstring(value)) return FALSE;
  /****************************************************************************
  * Decode/validate value.
  ****************************************************************************/
  if (sscanf(value,"%d",&newWidth) != 1) {
    DisplayMessage ("Error decoding width.", BEEPWAIT1);
    return FALSE;
  }
  if (newWidth < 0) {
    DisplayMessage ("Illegal width.", BEEPWAIT1);
    return FALSE;
  }
  /****************************************************************************
  * Save new width.
  ****************************************************************************/
  Item->width = newWidth;
  return TRUE;
}

/******************************************************************************
* PromptForReserve.
******************************************************************************/

Logical PromptForReserve (Var)
struct VarStructXP *Var;
{
  static char value[MAXreserveLEN+1]; long newReserve;
  /****************************************************************************
  * Set initial value.
  ****************************************************************************/
  snprintf (value, (size_t) sizeof(value), "%ld", Var->reserve);
  /****************************************************************************
  * Prompt for new value.
  ****************************************************************************/
  if (!PromptFor(value,MAXreserveLEN,strlen(value),
		 "Enter new reserve percentage...",
		 RESERVEhelpID)) return FALSE;
  /****************************************************************************
  * Check if nothing entered.
  ****************************************************************************/
  if (NULstring(value)) return FALSE;
  /****************************************************************************
  * Decode/validate value.
  ****************************************************************************/
  if (sscanf(value,"%ld",&newReserve) != 1) {
    DisplayMessage ("Error decoding reserve percentage.", BEEPWAIT1);
    return FALSE;
  }
  if (newReserve < 0) {
    DisplayMessage ("Illegal reserve percentage.", BEEPWAIT1);
    return FALSE;
  }
  /****************************************************************************
  * Save new reserve.
  ****************************************************************************/
  Var->reserve = newReserve;
  return TRUE;
}

/******************************************************************************
* PromptForBlocking.
******************************************************************************/

Logical PromptForBlocking (Var)
struct VarStructXP *Var;
{
  static char value[MAXblockingLEN+1]; long newBlocking;
  /****************************************************************************
  * Set initial value.
  ****************************************************************************/
  snprintf (value, (size_t) sizeof(value), "%ld", Var->blocking);
  /****************************************************************************
  * Prompt for new value.
  ****************************************************************************/
  if (!PromptFor(value,MAXblockingLEN,strlen(value),
		 "Enter new blocking factor...",BLOCKINGhelpID)) return FALSE;
  /****************************************************************************
  * Check if nothing entered.
  ****************************************************************************/
  if (NULstring(value)) return FALSE;
  /****************************************************************************
  * Decode/validate value.
  ****************************************************************************/
  if (sscanf(value,"%ld",&newBlocking) != 1) {
    DisplayMessage ("Error decoding blocking factor.", BEEPWAIT1);
    return FALSE;
  }
  if (newBlocking < 0) {
    DisplayMessage ("Illegal blocking factor.", BEEPWAIT1);
    return FALSE;
  }
  /****************************************************************************
  * Save new blocking factor.
  ****************************************************************************/
  Var->blocking = newBlocking;
  return TRUE;
}

/******************************************************************************
* PromptForFormat.
******************************************************************************/

Logical PromptForFormat (Item)
struct ItemStruct *Item;
{
  char format[MAXitemFieldLEN+1];
  /****************************************************************************
  * Set initial format.
  ****************************************************************************/
  strcpyX (format, BOO(Item->Var->format == NULL,"",Item->Var->format),
	   MAXitemFieldLEN);
  /****************************************************************************
  * Prompt for new format.
  ****************************************************************************/
  if (!PromptFor(format,MAXitemFieldLEN,strlen(format),
		 "Enter new format...",FORMAThelpID)) return FALSE;
  /****************************************************************************
  * Check if nothing entered.
  ****************************************************************************/
  if (NULstring(format)) {
    if (Item->Var->format != NULL) {
      cdf_FreeMemory (Item->Var->format, FatalError);
      Item->Var->format = NULL;
      return TRUE;
    }
    else
      return FALSE;
  }
  /****************************************************************************
  * Decode/validate new format?
  ****************************************************************************/
  if (!ValidFormat(format)) {
    DisplayMessage ("Illegal format specification.", BEEPWAIT1);
    return FALSE;
  }
  /****************************************************************************
  * Save new format.
  ****************************************************************************/
  if (Item->Var->format != NULL)
    cdf_FreeMemory (Item->Var->format, FatalError);
  Item->Var->format = (char *) cdf_AllocateMemory ((size_t)strlen(format) + 1,
					       FatalError);
  strcpyX (Item->Var->format, format, 0);
  /****************************************************************************
  * Possibly increase width based on new format.
  ****************************************************************************/
  Item->width = MaxInt(Item->width,VariableWidth(Item->Var));
  /****************************************************************************
  * Return success.
  ****************************************************************************/
  return TRUE;
}

/******************************************************************************
* PromptForCompression.
******************************************************************************/

Logical PromptForCompression (cType, cParms)
long *cType;
long cParms[CDF_MAX_PARMS];
{
  static Logical first = TRUE;
  static int exitChars[] = { ENTERkey_FSI, EXITkey_FSI, HELPkey_FSI, NUL };
  AOSs1 (iLines, "None   RLE.0   HUFF.0   AHUFF.0   GZIP...")
  static int iLineNs[] = { 0,0,0,0,0 };
  static int iCols[] = { 0,7,15,24,34 };
  static int iLens[] = { 4,5,6,7,7 };
  static int ibLens[] = { 4,5,6,7,7 };
  static struct ItemWindowStruct IW = {
    21, 0, 80, " Select new compression... ", 0, NULL, 1, iLines, 5, iLineNs,
    iCols, iLens, ibLens, 1, 0, NULL, exitChars, REFRESHkey_FSI, FALSE, NUL,
    NUL
  };
  static char keyDefs[] = {
    "Enter: ________    Help: ________    Exit: ________\n\n"
  };
  static char keyDefsBlank[] = "";
  if (first) {
    char *p1 = keyDefs;
    EncodeKeyDefinitions (1, &p1, ENTERkey_FSI, HELPkey_FSI, EXITkey_FSI);
    first = FALSE;
  }
  NEWkeyDEFS (EWkey, keyDefsBlank, batchMode)
  ItemWindow (NEWiw, &IW, 0);
  NEWkeyDEFS (EWkey, keyDefs, batchMode)
  for (;;) {
     ItemWindow (READiw, &IW);
     switch (IW.key) {
       case ENTERkey_FSI:
	 switch (IW.itemN) {
	   case NONEin:
	     *cType = NO_COMPRESSION;
	     NEWkeyDEFS (EWkey, keyDefsBlank, batchMode)
	     ItemWindow (DELETEiw, &IW);
	     return TRUE;
	   case RLE0in:
	     *cType = RLE_COMPRESSION;
	     cParms[0] = RLE_OF_ZEROs;
	     NEWkeyDEFS (EWkey, keyDefsBlank, batchMode)
	     ItemWindow (DELETEiw, &IW);
	     return TRUE;
	   case HUFF0in:
	     *cType = HUFF_COMPRESSION;
	     cParms[0] = OPTIMAL_ENCODING_TREES;
	     NEWkeyDEFS (EWkey, keyDefsBlank, batchMode)
	     ItemWindow (DELETEiw, &IW);
	     return TRUE;
	   case AHUFF0in:
	     *cType = AHUFF_COMPRESSION;
	     cParms[0] = OPTIMAL_ENCODING_TREES;
	     NEWkeyDEFS (EWkey, keyDefsBlank, batchMode)
	     ItemWindow (DELETEiw, &IW);
	     return TRUE;
	   case GZIPin: {
	     Logical done = FALSE;
	     static char token[MAX_GZIP_TOKEN_LEN+1] = "GZIP.";
	     static int gzipExit[] = {
	       ENTERkey_FSI, EXITkey_FSI, HELPkey_FSI, NUL
	     };
	     static struct PromptWindowStruct PW = {
	       "Enter GnuZIP compression parameters...", 21, 0, 80, 0, NULL,
	       MAX_GZIP_TOKEN_LEN, token, 0, NULL, gzipExit, REFRESHkey_FSI,
	       SOLkey_FSI, EOLkey_FSI, INSERTorOVERkey_FSI
	     };
	     ItemWindow (UNDISPLAYiw, &IW);
	     PromptWindow (NEWpw, &PW, (int) strlen(PW.value), LogicalTRUE);
	     while (!done) {
		PromptWindow (READpw, &PW);
		switch (PW.key) {
		  case ENTERkey_FSI: {
		    int level;
		    if (sscanf(PW.value,"GZIP.%d",&level) == 1) {
		      if (INCLUSIVE(1,level,9)) {
			*cType = GZIP_COMPRESSION;
			cParms[0] = level;
			NEWkeyDEFS (EWkey, keyDefsBlank, batchMode)
			PromptWindow (DELETEpw, &PW);
			ItemWindow (DELETEiw, &IW);
			return TRUE;
		      }
		    }
		    PromptWindow (UNDISPLAYpw, &PW);
		    DisplayMessage ("Illegal GZIP parameters.", BEEPWAIT1);
		    PromptWindow (REDISPLAYpw, &PW);
		    break;
		  }
		  case HELPkey_FSI:
		    OnlineHelpWindow ("cdfxp.ilh", GZIPhelpID);
		    break;
		  case EXITkey_FSI:
		    PromptWindow (DELETEpw, &PW);
		    ItemWindow (REDISPLAYiw, &IW);
		    done = TRUE;
		    break;
		}
	     }
	     break;
	   }
	 }
	 break;
       case HELPkey_FSI:
	 OnlineHelpWindow ("cdfxp.ilh", COMPRESShelpID);
	 break;
       case EXITkey_FSI:
	 NEWkeyDEFS (EWkey, keyDefsBlank, batchMode)
	 ItemWindow (DELETEiw, &IW);
	 return FALSE;
     }
  }
}

/******************************************************************************
* PromptForChecksum.
******************************************************************************/

Logical PromptForChecksum (checksum)
long *checksum;
{
  static Logical first = TRUE;
  static int exitChars[] = { ENTERkey_FSI, EXITkey_FSI, HELPkey_FSI, NUL };
  AOSs1 (iLines, "None   MD5")
  static int iLineNs[] = { 0,0 };
  static int iCols[] = { 0,7 };
  static int iLens[] = { 4,3 };
  static int ibLens[] = { 4,3 };
  static struct ItemWindowStruct IW = {
    21, 0, 80, " Select new checksum... ", 0, NULL, 1, iLines, 2, iLineNs,
    iCols, iLens, ibLens, 1, 0, NULL, exitChars, REFRESHkey_FSI, FALSE, NUL,
    NUL
  };
  static char keyDefs[] = {
    "Enter: ________    Help: ________    Exit: ________\n\n"
  };
  static char keyDefsBlank[] = "";
  if (first) {
    char *p1 = keyDefs;
    EncodeKeyDefinitions (1, &p1, ENTERkey_FSI, HELPkey_FSI, EXITkey_FSI);
    first = FALSE;
  }
  NEWkeyDEFS (EWkey, keyDefsBlank, batchMode)
  ItemWindow (NEWiw, &IW, 0);
  NEWkeyDEFS (EWkey, keyDefs, batchMode)
  for (;;) {
     ItemWindow (READiw, &IW);
     switch (IW.key) {
       case ENTERkey_FSI:
	 switch (IW.itemN) {
	   case NONEin:
	     *checksum = NO_CHECKSUM;
	     NEWkeyDEFS (EWkey, keyDefsBlank, batchMode)
	     ItemWindow (DELETEiw, &IW);
	     return TRUE;
	   case MD5in:
	     *checksum = MD5_CHECKSUM;
	     NEWkeyDEFS (EWkey, keyDefsBlank, batchMode)
	     ItemWindow (DELETEiw, &IW);
	     return TRUE;
	 }
	 break;
       case HELPkey_FSI:
	 OnlineHelpWindow ("cdfxp.ilh", CHECKSUMhelpID);
	 break;
       case EXITkey_FSI:
	 NEWkeyDEFS (EWkey, keyDefsBlank, batchMode)
	 ItemWindow (DELETEiw, &IW);
	 return FALSE;
     }
  }
}

/******************************************************************************
* PromptForSparseness.
******************************************************************************/

Logical PromptForSparseness (Var)
struct VarStructXP *Var;
{
  static Logical first = TRUE;
  static int exitChars[] = { ENTERkey_FSI, EXITkey_FSI, HELPkey_FSI, NUL };
  AOSs1 (iLines, "sRecords.NO     sRecords.PAD     sRecords.PREV")
  static int iLineNs[] = { 0,0,0 };
  static int iCols[] = { 0,16,33 };
  static int iLens[] = { 11,12,13 };
  static int ibLens[] = { 11,12,13 };
  static struct ItemWindowStruct IW = {
    21, 0, 80, " Select new sparseness... ", 0, NULL, 1, iLines, 3, iLineNs,
    iCols, iLens, ibLens, 1, 0, NULL, exitChars, REFRESHkey_FSI, FALSE, NUL,
    NUL
  };
  static char keyDefsPrompt[] = {
    "Enter: ________    Help: ________    Exit: ________\n\n"
  };
  static char keyDefsBlank[] = "";
  if (first) {
    char *p1 = keyDefsPrompt;
    EncodeKeyDefinitions (1, &p1, ENTERkey_FSI, HELPkey_FSI, EXITkey_FSI);
    first = FALSE;
  }
  ItemWindow (NEWiw, &IW, 0);
  NEWkeyDEFS (EWkey, keyDefsPrompt, batchMode)
  for (;;) {
     ItemWindow (READiw, &IW);
     switch (IW.key) {
       case ENTERkey_FSI:
	 switch (IW.itemN) {
	   case NOsRECORDSin: Var->sRecordsType = NO_SPARSERECORDS; break;
	   case PADsRECORDSin: Var->sRecordsType = PAD_SPARSERECORDS; break;
	   case PREVsRECORDSin: Var->sRecordsType = PREV_SPARSERECORDS; break;
	 }
	 ItemWindow (DELETEiw, &IW);
	 NEWkeyDEFS (EWkey, keyDefsBlank, batchMode)
	 return TRUE;
       case HELPkey_FSI:
	 OnlineHelpWindow ("cdfxp.ilh", SPARSEhelpID);
	 break;
       case EXITkey_FSI:
	 ItemWindow (DELETEiw, &IW);
	 NEWkeyDEFS (EWkey, keyDefsBlank, batchMode)
	 return FALSE;
     }
  }
}

/******************************************************************************
* FlipItems.
******************************************************************************/

Logical FlipItems (itemX)
int itemX;
{
  struct ItemStruct *Item = itemHead, *prevItem = NULL, *tItem; int itemXt;
  /****************************************************************************
  * Locate Item (and previous Item) to be flipped.
  ****************************************************************************/
  for (itemXt = 0; itemXt < itemX; itemXt++) {
     prevItem = Item;
     Item = Item->nextItem;
  }
  /****************************************************************************
  * Check if only one Item.
  ****************************************************************************/
  if (Item == itemHead && Item->nextItem == NULL) return FALSE;
  /****************************************************************************
  * Check if last Item.
  ****************************************************************************/
  if (Item->nextItem == NULL) {
    prevItem->nextItem = NULL;
    Item->nextItem = itemHead;
    itemHead = Item;
    return TRUE;
  }
  /****************************************************************************
  * Check if first Item.
  ****************************************************************************/
  if (Item == itemHead) {
    tItem = Item->nextItem;
    Item->nextItem = tItem->nextItem;
    tItem->nextItem = Item;
    itemHead = tItem;
    return TRUE;
  }
  /****************************************************************************
  * In the middle of the Item's.
  ****************************************************************************/
  tItem = Item->nextItem;
  Item->nextItem = tItem->nextItem;
  tItem->nextItem = Item;
  prevItem->nextItem = tItem;
  return TRUE;
}

/******************************************************************************
* VariableWidth.
******************************************************************************/

int VariableWidth (Var)
struct VarStructXP *Var;
{
  int width;
  /****************************************************************************
  * Check for a string data type.  In this case the format is ignored.
  ****************************************************************************/
  if (STRINGdataType(Var->dataType)) {
    return MaxInt(MIN_VARIABLE_WIDTH,(int)(Var->numElems+2));
  }
  /****************************************************************************
  * Check for an EPOCH data type.  Depending on the style the format may be
  * ignored.
  ****************************************************************************/
  if (EPOCHdataType(Var->dataType)) {
    switch (opt.epochStyle) {
      case EPOCH0_STYLE:
	return MAXIMUM(EPOCH_STRING_LEN,MIN_VARIABLE_WIDTH);
      case EPOCH1_STYLE:
	return MAXIMUM(EPOCH1_STRING_LEN,MIN_VARIABLE_WIDTH);
      case EPOCH2_STYLE:
	return MAXIMUM(EPOCH2_STRING_LEN,MIN_VARIABLE_WIDTH);
      case EPOCH3_STYLE:
	return MAXIMUM(EPOCH3_STRING_LEN,MIN_VARIABLE_WIDTH);
      case EPOCH4_STYLE:
	return MAXIMUM(EPOCH4_STRING_LEN,MIN_VARIABLE_WIDTH);
      case EPOCHf_STYLE:
	break;                  /* Continue on... */
      case EPOCHx_STYLE:
	return MAXIMUM(EPOCHx_STRING_MAX,MIN_VARIABLE_WIDTH);
    }
  }
  /****************************************************************************
  * Check for an EPOCH16 data type.  Depending on the style the format may be
  * ignored.
  ****************************************************************************/
  else if (EPOCH16dataType(Var->dataType)) {
    switch (opt.epochStyle) {
      case EPOCH0_STYLE:
        return MAXIMUM(EPOCH16_STRING_LEN,MIN_VARIABLE_WIDTH);
      case EPOCH1_STYLE:
        return MAXIMUM(EPOCH16_1_STRING_LEN,MIN_VARIABLE_WIDTH);
      case EPOCH2_STYLE:
        return MAXIMUM(EPOCH16_2_STRING_LEN,MIN_VARIABLE_WIDTH);
      case EPOCH3_STYLE:
        return MAXIMUM(EPOCH16_3_STRING_LEN,MIN_VARIABLE_WIDTH);
      case EPOCH4_STYLE:
        return MAXIMUM(EPOCH16_4_STRING_LEN,MIN_VARIABLE_WIDTH);
      case EPOCHf_STYLE:
        break;                  /* Continue on... */
      case EPOCHx_STYLE:
        return MAXIMUM(EPOCHx_STRING_MAX,MIN_VARIABLE_WIDTH);
    }
  }
  /****************************************************************************
  * Check for a TT2000 data type.  Always use ISO 8601 form.
  * ignored.
  ****************************************************************************/
  else if (TT2000dataType(Var->dataType)) {
    switch (opt.epochStyle) {
      case EPOCH0_STYLE:
        return MAXIMUM(TT2000_0_STRING_LEN,MIN_VARIABLE_WIDTH);
      case EPOCH1_STYLE:
        return MAXIMUM(TT2000_1_STRING_LEN,MIN_VARIABLE_WIDTH);
      case EPOCH2_STYLE:
        return MAXIMUM(TT2000_2_STRING_LEN,MIN_VARIABLE_WIDTH);
      case EPOCH3_STYLE:
        return MAXIMUM(TT2000_4_STRING_LEN,MIN_VARIABLE_WIDTH);
      case EPOCH4_STYLE:
        return MAXIMUM(TT2000_3_STRING_LEN,MIN_VARIABLE_WIDTH);
    }
  }
  /****************************************************************************
  * Check if a format exists.
  ****************************************************************************/
  if (Var->format != NULL) {
    int ww = 0;
    width = FormatWidth(Var->format);
    if (IsHexFormat(Var->format)) {
      switch (Var->dataType) {
	case CDF_BYTE:
	case CDF_INT1:
	case CDF_UINT1:
	      ww = 2+2;
	      break;
	case CDF_INT2:
	case CDF_UINT2:
	      ww = 4+2;
	      break;
	case CDF_INT4:
	case CDF_UINT4:
	case CDF_REAL4:
	case CDF_FLOAT:
	      ww = 8+2;
	      break;
	case CDF_INT8:
	case CDF_REAL8:
	case CDF_DOUBLE:
	      ww = 16+2;
	      break;
	case CDF_EPOCH:     /* Format (C/Fortran) style. */
	      if (!ziso8601) width = 23;
	      else width = 24;
	      break;
	case CDF_EPOCH16:   /* Format (C/Fortran) style. */
	      if (!ziso8601) width = 36;
	      else width = 32;
	      break;
	case CDF_TIME_TT2000:       /* Format (C/Fortran) style. */
	      if (!ziso8601) width = 29;
	      else width = 30;
	      break;
	default:            /* Unknown data type. */
	      ww = 0;
	}
    }
    if (width != 0)
	return MAXIMUM(width,MAXIMUM(MIN_VARIABLE_WIDTH,ww));
  }
  /****************************************************************************
  * Either a format doesn't exist or is illegal.  Use the default width for
  * the data type.
  ****************************************************************************/
  switch (Var->dataType) {
    case CDF_BYTE:
    case CDF_INT1:
      width = 4;
      break;
    case CDF_UINT1:
      width = 3;
      break;
    case CDF_INT2:
      width = 6;
      break;
    case CDF_UINT2:
      width = 5;
      break;
    case CDF_INT4:
      width = 11;
      break;
    case CDF_INT8:
      width = 20;
      break;
    case CDF_UINT4:
      width = 10;
      break;
    case CDF_REAL4:
    case CDF_FLOAT:
      width = 12;
      break;
    case CDF_REAL8:
    case CDF_DOUBLE:
      width = 12;
      break;
    case CDF_EPOCH:     /* Format (C/Fortran) style. */
      if (!ziso8601) width = 23;
      else width = 24;
      break;
    case CDF_EPOCH16:	/* Format (C/Fortran) style. */
      if (!ziso8601) width = 36;
      else width = 32;
      break;
    case CDF_TIME_TT2000:	/* Format (C/Fortran) style. */
      if (!ziso8601) width = 29;
      else width = 30;
      break;
    default:            /* Unknown data type. */
      width = 0;
  }
  return MAXIMUM(MIN_VARIABLE_WIDTH,width);
}

/******************************************************************************
* OptDefaults.
******************************************************************************/

void OptDefaults () {
  if (simpleMode) {
    opt.eachFilter = FORCEeachFilterSIMPLE;
    opt.overallFilter = FORCEoverallFilterSIMPLE;
    opt.useFills = FORCEfillsSIMPLE;
    opt.useFORMAT = DEFAULTformatSIMPLE;
    opt.useFILLVAL = FORCEfillvalSIMPLE;
    opt.useVALIDMIN = FORCEvalidminSIMPLE;
    opt.useVALIDMAX = FORCEvalidmaxSIMPLE;
    opt.useMONOTON = FORCEmonotonSIMPLE;
    opt.horizontalMode = DEFAULThorizontalSIMPLE;
    opt.showRecord = DEFAULTrecordSIMPLE;
    opt.showIndices = DEFAULTindicesSIMPLE;
    opt.outputItem = DEFAULToutputSIMPLE;
    if (!ziso8601)
      opt.epochStyle = DEFAULTepochSIMPLE;
    else
      opt.epochStyle = EPOCH3_STYLE;
    opt.majority = DEFAULTmajoritySIMPLE;
    opt.spacing = DEFAULTspacingSIMPLE;
    opt.singleFile = NAsingleSIMPLE;
    opt.encoding = BOO(NAnetworkSIMPLE,NETWORK_ENCODING,HOST_ENCODING);
    opt.showFiltered = NAshowSIMPLE;
    opt.exclusive = NAexclusiveSIMPLE;
    opt.deleteExisting = NAdeleteSIMPLE;
    opt.preAllocate = NApreAllocateSIMPLE;
    opt.textHeading = DEFAULTheadingSIMPLE;
    poundedheading = 0;
  }
  else {
    opt.eachFilter = DEFAULTeachFilterEXPORT;
    opt.overallFilter = DEFAULToverallFilterEXPORT;
    opt.useFills = DEFAULTfillsEXPORT;
    opt.useFORMAT = DEFAULTformatEXPORT;
    opt.useFILLVAL = DEFAULTfillvalEXPORT;
    opt.useVALIDMIN = DEFAULTvalidminEXPORT;
    opt.useVALIDMAX = DEFAULTvalidmaxEXPORT;
    opt.useMONOTON = DEFAULTmonotonEXPORT;
    opt.horizontalMode = DEFAULThorizontalEXPORT;
    opt.showRecord = DEFAULTrecordEXPORT;
    opt.showIndices = DEFAULTindicesEXPORT;
    opt.outputItem = DEFAULToutputEXPORT;
    if (!ziso8601)
      opt.epochStyle = DEFAULTstyleEXPORT;
    else
      opt.epochStyle = EPOCH3_STYLE;
    opt.majority = DEFAULTmajorityEXPORT;
    opt.spacing = DEFAULTspacingEXPORT;
    opt.singleFile = DEFAULTsingleEXPORT;
    opt.encoding = BOO(DEFAULTnetworkEXPORT,NETWORK_ENCODING,HOST_ENCODING);
    opt.showFiltered = DEFAULTshowEXPORT;
    opt.exclusive = DEFAULTexclusiveEXPORT;
    opt.deleteExisting = DEFAULTdeleteEXPORT;
    opt.preAllocate = DEFAULTpreAllocateEXPORT;
    opt.textHeading = DEFAULTheadingEXPORT;
    poundedheading = 0;
  }
  return;
}

/******************************************************************************
* LoadVarsTextFile.
******************************************************************************/

Logical LoadVarsTextFile (varsFile)
char *varsFile;
{
  FILE *varsfp;
  int  i, j;
  char line[CDF_VAR_NAME_LEN256+1], item[CDF_VAR_NAME_LEN256+1];
  Logical status;

  varsfp = fopen (varsFile, "r");
  if (varsfp == NULL) return FALSE;
  numVars = 0;
  numVarsO = 0;
  while (fgets(line,CDF_VAR_NAME_LEN256,varsfp) != NULL) {
    if (sscanf(line, "%s\n", item) != 1) continue;
    for (i = 0; line[i] != NUL; i++)
       if (line[i] == Nl) line[i] = '\0';
    RemoveLeadingBlanks (line);
    RemoveTrailingBlanks (line);
    if (line[0] == '\0' || strlen(line) == 0) continue;
    ++numVars;
  }
  if (numVars > 0) {
    vars = (char **) cdf_AllocateMemory ((size_t)sizeof(char *)*numVars, FatalError);
    for (i = 0; i < numVars; i++)
      vars[i] = (char *) cdf_AllocateMemory ((size_t)CDF_VAR_NAME_LEN256+1,
                                             FatalError);
    j = 0;
    rewind(varsfp);
    while (fgets(line,CDF_VAR_NAME_LEN256,varsfp) != NULL) {
      if (sscanf(line, "%s\n", item) != 1) continue;
      for (i = 0; line[i] != NUL; i++)
        if (line[i] == Nl) line[i] = '\0';    
      RemoveLeadingBlanks (line);
      RemoveTrailingBlanks (line);
      if (line[0] == '\0' || strlen(line) == 0) continue;
      strcpyX (vars[j], line, CDF_VAR_NAME_LEN256);
      ++j;
    }
    status = TRUE;
  } else
    status = FALSE;

  fclose (varsfp);
  return status;
}

/******************************************************************************
* ParseEpochRange.
******************************************************************************/

Logical ParseEpochRange (epochStrings)
char **epochStrings;
{
  double epochTemp;
  int len1, len2;

  len1 = (int) strlen(epochStrings[0]);
  len2 = (int) strlen(epochStrings[1]);
  if (len1 != len2) {
    DisplayError ("Starting and Ending epochs don't match.");
    return FALSE;
  }
  if (len1 != 24 && len1 != 23 &&
      len1 != 29 && len1 != 30 &&
      len1 != 36 && len1 != 32) {
    DisplayError ("Illegal/invalid format for Starting/ending Epoch.");
    return FALSE;
  }
  if (len1 == 24 || len1 == 23) {
    epochStart = toParseEPOCH (epochStrings[0]);
    epochEnd = toParseEPOCH (epochStrings[1]);
  } else if (len1 == 36 || len1 == 32) {
    epochTemp = toParseEPOCH16 (epochStrings[0], epoch16Start);
    epochTemp = toParseEPOCH16 (epochStrings[1], epoch16End);
  } else {
    tt2000Start = toParseTT2000 (epochStrings[0]);
    tt2000End = toParseTT2000 (epochStrings[1]);
  }
  return TRUE;
}


/*****************************************************************************
* FreeTemps.
******************************************************************************/

void FreeTemps ()
{
  int i;
  if (numVars > 0) {
    for (i = 0; i < numVars; ++i)
      if (vars[i] != NULL) cdf_FreeMemory  (vars[i], FatalError);
    cdf_FreeMemory (vars, FatalError);
  }
  if (numEpochs > 0) {
    for (i = 0; i < numEpochs; ++i) {
      if (epochs[i] != NULL) {
        free (epochs[i]);
        epochs[i] = NULL;
      }
    }
    free (epochs);
    free (epochTypes);
    epochs = NULL;
    epochTypes = NULL;
  }
  if (numGroups > 0) {
    int j;
    for (i = 0; i < numGroups; ++i) {
      for (j = 0; j < numVarsInGroup[i]; ++j) {
        if (varsInGroup[i][j] != NULL) {
          free (varsInGroup[i][j]);
          varsInGroup[i][j] = NULL;
        }
        if (varPtrsInGroup[i][j] != NULL) {
          free (varPtrsInGroup[i][j]);
          varPtrsInGroup[i][j] = NULL;
        }
      }
    }
    free (varsInGroup);
    free (varPtrsInGroup);
    free (numVarsInGroup);
    varsInGroup = NULL;
    varPtrsInGroup = NULL;
    numVarsInGroup = NULL;
  }
}


