/******************************************************************************
*
*  NSSDC/CDF						      SkeletonTable.
*
*  Version 1.3g, 28-Sep-95, Hughes STX.
*
*  Modification history:
*
*   V1.0  18-May-92, J Love	Original version.
*   V1.1   2-Sep-92, J Love	CDF V2.3 (shareable/NeXT/zVar).
*   V1.2  25-Jan-94, J Love	CDF V2.4.
*   V1.3  13-Dec-94, J Love	CDF V2.5.
*   V1.3a 10-Jan-95, J Love	Uppercase file extensions on the Macintosh.
*   V1.3b 28-Feb-95, J Love	Pass `char' as `int'.
*   V1.3c  6-Apr-95, J Love	POSIX.
*   V1.3d  9-May-95, J Love	EPOCH styles.
*   V1.3e  4-Aug-95, J Love	CDFexport-related changes.
*   V1.3f 19-Sep-95, J Love	CHECKforABORTso.
*   V1.3g 28-Sep-95, J Love	Macintosh dialog filtering.  Outline default
*				button.
*
******************************************************************************/

#include "cdf2skt.h"

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

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

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

Logical mLog;
FILE *SKTfp;
Logical useFormat;
Logical report[3];

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

MAIN {
#if defined(mac)
  strcpyX (pgmName, "SkeletonTable", MAX_PROGRAM_NAME_LEN);
  MacExecuteSO (CreateSkeletonTable, SkeletonTableQOPs);
  if (FreeMemory(NULL,FatalError) > 0) DisplayWarning ("Abandoned buffers.");
  return EXIT_SUCCESS_;
#else
  Logical success;
  strcpyX (pgmName, "SkeletonTable", MAX_PROGRAM_NAME_LEN);
  success = CreateSkeletonTable (argc, argv);
  if (FreeMemory(NULL,FatalError) > 0) DisplayWarning ("Abandoned buffers.");
  return BOO(success,EXIT_SUCCESS_,EXIT_FAILURE_);
#endif
}

/******************************************************************************
* CreateSkeletonTable.
******************************************************************************/

Logical CreateSkeletonTable (argC, argV)
int argC;
char *argV[];
{
CDFstatus status;
CDFid id;
char CDFpath[DU_MAX_PATH_LEN+1];
char CDFpathX[DU_MAX_PATH_LEN+1];
char CDFname[DU_MAX_NAME_LEN+1];
char dir[DU_MAX_DIR_LEN+1];
char SKTpath[DU_MAX_PATH_LEN+1];
char SKTpathX[DU_MAX_PATH_LEN+1];
char creationStamp[TIME_STAMP_LEN+1];
int count;
long zMode, cacheSize;
Logical negToPosFp0;
Logical outToScreen;
int varValues;
char *variables = NULL;
Logical qopError = FALSE;
QOP *qop;
static char *validQuals[] = { "skeleton", "nonrv", "nrvfile", "nrvtable",
			      "log", "nolog", "zmode", "neg2posfp0",
			      "noneg2posfp0", "format", "noformat", "report",
			      "screen", "noscreen", "cache", "values",
			      "page", "nopage", NULL };
static int optRequired[] = { TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE,
			     FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE,
			     TRUE, TRUE, FALSE, FALSE, 0 };
static char *reportTokens[] = { "errors", "warnings", "informationals" };

/******************************************************************************
* Parse qualifiers/options/parameters (QOP).
******************************************************************************/

switch (argC) {
  case 1:
    PageOLH ("cdf2skt.olh", argV[0]);
    return TRUE;

  default:
    qop = Qop (argC, argV, validQuals, optRequired);
    if (qop == NULL) return FALSE;

    /**************************************************************************
    * Get CDF pathname.
    **************************************************************************/

    if (qop->Nparms < 1) {
      DisplayError ("Missing parameter.");
      qopError = TRUE;
    }
    else {
      strcpyX (CDFpath, qop->parms[CDFPATHparm], DU_MAX_PATH_LEN);
      ParsePath (CDFpath, dir, CDFname);
    }

    /**************************************************************************
    * Check if a skeleton table pathname was specified.
    **************************************************************************/

    if (qop->qualEntered[SKTqual])
      strcpyX (SKTpath, qop->qualOpt[SKTqual], DU_MAX_PATH_LEN);
    else
      strcpyX (SKTpath, CDFname, DU_MAX_PATH_LEN);

    /**************************************************************************
    * Check if which variable values should be displayed was specified.
    **************************************************************************/

    count = 0;
    if (qop->qualEntered[NONRVqual]) count++;
    if (qop->qualEntered[NRVFILEqual]) count++;
    if (qop->qualEntered[NRVTABLEqual]) count++;
    if (qop->qualEntered[VALUESqual]) count++;
    switch (count) {
      case 0:
	varValues = DEFAULTvaluesCDF2SKT;
	break;
      case 1:
	if (qop->qualEntered[NONRVqual]) {
	  varValues = NOvalues;
	  break;
	}
	if (qop->qualEntered[NRVFILEqual]) {
	  DisplayWarning ("NRV files are no longer supported.");
	  varValues = NRVvalues;
	  break;
	}
	if (qop->qualEntered[NRVTABLEqual]) {
	  varValues = NRVvalues;
	  break;
	}
	if (qop->qualEntered[VALUESqual]) {
	  size_t len = strlen(qop->qualOpt[VALUESqual]);
	  if (!strcmpIgCase(qop->qualOpt[VALUESqual],"none"))
	    varValues = NOvalues;
	  else if (!strcmpIgCase(qop->qualOpt[VALUESqual],"nrv"))
	    varValues = NRVvalues;
	  else if (!strcmpIgCase(qop->qualOpt[VALUESqual],"rv"))
	    varValues = RVvalues;
	  else if (!strcmpIgCase(qop->qualOpt[VALUESqual],"all"))
	    varValues = ALLvalues;
#if defined(vms)
	  else if (qop->qualOpt[VALUESqual][0] == '(' &&
		   qop->qualOpt[VALUESqual][len-1] == '(') {
 	    varValues = NAMEDvalues;
 	    variables = AllocateMemory (len + 1, FatalError);
 	    strcpyX (variables, qop->qualOpt[VALUESqual], len);
 	  }
	  else {
	    DisplayError ("Unknown `values' option.");
	    qopError = TRUE;
	  }
#else
	  else {
	    varValues = NAMEDvalues;
 	    variables = AllocateMemory (len + 1, FatalError);
 	    strcpyX (variables, qop->qualOpt[VALUESqual], len);
	  }
#endif
	}
	break;
      default:
	DisplayError ("Specify only one variable values qualifier.");
	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 = DEFAULTzModeCDF2SKT;

    /**************************************************************************
    * 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 `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 `log', `neg2posfp0', `screen', `page', and `format' qualifiers.
    **************************************************************************/

    qopError = qopError | !TFqualifier(qop,&outToScreen,SCREENqual,
				       NOSCREENqual,DEFAULTscreenCDF2SKT,
				       "screen");
    qopError = qopError | !TFqualifier(qop,&pagingOn,PAGEqual,NOPAGEqual,
				       DEFAULTpageCDF2SKT,"page");
    qopError = qopError | !TFqualifier(qop,&mLog,LOGqual,NOLOGqual,
				       DEFAULTlogCDF2SKT,"log");
    qopError = qopError | !TFqualifier(qop,&negToPosFp0,NEG2POSqual,
				       NONEG2POSqual,DEFAULT_NEGtoPOSfp0,
				       "neg2posfp0");
    qopError = qopError | !TFqualifier(qop,&useFormat,FORMATqual,NOFORMATqual,
				       DEFAULTformatCDF2SKT,"format");

    /**************************************************************************
    * Check for conflicting/missing qualifiers.
    **************************************************************************/

    if (qop->qualEntered[SKTqual] && qop->qualEntered[SCREENqual]) {
      DisplayError ("Conflicting qualifiers (`skeleton' and `screen').");
      qopError = TRUE;
    }
    if (!qop->qualEntered[SCREENqual] && qop->qualEntered[PAGEqual]) {
      DisplayError ("Conflicting qualifiers (`noscreen' and `page').");
      qopError = TRUE;
    }
    
    /**************************************************************************
    * Check for overridding qualifiers.
    **************************************************************************/

    if (qop->qualEntered[SCREENqual]) mLog = FALSE;

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

    FreeMemory (qop, FatalError);
    if (qopError) return FALSE;

    break;
}
  
/******************************************************************************
* Create skeleton table.
******************************************************************************/

if (mLog) {
  WriteOut (stdout, "Name of CDF: ");
  WriteOut (stdout, CDFname);
  WriteOut (stdout, "\n");
}

TimeStamp (creationStamp);

if (outToScreen)
  SKTfp = stdout;
else {
  strcatX (SKTpath, ".skt", DU_MAX_PATH_LEN);
  ExpandPath (SKTpath, SKTpathX);
  SKTfp = fopen (SKTpathX, "w");
  if (SKTfp == NULL) {
    WriteOut (stdout, "Error creating skeleton table (");
    WriteOut (stdout, SKTpath);
    WriteOut (stdout, ").\n");
    return FALSE;
  }
}

WriteOut (SKTfp, "! Skeleton table for the \"");
WriteOut (SKTfp, CDFname);
WriteOut (SKTfp, "\" CDF.");

WriteOut (SKTfp, "\n! Generated: ");
WriteOut (SKTfp, creationStamp);

/******************************************************************************
* Open CDF.
******************************************************************************/

ExpandPath (CDFpath, CDFpathX);
status = CDFlib (OPEN_, CDF_, CDFpathX, &id,
		 SELECT_, CDF_READONLY_MODE_, READONLYon,
			  CDF_zMODE_, zMode,
			  CDF_NEGtoPOSfp0_MODE_, BOO(negToPosFp0,
			  			     NEGtoPOSfp0on,
			  			     NEGtoPOSfp0off),
			  CDF_CACHESIZE_, cacheSize,
		 NULL_);
if (!StatusHandler(status)) return FALSE;

/******************************************************************************
* Write header section.
******************************************************************************/

CHECKforABORTso
if (mLog) WriteOut (stdout, "Printing Header Information...\n");
if (!WriteHeader(CDFname)) return FALSE;

/******************************************************************************
* Write global scope attributes section.
******************************************************************************/

if (mLog) WriteOut (stdout, "Printing Attribute Information...\n");
if (!WriteGlobalAttr()) return FALSE;

/******************************************************************************
* Write variable scope attributes section.
******************************************************************************/

if (!WriteVarAttr()) return FALSE;

/******************************************************************************
* Write variables section.
******************************************************************************/

if (mLog) WriteOut (stdout, "Printing Variable Information...\n");
if (!WriteVars(varValues,variables)) return FALSE;

/******************************************************************************
* End section.
******************************************************************************/

if (!WriteEnd()) return FALSE;

/******************************************************************************
* Clean up.
******************************************************************************/

status = CDFlib (CLOSE_, CDF_,
		 NULL_);
if (!StatusHandler(status)) return FALSE;

WriteOut (SKTfp, "\n");
if (SKTfp != stdout) fclose (SKTfp);

if (variables != NULL) FreeMemory (variables, FatalError);

return TRUE;
}


/******************************************************************************
* WriteHeader.
******************************************************************************/

Logical WriteHeader (CDFname)
char *CDFname;
{
CDFstatus status;
long encoding, majority, format;
long numDims;
long dimSizes[CDF_MAX_DIMS];
long numVars, numZvars, maxRec;
long numVattrs, numGattrs;
int dimN;
long version, release, increment;
char sizes[MAX_SIZES_LEN+1], subIncrement;
char text[MAX_TEXT_LEN+1], tempS[MAX_LINE_LEN+1];

status = CDFlib (GET_, CDF_VERSION_, &version,
		       CDF_RELEASE_, &release,
		       CDF_INCREMENT_, &increment,
		 NULL_);
if (!StatusHandler(status)) return FALSE;

WriteOutFP (SKTfp, "\n! CDF created/modified by CDF V%ld.%ld.%ld",
	    version, release, increment);

status = CDFlib (GET_, LIB_VERSION_, &version,
		       LIB_RELEASE_, &release,
		       LIB_INCREMENT_, &increment,
		       LIB_subINCREMENT_, &subIncrement,
		 NULL_);
if (!StatusHandler(status)) return FALSE;

WriteOutFP (SKTfp, "\n! Skeleton table created by CDF V%ld.%ld.%ld%c",
	    version, release, increment, subIncrement);

WriteOut (SKTfp, "\n");
WriteOut (SKTfp, "\n#header");

status = CDFlib (GET_, CDF_ENCODING_, &encoding,
		       CDF_MAJORITY_, &majority,
		       CDF_FORMAT_, &format,
		       rVARs_NUMDIMS_, &numDims,
		       rVARs_DIMSIZES_, dimSizes,
		       CDF_NUMrVARS_, &numVars,
		       CDF_NUMzVARS_, &numZvars,
		       CDF_NUMgATTRS_, &numGattrs,
		       CDF_NUMvATTRS_, &numVattrs,
		       rVARs_MAXREC_, &maxRec,
		 NULL_);
if (!StatusHandler(status)) return FALSE;

WriteOut (SKTfp, "\n");
WriteOut (SKTfp, "\n                       CDF NAME: ");
WriteOut (SKTfp, CDFname);

WriteOut (SKTfp, "\n                  DATA ENCODING: ");
WriteOut (SKTfp, EncodingToken(encoding));

WriteOut (SKTfp, "\n                       MAJORITY: ");
WriteOut (SKTfp, MajorityToken(majority));

WriteOut (SKTfp, "\n                         FORMAT: ");
WriteOut (SKTfp, FormatToken(format));

if (numDims > 0) {
  sizes[0] = NUL;
  for (dimN = 0; dimN < numDims; dimN++) {
     sprintf (&sizes[strlen(sizes)], "%ld ", dimSizes[dimN]);
  }
  sizes[strlen(sizes)-1] = NUL;			/* Wipe out trailing blank. */
}
else
  strcpyX (sizes, "", MAX_SIZES_LEN);

WriteOut (SKTfp, "\n");
WriteOut (SKTfp,
	  "\n! Variables  G.Attributes  V.Attributes  Records  Dims  ");

Ncharacters (SKTfp, FRONTpadLABEL("Sizes",sizes), (int) ' ');
WriteOut (SKTfp, "Sizes");

WriteOut (SKTfp,
	  "\n! ---------  ------------  ------------  -------  ----  ");

Ncharacters (SKTfp, MAXIMUM((size_t)strlen("Sizes"),
			    (size_t)strlen(sizes)), (int) '-');

WriteOut (SKTfp, "\n");
Ncharacters (SKTfp, 2, (int) ' ');
sprintf (text, "%ld/%ld", numVars, numZvars);
Ncharacters (SKTfp, MAXIMUM((size_t)(6-strlen(text)),(size_t)0), (int) ' ');
sprintf (tempS, "%s     %7ld       %7ld     %5ld/z    %3ld",
	 text, numGattrs, numVattrs, maxRec + 1, numDims);
WriteOut (SKTfp, tempS);

if (numDims > 0) {
  WriteOut (SKTfp, "   ");
  Ncharacters (SKTfp, FRONTpadVALUE("Sizes",sizes), (int) ' ');
  WriteOut (SKTfp, sizes);
}

return TRUE;
}


/******************************************************************************
* WriteGlobalAttr.
******************************************************************************/

Logical WriteGlobalAttr ()
{
CDFstatus status;
char delim;			     /* Delimeter for attribute name. */
long attrN, numAttrs, scope, maxEntry;
long dataType, numElements, entryN;
int ccc;			     /* Current Cursor Column (base is 0). */
void *value;
char attrName[CDF_ATTR_NAME_LEN+1],
     tempS[MAX_LINE_LEN+1];
int GattrCount = 0;		     /* Number of global scope attributes. */
int entryCount;

WriteOut (SKTfp, "\n\n");
WriteOut (SKTfp, "\n#GLOBALattributes");

status = CDFlib (GET_, CDF_NUMATTRS_, &numAttrs,
		 NULL_);
if (!StatusHandler(status)) return FALSE;

if (numAttrs > 0) {
  for (attrN = 0; attrN < numAttrs; attrN++) {
     status = CDFlib (SELECT_, ATTR_, attrN,
		      GET_, ATTR_NAME_, attrName,
			    ATTR_SCOPE_, &scope,
		      NULL_);
     if (!StatusHandler(status)) return FALSE;
     if (scope == GLOBAL_SCOPE) {
       /***********************************************************************
       * Global scope attribute...
       ***********************************************************************/
       GattrCount++;

       status = CDFlib (GET_, ATTR_MAXgENTRY_, &maxEntry,
		        NULL_);
       if (!StatusHandler(status)) return FALSE;

       /***********************************************************************
       * If first global scope attribute found, print field headings.
       ***********************************************************************/

       if (GattrCount == 1) {
	 WriteOut (SKTfp, "\n\n");
	 ccc = WriteOut (SKTfp, "! Attribute");
	 Ncharacters (SKTfp, ENTRY_NUM_COL - ccc, (int) ' ');
	 ccc += ENTRY_NUM_COL - ccc;
	 ccc += WriteOut (SKTfp, "Entry       Data");

	 WriteOut (SKTfp, "\n");
	 ccc = WriteOut (SKTfp, "! Name     ");
	 Ncharacters (SKTfp, ENTRY_NUM_COL - ccc, (int) ' ');
	 ccc += ENTRY_NUM_COL - ccc;
	 ccc += WriteOut (SKTfp, "Number      Type       Value");

	 WriteOut (SKTfp, "\n");
	 ccc = WriteOut (SKTfp, "! ---------");
	 Ncharacters (SKTfp, ENTRY_NUM_COL - ccc, (int) ' ');
	 ccc += ENTRY_NUM_COL - ccc;
	 ccc += WriteOut (SKTfp, "------      ----       -----");
       }

       /***********************************************************************
       * Write name.
       ***********************************************************************/

       delim = PickDelimiter (attrName, strlen(attrName));
       WriteOut (SKTfp, "\n\n");
       sprintf (tempS, "  %c%s%c", delim, attrName, delim);
       ccc = WriteOut (SKTfp, tempS);

       /***********************************************************************
       * Write each entry.
       ***********************************************************************/

       entryCount = 0;

       for (entryN = 0; entryN <= maxEntry; entryN++) {
	  status = CDFlib (SELECT_, gENTRY_, entryN,
			   GET_, gENTRY_DATATYPE_, &dataType,
				 gENTRY_NUMELEMS_, &numElements,
			   NULL_);
	  if (status != NO_SUCH_ENTRY) {
	    if (!StatusHandler(status)) return FALSE;
	    entryCount++;

	    value = AllocateMemory ((size_t) (CDFelemSize(dataType) *
					      numElements), FatalError);

	    status = CDFlib (GET_, gENTRY_DATA_, value,
			     NULL_);
	    if (!StatusHandler(status)) return FALSE;

	    if (entryCount == 1) {
	      if (ccc > ENTRY_NUM_COL - 1) {
		WriteOut (SKTfp, "\n");
		ccc = 0;
	      }
	    }
	    else {
	      WriteOut (SKTfp, "\n");
	      ccc = 0;
	    }

	    Ncharacters (SKTfp, ENTRY_NUM_COL - ccc, (int) ' ');
	    ccc += ENTRY_NUM_COL - ccc;

	    sprintf (tempS, "%*ld:    %s   ", ENTRY_NUM_WIDTH, entryN + 1,
		     DataTypePaddedString(dataType));
	    ccc += WriteOut (SKTfp, tempS);

	    ccc += WriteOut (SKTfp, "{ ");
	    WriteEntryValue (SKTfp, dataType, numElements, value, ccc,
			     MAX_COL_TO_USE - 4);
						/* -4 for possible " } ." */
	    ccc += WriteOut (SKTfp, " }");

	    FreeMemory (value, FatalError);	    
	  }
	  CHECKforABORTso
       }
       /***********************************************************************
       * Write '.' after last entry.
       ***********************************************************************/
       WriteOut (SKTfp, " .");
     }
     CHECKforABORTso
  }
  if (GattrCount == 0) WriteOut (SKTfp, "\n\n! No global scope attributes.");
}
else
  WriteOut (SKTfp, "\n\n! No global scope attributes.");

return TRUE;
}


/******************************************************************************
* WriteVarAttr.
******************************************************************************/

Logical WriteVarAttr ()
{
CDFstatus status;
char delim,			     /* Delimeter for attribute name. */
     tempS[MAX_LINE_LEN+1];
long attrN, numAttrs, scope;
char attrName[CDF_ATTR_NAME_LEN+1];
int VattrCount = 0;		     /* Number of variable scope attributes. */

WriteOut (SKTfp, "\n\n");
WriteOut (SKTfp, "\n#VARIABLEattributes");
WriteOut (SKTfp, "\n");

status = CDFlib (GET_, CDF_NUMATTRS_, &numAttrs,
		 NULL_);
if (!StatusHandler(status)) return FALSE;

if (numAttrs > 0) {
  for (attrN = 0; attrN < numAttrs; attrN++) {
     status = CDFlib (SELECT_, ATTR_, attrN,
		      GET_, ATTR_NAME_, attrName,
			    ATTR_SCOPE_, &scope,
		      NULL_);
     if (!StatusHandler(status)) return FALSE;
     if (scope == VARIABLE_SCOPE) {
       /***********************************************************************
       * Variable scope attribute...
       ***********************************************************************/
       VattrCount++;
       delim = PickDelimiter (attrName, strlen(attrName));
       sprintf (tempS, "\n  %c%s%c", delim, attrName, delim);
       WriteOut (SKTfp, tempS);
     }
     CHECKforABORTso
  }
  if (VattrCount == 0) WriteOut (SKTfp, "\n! No variable scope attributes.");
}
else
  WriteOut (SKTfp, "\n! No variable scope attributes.");

return TRUE;
}


/******************************************************************************
* WriteVars.
******************************************************************************/

Logical WriteVars (varValues, variables)
int varValues;
char *variables;
{
CDFstatus status;
long numVars;
long numZvars;
long varN;

status = CDFlib (GET_, CDF_NUMrVARS_, &numVars,
		       CDF_NUMzVARS_, &numZvars,
		 NULL_);
if (!StatusHandler(status)) return FALSE;

WriteOut (SKTfp, "\n\n");
WriteOut (SKTfp, "\n#variables");

if (numVars == 0)
  WriteOut (SKTfp, "\n\n! No rVariables.");
else
  for (varN = 0; varN < numVars; varN++) {
     if (!WriteVar(varN,varValues,variables,FALSE)) return FALSE;
  }

WriteOut (SKTfp, "\n\n");
WriteOut (SKTfp, "\n#zVariables");

if (numZvars == 0)
  WriteOut (SKTfp, "\n\n! No zVariables.");
else
  for (varN = 0; varN < numZvars; varN++) {
     if (!WriteVar(varN,varValues,variables,TRUE)) return FALSE;
  }

return TRUE;
}

/******************************************************************************
* WriteVar.
******************************************************************************/

Logical WriteVar (varN, varValues, variables, zVar)
long varN;
int varValues;
char *variables;
Logical zVar;
{
CDFstatus status;
long numDims, dimSizes[CDF_MAX_DIMS];
long numAttrs;
long maxRec;
long varDataType, varNumElements;
long entryDataType, entryNumElements;
long recVary, dimVarys[CDF_MAX_DIMS];
char varName[CDF_VAR_NAME_LEN+1];
char attrName[CDF_ATTR_NAME_LEN+1];
char delim;
long attrN;
long scope;
int dimN;
int ccc;			      /* Current Cursor Column (base is 0). */
void *value;
int VattrCount;
char varys[MAX_VARYS_LEN+1];
char sizes[MAX_SIZES_LEN+1];
char tempS[MAX_LINE_LEN+1];

status = CDFlib (SELECT_, Zq(zVar,zVAR_,rVAR_), varN,
		 GET_, Zq(zVar,zVAR_NAME_,rVAR_NAME_), varName,
		       Zq(zVar,zVAR_DATATYPE_,rVAR_DATATYPE_), &varDataType,
		       Zq(zVar,zVAR_NUMELEMS_,rVAR_NUMELEMS_), &varNumElements,
		       Zq(zVar,zVAR_RECVARY_,rVAR_RECVARY_), &recVary,
		       Zq(zVar,zVAR_DIMVARYS_,rVAR_DIMVARYS_), dimVarys,
		       Zq(zVar,zVAR_MAXREC_,rVAR_MAXREC_), &maxRec,
		 NULL_);
if (!StatusHandler(status)) return FALSE;

if (zVar)
  status = CDFlib (SELECT_, zVAR_, varN,
		   GET_, zVAR_NUMDIMS_, &numDims,
			 zVAR_DIMSIZES_, dimSizes,
		   NULL_);
else
  status = CDFlib (GET_, rVARs_NUMDIMS_, &numDims,
			 rVARs_DIMSIZES_, dimSizes,
		   NULL_);
if (!StatusHandler(status)) return FALSE;

/***************************************************************************
* If zVariable, build dimension sizes string.
***************************************************************************/

if (numDims > 0) {
  sizes[0] = NUL;
  for (dimN = 0; dimN < numDims; dimN++) {
     sprintf (&sizes[strlen(sizes)], "%ld ", dimSizes[dimN]);
  }
  sizes[strlen(sizes)-1] = NUL;			/* Wipe out trailing blank. */
}
else
  strcpyX (sizes, "", MAX_SIZES_LEN);

/***************************************************************************
* Build dimension variance string.
***************************************************************************/

if (numDims > 0) {
  strcpyX (varys, "", MAX_VARYS_LEN);
  for (dimN = 0; dimN < numDims; dimN++) {
     strcatX (varys, TFvarianceToken(dimVarys[dimN]), MAX_VARYS_LEN);
     strcatX (varys, " ", MAX_VARYS_LEN);
  }
  varys[strlen(varys)-1] = NUL;		/* Wipe out trailing blank. */
}
else
  strcpyX (varys, "", MAX_VARYS_LEN);

/***************************************************************************
* Write headings.
***************************************************************************/

if (varN != 0) WriteOut (SKTfp, "\n");		/* Skip 2 lines after first
						   variable. */
WriteOut (SKTfp, "\n\n");
ccc = WriteOut (SKTfp, "! Variable");
Ncharacters (SKTfp, VAR_DATATYPE_COL - ccc, (int) ' ');
WriteOut (SKTfp, "  Data      Number   ");

if (zVar) {
  Ncharacters (SKTfp, 4, (int) ' ');
  Ncharacters (SKTfp, 2, (int) ' ');
  Ncharacters (SKTfp, MAXIMUM((size_t)strlen(sizes),
  			      (size_t)strlen("Sizes")), (int) ' ');
  Ncharacters (SKTfp, 2, (int) ' ');
}

WriteOut (SKTfp, " Record   ");
Ncharacters (SKTfp, FRONTpadLABEL("Dimension",varys), (int) ' ');
WriteOut (SKTfp, "Dimension");

WriteOut (SKTfp, "\n");
ccc = WriteOut (SKTfp, "! Name     ");
Ncharacters (SKTfp, VAR_DATATYPE_COL - ccc, (int) ' ');
WriteOut (SKTfp, "  Type     Elements  ");

if (zVar) {
  WriteOut (SKTfp, "Dims");
  Ncharacters (SKTfp, 2, (int) ' ');
  Ncharacters (SKTfp, FRONTpadLABEL("Sizes",sizes), (int) ' ');
  WriteOut (SKTfp, "Sizes");
  Ncharacters (SKTfp, BACKpadLABEL("Sizes",sizes), (int) ' ');
  Ncharacters (SKTfp, 2, (int) ' ');
}

WriteOut (SKTfp, "Variance  ");

Ncharacters (SKTfp, FRONTpadLABEL("Variances",varys), (int) ' ');
WriteOut (SKTfp, "Variances");

WriteOut (SKTfp, "\n");
ccc = WriteOut (SKTfp, "! --------");
Ncharacters (SKTfp, VAR_DATATYPE_COL - ccc, (int) ' ');
WriteOut (SKTfp, "  ----     --------  ");

if (zVar) {
  Ncharacters (SKTfp, 4, (int) '-');
  Ncharacters (SKTfp, 2, (int) ' ');
  Ncharacters (SKTfp, MAXIMUM((size_t)strlen("Sizes"),
  			      (size_t)strlen(sizes)), (int) '-');
  Ncharacters (SKTfp, 2, (int) ' ');
}

WriteOut (SKTfp, "--------  ");

Ncharacters (SKTfp, MAXIMUM((size_t)strlen("Variances"),
			    (size_t)strlen(varys)), (int) '-');

/***************************************************************************
* Write variable definition line.
***************************************************************************/

WriteOut (SKTfp, "\n");

delim = PickDelimiter (varName, strlen(varName));
WriteOut (SKTfp, "\n");
sprintf (tempS, "  %c%s%c", delim, varName, delim);
ccc = WriteOut (SKTfp, tempS);

if (ccc > VAR_DATATYPE_COL - 3) {
  WriteOut (SKTfp, "\n");
  ccc = 0;
}

Ncharacters (SKTfp, VAR_DATATYPE_COL - ccc, (int) ' ');

sprintf (tempS, "%s %*ld   ", DataTypePaddedString(varDataType),
	 VAR_NUMELEMS_WIDTH, varNumElements);
WriteOut (SKTfp, tempS);

Ncharacters (SKTfp, 2, (int) ' ');

if (zVar) {
  sprintf (tempS, " %*ld ", zVAR_NUMDIMS_WIDTH, numDims);
  WriteOut (SKTfp, tempS);
  Ncharacters (SKTfp, 2, (int) ' ');
  Ncharacters (SKTfp, FRONTpadVALUE("Sizes",sizes), (int) ' ');
  WriteOut (SKTfp, sizes);
  Ncharacters (SKTfp, BACKpadVALUE("Sizes",sizes), (int) ' ');
  Ncharacters (SKTfp, 2, (int) ' ');
}

WriteOut (SKTfp, "    ");
WriteOut (SKTfp, TFvarianceToken(recVary));

if (numDims > 0) {
  Ncharacters (SKTfp, 3, (int) ' ');
  Ncharacters (SKTfp, 2, (int) ' ');
  Ncharacters (SKTfp, FRONTpadVALUE("Variances",varys), (int) ' ');
  WriteOut (SKTfp, varys);
}

CHECKforABORTso

/***************************************************************************
* Write corresponding attribute entries.
***************************************************************************/

status = CDFlib (GET_, CDF_NUMATTRS_, &numAttrs,
		 NULL_);
if (!StatusHandler(status)) return FALSE;

VattrCount = 0;

WriteOut (SKTfp, "\n");

for (attrN = 0; attrN < numAttrs; attrN++) {
   status = CDFlib (SELECT_, ATTR_, attrN,
		    GET_, ATTR_SCOPE_, &scope,
			  ATTR_NAME_, attrName,
		    NULL_);
   if (!StatusHandler(status)) return FALSE;

   if (scope == VARIABLE_SCOPE) {
     status = CDFlib (SELECT_, Zq(zVar,zENTRY_,rENTRY_), varN,
		      GET_, Zq(zVar,zENTRY_DATATYPE_,
				 rENTRY_DATATYPE_), &entryDataType,
			    Zq(zVar,zENTRY_NUMELEMS_,
				 rENTRY_NUMELEMS_), &entryNumElements,
		      NULL_);
     if (status != NO_SUCH_ENTRY) {
       if (!StatusHandler(status)) return FALSE;
       VattrCount++;

       if (VattrCount == 1) {
	 WriteOut (SKTfp, "\n");
	 ccc = WriteOut (SKTfp, "  ! Attribute");
	 Ncharacters (SKTfp, ENTRY_DATATYPE_COL - ccc, (int) ' ');
	 ccc += ENTRY_DATATYPE_COL - ccc;
	 ccc += WriteOut (SKTfp, "  Data");

	 WriteOut (SKTfp, "\n");
	 ccc = WriteOut (SKTfp, "  ! Name     ");
	 Ncharacters (SKTfp, ENTRY_DATATYPE_COL - ccc, (int) ' ');
	 ccc += ENTRY_DATATYPE_COL - ccc;
	 ccc += WriteOut (SKTfp, "  Type       Value");

	 WriteOut (SKTfp, "\n");
	 ccc = WriteOut (SKTfp, "  ! --------");
	 Ncharacters (SKTfp, ENTRY_DATATYPE_COL - ccc, (int) ' ');
	 ccc += ENTRY_DATATYPE_COL - ccc;
	 ccc += WriteOut (SKTfp, "  ----       -----");

	 WriteOut (SKTfp, "\n");
       }

       value = AllocateMemory ((size_t) (entryNumElements *
				         CDFelemSize(entryDataType)),
			       FatalError);

       status = CDFlib (GET_, Zq(zVar,zENTRY_DATA_,rENTRY_DATA_), value,
		        NULL_);
       if (!StatusHandler(status)) return FALSE;

       delim = PickDelimiter (attrName, strlen(attrName));
       WriteOut (SKTfp, "\n");
       sprintf (tempS, "    %c%s%c", delim, attrName, delim);
       ccc = WriteOut (SKTfp, tempS);

       if (ccc > ENTRY_DATATYPE_COL - 3) {
	 WriteOut (SKTfp, "\n");
	 ccc = 0;
       }

       Ncharacters (SKTfp, ENTRY_DATATYPE_COL - ccc, (int) ' ');
       ccc += ENTRY_DATATYPE_COL - ccc;

       ccc += WriteOut (SKTfp, DataTypePaddedString(entryDataType));
       ccc += WriteOut (SKTfp, "   ");

       ccc += WriteOut (SKTfp, "{ ");
       WriteEntryValue (SKTfp, entryDataType, entryNumElements,
			value, ccc, MAX_COL_TO_USE - 4);
						/* -4 for possible " } ." */
       ccc += WriteOut (SKTfp, " }");

       FreeMemory (value, FatalError);
     }
   }
   CHECKforABORTso
}

if (VattrCount == 0) {
  WriteOut (SKTfp,
	   "\n  ! No variable scope attribute entries for this variable.");
}

/***************************************************************************
* Write terminating period.
***************************************************************************/

if (VattrCount == 0) {
  WriteOut (SKTfp, "\n\n  .");
  WriteOut (SKTfp,
	    "                         ! Terminating period required.");
}
else
  WriteOut (SKTfp, " .");

/***************************************************************************
* Write data values (if requested).
***************************************************************************/

switch (varValues) {
  case NOvalues:
    WriteOut (SKTfp, "\n\n  ! Values were not requested.");
    break;
  case NRVvalues:
    if (recVary)
      WriteOut (SKTfp, "\n\n  ! RV values were not requested.");
    else
      if (maxRec == 0) {
	WriteOut (SKTfp, "\n\n  ! NRV values follow...\n");
	if (!WriteVariableData(SKTfp,zVar,varN,varDataType,
			       varNumElements,numDims,dimSizes,
			       recVary,dimVarys,maxRec)) return FALSE;
      }
      else
        WriteOut (SKTfp, "\n\n  ! No values (no records for this variable).");
    break;
  case RVvalues:
    if (!recVary)
      WriteOut (SKTfp, "\n\n  ! NRV values were not requested.");
    else
      if (maxRec > -1) {
	WriteOut (SKTfp, "\n\n  ! RV values follow...\n");
	if (!WriteVariableData(SKTfp,zVar,varN,varDataType,
			       varNumElements,numDims,dimSizes,
			       recVary,dimVarys,maxRec)) return FALSE;
      }
      else
        WriteOut (SKTfp, "\n\n  ! No values (no records for this variable).");
    break;
  case ALLvalues:
    if (maxRec > -1) {
      WriteOut (SKTfp, "\n\n  ! Values follow...\n");
      if (!WriteVariableData(SKTfp,zVar,varN,varDataType,
			     varNumElements,numDims,dimSizes,
			     recVary,dimVarys,maxRec)) return FALSE;
    }
    else
      WriteOut (SKTfp, "\n\n  ! No values (no records for this variable).");
    break;
  case NAMEDvalues:
    if (VariableSelected(varName,variables))
      if (maxRec > -1) {
        WriteOut (SKTfp, "\n\n  ! Values follow...\n");
	if (!WriteVariableData(SKTfp,zVar,varN,varDataType,
			       varNumElements,numDims,dimSizes,
			       recVary,dimVarys,maxRec)) return FALSE;
      }
      else
        WriteOut (SKTfp, "\n\n  ! No values (no records for this variable).");
    else
      WriteOut (SKTfp, "\n\n  ! Values were not requested.");
    break;
}

return TRUE;
}

/******************************************************************************
* WriteEnd.
******************************************************************************/

Logical WriteEnd ()
{
  WriteOut (SKTfp, "\n\n");
  WriteOut (SKTfp, "\n#end");
  return TRUE;
}

/******************************************************************************
* WriteVariableData.
*     It is assumed that there is at least one record in the CDF.
******************************************************************************/

Logical WriteVariableData (fp, zVar, varN, dataType, numElements, numDims,
			   dimSizes, recVary, dimVarys, maxRec)
FILE *fp;
Logical zVar;
long varN;
long dataType;
long numElements;
long numDims;
long dimSizes[];
long recVary;
long dimVarys[];
long maxRec;
{
  CDFstatus status;
  long indices[CDF_MAX_DIMS];
  long counts[CDF_MAX_DIMS];
  void *value;
  long majority;
  int ccc;
  long nRecValues, i, recN;
  int dimN;
  char Evalue[80+1], *format, tempS[MAX_LINE_LEN+1];

  status = CDFlib (SELECT_, Zq(zVar,zVAR_,rVAR_), varN,
		   GET_, CDF_MAJORITY_, &majority,
		   NULL_);
  if (!StatusHandler(status)) return FALSE;

  nRecValues = 1;
  if (numDims > 0)
    for (dimN = 0; dimN < numDims; dimN++) {
       indices[dimN] = 0;
       if (dimVarys[dimN]) {
         nRecValues *= dimSizes[dimN];
         counts[dimN] = dimSizes[dimN];
       }
       else
         counts[dimN] = 1;
    }

  value = AllocateMemory ((size_t) (numElements * CDFelemSize(dataType)),
			  FatalError);
  format = (useFormat ? GetFormatEntry(zVar,varN) : NULL);

  for (recN = 0; recN <= maxRec; recN++) {
     status = CDFlib (SELECT_, Zq(zVar,zVAR_RECNUMBER_,rVARs_RECNUMBER_), recN,
		      NULL_);
     if (!StatusHandler(status)) return FALSE;

     for (i = 0; i < nRecValues; i++) {
        status = CDFlib (SELECT_, Zq(zVar,zVAR_DIMINDICES_,
				          rVARs_DIMINDICES_), indices,
		         GET_, Zq(zVar,zVAR_DATA_,rVAR_DATA_), value,
		         NULL_);
        if (!StatusHandler(status)) return FALSE;

        ccc = WriteOut (fp, "\n    ");

	if (recVary) {
	  sprintf (tempS, "%ld:[", recN + 1);	  
	}
	else
	  strcpyX (tempS, "[", MAX_LINE_LEN);
        if (numDims > 0)
           for (dimN = 0; dimN < numDims; dimN++) {
              sprintf (EofS(tempS), "%ld", indices[dimN] + 1);
	      if (dimN != numDims-1) strcatX (tempS, ",", MAX_LINE_LEN);
           }
        strcatX (tempS, "] = ",MAX_LINE_LEN);

	ccc += WriteOut (SKTfp, tempS);

        if (STRINGdataType(dataType)) {
          ccc += WriteOut (fp, "{ ");
          WriteStringValue (fp, numElements, value, ccc,
		            MAX_COL_TO_USE - 2);    /* -2 for " }" */
          WriteOut (fp, " }");
        }
        else {
          EncodeValuesFormat (dataType, 1L, value, Evalue,
			      format, 0, 0, EPOCH0_STYLE);
						/* Don't care about width. */
          WriteOut (fp, Evalue);
        }

        if (ROWmajor(majority))
          INCRindicesROW (numDims, counts, indices);
        else
          INCRindicesCOL (numDims, counts, indices);

	CHECKforABORTso
     }
  }

  FreeMemory (value, FatalError);
  if (format != NULL) FreeMemory (format, FatalError);

  return TRUE;
}

/******************************************************************************
* VariableSelected.
*      The assumed format of the list of delimited variable names is...
* <delim><chars><delim>,<delim><chars><delim>,...,<delim><chars><delim>
******************************************************************************/

Logical VariableSelected (varName, variables)
char *varName;
char *variables;
{
  char *d1, *d2, varNameT[CDF_VAR_NAME_LEN+1];
  size_t len;
  d1 = variables;
  for (;;) {
    while (*d1 != NUL && IsSpaceChr(*d1)) d1++;
    if (*d1 == NUL) return FALSE;
    d2 = d1 + 1;
    while (*d2 != NUL && *d2 != *d1) d2++;
    if (*d2 == NUL) return FALSE;
    len = (size_t) (d2 - d1 - 1);
    strcpyX (varNameT, d1 + 1, MINIMUM(len,CDF_VAR_NAME_LEN));
    if (!strcmpITB(varName,varNameT)) return TRUE;
    d1 = d2 + 1;
    while (*d1 != NUL && *d1 != ',') d1++;
    if (*d1 == NUL) return FALSE;
    d1++;
  }
}

/******************************************************************************
* DataTypePaddedString.
*    Strings are blank-padded on the end to all be the same length.
******************************************************************************/

char *DataTypePaddedString (dataType)
long dataType;
{
switch (dataType) {
  case CDF_BYTE:   return "CDF_BYTE  ";
  case CDF_INT1:   return "CDF_INT1  ";
  case CDF_INT2:   return "CDF_INT2  ";
  case CDF_INT4:   return "CDF_INT4  ";
  case CDF_UINT1:  return "CDF_UINT1 ";
  case CDF_UINT2:  return "CDF_UINT2 ";
  case CDF_UINT4:  return "CDF_UINT4 ";
  case CDF_REAL4:  return "CDF_REAL4 ";
  case CDF_REAL8:  return "CDF_REAL8 ";
  case CDF_FLOAT:  return "CDF_FLOAT ";
  case CDF_DOUBLE: return "CDF_DOUBLE";
  case CDF_EPOCH:  return "CDF_EPOCH ";
  case CDF_CHAR:   return "CDF_CHAR  ";
  case CDF_UCHAR:  return "CDF_UCHAR ";
}
return "??????????";
}

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

Logical StatusHandler (status)
CDFstatus status;
{
  char text[CDF_STATUSTEXT_LEN + 1];

  if (StatusERROR(status)) {
    if (report[ERRORs]) {
      CDFlib (SELECT_, CDF_STATUS_, status,
	      GET_, STATUS_TEXT_, text,
	      NULL_);
      WriteOut (stdout, "\nERROR> ");
      WriteOut (stdout, text);
      WriteOut (stdout, "\n");
    }
    CDFlib (CLOSE_, CDF_,
	    NULL_);
    WriteOut (stdout, "**** THE SKELETON TABLE IS INCOMPLETE ****\n");
    if (SKTfp != stdout) {
      WriteOut (SKTfp, "\n");
      WriteOut (SKTfp, "\n**** THIS SKELETON TABLE IS NOT COMPLETE ****");
      WriteOut (SKTfp, "\n");
      fclose (SKTfp);
    }
    return FALSE;
  }

  if (StatusWARN(status) && report[WARNs]) {
    CDFlib (SELECT_, CDF_STATUS_, status,
	    GET_, STATUS_TEXT_, text,
	    NULL_);
    WriteOut (stdout, "\nWARNING> ");
    WriteOut (stdout, text);
    WriteOut (stdout, "\n");
    return TRUE;
  }

  if (StatusINFO(status) && report[INFOs]) {
    CDFlib (SELECT_, CDF_STATUS_, status,
	    GET_, STATUS_TEXT_, text,
	    NULL_);
    WriteOut (stdout, "\nINFO> ");
    WriteOut (stdout, text);
    WriteOut (stdout, "\n");
    return TRUE;
  }

  return TRUE;		/* CDF_OK */
}

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

#if defined(mac)
Logical SkeletonTableQOPs (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 outToScreen = DEFAULTscreenCDF2SKT;
  static Logical useFormat = DEFAULTformatCDF2SKT;
  static Logical negToPos = DEFAULT_NEGtoPOSfp0;
  static Logical pageOutput = DEFAULTpageCDF2SKT;
  static Logical reportInfos = REPORTinfosDEFAULT;
  static Logical reportWarns = REPORTwarningsDEFAULT;
  static Logical reportErrors = REPORTerrorsDEFAULT;
  static Logical logMsg = DEFAULTlogCDF2SKT;
  static int zModeSrc = DEFAULTzModeCDF2SKT;
  static int varValues = DEFAULTvaluesCDF2SKT;
  static Str255 CDFtext = "\p";
  static Str255 sktText = "\p";
  static Str255 cacheText = "\p";
  static Str255 varsText = "\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[CDFTEXTin], CDFtext);
  SetIText ((Handle) controlHs[SKTTEXTin], sktText);
  SetIText ((Handle) controlHs[CACHEin], cacheText);
  SetIText ((Handle) controlHs[VARSin], varsText);

  if (outToScreen) SetCtlValue (controlHs[SCREENin], 1);
  if (useFormat) SetCtlValue (controlHs[FORMATin], 1);
  if (negToPos) SetCtlValue (controlHs[NEGZin], 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 (logMsg) SetCtlValue (controlHs[LOGin], 1);

  SetCtlValue (controlHs[ZMODEinBASE+zModeSrc], 1);
  SetCtlValue (controlHs[VALUESinBASE+varValues], 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 *valuesOptions[5] = { "off", "nrv", "rv", "all", NULL };
	int n;
	char tempS1[1+1];

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

	GetIText ((Handle) controlHs[CDFTEXTin], CDFtext);
	GetIText ((Handle) controlHs[SKTTEXTin], sktText);
	GetIText ((Handle) controlHs[CACHEin], cacheText);
	GetIText ((Handle) controlHs[VARSin], varsText);

	outToScreen = GetCtlValue (controlHs[SCREENin]);
	useFormat = GetCtlValue (controlHs[FORMATin]);
	negToPos = GetCtlValue (controlHs[NEGZin]);
	pageOutput = GetCtlValue (controlHs[PAGEin]);
	reportInfos = GetCtlValue (controlHs[INFOin]);
	reportWarns = GetCtlValue (controlHs[WARNin]);
	reportErrors = GetCtlValue (controlHs[ERRORin]);
	logMsg = GetCtlValue (controlHs[LOGin]);
	
	for (varValues = 0; varValues < 5; varValues++) {
	   if (GetCtlValue(controlHs[VALUESinBASE+varValues])) break;
	}
	for (zModeSrc = 0; zModeSrc < 3; zModeSrc++) {
	   if (GetCtlValue(controlHs[ZMODEinBASE+zModeSrc])) break;
	}
	
	/**********************************************************************
	* Build argc/argv.
	**********************************************************************/

        *argC = 12 + BOO(NULpString(CDFtext),0,1) +
		     BOO(NULpString(sktText),0,2) +
		     BOO(NULpString(cacheText),0,2);
        *argV = (char **) AllocateMemory (*argC * sizeof(char *), FatalError);
	
	n = 0;
	MAKEstrARGv (argV, n, pgmName)

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

	MAKEbooARGv (argV, n, outToScreen, "-screen", "-noscreen")
	MAKEbooARGv (argV, n, useFormat, "-format", "-noformat")
	MAKEbooARGv (argV, n, negToPos, "-neg2posfp0", "-noneg2posfp0")
	MAKEbooARGv (argV, n, pageOutput, "-page", "-nopage")
	MAKEbooARGv (argV, n, logMsg, "-log", "-nolog")
	
	MAKEstrARGv (argV, n, "-zmode")
	sprintf (tempS1, "%d", zModeSrc);
	MAKEstrARGv (argV, n, tempS1)

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

	MAKEstrARGv (argV, n, "-values")
	switch (varValues) {
	  case NAMEDvalues:
	    PtoCstr (varsText);
	    MAKEstrARGv (argV, n, (char *) varsText)
	    CtoPstr ((char *) varsText);
	    break;
	  default:
	    MAKEstrARGv (argV, n, valuesOptions[varValues])
	    break;
	}

	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 CDF specification.
      ************************************************************************/
      case CDFSELECTin: {
	StandardFileReply CDFreply;
	char CDFpath[DU_MAX_PATH_LEN+1];
	StandardGetFile (FilterForCDFs, -1, NULL, &CDFreply);
	if (CDFreply.sfGood && !CDFreply.sfIsFolder && !CDFreply.sfIsVolume) {
	  BuildMacPath (&CDFreply.sfFile, CDFpath, TRUE);
	  CDFtext[0] = strlen (CDFpath);
	  strcpyX ((char *) &CDFtext[1], CDFpath, 255);
	  SetIText ((Handle) controlHs[CDFTEXTin], CDFtext);
	}
	break;
      }
      /************************************************************************
      * Select skeleton CDF.
      *     The cursor is set because `StandardPutFile' leaves the cursor as
      * an iBeam (instead of returning it to what it was).
      ************************************************************************/
      case SKTSELECTin: {
	StandardFileReply sktReply;
	char sktPath[DU_MAX_PATH_LEN+1], prompt[] = "Enter skeleton table:";
	StandardPutFile (CtoPstr(prompt), CtoPstr(""), &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);
	}
	SetCursor (&(qd.arrow));
	break;
      }
      /************************************************************************
      * Check boxes.
      ************************************************************************/
      case SCREENin:
      case FORMATin:
      case NEGZin:
      case PAGEin:
      case INFOin:
      case WARNin:
      case ERRORin:
      case LOGin:
        SetCtlValue (controlHs[itemN], BOO(GetCtlValue(controlHs[itemN]),0,1));
        break;
      /************************************************************************
      * Radio buttons.
      ************************************************************************/
      case VALUESinBASE+0:
      case VALUESinBASE+1:
      case VALUESinBASE+2:
      case VALUESinBASE+3:
      case VALUESinBASE+4:
        for (i = 0; i < 5; i++) SetCtlValue (controlHs[VALUESinBASE+i], 0);
        SetCtlValue (controlHs[itemN], 1);
        break;
      case ZMODEinBASE+0:
      case ZMODEinBASE+1:
      case ZMODEinBASE+2:
        for (i = 0; i < 3; i++) SetCtlValue (controlHs[ZMODEinBASE+i], 0);
        SetCtlValue (controlHs[itemN], 1);
        break;
    }
  }
}
#endif
