/******************************************************************************
*
*  NSSDC/CDF                                                    CDFconvert.
*
*  Version 2.4b, 29-Sep-95, 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.
*
******************************************************************************/

#include "cdfcvt.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;
CDFid srcId, dstId, sktId;
long zMode;
Logical report[3];
long cacheSize;
Logical dumpStatistics;
Logical pctOn;          /* TRUE when percentage is being displayed (meaning
			   that the cursor is at the end of a line - a newline
			   is required before displaying the next line). */

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

MAIN {
#if defined(mac)
  strcpyX (pgmName, "CDFconvert", MAX_PROGRAM_NAME_LEN);
  MacExecuteSO (ConvertCDFs, ConvertQOPs);
  if (FreeMemory(NULL,FatalError) > 0) DisplayWarning ("Abandoned buffers.");
  return EXIT_SUCCESS_;
#else
  Logical success;
  strcpyX (pgmName, "CDFconvert", MAX_PROGRAM_NAME_LEN);
  success = ConvertCDFs (argc, argv);
  if (FreeMemory(NULL,FatalError) > 0) DisplayWarning ("Abandoned buffers.");
  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", 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, 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;
  pctOn = FALSE;

  /****************************************************************************
  * Get qualifiers/options/parameters.
  ****************************************************************************/

  switch (argC) {
    case 1:
      PageOLH ("cdfcvt.olh", argV[0]);
      return TRUE;
    default:
      qop = Qop (argC, argV, validQuals, optRequired);
      if (qop == NULL) return FALSE;

      /************************************************************************
      * 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)
	  Uppercase (srcSpec);
	  Uppercase (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,COL_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 {
	  if (!strcmpIgCase(qop->qualOpt[ENCODINGqual],"host"))
	    dstEncoding = HOST_ENCODING;
	  else if (!strcmpIgCase(qop->qualOpt[ENCODINGqual],"network"))
	    dstEncoding = NETWORK_ENCODING;
	  else if (!strcmpIgCase(qop->qualOpt[ENCODINGqual],"sun"))
	    dstEncoding = SUN_ENCODING;
	  else if (!strcmpIgCase(qop->qualOpt[ENCODINGqual],"vax"))
	    dstEncoding = VAX_ENCODING;
	  else if (!strcmpIgCase(qop->qualOpt[ENCODINGqual],"decstation"))
	    dstEncoding = DECSTATION_ENCODING;
	  else if (!strcmpIgCase(qop->qualOpt[ENCODINGqual],"sgi"))
	    dstEncoding = SGi_ENCODING;
	  else if (!strcmpIgCase(qop->qualOpt[ENCODINGqual],"ibmpc"))
	    dstEncoding = IBMPC_ENCODING;
	  else if (!strcmpIgCase(qop->qualOpt[ENCODINGqual],"ibmrs"))
	    dstEncoding = IBMRS_ENCODING;
	  else if (!strcmpIgCase(qop->qualOpt[ENCODINGqual],"mac"))
	    dstEncoding = MAC_ENCODING;
	  else if (!strcmpIgCase(qop->qualOpt[ENCODINGqual],"hp"))
	    dstEncoding = HP_ENCODING;
	  else if (!strcmpIgCase(qop->qualOpt[ENCODINGqual],"next"))
	    dstEncoding = NeXT_ENCODING;
	  else if (!strcmpIgCase(qop->qualOpt[ENCODINGqual],"alphaosf1"))
	    dstEncoding = ALPHAOSF1_ENCODING;
	  else if (!strcmpIgCase(qop->qualOpt[ENCODINGqual],"alphavmsd"))
	    dstEncoding = ALPHAVMSd_ENCODING;
	  else if (!strcmpIgCase(qop->qualOpt[ENCODINGqual],"alphavmsg"))
	    dstEncoding = ALPHAVMSg_ENCODING;
	  else {
	    DisplayError ("Unknown encoding.");
	    qopError = TRUE;
	  }
	}
      }

      /************************************************************************
      * 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 (sscanf(qop->qualOpt[CACHEqual],"%ld",&cacheSize) != 1) {
	     DisplayError ("Illegal cache size for `.cdf' file.");
	     qopError = TRUE;
	   }
	 }
	 else
	   cacheSize = 0;

      /************************************************************************
      * 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 `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 ("Message logging must be enabled with pct. logging.");
	qopError = TRUE;
      }

      /************************************************************************
      * Free QOP memory and check for an error.
      ************************************************************************/

      FreeMemory (qop, FatalError);
      if (qopError) 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)
    Uppercase (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,
		     NULL_);
    if (StatusBAD(status)) {
       StatusHandler ("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) FreeMemory (directories, FatalError);
  if (CDFnames != NULL) FreeMemory (CDFnames, FatalError);

  /****************************************************************************
  * Close skeleton CDF if one was used.
  ****************************************************************************/

  if (useSkeletonCDF) {
    status = CDFclose (sktId);
    StatusHandler ("STK", status);                        /* Ignore return. */
  }

  return TRUE;
}

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

Logical ConvertCDF (srcPath, dstPath)
char *srcPath;
char *dstPath;
{
  CDFstatus status;
  long format, majority, encoding;
  long numDims, dimSizes[CDF_MAX_DIMS];

  WriteOut (stdout, "Converting \"");
  WriteOut (stdout, srcPath);
  WriteOut (stdout, "\" to \"");
  WriteOut (stdout, dstPath);
  WriteOut (stdout, "\"\n");

  /***************************************************************************
  * Open source CDF.  If an error occurs, skip to next CDF.
  ***************************************************************************/

  status = CDFlib (OPEN_, CDF_, srcPath, &srcId,
		   SELECT_, CDF_READONLY_MODE_, READONLYon,
			    CDF_zMODE_, zMode,
			    CDF_NEGtoPOSfp0_MODE_, BOO(negToPosFp0,
						       NEGtoPOSfp0on,
						       NEGtoPOSfp0off),
			    CDF_CACHESIZE_, cacheSize,
		   GET_, CDF_FORMAT_, &srcFormat,
			 CDF_MAJORITY_, &srcMajority,
			 CDF_ENCODING_, &srcEncoding,
			 rVARs_NUMDIMS_, &numDims,
			 rVARs_DIMSIZES_, dimSizes,
		   NULL_);
  if (!StatusHandler("SRC",status)) return FALSE;

  /***************************************************************************
  * Determine format, majority, and encoding of destination CDF.
  ***************************************************************************/

  if (dstFormat == SOURCEformat)
    format = srcFormat;
  else
    format = dstFormat;

  if (dstMajority == SOURCEmajority)
    majority = srcMajority;
  else
    majority = dstMajority;

  if (dstEncoding == SOURCEencoding)
    encoding = srcEncoding;
  else
    encoding = dstEncoding;

  /***************************************************************************
  * 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.
  ***************************************************************************/

  status = CDFlib (CREATE_, CDF_, dstPath, numDims, dimSizes, &dstId,
		   NULL_);
  if (status == CDF_EXISTS && deleteIFexists) {
    status = CDFlib (OPEN_, CDF_, dstPath, &dstId,
		     DELETE_, CDF_,
		     NULL_);
    if (!StatusHandler("DST",status)) {
      WriteOut (stdout, "  Unabled to delete existing destination CDF.\n");
      status = CDFlib (SELECT_, CDF_, srcId,
		       CLOSE_, CDF_,
		       NULL_);
      StatusHandler ("SRC", status);
      return FALSE;
    }
    status = CDFlib (CREATE_, CDF_, dstPath, numDims, dimSizes, &dstId,
		     NULL_);
  }
  if (!StatusHandler("DST",status)) {
    status = CDFlib (SELECT_, CDF_, srcId,
		     CLOSE_, CDF_,
		     NULL_);
    StatusHandler ("SRC", status);
    return FALSE;
  }

  status = CDFlib (SELECT_, CDF_, dstId,
		   PUT_, CDF_FORMAT_, format,
			 CDF_MAJORITY_, majority,
			 CDF_ENCODING_, encoding,
		   SELECT_, CDF_CACHESIZE_, cacheSize,
		   NULL_);
  if (!StatusHandler("DST",status)) {
    status = CDFclose (srcId);
    StatusHandler ("SRC", status);
    return FALSE;
  }
  CHECKforABORTso

  /***************************************************************************
  * Convert attributes.  If that is successful, convert variables.
  ***************************************************************************/

  if (!ConvertAttributes()) {
    status = CDFclose (srcId);
    StatusHandler ("SRC", status);
    status = CDFclose (dstId);
    StatusHandler ("DST", status);
    return FALSE;
  }

  /***************************************************************************
  * Convert variables.
  ***************************************************************************/

  if (!ConvertVariables (srcMajority, majority)) {
    status = CDFclose (srcId);
    StatusHandler ("SRC", status);
    status = CDFclose (dstId);
    StatusHandler ("DST", status);
    return FALSE;
  }

  /***************************************************************************
  * Close source and destination CDFs.
  ***************************************************************************/

  if (dumpStatistics) {
    vSTATS vStats;
    status = CDFlib (SELECT_, CDF_, srcId,
		     CLOSE_, CDFwithSTATS_, &vStats,
		     NULL_);
    StatusHandler ("SRC", status);
    DisplayStatistics ("source", &vStats);
    status = CDFlib (SELECT_, CDF_, dstId,
		     CLOSE_, CDFwithSTATS_, &vStats,
		     NULL_);
    StatusHandler ("DST", status);
    DisplayStatistics ("destination", &vStats);
  }
  else {
    status = CDFlib (SELECT_, CDF_, srcId,
		     CLOSE_, CDF_,
		     NULL_);
    StatusHandler ("SRC", status);
    status = CDFlib (SELECT_, CDF_, dstId,
		     CLOSE_, CDF_,
		     NULL_);
    StatusHandler ("DST", status);
  }

  return TRUE;    /* Conversion successful. */
}

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

Logical ConvertAttributes ()
{
  CDFstatus status;
  long attrNum, entryNum, ignoredNum;
  long numAttrs, maxEntry, maxZentry;
  long scope;
  char attrName[CDF_ATTR_NAME_LEN + 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 (!StatusHandler("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 (!StatusHandler("SRC",status)) return FALSE;

     if (mLog) {
       WriteOut (stdout, "    converting ");
       WriteOut (stdout, Gq(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 (!StatusHandler("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 (!StatusHandler("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 (!StatusHandler("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;    /* Success. */
}

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

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

  status = CDFlib (SELECT_, CDF_, srcId,
			    E3(entryType,gENTRY_,rENTRY_,zENTRY_), entryNum,
		   GET_, E3(entryType,gENTRY_DATATYPE_,
			    rENTRY_DATATYPE_,zENTRY_DATATYPE_), &dataType,
			 E3(entryType,gENTRY_NUMELEMS_,
			    rENTRY_NUMELEMS_,zENTRY_NUMELEMS_), &numElements,
		   NULL_);
  if (status != NO_SUCH_ENTRY) {
    if (!StatusHandler("SRC",status)) return FALSE;
    value = AllocateMemory ((size_t) (CDFelemSize(dataType) * numElements),
			    FatalError);
    status = CDFlib (SELECT_, CDF_, srcId,
		     GET_, E3(entryType,
			      gENTRY_DATA_,rENTRY_DATA_,zENTRY_DATA_), value,
		     NULL_);
    if (!StatusHandler("SRC",status)) return FALSE;
    status = CDFlib (SELECT_, CDF_, dstId,
			      E3(entryType,gENTRY_,rENTRY_,zENTRY_), entryNum,
		     PUT_, E3(entryType,gENTRY_DATA_,
					rENTRY_DATA_,
					zENTRY_DATA_), dataType, numElements,
						       value,
		     NULL_);
    if (!StatusHandler("DST",status)) return FALSE;
    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 (!StatusHandler("SRC",status)) return FALSE;

  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;
}

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

Logical ConvertVariable (varNum, Z, SRCmajority, DSTmajority)
long varNum;
Logical Z;
long SRCmajority;
long DSTmajority;
{
   CDFstatus status;
   long ignoredNum, dataType, numElements, recVary, dimVarys[CDF_MAX_DIMS];
   long numDims, dimSizes[CDF_MAX_DIMS], NvalueBytes, maxRec, NextendRecs;
   char varName[CDF_VAR_NAME_LEN + 1];
   int dimN; void *padValue; long nValuesPerRecord;
   Byte **handles[2], *buffer1, *buffer2;
   size_t nValueBytes[2]; long nHypers, nValues, hyperN;
   struct GroupStruct groups; struct HyperStruct hyper;
   Logical srcRowMajor = ROWmajor(SRCmajority);
   static char hyperMsg[] = {
     "      converting values with hyper reads/writes..."
   };
   static char hyperSwitchMsg[] = {
     "      converting values with hyper reads/switching/writes..."
   };
   static char hyperSingleMsg[] = {
     "      converting values with hyper reads/single writes..."
   };
   /***************************************************************************
   * Inquire existing variable in source CDF.
   ***************************************************************************/
   status = CDFlib (SELECT_, CDF_, srcId,
			     Zq(Z,zVAR_,rVAR_), varNum,
		    GET_, Zq(Z,zVAR_NAME_,rVAR_NAME_), varName,
			  Zq(Z,zVAR_DATATYPE_,rVAR_DATATYPE_), &dataType,
			  Zq(Z,zVAR_NUMELEMS_,rVAR_NUMELEMS_), &numElements,
			  Zq(Z,zVAR_RECVARY_,rVAR_RECVARY_), &recVary,
			  Zq(Z,zVAR_DIMVARYS_,rVAR_DIMVARYS_), dimVarys,
			  Zq(Z,zVAR_MAXREC_,rVAR_MAXREC_), &maxRec,
			  Zq(Z,zVAR_EXTENDRECS_,
			       rVAR_EXTENDRECS_), &NextendRecs,
		    NULL_);
   if (!StatusHandler("SRC",status)) return FALSE;
   if (Z) {
     status = CDFlib (SELECT_, CDF_, srcId,
		      GET_, zVAR_NUMDIMS_, &numDims,
			    zVAR_DIMSIZES_, dimSizes,
		      NULL_);
     if (!StatusHandler("SRC",status)) return FALSE;
   }
   else {
     status = CDFlib (SELECT_, CDF_, srcId,
		      GET_, rVARs_NUMDIMS_, &numDims,
			    rVARs_DIMSIZES_, dimSizes,
		      NULL_);
     if (!StatusHandler("SRC",status)) return FALSE;
   }
   /***************************************************************************
   * Creating new variable in destination CDF.
   ***************************************************************************/
   if (mLog) {
     WriteOut (stdout, "    converting ");
     WriteOut (stdout, Zq(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,
		      PUT_, zVAR_EXTENDRECS_, NextendRecs,
		      NULL_);
     if (!StatusHandler("DST",status)) return FALSE;
   }
   else {
     status = CDFlib (SELECT_, CDF_, dstId,
		      CREATE_, rVAR_, varName, dataType, numElements, recVary,
				     dimVarys, &ignoredNum,
		      PUT_, rVAR_EXTENDRECS_, NextendRecs,
		      NULL_);
     if (!StatusHandler("DST",status)) return FALSE;
   }
   /***************************************************************************
   * Specify pad value for new variable (if it exists for old variable).
   ***************************************************************************/
   NvalueBytes = numElements * CDFelemSize(dataType);
   padValue = AllocateMemory ((size_t) NvalueBytes, FatalError);
   status = CDFlib (SELECT_, CDF_, srcId,
		    GET_, Zq(Z,zVAR_PADVALUE_,rVAR_PADVALUE_), padValue,
		    NULL_);
   if (status != NO_PADVALUE_SPECIFIED) {
     if (!StatusHandler("SRC",status)) return FALSE;
     status = CDFlib (SELECT_, CDF_, dstId,
		      PUT_, Zq(Z,zVAR_PADVALUE_,rVAR_PADVALUE_), padValue,
		      NULL_);
     if (!StatusHandler("DST",status)) return FALSE;
   }
   FreeMemory (padValue, FatalError);
   CHECKforABORTso
   /***************************************************************************
   * Allocate the needed records for the variable.
   ***************************************************************************/
   if (maxRec > -1) {
     status = CDFlib (SELECT_, CDF_, dstId,
		      PUT_, Zq(Z,zVAR_ALLOCATERECS_,
				 rVAR_ALLOCATERECS_), maxRec + 1,
		      NULL_);
     if (!StatusHandler("DST",status)) return FALSE;
   }
   CHECKforABORTso
   /***************************************************************************
   * 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;
   /***************************************************************************
   * Check for zero or one dimensions or the same majorities (if two or more
   * dimensions).
   ***************************************************************************/
   if (numDims < 2 || SRCmajority == DSTmajority) {
     if (mLog) {
       WriteOut (stdout, hyperMsg);
       WriteOut (stdout, BOO(pctLog,"..0%","\n"));
     }
     AllocateBuffers (maxRec + 1, numDims, dimSizes, &groups, 0, 1, handles,
		      nValueBytes, srcRowMajor, MINnHYPERS, FatalError);
     InitHyperParms (&hyper, &groups, numDims, &nHypers, &nValues);
     for (hyperN = 0; hyperN < nHypers; hyperN++) {
	status = HYPER_READ (srcId, Z, hyper, buffer1);
	if (!StatusHandler("SRC",status)) return FALSE;
	if (pctLog) WriteOutPct (PCT(hyperN,nHypers,1,2));
	CHECKforABORTso
	status = HYPER_WRITE (dstId, Z, hyper, buffer1);
	if (!StatusHandler("DST",status)) return FALSE;
	if (pctLog) WriteOutPct (PCT(hyperN,nHypers,2,2));
	CHECKforABORTso
	IncrHyperParms (&hyper, &groups, numDims, srcRowMajor, &nValues);
     }
     FreeMemory (buffer1, FatalError);
     if (pctLog) WriteOut (stdout, "\n");
     return TRUE;
   }
   /***************************************************************************
   * There must be two or more dimensions with different majorities.  Attempt
   * to allocate two buffers.
   ***************************************************************************/
   AllocateBuffers (maxRec + 1, numDims, dimSizes, &groups, 0, 2, handles,
		    nValueBytes, srcRowMajor, MINnHYPERS, FatalError);
   /***************************************************************************
   * Check if full records are being read/written.  If so, switch the majority
   * in the buffer between the read and write.
   ***************************************************************************/
   if (HyperFullRecord(&groups,numDims)) {
     long nBytesPerRecord = nValuesPerRecord * NvalueBytes, recX;
     if (mLog) {
       WriteOut (stdout, hyperSwitchMsg);
       WriteOut (stdout, BOO(pctLog,"..0%","\n"));
     }
     InitHyperParms (&hyper, &groups, numDims, &nHypers, &nValues);
     for (hyperN = 0; hyperN < nHypers; hyperN++) {
	status = HYPER_READ (srcId, Z, hyper, buffer1);
	if (!StatusHandler("SRC",status)) return FALSE;
	if (pctLog) WriteOutPct (PCT(hyperN,nHypers,1,3));
	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) WriteOutPct (PCT(hyperN,nHypers,2,3));
	CHECKforABORTso
	status = HYPER_WRITE (dstId, Z, hyper, buffer2);
	if (!StatusHandler("DST",status)) return FALSE;
	if (pctLog) WriteOutPct (PCT(hyperN,nHypers,3,3));
	CHECKforABORTso
	IncrHyperParms (&hyper, &groups, numDims, srcRowMajor, &nValues);
     }
     FreeMemory (buffer1, FatalError);
     FreeMemory (buffer2, FatalError);
     if (pctLog) WriteOut (stdout, "\n");
     return TRUE;
   }
   /***************************************************************************
   * Less than full records are being read/written.  Hyper read into the
   * buffer but then use single writes to reverse the majority.
   ***************************************************************************/
   FreeMemory (buffer2, FatalError);
   if (mLog) {
     WriteOut (stdout, hyperSingleMsg);
     WriteOut (stdout, BOO(pctLog,"..0%","\n"));
   }
   InitHyperParms (&hyper, &groups, numDims, &nHypers, &nValues);
   for (hyperN = 0; hyperN < nHypers; hyperN++) {
      long indices[CDF_MAX_DIMS]; Byte *value = buffer1; long valueN;
      status = HYPER_READ (srcId, Z, hyper, buffer1);
      if (!StatusHandler("SRC",status)) return FALSE;
      CHECKforABORTso
      if (pctLog) WriteOutPct (PCT(hyperN,nHypers,1,2));
      status = CDFlib (SELECT_, CDF_, dstId,
				Zq(Z,zVAR_RECNUMBER_,
				     rVARs_RECNUMBER_), hyper.recNumber,
		       NULL_);
      if (!StatusHandler("DST",status)) return FALSE;
      for (dimN = 0; dimN < numDims; dimN++) {
	 indices[dimN] = hyper.dimIndices[dimN];
      }
      for (valueN = 0; valueN < nValues; valueN++) {
	 status = CDFlib (SELECT_, Zq(Z,zVAR_DIMINDICES_,
					rVARs_DIMINDICES_), indices,
			  PUT_, Zq(Z,zVAR_DATA_,rVAR_DATA_), value,
			  NULL_);
	 if (!StatusHandler("DST",status)) return FALSE;
	 if (srcRowMajor)
	   INCRindicesROW (numDims, dimSizes, indices);
	 else
	   INCRindicesCOL (numDims, dimSizes, indices);
	 value += (size_t) NvalueBytes;
      }
      if (pctLog) WriteOutPct (PCT(hyperN,nHypers,2,2));
      IncrHyperParms (&hyper, &groups, numDims, srcRowMajor, &nValues);
      CHECKforABORTso
   }
   FreeMemory (buffer1, FatalError);
   if (pctLog) WriteOut (stdout, "\n");
   return TRUE;
}

/******************************************************************************
* StatusHandler.
******************************************************************************/

Logical StatusHandler (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. */
      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. */
      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. */
      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;
  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";

  /****************************************************************************
  * 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);

  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);

  SetDItem (dialogP, (short) ODBin, (short) userItem,
	    (Handle) OutlineDefaultButton, &iRect);

  /****************************************************************************
  * 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);

  for (;;) {
    ModalDialog (FilterDialogQOPso, &itemN);
    switch (itemN) {
      /************************************************************************
      * Ok.
      ************************************************************************/
      case OKin: {
	char *formatOptions[3] = { NULL, "-single", "-multi" };
	char *majorityOptions[3] = { NULL, "-row", "-column" };
	char *encodingSymbols[15] = { NULL, "host", "sun", "vax", "sgi",
				      "hp", "ibmpc", "ibmrs", "network",
				      "mac", "decstation", "next", "alphavmsd",
				      "alphavmsg", "alphaosf1" };
	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);

	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 < 15; 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(dstFormat != 0, 1, 0) +
		     BOO(dstMajority != 0, 1, 0) +
		     BOO(dstEncoding != 0, 2, 0);
	*argV = (char **) 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);
	}

	/**********************************************************************
	* Close the dialog and return.
	**********************************************************************/
	CloseDialog (dialogP);
	return TRUE;
      }
      /************************************************************************
      * Help.
      ************************************************************************/
      case HELPin: {
	int n;
	*argC = 1;
	*argV = (char **) AllocateMemory (*argC * sizeof(char *), FatalError);
	n = 0;
	MAKEstrARGv (argV, n, pgmName)
	CloseDialog (dialogP);
	return TRUE;
      }
      /************************************************************************
      * Cancel.
      ************************************************************************/
      case CANCELin:
	CloseDialog (dialogP);
	return FALSE;
      /************************************************************************
      * Select source CDF specification.
      ************************************************************************/
      case SRCSELECTin: {
	StandardFileReply srcReply;
	char srcPath[DU_MAX_PATH_LEN+1];
	StandardGetFile (FilterForCDFs, -1, NULL, &srcReply);
	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];
	StandardGetFile (FilterForCDFs, -1, NULL, &sktReply);
	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:
      case PCTin:
      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:
	for (i = 0; i < 15; 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
