/******************************************************************************
*
*  NSSDC/CDF                                                    CDFconvert.
*
*  Version 2.5c, 14-Dec-97, Hughes STX.
*
*  Modification history:
*
*   V1.0  24-Jan-91, H Leckner  Original version (for CDF V2.0).
*   V2.0  17-May-92, J Love     IBM PC port (major changes).
*   V2.1  29-Sep-92, J Love     CDF V2.3 (shareable/NeXT/zVar).
*   V2.1a  6-Oct-92, J Love     Fixed freeing of `bufferX' if 1-dimensional.
*   V2.2  25-Jan-94, J Love     CDF V2.4.
*   V2.3   7-Dec-94, J Love     CDF V2.5.
*   V2.3a 10-Jan-95, J Love     Uppercase file extensions on the Macintosh.
*   V2.3b  6-Apr-95, J Love     POSIX.
*   V2.4   6-Sep-95, J Love     CDFexport-related changes.  Hyper groups.
*   V2.4a 19-Sep-95, J Love     CHECKforABORTso.
*   V2.4b 29-Sep-95, J Love     Macintosh dialog filtering.  Outline default
*                               button.  Less CHECKforABORTso.
*   V2.5   9-Sep-96, J Love     CDF V2.6.
*   V2.5a 21-Feb-97, J Love	Removed RICE.
*   V2.5b 17-Nov-97, J Love	Windows NT/Visual C++.
*   V2.5c 14-Dec-97, J Love	Added ALPHAVMSi encoding.
*   V2.6  17-Apr-01, M Liu      Added checking for variable names entered in
*                               the compression option
*   V2.7  03-May-06, M Liu      Added checksum option for the converted files.
*   V2.8  13-Oct-06, M Liu      Changed to allow upper and lower case CDF  
*                               name to be used on win32.
*
******************************************************************************/
#include "cdfcvt.h"
#include "cdflib.h"
#include "cdflib64.h"

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

#if defined(BORLANDC)
extern unsigned _stklen = BORLANDC_STACK_SIZE;
#endif

/******************************************************************************
* Global variables.
******************************************************************************/

Logical useSkeletonCDF;
Logical mLog, pctLog;
Logical deleteIFexists;
Logical negToPosFp0;
long dstFormat;
long dstMajority;
long dstEncoding;
long srcFormat, srcMajority, srcEncoding, srcVersion, srcRelease, srcIncrement;
CDFid srcId, dstId, sktId;
long zMode;
Logical report[3];
Logical backward = FALSE;
int checksumFlag;
long checksum, srcChecksum = -999;
long workingCache, stageCache, compressCache;
Logical dumpStatistics;
struct CompressionStruct *compression;
struct SparseRecordsStruct *sparseRecords;
Logical pctOn;

/******************************************************************************
* Main.
******************************************************************************/

#if !defined(win32) || (defined(win32) && defined(ALONE))
MAIN {
  Logical success = TRUE;
  strcpyX (pgmName, "CDFconvert", MAX_PROGRAM_NAME_LEN);
#if defined(mac)
  MacExecuteSO (ConvertCDFs, ConvertQOPs);
#else
  success = ConvertCDFs (argc, argv);
#endif
#if defined(DEBUG)
  if (cdf_FreeMemory(NULL,FatalError) > 0) DisplayWarning ("Abandoned buffers.");
#else
  cdf_FreeMemory (NULL, FatalError);
#endif
  return BOO(success,EXIT_SUCCESS_,EXIT_FAILURE_);
}
#endif

/******************************************************************************
* ConvertCDFs.
******************************************************************************/

Logical ConvertCDFs (argC, argV)
int argC;
char *argV[];
{
  QOP *qop;
  static char *validQuals[] = {
    "single", "multi", "row", "column", "host", "network", "skeleton", "log",
    "nolog", "percent", "nopercent", "delete", "nodelete", "zmode",
    "neg2posfp0", "noneg2posfp0", "report", "page", "nopage", "cache",
    "statistics", "nostatistics", "encoding", "compression", "sparseness",
    "about", "backward", "checksum", NULL };
  static int optRequired[] = {
    FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE,
    FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE,
    TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, 0 };
  static char *reportTokens[] = { "errors", "warnings", "informationals" };
  CDFstatus status;
  char srcSpec[DU_MAX_PATH_LEN+1];
  char dstSpec[DU_MAX_PATH_LEN+1];
  char srcPath[DU_MAX_PATH_LEN+1];
  char dstPath[DU_MAX_PATH_LEN+1];
  char sktPath[DU_MAX_PATH_LEN+1];
  char CDFname[DU_MAX_NAME_LEN+1];
  long numCDFs;
  int i;
  char **directories = NULL;
  char **CDFnames = NULL;
  Logical qopError = FALSE;
  /****************************************************************************
  * Set global variables.
  ****************************************************************************/
  dstFormat = SOURCEformat;
  dstMajority = SOURCEmajority;
  dstEncoding = SOURCEencoding;
  /****************************************************************************
  * Get qualifiers/options/parameters.
  ****************************************************************************/
  switch (argC) {
    case 1:
      PageOLH ("cdfcvt.olh", argV[0]);
      return TRUE;
    case 2:
      if (strcmp(argV[1],"-java") == 0) {
        pagingOn = FALSE;
        PageOLH ("cdfcvtj.olh", argV[0]);
        return TRUE;
      }
    default:
      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;
      }
      /************************************************************************
      * Get CDFs/paths to convert.
      ************************************************************************/
      switch (qop->Nparms) {
	case 0:
	  DisplayError ("Missing source and destination CDF specifications.");
	  qopError = TRUE;
	  break;
	case 1:
	  DisplayError ("Missing source or destination CDF specification.");
	  qopError = TRUE;
	  break;
	case 2:
	  strcpyX (srcSpec, qop->parms[CDFSPEC1parm], DU_MAX_PATH_LEN);
	  strcpyX (dstSpec, qop->parms[CDFSPEC2parm], DU_MAX_PATH_LEN);
#if defined(vms) || defined(dos)
	  MakeUpperString (srcSpec);
	  MakeUpperString (dstSpec);
#endif
	  break;
	default:
	  DisplayError ("Too many parameters.");
	  qopError = TRUE;
	  break;
      }
      if (IsWild(dstSpec)) {
	DisplayError ("Destination cannot be a wildcard specification.");
	qopError = TRUE;
      }
      if (IsDir(srcSpec) || IsWild(srcSpec)) {
	if (!IsDir(dstSpec)) {
	  DisplayError ("Destination must be a directory.");
	  qopError = TRUE;
	}
      }
      /************************************************************************
      * Check for skeleton CDF qualifier.
      ************************************************************************/
      if (qop->qualEntered[SKELqual])
	strcpyX (sktPath, qop->qualOpt[SKELqual], DU_MAX_PATH_LEN);
      else
	strcpyX (sktPath, "", DU_MAX_PATH_LEN);
      /************************************************************************
      * Check for an overriding format, majority, or encoding qualifier.
      ************************************************************************/
      qopError = qopError | !S2qualifierLong(qop,&dstFormat,SINGLEqual,
					     SINGLE_FILE,MULTIqual,MULTI_FILE,
					     dstFormat,"format");
      qopError = qopError | !S2qualifierLong(qop,&dstMajority,ROWqual,
					     ROW_MAJOR,COLqual,COLUMN_MAJOR,
					     dstMajority,"majority");
      qopError = qopError | !S2qualifierLong(qop,&dstEncoding,HOSTqual,
					     HOST_ENCODING,NETqual,
					     NETWORK_ENCODING,dstEncoding,
					     "encoding");
      if (qop->qualEntered[ENCODINGqual]) {
	if (dstEncoding != SOURCEencoding) {
	  DisplayError ("Conflicting qualifiers (encoding/host/network).");
	  qopError = TRUE;
	}
	else {
	  static char *encodingStrings[] = {
	    "host", "network", "sun", "vax", "decstation", "sgi",
	    "ibmpc", "ibmrs", "mac", "hp", "next", "alphaosf1",
	    "alphavmsd", "alphavmsg", "alphavmsi", NULL
	  };
	  static long encodings[] = {
	    HOST_ENCODING, NETWORK_ENCODING, SUN_ENCODING, VAX_ENCODING,
	    DECSTATION_ENCODING, SGi_ENCODING, IBMPC_ENCODING, IBMRS_ENCODING,
	    MAC_ENCODING, HP_ENCODING, NeXT_ENCODING, ALPHAOSF1_ENCODING,
	    ALPHAVMSd_ENCODING, ALPHAVMSg_ENCODING, ALPHAVMSi_ENCODING
	  };
	  int match = FindUniqueMatch (qop->qualOpt[ENCODINGqual],
				       encodingStrings);
	  switch (match) {
	    case NOMATCH:
	      DisplayError ("Unknown encoding.");
	      qopError = TRUE;
	      break;
	    case MATCHES:
	      DisplayError ("Ambiguous encoding.");
	      qopError = TRUE;
	      break;
	    default:
	      dstEncoding = encodings[match];
	      break;
	  }
	}
      }
      /************************************************************************
      * Check for /ZMODE,-zmode qualifier.
      ************************************************************************/
      if (qop->qualEntered[ZMODEqual]) {
	switch (qop->qualOpt[ZMODEqual][0]) {
	  case '0': zMode = zMODEoff; break;
	  case '1': zMode = zMODEon1; break;
	  case '2': zMode = zMODEon2; break;
	  default: {
	    DisplayError ("Illegal zMode.");
	    qopError = TRUE;
	  }
	}
      }
      else
	zMode = DEFAULTzModeCVT;
      /*********************************************************************
      * Check for `cache' qualifier.
      *********************************************************************/
      if (qop->qualEntered[CACHEqual]) {
	if (!ParseCacheSizes(qop->qualOpt[CACHEqual],
			     &workingCache,&stageCache,&compressCache)) {
	  DisplayError ("Illegal cache size/type.");
	  qopError = TRUE;
	}
      }
      else {
	workingCache = useDEFAULTcacheSIZE;
	stageCache = useDEFAULTcacheSIZE;
	compressCache = useDEFAULTcacheSIZE;
      }
      /************************************************************************
      * Check for `report' qualifier.  If absent, use defaults.
      ************************************************************************/
      if (qop->qualEntered[REPORTqual]) {
	if (!ParseOptionList(3,reportTokens,qop->qualOpt[REPORTqual],report)) {
	  DisplayError ("Illegal list of `report' options.");
	  qopError = TRUE;
	}
      }
      else {
	report[ERRORs] = REPORTerrorsDEFAULT;
	report[WARNs] = REPORTwarningsDEFAULT;
	report[INFOs] = REPORTinfosDEFAULT;
      }
      /************************************************************************
      * Check for `compression' qualifier.
      ************************************************************************/
      if (qop->qualEntered[COMPRESSqual]) {
	compression = ParseCompressionOptions (qop->qualOpt[COMPRESSqual]);
	if (compression == NULL) {
	  DisplayError ("Illegal `compression' options.");
	  qopError = TRUE;
	}
      }
      else
	compression = NULL;
      /************************************************************************
      * Check for `sparseness' qualifier.
      *
      * NOTE: When sparse arrays are added the call to `ParseSparsenessOptions'
      * will have to be changed to return both `sparseRecords' and
      * `sparseArrays' (or something like that).
      ************************************************************************/
      if (qop->qualEntered[SPARSEqual]) {
	sparseRecords = ParseSparsenessOptions (qop->qualOpt[SPARSEqual]);
	if (sparseRecords == NULL) {
	  DisplayError ("Illegal `sparseness' options.");
	  qopError = TRUE;
	}
      }
      else
	sparseRecords = NULL;
      /************************************************************************
      * Check for `backward' qualifier.
      ************************************************************************/
      if (qop->qualEntered[BACKWARDqual]) {
        CDFsetFileBackward(BACKWARDFILEon);
        backward = TRUE;
      }
      /************************************************************************
      * Check for `checksum' qualifier.
      ************************************************************************/
      if (qop->qualEntered[CHECKSUMqual]) {
        char *cks = qop->qualOpt[CHECKSUMqual];
	if (StrStrIgCaseX(cks, "no") || StrStrIgCaseX(cks, "none")) {
          checksumFlag = 0;
	  checksum = NO_CHECKSUM;
	} else if (StrStrIgCaseX(cks, "md5")) {
           checksumFlag = 1;
           checksum = MD5_CHECKSUM;
        } else if (StrStrIgCaseX(cks, "source")) {
           checksumFlag = 2;
        } else {
            DisplayError ("Illegal checksum method.");
            qopError = TRUE;
        }
      }
      else
        checksumFlag = -1;

      /************************************************************************
      * Check for `page', `log', `percent', `delete', `neg2posfp0', and
      * `statistics' qualifiers.
      ************************************************************************/
      qopError = qopError | !TFqualifier (qop,&pagingOn,PAGEqual,NOPAGEqual,
					  DEFAULTpageCVT,"page");
      qopError = qopError | !TFqualifier (qop,&mLog,LOGqual,NOLOGqual,
					  DEFAULTlogCVT,"log");
      qopError = qopError | !TFqualifier (qop,&pctLog,PCTqual,NOPCTqual,
					  DEFAULTpctCVT,"percent");
      qopError = qopError | !TFqualifier (qop,&deleteIFexists,DELqual,
					  NODELqual,DEFAULTdelCVT,"delete");
      qopError = qopError | !TFqualifier (qop,&negToPosFp0,NEG2POSqual,
					  NONEG2POSqual,DEFAULT_NEGtoPOSfp0,
					  "neg2posfp0");
      qopError = qopError | !TFqualifier (qop,&dumpStatistics,STATSqual,
					  NOSTATSqual,DEFAULTstatsCVT,
					  "neg2posfp0");
      /************************************************************************
      * Check for qualifier compatibility.
      ************************************************************************/
      if (pctLog && (!mLog)) {
	DisplayError ("`log' must be used with `percentage'.");
	qopError = TRUE;
      }
      /************************************************************************
      * Free QOP memory and check for an error.
      ************************************************************************/
      cdf_FreeMemory (qop, FatalError);
      if (qopError) {
	if (compression != NULL) FreeCompression (compression);
	if (sparseRecords != NULL) FreeSparseness (sparseRecords);
	return FALSE;
      }
      break;
  }
  /****************************************************************************
  * If a skeleton CDF was specified, open it and set the destination format,
  * majority, and encoding (unless they were explicitly specified).
  ****************************************************************************/
  if (!NULstring(sktPath)) {
    long sktFormat, sktMajority, sktEncoding;
#if defined(vms) || defined(dos)
    MakeUpperString (sktPath);
#endif
    WriteOut (stdout, "Opening Skeleton CDF: ");
    WriteOut (stdout, sktPath);
    WriteOut (stdout, "\n");
    status = CDFlib (OPEN_, CDF_, sktPath, &sktId,
		     GET_, CDF_FORMAT_, &sktFormat,
			   CDF_MAJORITY_, &sktMajority,
			   CDF_ENCODING_, &sktEncoding,
			   CDF_VERSION_, &srcVersion,
                           CDF_RELEASE_, &srcRelease,
                           CDF_INCREMENT_, &srcIncrement,
		     NULL_);
    if (StatusBAD(status)) {
       StatusHandlerCvt ("SKT", status);
       useSkeletonCDF = FALSE;
    }
    if (!PriorTo ("3.2.0", srcVersion, srcRelease, srcIncrement)) {
      status = CDFlib (CDF_CHECKSUM_, &srcChecksum,
                       NULL_);
      if (StatusBAD(status)) {
         StatusHandlerCvt ("SKT", status);
         useSkeletonCDF = FALSE;
      }
    }
    else {
      useSkeletonCDF = TRUE;
      if (dstFormat == SOURCEformat) dstFormat = sktFormat;
      if (dstMajority == SOURCEmajority) dstMajority = sktMajority;
      if (dstEncoding == SOURCEencoding) dstEncoding = sktEncoding;
    }
  }
  else
    useSkeletonCDF = FALSE;
  /****************************************************************************
  * Convert CDFs.
  ****************************************************************************/
  if (IsDir(srcSpec) || IsWild(srcSpec)) {
    numCDFs = CDFdirList (srcSpec, &directories, &CDFnames);
    if (numCDFs < 1) {
      WriteOut (stdout, "No CDFs found in source directory.\n");
    }
    else {
      for (i = 0; i < numCDFs; i++) {
	 strcpyX (srcPath, directories[i], DU_MAX_PATH_LEN);
	 AppendToDir (srcPath, CDFnames[i]);
	 strcpyX (dstPath, dstSpec, DU_MAX_PATH_LEN);
	 AppendToDir (dstPath, CDFnames[i]);
	 ConvertCDF (srcPath, dstPath);
      }
    }
  }
  else {
    if (IsDir(dstSpec)) {
      ParsePath (srcSpec, NULL, CDFname);
      strcpyX (dstPath, dstSpec, DU_MAX_PATH_LEN);
      AppendToDir (dstPath, CDFname);
      ConvertCDF (srcSpec, dstPath);
    }
    else {
      ConvertCDF (srcSpec, dstSpec);
    }
  }
  if (directories != NULL) cdf_FreeMemory (directories, FatalError);
  if (CDFnames != NULL) cdf_FreeMemory (CDFnames, FatalError);
  if (compression != NULL) FreeCompression (compression);
  if (sparseRecords != NULL) FreeSparseness (sparseRecords);
  /****************************************************************************
  * Close skeleton CDF if one was used.
  ****************************************************************************/
  if (useSkeletonCDF) {
    status = CDFclose (sktId);
    StatusHandlerCvt ("SKT", status);	/* Ignore return. */
  }
  return TRUE;
}

/******************************************************************************
* ConvertCDF.
******************************************************************************/

Logical ConvertCDF (srcPath, dstPath)
char *srcPath;
char *dstPath;
{
  return ConvertCDFx (srcPath, dstPath);
}

/******************************************************************************
* ConvertCDFx.
******************************************************************************/

Logical ConvertCDFx (srcPath, dstPath)
char *srcPath;
char *dstPath;
{
  CDFstatus status; int pN;
  long format, majority, encoding, version, release, increment;
  long numDims, dimSizes[CDF_MAX_DIMS];
  long SRCcType, SRCcParms[CDF_MAX_PARMS], SRCcPct;
  long cType, cParms[CDF_MAX_PARMS];
  long numVars, numZvars;
  char text[MAX_OUTPUT_TEXT_LEN+1];
  /***************************************************************************
  * Display converting message.
  ***************************************************************************/
  WriteOut (stdout, "Converting \"");
  WriteOut (stdout, srcPath);
  if (!EndsWithIgCase(srcPath, ".cdf"))
    WriteOut (stdout, ".cdf");
  WriteOut (stdout, "\" to \"");
  WriteOut (stdout, dstPath);
  if (!EndsWithIgCase(dstPath, ".cdf"))
    WriteOut (stdout, ".cdf");
  WriteOut (stdout, "\"\n");
  
  /***************************************************************************
  * Open source CDF.  If an error occurs, skip to next CDF.
  ***************************************************************************/
  if (mLog) WriteOut (stdout, "  Opening source CDF...\n");
  status = CDFlib (OPEN_, CDF_, srcPath, &srcId,
                   GET_, CDF_NUMrVARS_, &numVars,                     
		         CDF_NUMzVARS_, &numZvars,
	           NULL_);
  if (!StatusHandlerCvt("SRC",status)) return FALSE;
  status = CDFlib (SELECT_, CDF_, srcId,
		   SELECT_, CDF_READONLY_MODE_, READONLYon,
			    CDF_zMODE_, zMode,
			    CDF_NEGtoPOSfp0_MODE_, BOO(negToPosFp0,
						       NEGtoPOSfp0on,
						       NEGtoPOSfp0off),
			    CDF_CACHESIZE_, workingCache,
			    STAGE_CACHESIZE_, stageCache,
			    COMPRESS_CACHESIZE_, compressCache,
		   GET_, CDF_FORMAT_, &srcFormat,
                         CDF_VERSION_, &version,
                         CDF_RELEASE_, &release,
                         CDF_INCREMENT_, &increment,
		         CDF_NUMrVARS_, &numVars,
		         CDF_NUMzVARS_, &numZvars,
			 CDF_MAJORITY_, &srcMajority,
			 CDF_ENCODING_, &srcEncoding,
			 CDF_COMPRESSION_, &SRCcType, SRCcParms, &SRCcPct,
			 rVARs_NUMDIMS_, &numDims,
			 rVARs_DIMSIZES_, dimSizes,
		   NULL_);
  if (!StatusHandlerCvt("SRC",status)) return FALSE;
  if (!PriorTo ("3.2.0", version, release, increment)) {
    status = CDFlib (GET_, CDF_CHECKSUM_, &srcChecksum,
                     NULL_);
    if (!StatusHandlerCvt("SRC",status)) return FALSE;
  }
  CHECKforABORTso
  if (CDFgetFileBackward()) {
    /*************************************************************************
    * Check the size of source CDF.  Give errors if it's over 2G when
    * converting it to V2.7 version. It's only applicable to V3.* files.
    *************************************************************************/
    if (version >= 3) {
      OFF_T cSize, uSize;
      status = CDFlib (GET_, CDF_INFO_, srcPath, &SRCcType, SRCcParms,
                                        &cSize, &uSize,
                       NULL_);
      if (!StatusHandlerCvt("SRC",status)) return FALSE;
#if defined(win32)
      if ((cSize >= (OFF_T) ((1i64 << 31) - 1)) ||
          (uSize >= (OFF_T) ((1i64 << 31) - 1))) {
#else
      if ((cSize >= (OFF_T) ((1LL << 31) - 1)) ||
          (uSize >= (OFF_T) ((1LL << 31) - 1))) {
#endif
        WriteOut (stdout, "Soruce file size: ");
#if !defined(win32)
        sprintf (text, "cSize(%lld) uSize(%lld)", cSize, uSize);
#else
        sprintf (text, "cSize(%I64d) uSize(%I64d)", cSize, uSize);
#endif
        WriteOut (stdout, text);
        WriteOut (stdout, " -- is too big to be converted to a V2.7 file. \n");
	status = CDFlib (CLOSE_, CDF_,
		         NULL_);
        return FALSE;
      }
    }
  }

  /***************************************************************************
  * Determine format, majority, encoding, and compression of destination CDF.
  ***************************************************************************/
  format = BOO(dstFormat == SOURCEformat,srcFormat,dstFormat);
  majority = BOO(dstMajority == SOURCEmajority,srcMajority,dstMajority);
  encoding = BOO(dstEncoding == SOURCEencoding,srcEncoding,dstEncoding);
  cType = SRCcType;
  for (pN = 0; pN < CDF_MAX_PARMS; pN++) cParms[pN] = SRCcParms[pN];
  if (compression != NULL) {
    if (compression->CDF.cType != SOURCEcompression) {
      cType = compression->CDF.cType;
      for (pN = 0; pN < CDF_MAX_PARMS; pN++) {
	 cParms[pN] = compression->CDF.cParms[pN];
      }
    }
  }
  /***************************************************************************
  * Create destination CDF.  Note that the cache size is selected after the
  * CDF's format is specified.  This is because changing a CDF's format will
  * also cause it's cache size to be changed.
  ***************************************************************************/
  if (mLog) WriteOut (stdout, "  Creating destination CDF...\n");
  status = CDFlib (CREATE_, CDF_, dstPath, numDims, dimSizes, &dstId,
		   NULL_);
  if (status == CDF_EXISTS && deleteIFexists) {
    status = CDFlib (OPEN_, CDF_, dstPath, &dstId,
		     DELETE_, CDF_,
		     NULL_);
    if (!StatusHandlerCvt("DST",status)) {
      WriteOut (stdout, "  Unabled to delete existing destination CDF.\n");
      if (mLog) WriteOut (stdout, "  Closing source CDF...\n");
      StatusHandlerCvt ("SRC", CDFclose(srcId));
      return FALSE;
    }
    status = CDFlib (CREATE_, CDF_, dstPath, numDims, dimSizes, &dstId,
		     NULL_);
  }
  if (!StatusHandlerCvt("DST",status)) {
    if (mLog) WriteOut (stdout, "  Closing source CDF...\n");
    StatusHandlerCvt ("SRC", CDFclose(srcId));
    return FALSE;
  }
  CHECKforABORTso
  status = CDFlib (SELECT_, CDF_, dstId,
		   PUT_, CDF_FORMAT_, format,
			 CDF_MAJORITY_, majority,
			 CDF_ENCODING_, encoding,
			 CDF_COMPRESSION_, cType, cParms,
		   SELECT_, CDF_CACHESIZE_, workingCache,
			    STAGE_CACHESIZE_, stageCache,
			    COMPRESS_CACHESIZE_, compressCache,
		   NULL_);
  if (!StatusHandlerCvt("DST",status)) {
    if (mLog) WriteOut (stdout, "  Closing destination CDF...\n");
    StatusHandlerCvt ("DST", CDFclose(dstId));
    if (mLog) WriteOut (stdout, "  Closing source CDF...\n");
    StatusHandlerCvt ("SRC", CDFclose(srcId));
    return FALSE;
  }
  CHECKforABORTso

  if (!backward) {
    if (checksumFlag == 0 || checksumFlag == 1) 	/* no or md5 */
      status = CDFlib (SELECT_, CDF_, dstId,
                       PUT_, CDF_CHECKSUM_, checksum,
                       NULL_);
    else if (checksumFlag == 2) 			/* source */
      if (srcChecksum != -999) {
        status = CDFlib (SELECT_, CDF_, dstId,
                         PUT_, CDF_CHECKSUM_, srcChecksum,
                         NULL_);
      }
    else {					/* not specified */
      int env = CDFgetChecksumEnvVar();
      if (env == 0) 				/* env var not set */
        status = CDFlib (SELECT_, CDF_, dstId,
                         PUT_, CDF_CHECKSUM_, srcChecksum,
                         NULL_);
      else					/* env var set to md5 */
        status = CDFlib (SELECT_, CDF_, dstId,
                         PUT_, CDF_CHECKSUM_, MD5_CHECKSUM,
                         NULL_);
    }
  }
  if (!StatusHandlerCvt("DST",status)) {
    if (mLog) WriteOut (stdout, "  Closing destination CDF...\n");
    StatusHandlerCvt ("DST", CDFclose(dstId));
    if (mLog) WriteOut (stdout, "  Closing source CDF...\n");
    StatusHandlerCvt ("SRC", CDFclose(srcId));
    return FALSE;
  }
  CHECKforABORTso
  /***************************************************************************
  * Convert attributes.  If that is successful, convert variables.
  ***************************************************************************/
  if (!ConvertAttributes()) {
    if (mLog) WriteOut (stdout, "  Closing source CDF...\n");
    StatusHandlerCvt ("SRC", CDFclose(srcId));
    if (mLog) WriteOut (stdout, "  Closing destination CDF...\n");
    StatusHandlerCvt ("DST", CDFclose(dstId));
    return FALSE;
  }
  /***************************************************************************
  * Convert variables.
  ***************************************************************************/
  if (!ConvertVariables (srcMajority, majority)) {
    if (mLog) WriteOut (stdout, "  Closing source CDF...\n");
    StatusHandlerCvt ("SRC", CDFclose(srcId));
    if (mLog) WriteOut (stdout, "  Closing destination CDF...\n");
    StatusHandlerCvt ("DST", CDFclose(dstId));
    return FALSE;
  }
  /***************************************************************************
  * Close source and destination CDFs.
  ***************************************************************************/
  if (dumpStatistics) {
    vSTATS vStatsDotCDF, vStatsStage, vStatsCompress;
    if (mLog) WriteOut (stdout, "  Closing source CDF...\n");
    status = CDFlib (SELECT_, CDF_, srcId,
		     CLOSE_, CDFwithSTATS_, &vStatsDotCDF,
					    &vStatsStage,
					    &vStatsCompress,
		     NULL_);
    StatusHandlerCvt ("SRC", status);
    CHECKforABORTso
    DisplayStatistics ("source", &vStatsDotCDF, &vStatsStage, &vStatsCompress);
    if (mLog) WriteOut (stdout, "  Closing destination CDF...\n");
    status = CDFlib (SELECT_, CDF_, dstId,
		     CLOSE_, CDFwithSTATS_, &vStatsDotCDF,
					    &vStatsStage,
					    &vStatsCompress,
		     NULL_);
    StatusHandlerCvt ("DST", status);
    DisplayStatistics ("destination", &vStatsDotCDF, &vStatsStage,
		       &vStatsCompress);
  }
  else {
    if (mLog) WriteOut (stdout, "  Closing source CDF...\n");
    status = CDFlib (SELECT_, CDF_, srcId,
		     CLOSE_, CDF_,
		     NULL_);
    StatusHandlerCvt ("SRC", status);
    CHECKforABORTso
    if (mLog) WriteOut (stdout, "  Closing destination CDF...\n");
    status = CDFlib (SELECT_, CDF_, dstId,
		     CLOSE_, CDF_,
		     NULL_);
    StatusHandlerCvt ("DST", status);
  }
  return TRUE;
}

/******************************************************************************
* ConvertAttributes.
******************************************************************************/

Logical ConvertAttributes ()
{
  CDFstatus status;
  long attrNum, entryNum, ignoredNum;
  long numAttrs, maxEntry, maxZentry;
  long scope;
  char attrName[CDF_ATTR_NAME_LEN256 + 1];

  /****************************************************************************
  * Inquire number of attributes to be converted.
  ****************************************************************************/

  if (mLog) WriteOut (stdout, "  Converting attributes...\n");

  status = CDFlib (SELECT_, CDF_, srcId,
		   GET_, CDF_NUMATTRS_, &numAttrs,
		   NULL_);
  if (!StatusHandlerCvt("SRC",status)) return FALSE;

  for (attrNum = 0; attrNum < numAttrs; attrNum++) {
     /*************************************************************************
     * Inquire attribute in source CDF.
     *************************************************************************/
  
     status = CDFlib (SELECT_, CDF_, srcId,
			       ATTR_, attrNum,
		      GET_, ATTR_NAME_, attrName,
			    ATTR_SCOPE_, &scope,
		      NULL_);
     if (!StatusHandlerCvt("SRC",status)) return FALSE;

     if (mLog) {
       WriteOut (stdout, "    Converting ");
       WriteOut (stdout, BOO(scope == GLOBAL_SCOPE,"g","v"));
       WriteOut (stdout, "Attribute \"");
       WriteOut (stdout, attrName);
       WriteOut (stdout, "\"\n");
     }

     /*************************************************************************
     * Create new attribute in destination CDF.
     *************************************************************************/

     status = CDFlib (SELECT_, CDF_, dstId,
		      CREATE_, ATTR_, attrName, scope, &ignoredNum,
		      NULL_);
     if (!StatusHandlerCvt("DST",status)) return FALSE;

     /*************************************************************************
     * Copy entries from source CDF to destination CDF.
     *************************************************************************/

     if (scope == GLOBAL_SCOPE) {
       status = CDFlib (SELECT_, CDF_, srcId,
			GET_, ATTR_MAXgENTRY_, &maxEntry,
			NULL_);
       if (!StatusHandlerCvt("SRC",status)) return FALSE;
       if (mLog) {
	 WriteOut (stdout, "      Converting entries...\n");
       }
       for (entryNum = 0; entryNum <= maxEntry; entryNum++) {
	  if (!ConvertEntry(entryNum,gENTRYt)) return FALSE;
       }
     }
     else {
       status = CDFlib (SELECT_, CDF_, srcId,
			GET_, ATTR_MAXrENTRY_, &maxEntry,
			      ATTR_MAXzENTRY_, &maxZentry,
			NULL_);
       if (!StatusHandlerCvt("SRC",status)) return FALSE;
       if (mLog) {
	 WriteOut (stdout, "      Converting entries...\n");
       }
       for (entryNum = 0; entryNum <= maxEntry; entryNum++) {
	  if (!ConvertEntry(entryNum,rENTRYt)) return FALSE;
       }
       for (entryNum = 0; entryNum <= maxZentry; entryNum++) {
	  if (!ConvertEntry(entryNum,zENTRYt)) return FALSE;
       }
     }
     CHECKforABORTso
  }

  return TRUE;
}

/******************************************************************************
* ConvertEntry.
******************************************************************************/

Logical ConvertEntry (entryNum, entryType)
long entryNum;
int entryType;
{
  CDFstatus status;
  long dataType;
  long numElements;
  void *value;

  status = CDFlib (SELECT_, CDF_, srcId,
			    ENTRY(entryType), entryNum,
		   GET_, ENTRY_DATATYPE(entryType), &dataType,
			 ENTRY_NUMELEMS(entryType), &numElements,
		   NULL_);
  if (status != NO_SUCH_ENTRY) {
    if (!StatusHandlerCvt("SRC",status)) return FALSE;
    value = cdf_AllocateMemory ((size_t) (CDFelemSize(dataType) * numElements),
			    FatalError);
    status = CDFlib (SELECT_, CDF_, srcId,
		     GET_, ENTRY_DATA(entryType), value,
		     NULL_);
    if (!StatusHandlerCvt("SRC",status)) return FALSE;
    status = CDFlib (SELECT_, CDF_, dstId,
			      ENTRY(entryType), entryNum,
		     PUT_, ENTRY_DATA(entryType), dataType, numElements, value,
		     NULL_);
    if (!StatusHandlerCvt("DST",status)) return FALSE;
    cdf_FreeMemory (value, FatalError);
  }
  CHECKforABORTso
  return TRUE;
}

/******************************************************************************
* ConvertVariables.
******************************************************************************/

Logical ConvertVariables (SRCmajority, DSTmajority)
long SRCmajority;
long DSTmajority;
{
  CDFstatus status;
  long numVars, numZvars;
  long varNum;

  if (mLog) WriteOut (stdout, "  Converting variables...\n");

  /****************************************************************************
  * Inquire number of variables to be converted.
  ****************************************************************************/

  status = CDFlib (SELECT_, CDF_, srcId,
		   GET_, CDF_NUMrVARS_, &numVars,
			 CDF_NUMzVARS_, &numZvars,
		   NULL_);
  if (!StatusHandlerCvt("SRC",status)) return FALSE;

  if (compression != NULL) CheckEnteredVarNames();
  for (varNum = 0; varNum < numVars; varNum++) {
     if (!ConvertVariable(varNum,FALSE,SRCmajority,DSTmajority)) return FALSE;
  }

  for (varNum = 0; varNum < numZvars; varNum++) {
     if (!ConvertVariable(varNum,TRUE,SRCmajority,DSTmajority)) return FALSE;
  }

  return TRUE;
}

/******************************************************************************
* CheckEnteredVarNames.
******************************************************************************/

void CheckEnteredVarNames ()
{
  CDFstatus status; 
  struct cVarStruct *Var;
  long numVars, numZvars;
  long varNum;
  Logical found;
  char varName[CDF_VAR_NAME_LEN256 + 1];

  /****************************************************************************
  * Inquire number of variables to be checked.
  ****************************************************************************/

  status = CDFlib (SELECT_, CDF_, srcId,
                   GET_, CDF_NUMrVARS_, &numVars,
                         CDF_NUMzVARS_, &numZvars,
                   NULL_);
  if (!StatusHandlerCvt("SRC",status)) return;

  for (Var = compression->VARhead; Var != NULL; Var = Var->next) {
     found = FALSE;
     for (varNum = 0; varNum < numVars; varNum++) {
       status = CDFlib (SELECT_, CDF_, srcId,
                                 rVAR_, varNum,
                        GET_, rVAR_NAME_, varName,
                        NULL_);
       if (!StatusHandlerCvt("SRC",status)) return;
       if (!strcmpITB(Var->name,varName)) {
         found = TRUE;
         break;
       }
     }
     if (found) continue;
     for (varNum = 0; varNum < numZvars; varNum++) {
       status = CDFlib (SELECT_, CDF_, srcId,
                                 zVAR_, varNum,
                        GET_, zVAR_NAME_, varName,
                        NULL_);
       if (!StatusHandlerCvt("SRC",status)) return;
       if (!strcmpITB(Var->name,varName)) {
         found = TRUE;
         break;
       }
     }
     if (found) continue;
     WriteOut (stdout, "Warning: variable name: ");
     WriteOut (stdout, Var->name);
     WriteOut (stdout, " not found in the CDF...\n");
  }
}

/******************************************************************************
* ConvertVariable.
******************************************************************************/

Logical ConvertVariable (varNum, Z, SRCmajority, DSTmajority)
long varNum;
Logical Z;
long SRCmajority;
long DSTmajority;
{
   CDFstatus status; long cPct, sArraysPct;
   long ignoredNum, dataType, numElements, recVary, dimVarys[CDF_MAX_DIMS];
   long numDims, dimSizes[CDF_MAX_DIMS], NvalueBytes, maxRec, blockingFactor;
   long cType, cParms[CDF_MAX_PARMS], sArraysType, sArraysParms[CDF_MAX_PARMS],
	sRecordsType, reservePct;
   char varName[CDF_VAR_NAME_LEN256 + 1]; long recNum, fromRec, toRec;
   int dimN; void *padValue; long nValuesPerRecord, nRecords;
   Byte **handles[2], *buffer1, *buffer2;
   size_t nValueBytes[2]; long nHypers, nValues, hyperN;
   struct GroupStruct groups; struct HyperStruct hyper;
   Logical srcRowMajor = ROWmajor(SRCmajority), switchMajority;
   static char cvtMsg[] = "      converting variable values...    ";
   /***************************************************************************
   * Inquire existing variable in source CDF.
   ***************************************************************************/
   status = CDFlib (SELECT_, CDF_, srcId,
			     VAR(Z), varNum,
		    GET_, VAR_NAME(Z), varName,
			  VAR_DATATYPE(Z), &dataType,
			  VAR_NUMELEMS(Z), &numElements,
			  VAR_RECVARY(Z), &recVary,
			  VAR_DIMVARYS(Z), dimVarys,
			  VAR_MAXREC(Z), &maxRec,
			  VAR_BLOCKINGFACTOR(Z), &blockingFactor,
			  VAR_SPARSERECORDS(Z), &sRecordsType,
			  VAR_SPARSEARRAYS(Z), &sArraysType,
					       sArraysParms,
					       &sArraysPct,
			  VAR_COMPRESSION(Z), &cType, cParms, &cPct,
		    NULL_);
   if (!StatusHandlerCvt("SRC",status)) return FALSE;
   if (cType != NO_COMPRESSION) {
     status = CDFlib (CONFIRM_, VAR_RESERVEPERCENT(Z), &reservePct,
		      NULL_);
     if (!StatusHandlerCvt("SRC",status)) return FALSE;
   }
   if (Z) {
     status = CDFlib (SELECT_, CDF_, srcId,
		      GET_, zVAR_NUMDIMS_, &numDims,
			    zVAR_DIMSIZES_, dimSizes,
		      NULL_);
     if (!StatusHandlerCvt("SRC",status)) return FALSE;
   }
   else {
     status = CDFlib (SELECT_, CDF_, srcId,
		      GET_, rVARs_NUMDIMS_, &numDims,
			    rVARs_DIMSIZES_, dimSizes,
		      NULL_);
     if (!StatusHandlerCvt("SRC",status)) return FALSE;
   }
   /***************************************************************************
   * Creating new variable in destination CDF.
   ***************************************************************************/
   if (mLog) {
     WriteOut (stdout, "    Converting ");
     WriteOut (stdout, BOO(Z,"zV","rV"));
     WriteOut (stdout, "ariable \"");
     WriteOut (stdout, varName);
     WriteOut (stdout, "\"\n");
   }
   if (Z) {
     status = CDFlib (SELECT_, CDF_, dstId,
		      CREATE_, zVAR_, varName, dataType, numElements, numDims,
				      dimSizes, recVary, dimVarys, &ignoredNum,
		      NULL_);
     if (!StatusHandlerCvt("DST",status)) return FALSE;
   }
   else {
     status = CDFlib (SELECT_, CDF_, dstId,
		      CREATE_, rVAR_, varName, dataType, numElements, recVary,
				     dimVarys, &ignoredNum,
		      NULL_);
     if (!StatusHandlerCvt("DST",status)) return FALSE;
   }
   /***************************************************************************
   * Specify pad value for new variable (if it exists for old variable).
   ***************************************************************************/
   NvalueBytes = numElements * CDFelemSize(dataType);
   padValue = cdf_AllocateMemory ((size_t) NvalueBytes, FatalError);
   status = CDFlib (SELECT_, CDF_, srcId,
		    GET_, VAR_PADVALUE(Z), padValue,
		    NULL_);
   if (status != NO_PADVALUE_SPECIFIED) {
     if (!StatusHandlerCvt("SRC",status)) return FALSE;
     status = CDFlib (SELECT_, CDF_, dstId,
		      PUT_, VAR_PADVALUE(Z), padValue,
		      NULL_);
     if (!StatusHandlerCvt("DST",status)) return FALSE;
   }
   cdf_FreeMemory (padValue, FatalError);
   /***************************************************************************
   * Determine sparseness/compression/blocking factor.
   ***************************************************************************/
   if (sparseRecords != NULL) {
     struct sRecordsVarStruct *Var;
     if (sparseRecords->VARs.sRecordsType != SOURCEsparseRECORDS) {
       sRecordsType = sparseRecords->VARs.sRecordsType;
     }
     for (Var = sparseRecords->VARhead; Var != NULL; Var = Var->next) {
	if (!strcmpITB(Var->name,varName)) {
	  sRecordsType = Var->sRecordsType;
	  break;
	}
     }
   }
   if (compression != NULL) {
     struct cVarStruct *Var; int i;
     if (compression->VARs.cType != SOURCEcompression) {
       cType = compression->VARs.cType;
       for (i = 0; i < CDF_MAX_PARMS; i++) {
	  cParms[i] = compression->VARs.cParms[i];
       }
       blockingFactor = compression->VARs.bf;
       reservePct = compression->VARs.reserve;
     }
     for (Var = compression->VARhead; Var != NULL; Var = Var->next) {
	if (!strcmpITB(Var->name,varName)) {
	  cType = Var->cType;
	  for (i = 0; i < CDF_MAX_PARMS; i++) cParms[i] = Var->cParms[i];
	  blockingFactor = Var->bf;
	  reservePct = Var->reserve;
	  break;
	}
     }
   }
   if (!recVary) blockingFactor = MINIMUM(blockingFactor,1);
   /***************************************************************************
   * Put compression/sparseness/blocking factor.
   ***************************************************************************/
   status = CDFlib (SELECT_, CDF_, dstId,
		    PUT_, VAR_BLOCKINGFACTOR(Z), blockingFactor,
			  VAR_SPARSERECORDS(Z), sRecordsType,
			  VAR_SPARSEARRAYS(Z), sArraysType, sArraysParms,
			  VAR_COMPRESSION(Z), cType, cParms,
		    NULL_);
   if (!StatusHandlerCvt("DST",status)) return FALSE;
   if (cType != NO_COMPRESSION) {
     status = CDFlib (SELECT_, VAR_RESERVEPERCENT(Z), reservePct,
		      NULL_);
     if (!StatusHandlerCvt("DST",status)) return FALSE;
   }
   CHECKforABORTso
   /***************************************************************************
   * Return (success) if no records exist.
   ***************************************************************************/
   if (maxRec == NO_RECORD) return TRUE;
   /***************************************************************************
   * Read/write values using hyper groups...
   ***************************************************************************/
   for (dimN = 0, nValuesPerRecord = 1; dimN < numDims; dimN++) {
      if (dimVarys[dimN])
	nValuesPerRecord *= dimSizes[dimN];
      else
	dimSizes[dimN] = 1;
   }
   handles[0] = &buffer1;
   handles[1] = &buffer2;
   nValueBytes[0] = (size_t) NvalueBytes;
   nValueBytes[1] = (size_t) NvalueBytes;
   if (mLog) {
     WriteOut (stdout, cvtMsg);
     if (pctLog)
       pctOn = TRUE;
     else
       WriteOut (stdout, "\n");
   }
   switchMajority = (numDims > 1 && SRCmajority != DSTmajority);
   for (recNum = 0; recNum <= maxRec; recNum = toRec + 1) {
      /************************************************************************
      * Determine the next allocated record.
      ************************************************************************/
      status = CDFlib (SELECT_, CDF_, srcId,
		       GET_, VAR_ALLOCATEDFROM(Z), recNum, &fromRec,
		       NULL_);
      if (!StatusHandlerCvt("SRC",status)) return FALSE;
      /************************************************************************
      * Determine the last allocated record (before the next unallocated one).
      * Do not let this exceed the maximum record written to the variable.
      ************************************************************************/
      status = CDFlib (SELECT_, CDF_, srcId,
		       GET_, VAR_ALLOCATEDTO(Z), fromRec, &toRec,
		       NULL_);
      if (!StatusHandlerCvt("SRC",status)) return FALSE;
      toRec = MINIMUM(toRec,maxRec);
      /************************************************************************
      * Allocate the records unless the variable is compressed or has sparse
      * arrays.
      ************************************************************************/
      if (cType == NO_COMPRESSION && sArraysType == NO_SPARSEARRAYS) {
	status = CDFlib (SELECT_, CDF_, dstId,
			 PUT_, VAR_ALLOCATEBLOCK(Z), fromRec, toRec,
			 NULL_);
	if (!StatusHandlerCvt("DST",status)) return FALSE;
      }
      /************************************************************************
      * Calculate the number of records in this group.
      ************************************************************************/
      nRecords = toRec - fromRec + 1;
      /************************************************************************
      * If the majority is being switched...
      ************************************************************************/
      if (switchMajority) {
	AllocateBuffers (nRecords, numDims, dimSizes, &groups, 0, 2, handles,
			 nValueBytes, srcRowMajor, MINnHYPERS, FatalError);
	if (HyperFullRecord(&groups,numDims)) {
	  long nBytesPerRecord = nValuesPerRecord * NvalueBytes, recX;
	  InitHyperParms (&hyper, &groups, numDims, &nHypers, &nValues);
	  hyper.recNumber = fromRec;
	  for (hyperN = 0; hyperN < nHypers; hyperN++) {
	     status = HYPER_READ (srcId, Z, hyper, buffer1);
	     if (!StatusHandlerCvt("SRC",status)) return FALSE;
	     if (pctLog) {
	       if (!pctOn) WriteOut (stdout, cvtMsg);
	       WriteOutPct (PCTx(PCT(hyperN,nHypers,1,3),toRec,maxRec));
	       pctOn = TRUE;
	     }
	     CHECKforABORTso
	     for (recX = 0; recX < hyper.recCount; recX++) {
	        size_t offset = (size_t) (recX * nBytesPerRecord);
	        if (srcRowMajor)
	          ROWtoCOL (buffer1 + offset, buffer2 + offset, numDims,
		            dimSizes, NvalueBytes);
	        else
	          COLtoROW (buffer1 + offset, buffer2 + offset, numDims,
		            dimSizes, NvalueBytes);
	     }
	     if (pctLog) {
	       if (!pctOn) WriteOut (stdout, cvtMsg);
	       WriteOutPct (PCTx(PCT(hyperN,nHypers,2,3),toRec,maxRec));
	       pctOn = TRUE;
	     }
	     CHECKforABORTso
	     status = HYPER_WRITE (dstId, Z, hyper, buffer2);
	     if (!StatusHandlerCvt("DST",status)) return FALSE;
	     if (pctLog) {
	       if (!pctOn) WriteOut (stdout, cvtMsg);
	       WriteOutPct (PCTx(PCT(hyperN,nHypers,3,3),toRec,maxRec));
	       pctOn = TRUE;
	     }
	     CHECKforABORTso
	     IncrHyperParms (&hyper, &groups, numDims, srcRowMajor, &nValues);
          }
          cdf_FreeMemory (buffer1, FatalError);
          cdf_FreeMemory (buffer2, FatalError);
        }
	else {
          cdf_FreeMemory (buffer2, FatalError);
          InitHyperParms (&hyper, &groups, numDims, &nHypers, &nValues);
	  hyper.recNumber = fromRec;
          for (hyperN = 0; hyperN < nHypers; hyperN++) {
             long indices[CDF_MAX_DIMS]; Byte *value = buffer1; long valueN;
             status = HYPER_READ (srcId, Z, hyper, buffer1);
             if (!StatusHandlerCvt("SRC",status)) return FALSE;
             CHECKforABORTso
             if (pctLog) {
	       if (!pctOn) WriteOut (stdout, cvtMsg);
	       WriteOutPct (PCTx(PCT(hyperN,nHypers,1,2),toRec,maxRec));
	       pctOn = TRUE;
             }
             status = CDFlib (SELECT_,CDF_,dstId,
				      BOO(Z,zVAR_RECNUMBER_,
				            rVARs_RECNUMBER_),hyper.recNumber,
		              NULL_);
             if (!StatusHandlerCvt("DST",status)) return FALSE;
             for (dimN = 0; dimN < numDims; dimN++) {
	        indices[dimN] = hyper.dimIndices[dimN];
             }
             for (valueN = 0; valueN < nValues; valueN++) {
	        status = CDFlib (SELECT_, BOO(Z,zVAR_DIMINDICES_,
					        rVARs_DIMINDICES_), indices,
			         PUT_, VAR_DATA(Z), value,
			         NULL_);
	        if (!StatusHandlerCvt("DST",status)) return FALSE;
	        if (srcRowMajor)
	          INCRindicesROW (numDims, dimSizes, indices);
	        else
	          INCRindicesCOL (numDims, dimSizes, indices);
	        value += (size_t) NvalueBytes;
             }
             if (pctLog) {
	       if (!pctOn) WriteOut (stdout, cvtMsg);
	       WriteOutPct (PCTx(PCT(hyperN,nHypers,2,2),toRec,maxRec));
	       pctOn = TRUE;
             }
             IncrHyperParms (&hyper, &groups, numDims, srcRowMajor, &nValues);
             CHECKforABORTso
          }
          cdf_FreeMemory (buffer1, FatalError);
	}
      }
      else {
	AllocateBuffers (nRecords, numDims, dimSizes, &groups, 0, 1, handles,
			 nValueBytes, srcRowMajor, MINnHYPERS, FatalError);
	InitHyperParms (&hyper, &groups, numDims, &nHypers, &nValues);
	hyper.recNumber = fromRec;
	for (hyperN = 0; hyperN < nHypers; hyperN++) {
	   status = HYPER_READ (srcId, Z, hyper, buffer1);
	   if (!StatusHandlerCvt("SRC",status)) return FALSE;
	   if (pctLog) {
	     if (!pctOn) WriteOut (stdout, cvtMsg);
	     WriteOutPct (PCTx(PCT(hyperN,nHypers,1,2),toRec,maxRec));
	     pctOn = TRUE;
	   }
	   CHECKforABORTso
	   status = HYPER_WRITE (dstId, Z, hyper, buffer1);
	   if (!StatusHandlerCvt("DST",status)) return FALSE;
	   if (pctLog) {
	     if (!pctOn) WriteOut (stdout, cvtMsg);
	     WriteOutPct (PCTx(PCT(hyperN,nHypers,2,2),toRec,maxRec));
	     pctOn = TRUE;
	   }
	   CHECKforABORTso
	   IncrHyperParms (&hyper, &groups, numDims, srcRowMajor, &nValues);
	}
	cdf_FreeMemory (buffer1, FatalError);
      }
   }
   if (pctLog) {
     WriteOut (stdout, "\n");
     pctOn = FALSE;
   }
   return TRUE;
}

/******************************************************************************
* ParseSparsenessOptions.
******************************************************************************/

#define BADs(s) FreeSparseness(s); return NULL;

struct SparseRecordsStruct *ParseSparsenessOptions (options)
char *options;
{
  struct SparseRecordsStruct *S; size_t nBytes, len; Logical done;
  char *p1, *p2; struct sRecordsVarStruct *Var;
  /****************************************************************************
  * Allocate/initialize sparseness structure.
  ****************************************************************************/
  nBytes = sizeof(struct SparseRecordsStruct);
  S = (struct SparseRecordsStruct *) cdf_AllocateMemory (nBytes, FatalError);
  S->VARs.sRecordsType = SOURCEsparseRECORDS;
  S->VARhead = NULL;
  /****************************************************************************
  * Scan options...
  * NOTE: This duplication (see `ParseCompressionOptions') could probably be
  * eliminated.
  ****************************************************************************/
  switch (*options) {
    case '(':           /* VMS-style. */
      p1 = options + 1;
      len = strlen(p1);
      if (len == 0) { BADs(S) }
      if (p1[len-1] != ')') { BADs(S) }
      p1[len-1] = NUL;
      break;
    case '"':		/* UNIX-style on a Mac (double quotes not stripped). */
      p1 = options + 1;
      len = strlen(p1);
      if (len == 0) { BADs(S) }
      if (p1[len-1] != '"') { BADs(S) }
      p1[len-1] = NUL;
      break;
    default:            /* UNIX-style on a UNIX machine or IBM PC. */
      p1 = options;
      break;
  }
  for (;;) {
     p2 = strchr (p1, ':');
     if (p2 == NULL) { BADs(S) }
     *p2 = NUL;
     if (strcmpIgCase(p1,"vars") != 0) {
       p1 = p2 + 1;
       if (!ParseSparsenessToken(&p1,&p2,&(S->VARs.sRecordsType),&done)) {
	 BADs(S)
       }
       if (done) return S;
       p1 = p2 + 1;
       continue;
     }
     if (strcmpIgCase(p1,"var") != 0) {
       nBytes = sizeof(struct sRecordsVarStruct);
       Var = (struct sRecordsVarStruct *) cdf_AllocateMemory (nBytes, FatalError);
       Var->name = NULL;
       Var->next = S->VARhead;
       S->VARhead = Var;
       p1 = p2 + 1;
       if (*p1 == NUL) { BADs(S) }
       p2 = strchr (p1 + 1, *p1);
       if (p2 == NULL) { BADs(S) }
       p1 += 1;
       *p2 = NUL;
       len = strlen (p1);
       if (len < 1) { BADs(S) }
       Var->name = (char *) cdf_AllocateMemory (len, FatalError);
       strcpyX (Var->name, p1, len);
       p2 += 1;
       if (*p2 != ':') { BADs(S) }
       p1 = p2 + 1;
       if (!ParseSparsenessToken(&p1,&p2,&(Var->sRecordsType),&done)) {
	 BADs(S)
       }
       if (done) return S;
       p1 = p2 + 1;
       continue;
     }
     BADs(S)
  }
}

/******************************************************************************
* ParseSparsenessToken.
******************************************************************************/

Logical ParseSparsenessToken (p1, p2, sRecordsType, done)
char **p1;
char **p2;
long *sRecordsType;
Logical *done;
{
  char *sToken;
  if (**p1 == NUL) return FALSE;
  *p2 = strchr (*p1, ',');
  if (*p2 == NULL) {
    *done = TRUE;
  }
  else {
    *done = FALSE;
    **p2 = NUL;
  }
  sToken = *p1;
  if (strcmpIgCase(sToken,"sRecords.PAD") != 0) {
    *sRecordsType = PAD_SPARSERECORDS;
    return TRUE;
  }
  if (strcmpIgCase(sToken,"sRecords.PREV") != 0) {
    *sRecordsType = PREV_SPARSERECORDS;
    return TRUE;
  }
  if (strcmpIgCase(sToken,"sRecords.NO") != 0) {
    *sRecordsType = NO_SPARSERECORDS;
    return TRUE;
  }
  return FALSE;
}

/******************************************************************************
* ParseCompressionOptions.
******************************************************************************/

#define BADc(c) FreeCompression(c); return NULL;

struct CompressionStruct *ParseCompressionOptions (options)
char *options;
{
  struct CompressionStruct *C; size_t nBytes, len;
  Logical done; char *p1, *p2; struct cVarStruct *Var;
  /****************************************************************************
  * Allocate/initialize compression structure.
  ****************************************************************************/
  nBytes = sizeof(struct CompressionStruct);
  C = (struct CompressionStruct *) cdf_AllocateMemory (nBytes, FatalError);
  C->CDF.cType = SOURCEcompression;
  C->VARs.cType = SOURCEcompression;
  C->VARhead = NULL;
  /****************************************************************************
  * Scan options...
  ****************************************************************************/
  switch (*options) {
    case '(':           /* VMS-style. */
      p1 = options + 1;
      len = strlen(p1);
      if (len == 0) { BADc(C) }
      if (p1[len-1] != ')') { BADc(C) }
      p1[len-1] = NUL;
      break;
    case '"':		/* UNIX-style on a Mac (double quotes not stripped). */
      p1 = options + 1;
      len = strlen(p1);
      if (len == 0) { BADc(C) }
      if (p1[len-1] != '"') { BADc(C) }
      p1[len-1] = NUL;
      break;
    default:            /* UNIX-style on a UNIX machine or IBM PC. */
      p1 = options;
      break;
  }
  for (;;) {
     p2 = strchr (p1, ':');
     if (p2 == NULL) { BADc(C) }
     *p2 = NUL;
     if (strcmpIgCase(p1,"cdf") != 0) {
       p1 = p2 + 1;
       if (!ParseCompressionTokenAndBF(&p1,&p2,
				       &(C->CDF.cType),
				       C->CDF.cParms,
				       NULL,NULL,&done)) { BADc(C) }
       if (done) return C;
       p1 = p2 + 1;
       continue;
     }
     if (strcmpIgCase(p1,"vars") != 0) {
       p1 = p2 + 1;
       if (!ParseCompressionTokenAndBF(&p1,&p2,
				       &(C->VARs.cType),
				       C->VARs.cParms,
				       &(C->VARs.bf),
				       &(C->VARs.reserve),
				       &done)) { BADc(C) }
       if (done) return C;
       p1 = p2 + 1;
       continue;
     }
     if (strcmpIgCase(p1,"var") != 0) {
       nBytes = sizeof(struct cVarStruct);
       Var = (struct cVarStruct *) cdf_AllocateMemory (nBytes, FatalError);
       Var->name = NULL;
       Var->next = C->VARhead;
       C->VARhead = Var;
       p1 = p2 + 1;
       if (*p1 == NUL) { BADc(C) }
       p2 = strchr (p1 + 1, *p1);
       if (p2 == NULL) { BADc(C) }
       p1 += 1;
       *p2 = NUL;
       len = strlen (p1);
       if (len < 1) { BADc(C) }
       Var->name = (char *) cdf_AllocateMemory (len, FatalError);
       strcpyX (Var->name, p1, len);
       p2 += 1;
       if (*p2 != ':') { BADc(C) }
       p1 = p2 + 1;
       if (!ParseCompressionTokenAndBF(&p1,&p2,
				       &(Var->cType),
				       Var->cParms,
				       &(Var->bf),
				       &(Var->reserve),
				       &done)) { BADc(C) }
       if (done) return C;
       p1 = p2 + 1;
       continue;
     }
     BADc(C)
  }
}

/******************************************************************************
* ParseCompressionTokenAndBF.
******************************************************************************/

Logical ParseCompressionTokenAndBF (p1, p2, cType, cParms, bf, reserve, done)
char **p1;
char **p2;
long *cType;
long cParms[CDF_MAX_PARMS];
long *bf;
long *reserve;
Logical *done;
{
  int count, level; long v1, v2; char *cToken, *p;
  if (**p1 == NUL) return FALSE;
  *p2 = strchr (*p1, ',');
  if (*p2 == NULL) {
    *done = TRUE;
  }
  else {
    *done = FALSE;
    **p2 = NUL;
  }
  cToken = *p1;
  p = strchr (*p1, ':');
  if (p == NULL)
    count = 0;
  else {
    *p = NUL;
    count = sscanf (p+1, "%ld:%ld", &v1, &v2);
    if (count < 1) return FALSE;
  }
  if (strcmpIgCase(cToken,"none") != 0) {
    if (count > 0) return FALSE;
    *cType = NO_COMPRESSION;
    ASSIGNnotNULL (bf, 0)
    ASSIGNnotNULL (reserve, 0)
    return TRUE;
  }
  if (strcmpIgCase(cToken,"rle.0") != 0) {
    *cType = RLE_COMPRESSION;
    cParms[0] = RLE_OF_ZEROs;
    ASSIGNnotNULL (bf, BOO(count > 0,v1,0))
    ASSIGNnotNULL (reserve, BOO(count > 1,v2,0))
    return TRUE;
  }
  if (strcmpIgCase(cToken,"huff.0") != 0) {
    *cType = HUFF_COMPRESSION;
    cParms[0] = OPTIMAL_ENCODING_TREES;
    ASSIGNnotNULL (bf, BOO(count > 0,v1,0))
    ASSIGNnotNULL (reserve, BOO(count > 1,v2,0))
    return TRUE;
  }
  if (strcmpIgCase(cToken,"ahuff.0") != 0) {
    *cType = AHUFF_COMPRESSION;
    cParms[0] = OPTIMAL_ENCODING_TREES;
    ASSIGNnotNULL (bf, BOO(count > 0,v1,0))
    ASSIGNnotNULL (reserve, BOO(count > 1,v2,0))
    return TRUE;
  }
  for (level = 1; level <= 9; level++) {
     char gzipToken[MAX_GZIP_TOKEN_LEN+1];
     sprintf (gzipToken, "gzip.%d", level);
     if (strcmpIgCase(cToken,gzipToken) != 0) {
       *cType = GZIP_COMPRESSION;
       cParms[0] = level;
       ASSIGNnotNULL (bf, BOO(count > 0,v1,0))
       ASSIGNnotNULL (reserve, BOO(count > 1,v2,0))
       return TRUE;
     }
  }
/*
  if (strcmpIgCase(cToken,"zlib.0") != 0) {
    *cType = ZLIB_COMPRESSION;
    cParms[0] = ZLIB_OF_ZEROs;
    ASSIGNnotNULL (bf, BOO(count > 0,v1,0))
    ASSIGNnotNULL (reserve, BOO(count > 1,v2,0))
    return TRUE;
  }
*/
  return FALSE;
}

/******************************************************************************
* FreeSparseness.
******************************************************************************/

void FreeSparseness (sparseRecords)
struct SparseRecordsStruct *sparseRecords;
{
  struct sRecordsVarStruct *Var = sparseRecords->VARhead;
  while (Var != NULL) {
    struct sRecordsVarStruct *VARnext = Var->next;
    if (Var->name != NULL) cdf_FreeMemory (Var->name, FatalError);
    cdf_FreeMemory (Var, FatalError);
    Var = VARnext;
  }
  cdf_FreeMemory (sparseRecords, FatalError);
}

/******************************************************************************
* FreeCompression.
******************************************************************************/

void FreeCompression (compression)
struct CompressionStruct *compression;
{
  struct cVarStruct *Var = compression->VARhead;
  while (Var != NULL) {
    struct cVarStruct *VARnext = Var->next;
    if (Var->name != NULL) cdf_FreeMemory (Var->name, FatalError);
    cdf_FreeMemory (Var, FatalError);
    Var = VARnext;
  }
  cdf_FreeMemory (compression, FatalError);
}

/******************************************************************************
* StatusHandlerCvt.
******************************************************************************/

Logical StatusHandlerCvt (which, status)
char *which;
CDFstatus status;
{
  char text[CDF_STATUSTEXT_LEN+1];            /* Explanation text. */
  char oText[MAX_OUTPUT_TEXT_LEN+1];          /* Output text. */
  if (StatusERROR(status)) {
    if (report[ERRORs]) {
      if (pctOn) {
	WriteOut (stdout, "\n");	      /* Move to start of next line. */
	pctOn = FALSE;
      }
      CDFlib (SELECT_, CDF_STATUS_, status,
	      GET_, STATUS_TEXT_, text,
	      NULL_);
      sprintf (oText, "ERROR,%s> %s", which, text);
      OutputWithMargin (stdout, oText, MAX_SCREENLINE_LEN, 0);
    }
    return FALSE;
  }
  if (StatusWARN(status)) {
    if (report[WARNs]) {
      if (pctOn) {
	WriteOut (stdout, "\n");	      /* Move to start of next line. */
	pctOn = FALSE;
      }
      CDFlib (SELECT_, CDF_STATUS_, status,
	      GET_, STATUS_TEXT_, text,
	      NULL_);
      sprintf (oText, "WARNING,%s> %s", which, text);
      OutputWithMargin (stdout, oText, MAX_SCREENLINE_LEN, 0);
    }
    return TRUE;
  }
  if (StatusINFO(status)) {
    if (report[INFOs]) {
      if (pctOn) {
	WriteOut (stdout, "\n");	      /* Move to start of next line. */
	pctOn = FALSE;
      }
      CDFlib (SELECT_, CDF_STATUS_, status,
	      GET_, STATUS_TEXT_, text,
	      NULL_);
      sprintf (oText, "INFO,%s> %s", which, text);
      OutputWithMargin (stdout, oText, MAX_SCREENLINE_LEN, 0);
    }
    return TRUE;
  }
  return TRUE;          /* CDF_OK */
}

/******************************************************************************
* ConvertQOPs.
*    Returns TRUE if execution should continue.
******************************************************************************/

#if defined(mac)
Logical ConvertQOPs (argC, argV)
int *argC;
char **argV[];
{
  DialogPtr dialogP;
  DialogRecord dRecord;
  WindowPtr behind = (WindowPtr) -1;
  ControlHandle controlHs[MAXIMUMin+1];
  Rect iRect;
#ifdef __MWERKS__
  ModalFilterUPP FilterDialogQOPsoUPP = NULL;
  FileFilterUPP FilterForCDFsUPP = NULL;
  UserItemUPP OutlineDefaultButtonUPP;
#endif
  short itemN, iType, i;
  static Logical first = TRUE;
  char cancelTitle[] = "Cancel";

  static Logical logMsg = DEFAULTlogCVT;
  static Logical dispPct = DEFAULTpctCVT;
  static Logical deleteDst = DEFAULTdelCVT;
  static Logical pageOutput = DEFAULTpageCVT;
  static Logical reportInfos = REPORTinfosDEFAULT;
  static Logical reportWarns = REPORTwarningsDEFAULT;
  static Logical reportErrors = REPORTerrorsDEFAULT;
  static Logical negToPos = DEFAULT_NEGtoPOSfp0;
  static Logical dispStats = DEFAULTstatsCVT;
  static int dstFormat = 0;
  static int dstMajority = 0;
  static int zModeSrc = DEFAULTzModeCVT;
  static int dstEncoding = 0;
  static Str255 cacheText = "\p";
  static Str255 srcText = "\p";
  static Str255 dstText = "\p";
  static Str255 sktText = "\p";
  static Str255 sparseText = "\p";
  static Str255 compressText = "\p";

  /****************************************************************************
  * Create the dialog and get the control handles.
  ****************************************************************************/

  dialogP = GetNewDialog (QOPri, &dRecord, behind);
  
  for (itemN = 1; itemN <= MAXIMUMin; itemN++) {
     GetDItem (dialogP, itemN, &iType, (Handle *) &controlHs[itemN], &iRect);
  }

  /****************************************************************************
  * Set the control values.
  ****************************************************************************/

  SetIText ((Handle) controlHs[SRCTEXTin], srcText);
  SetIText ((Handle) controlHs[DSTTEXTin], dstText);
  SetIText ((Handle) controlHs[SKTTEXTin], sktText);
  SetIText ((Handle) controlHs[CACHEin], cacheText);
  SetIText ((Handle) controlHs[SPARSEin], sparseText);
  SetIText ((Handle) controlHs[COMPRESSin], compressText);

  if (logMsg) SetCtlValue (controlHs[LOGin], 1);
  if (dispPct) SetCtlValue (controlHs[PCTin], 1);
  if (deleteDst) SetCtlValue (controlHs[DELETEin], 1);
  if (pageOutput) SetCtlValue (controlHs[PAGEin], 1);
  if (reportInfos) SetCtlValue (controlHs[INFOin], 1);
  if (reportWarns) SetCtlValue (controlHs[WARNin], 1);
  if (reportErrors) SetCtlValue (controlHs[ERRORin], 1);
  if (negToPos) SetCtlValue (controlHs[NEGZin], 1);
  if (dispStats) SetCtlValue (controlHs[STATSin], 1);

  SetCtlValue (controlHs[DSTFORMATinBASE+dstFormat], 1);
  SetCtlValue (controlHs[DSTMAJORITYinBASE+dstMajority], 1);
  SetCtlValue (controlHs[SRCzMODEinBASE+zModeSrc], 1);
  SetCtlValue (controlHs[DSTENCODINGinBASE+dstEncoding], 1);

#ifndef __MWERKS__
  SetDItem (dialogP, (short) ODBin, (short) userItem,
	    (Handle) OutlineDefaultButton, &iRect);
#else
  OutlineDefaultButtonUPP = NewUserItemProc (OutlineDefaultButton);
  SetDItem (dialogP, (short) ODBin, (short) userItem,
	    (Handle) OutlineDefaultButtonUPP, &iRect);
#endif
  /****************************************************************************
  * Change the "Quit" button to a "Cancel" button after the first time.
  ****************************************************************************/

  if (first)
    first = FALSE;
  else
    SetCTitle (controlHs[CANCELin], CtoPstr(cancelTitle));

  /****************************************************************************
  * Display the dialog and wait for user actions.
  ****************************************************************************/
    
  ShowWindow ((WindowPtr) dialogP);
  SetCursor (ARROW_CURSOR);
#ifdef __MWERKS__
  FilterDialogQOPsoUPP = NewModalFilterProc((ProcPtr) FilterDialogQOPso);
#endif

  for (;;) {
#ifndef __MWERKS__
    ModalDialog (FilterDialogQOPso, &itemN);
#else
    ModalDialog (FilterDialogQOPsoUPP, &itemN);
#endif
    switch (itemN) {
      /************************************************************************
      * Ok.
      ************************************************************************/
      case OKin: {
		char *formatOptions[] = { NULL, "-single", "-multi" };
		char *majorityOptions[] = { NULL, "-row", "-column" };
		char *encodingSymbols[] = { NULL, "host", "sun", "vax", "sgi",
					      "hp", "ibmpc", "ibmrs", "network",
					      "mac", "decstation", "next", "alphavmsd",
					      "alphavmsg", "alphaosf1", "alphavmsi" };
		int n;
		char tempS1[1+1];

		/**********************************************************************
		* Get the value of each control.
		**********************************************************************/

		GetIText ((Handle) controlHs[SRCTEXTin], srcText);
		GetIText ((Handle) controlHs[DSTTEXTin], dstText);
		GetIText ((Handle) controlHs[SKTTEXTin], sktText);
		GetIText ((Handle) controlHs[CACHEin], cacheText);
		GetIText ((Handle) controlHs[SPARSEin], sparseText);
		GetIText ((Handle) controlHs[COMPRESSin], compressText);

		logMsg = GetCtlValue (controlHs[LOGin]);
		dispPct = GetCtlValue (controlHs[PCTin]);
		deleteDst = GetCtlValue (controlHs[DELETEin]);
		pageOutput = GetCtlValue (controlHs[PAGEin]);
		reportInfos = GetCtlValue (controlHs[INFOin]);
		reportWarns = GetCtlValue (controlHs[WARNin]);
		reportErrors = GetCtlValue (controlHs[ERRORin]);
		negToPos = GetCtlValue (controlHs[NEGZin]);
		dispStats = GetCtlValue (controlHs[STATSin]);
	
		for (dstFormat = 0; dstFormat < 3; dstFormat++) {
		   if (GetCtlValue(controlHs[DSTFORMATinBASE+dstFormat])) break;
		}
		for (dstMajority = 0; dstMajority < 3; dstMajority++) {
		   if (GetCtlValue(controlHs[DSTMAJORITYinBASE+dstMajority])) break;
		}
		for (dstEncoding = 0; dstEncoding < 16; dstEncoding++) {
		   if (GetCtlValue(controlHs[DSTENCODINGinBASE+dstEncoding])) break;
		}
		for (zModeSrc = 0; zModeSrc < 3; zModeSrc++) {
		   if (GetCtlValue(controlHs[SRCzMODEinBASE+zModeSrc])) break;
		}
	
		/**********************************************************************
		* Build argc/argv.
		**********************************************************************/

		*argC = 11 + BOO(NULpString(srcText),0,1) +
				     BOO(NULpString(dstText),0,1) +
				     BOO(NULpString(sktText),0,2) +
				     BOO(NULpString(cacheText),0,2) +
				     BOO(NULpString(sparseText),0,2) +
				     BOO(NULpString(compressText),0,2) +
				     BOO(dstFormat != 0, 1, 0) +
				     BOO(dstMajority != 0, 1, 0) +
				     BOO(dstEncoding != 0, 2, 0);
		*argV = (char **) cdf_AllocateMemory (*argC * sizeof(char *),
										  FatalError);
	
		n = 0;
		MAKEstrARGv (argV, n, pgmName)

		if (!NULpString(srcText)) {
		  PtoCstr (srcText);
		  MAKEstrARGv (argV, n, (char *) srcText)
		  CtoPstr ((char *) srcText);
		}

		if (!NULpString(dstText)) {
		  PtoCstr (dstText);
		  MAKEstrARGv (argV, n, (char *) dstText)
		  CtoPstr ((char *) dstText);
		}

		MAKEbooARGv (argV, n, logMsg, "-log", "-nolog")
		MAKEbooARGv (argV, n, dispPct, "-percent", "-nopercent")
		MAKEbooARGv (argV, n, deleteDst, "-delete", "-nodelete")
		MAKEbooARGv (argV, n, pageOutput, "-page", "-nopage")
		MAKEbooARGv (argV, n, negToPos, "-neg2posfp0", "-noneg2posfp0")
		MAKEbooARGv (argV, n, dispStats, "-statistics", "-nostatistics")
	
		MAKEstrARGv (argV, n, "-zmode")
		sprintf (tempS1, "%d", zModeSrc);
		MAKEstrARGv (argV, n, tempS1)

		MAKEstrARGv (argV, n, "-report")
		MAKEstrARGv (argV, n, StatusCodeReportOptions(reportErrors,
							      reportWarns,
							      reportInfos))

		if (dstFormat != 0) {
		  MAKEstrARGv (argV, n, formatOptions[dstFormat])
		}

		if (dstMajority != 0) {
		  MAKEstrARGv (argV, n, majorityOptions[dstMajority])
		}

		if (dstEncoding != 0) {
		  MAKEstrARGv (argV, n, "-encoding")
		  MAKEstrARGv (argV, n, encodingSymbols[dstEncoding])
		}

		if (!NULpString(sktText)) {
		  MAKEstrARGv (argV, n, "-skeleton")
		  PtoCstr (sktText);
		  MAKEstrARGv (argV, n, (char *) sktText)
		  CtoPstr ((char *) sktText);
		}

		if (!NULpString(cacheText)) {
		  MAKEstrARGv (argV, n, "-cache")
		  PtoCstr (cacheText);
		  MAKEstrARGv (argV, n, (char *) cacheText)
		  CtoPstr ((char *) cacheText);
		}

		if (!NULpString(sparseText)) {
		  MAKEstrARGv (argV, n, "-sparseness")
		  PtoCstr (sparseText);
		  MAKEstrARGv (argV, n, (char *) sparseText)
		  CtoPstr ((char *) sparseText);
		}

		if (!NULpString(compressText)) {
		  MAKEstrARGv (argV, n, "-compression")
		  PtoCstr (compressText);
		  MAKEstrARGv (argV, n, (char *) compressText)
		  CtoPstr ((char *) compressText);
		}

		/**********************************************************************
		* Close the dialog and return.
		**********************************************************************/
#ifdef __MWERKS__
        DisposeRoutineDescriptor (FilterDialogQOPsoUPP);
		DisposeRoutineDescriptor (OutlineDefaultButtonUPP);
#endif
		CloseDialog (dialogP);
		return TRUE;
      }
      /************************************************************************
      * Help.
      ************************************************************************/
      case HELPin: {
		int n;
		*argC = 1;
		*argV = (char **) cdf_AllocateMemory (*argC * sizeof(char *),
										  FatalError);
		n = 0;
		MAKEstrARGv (argV, n, pgmName)
#ifdef __MWERKS__
        DisposeRoutineDescriptor (FilterDialogQOPsoUPP);
		DisposeRoutineDescriptor (OutlineDefaultButtonUPP);
#endif
		CloseDialog (dialogP);
		return TRUE;
      }
      /************************************************************************
      * Cancel.
      ************************************************************************/
      case CANCELin:
#ifdef __MWERKS__
        DisposeRoutineDescriptor (FilterDialogQOPsoUPP);
		DisposeRoutineDescriptor (OutlineDefaultButtonUPP);
#endif
		CloseDialog (dialogP);
		return FALSE;
      /************************************************************************
      * Select source CDF specification.
      ************************************************************************/
      case SRCSELECTin: {
		StandardFileReply srcReply;
		char srcPath[DU_MAX_PATH_LEN+1];
#ifndef __MWERKS__
		StandardGetFile (FilterForCDFs, -1, NULL, &srcReply);
#else
		FilterForCDFsUPP = NewFileFilterProc((ProcPtr) FilterForCDFs);
		StandardGetFile (FilterForCDFsUPP, -1, NULL, &srcReply);
        DisposeRoutineDescriptor (FilterForCDFsUPP);
#endif
		if (srcReply.sfGood && !srcReply.sfIsFolder && !srcReply.sfIsVolume) {
		  BuildMacPath (&srcReply.sfFile, srcPath, TRUE);
		  srcText[0] = strlen (srcPath);
		  strcpyX ((char *) &srcText[1], srcPath, 255);
		  SetIText ((Handle) controlHs[SRCTEXTin], srcText);
		}
		break;
      }
      /************************************************************************
      * Select destination CDF specification.
      *     The cursor is set because `StandardPutFile' leaves the cursor as
      * an iBeam (instead of returning it to what it was).
      ************************************************************************/
      case DSTSELECTin: {
		StandardFileReply dstReply;
		char dstPath[DU_MAX_PATH_LEN+1], prompt[] = "Enter specification:";
		StandardPutFile (CtoPstr(prompt), CtoPstr(""), &dstReply);
		if (dstReply.sfGood && !dstReply.sfIsFolder && !dstReply.sfIsVolume) {
		  BuildMacPath (&dstReply.sfFile, dstPath, TRUE);
		  dstText[0] = strlen (dstPath);
		  strcpyX ((char *) &dstText[1], dstPath, 255);
		  SetIText ((Handle) controlHs[DSTTEXTin], dstText);
		}
		SetCursor (&(qd.arrow));
		break;
      }
      /************************************************************************
      * Select skeleton CDF.
      ************************************************************************/
      case SKTSELECTin: {
		StandardFileReply sktReply;
		char sktPath[DU_MAX_PATH_LEN+1];
#ifndef __MWERKS__
		StandardGetFile (FilterForCDFs, -1, NULL, &sktReply);
#else
		FilterForCDFsUPP = NewFileFilterProc((ProcPtr) FilterForCDFs);
		StandardGetFile (FilterForCDFsUPP, -1, NULL, &sktReply);
        DisposeRoutineDescriptor (FilterForCDFsUPP);
#endif
		if (sktReply.sfGood && !sktReply.sfIsFolder && !sktReply.sfIsVolume) {
		  BuildMacPath (&sktReply.sfFile, sktPath, TRUE);
		  sktText[0] = strlen (sktPath);
		  strcpyX ((char *) &sktText[1], sktPath, 255);
		  SetIText ((Handle) controlHs[SKTTEXTin], sktText);
		}
		break;
      }
      /************************************************************************
      * Check boxes.
      ************************************************************************/
      case LOGin:
		if (GetCtlValue(controlHs[LOGin])) {
		  SetCtlValue (controlHs[LOGin], 0);
		  SetCtlValue (controlHs[PCTin], 0);
		}
		else
		  SetCtlValue (controlHs[LOGin], 1);
		break;
 	  case PCTin:
		if (GetCtlValue(controlHs[PCTin]))
		  SetCtlValue (controlHs[PCTin], 0);
		else {
		  SetCtlValue (controlHs[PCTin], 1);
		  SetCtlValue (controlHs[LOGin], 1);
		}
		break;
      case DELETEin:
      case PAGEin:
      case INFOin:
      case WARNin:
      case ERRORin:
      case NEGZin:
      case STATSin:
		SetCtlValue (controlHs[itemN], BOO(GetCtlValue(controlHs[itemN]),0,1));
		break;
      /************************************************************************
      * Radio buttons.
      ************************************************************************/
      case DSTFORMATinBASE+0:
      case DSTFORMATinBASE+1:
      case DSTFORMATinBASE+2:
		for (i = 0; i < 3; i++) SetCtlValue (controlHs[DSTFORMATinBASE+i], 0);
		SetCtlValue (controlHs[itemN], 1);
		break;
      case DSTMAJORITYinBASE+0:
      case DSTMAJORITYinBASE+1:
      case DSTMAJORITYinBASE+2:
		for (i = 0; i < 3; i++) SetCtlValue (controlHs[DSTMAJORITYinBASE+i],0);
		SetCtlValue (controlHs[itemN], 1);
		break;
      case DSTENCODINGinBASE+0:
      case DSTENCODINGinBASE+1:
      case DSTENCODINGinBASE+2:
      case DSTENCODINGinBASE+3:
      case DSTENCODINGinBASE+4:
      case DSTENCODINGinBASE+5:
      case DSTENCODINGinBASE+6:
      case DSTENCODINGinBASE+7:
      case DSTENCODINGinBASE+8:
      case DSTENCODINGinBASE+9:
      case DSTENCODINGinBASE+10:
      case DSTENCODINGinBASE+11:
      case DSTENCODINGinBASE+12:
      case DSTENCODINGinBASE+13:
      case DSTENCODINGinBASE+14:
      case DSTENCODINGinBASE+15:
		for (i = 0; i < 16; i++) SetCtlValue(controlHs[DSTENCODINGinBASE+i],0);
		SetCtlValue (controlHs[itemN], 1);
		break;
      case SRCzMODEinBASE+0:
      case SRCzMODEinBASE+1:
      case SRCzMODEinBASE+2:
		for (i = 0; i < 3; i++) SetCtlValue (controlHs[SRCzMODEinBASE+i], 0);
		SetCtlValue (controlHs[itemN], 1);
		break;
    }
  }
}
#endif
