/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* This file is distributed subject to a Software License Agreement found
* in the file LICENSE that is included with this distribution. 
\*************************************************************************/

/*
 * $Log: not supported by cvs2svn $
 * Revision 1.12  2006/10/24 17:34:49  soliday
 * Added SDDS_USHORT and SDDS_ULONG support.
 *
 * Revision 1.11  2005/11/10 21:55:07  soliday
 * Removed some Linux compiler warnings.
 *
 * Revision 1.10  2005/11/10 21:48:15  soliday
 * Updated to compile with a 64bit compiler.
 *
 * Revision 1.9  2004/07/30 15:39:42  borland
 * Added getUnits command.
 *
 * Revision 1.8  2004/01/12 22:39:06  soliday
 * Added the ability to turn off the row count.
 *
 * Revision 1.7  2003/08/08 20:44:44  soliday
 * Updated code so that this is a dynamically loadable extension.
 *
 * Revision 1.6  2002/10/28 15:42:38  soliday
 * Fixed compiler warnings.
 *
 * Revision 1.5  2002/08/14 20:44:47  soliday
 * Added Open License
 *
 * Revision 1.4  2000/08/24 18:33:49  soliday
 * Fixed a problem with the sdds save command when long arrays are used.
 *
 * Revision 1.3  1999/09/30 17:34:56  soliday
 * Fixed bug in the sdds save command so that it can have a format_string
 *
 * Revision 1.2  1999/09/02 16:43:26  soliday
 * Fixed bug when setting long type columns with invalid data. It now sets them to
 * zero instead of crashing
 *
 * Revision 1.1  1999/06/10 19:44:51  soliday
 * Moved to oag tree.
 *
 * Revision 1.21  1999/06/08 21:18:39  soliday
 * Removed compiler warnings under Linux.
 *
 * Revision 1.20  1999/05/13 14:41:33  soliday
 * Added load and save commands
 *
 * Revision 1.19  1999/04/08 15:27:26  soliday
 * Added getDescription and setDescription
 *
 * Revision 1.18  1999/03/12 16:05:21  soliday
 * Added tclSDDSConvert
 *
 * Revision 1.17  1999/03/11 14:38:09  soliday
 * Added tclSDDSExpand
 *
 * Revision 1.16  1999/03/10 21:12:35  soliday
 * Added tclSDDSCollapse
 *
 * Revision 1.15  1999/03/10 17:06:48  soliday
 * Added tclSDDSCheck
 *
 * Revision 1.13  1999/03/09 16:42:26  soliday
 * Added getRowCount
 *
 * Revision 1.12  1997/05/19 16:07:16  borland
 * Increased size of string items to 8192 characters.
 *
 * Revision 1.11  1997/02/18 16:58:58  saunders
 * Fixed bug in handling of precision.
 *
 * Revision 1.10  1997/02/16 19:38:25  saunders
 * Added getColumnInformation, getParameterInformation, getArrayInformation
 * commands.
 *
 * Revision 1.9  1996/12/10 16:40:36  saunders
 * Added getArray command.
 *
 * Revision 1.8  1996/12/09 22:23:52  saunders
 * Complete set of SDDS write commands added.
 *
 * Revision 1.7  1996/09/26 15:35:58  saunders
 * Changed so that when all pages are desired, file is reopened for
 * every getColumn or getParameter. Waiting on mods to SDDSlib.
 *
 * Revision 1.6  1996/09/19 15:22:36  saunders
 * Initial tested release of tclSDDS extension.
 *
 * Revision 1.5  1996/09/16 19:47:08  saunders
 * Freeing up some error message memory from SDDS1 lib.
 *
 * Revision 1.4  1996/09/05 21:06:33  saunders
 * Forgot argument count checking in open and close functions.
 *
 * Revision 1.3  1996/08/29 19:43:01  saunders
 * Error message behavior fixed by using SDDS_ClearErrors() after every
 * use of SDDS_GetErrorMessages().
 *
 * Revision 1.2  1996/08/29 15:25:46  saunders
 * Initial release with open/close/getColumn/getParameter/getNames.
 *
 * Revision 1.1  1996/08/28 21:27:00  saunders
 * Initial prototype sdds extension for tcl.
 * */

#include "mdb.h"
#include <stdlib.h>
#include <time.h>
#include <ellLib.h>
#include "scan.h"

#include <tclSDDS.h>

#if ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 4)) || (TCL_MAJOR_VERSION > 8)
#define SDDSCONST const
#define SDDSCONST2 const char * const *
#else
#define SDDSCONST
#define SDDSCONST2 char**
#endif

typedef struct {
  SDDS_TABLE table;
  char fileName[255]; /* path of opened file */
  char mode;          /* r or w */
  int pageStarted;    /* has user done a startPage */
  int free;           /* this sdds fd is free */
  int currentPage;
} SDDS_FD;
typedef char *STRING_PAIR[2];
typedef struct {
  char *match_string, *edit_string;
} EDIT_NAME_REQUEST;

static SDDS_FD sddsFdTable[MAX_OPEN_SDDS_FILES];

/*****************************/
/* Local Function Prototypes */
/*****************************/
static int tclSDDSReopenFd(int fd);
static int tclSDDSGetFreeFd();
static long constructIndex(int element, long dimensions, 
			   int32_t dim[], char *indexBuf);
static long convertTypeStringToNumeric(char *type);
static char *convertNumericToTypeString(long type);
char **process_name_options(char **orig_name, long **orig_flag, long orig_names, 
                            char **delete, long deletes,
                            char **retain, long retains,
                            STRING_PAIR *rename, long renames,
                            EDIT_NAME_REQUEST *edit_request, long edit_requests);
Tcl_Obj *Tcl_SDDS_HandleColumn(SDDS_TABLE *Table, COLUMN_DEFINITION *def, long len);
Tcl_Obj *Tcl_SDDS_HandleArray(SDDS_ARRAY *array);
Tcl_Obj *Tcl_SDDS_HandleParameter(SDDS_TABLE *Table, PARAMETER_DEFINITION *def);
long constructIndex2(int element, long dimensions, int32_t dim[], long count);

/******************************************
 *
 *****************************************/
static int tclSDDSReopenFd(int fd) {

  if (!SDDS_Terminate(&(sddsFdTable[fd].table))) {
    sddsFdTable[fd].free = 1;
    sddsFdTable[fd].currentPage = 0;
    return -1;
  }
  if (!SDDS_InitializeInput(&(sddsFdTable[fd].table), 
			    sddsFdTable[fd].fileName)) {
    sddsFdTable[fd].free = 1;
    sddsFdTable[fd].currentPage = 0;
    return -1;
  }
  sddsFdTable[fd].currentPage = 0;
  return 0;
}

/******************************************
 *
 *****************************************/
static int tclSDDSGetFreeFd() {
  int i = 0;

  while (i < MAX_OPEN_SDDS_FILES) {
    if (sddsFdTable[i].free == 1) 
      break;
    i++;
  }
  if (i < MAX_OPEN_SDDS_FILES) 
    return i;
  else 
    return -1;
}
 
/******************************************
 *
 *****************************************/
int tclSDDSOpen(Tcl_Interp *interp, int argc, char *argv[]) {
  char **sddsErrs;
  int32_t sddsNumErrs;
  int fd;
  char buffer[50];
  char *fileName = argv[2];
  char mode = 'r';
  long dataMode = SDDS_ASCII;
  
  if (argc != 3 && argc != 4 && argc != 5) {
    Tcl_SetResult(interp, "usage: sdds open <fileName> [<mode>] [SDDS_BINARY], returns <fd>",
		  NULL);
    return TCL_ERROR;    
  }

  if ((argc == 4 || argc == 5) && (*(argv[3]) == 'r' || *(argv[3]) == 'w')) {
    mode = *(argv[3]);
    if (argc == 5 && !strcmp(argv[4],"SDDS_BINARY")) {
      dataMode = SDDS_BINARY;
    }
  } else if (argc == 4 || argc == 5) {
    Tcl_SetResult(interp, "usage: sdds open <fileName> [<mode>] [SDDS_BINARY], <mode>='r' or 'w'",NULL);
    return TCL_ERROR;
  }

  if ((fd = tclSDDSGetFreeFd()) == -1) {
    Tcl_SetResult(interp, "sdds open: too many SDDS files open", NULL);
    return TCL_ERROR;
  }

  sddsFdTable[fd].mode = mode;
  if (mode == 'r') {
    if (!SDDS_InitializeInput(&(sddsFdTable[fd].table), fileName)) {
      sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
      Tcl_AppendResult(interp, "sdds open: ", sddsErrs[0], NULL);
      SDDS_ClearErrors();
      free(sddsErrs[0]);
      return TCL_ERROR;
    }
    strcpy(sddsFdTable[fd].fileName,fileName);
    sddsFdTable[fd].free = 0;
    
  } else {  /* mode == 'w' */
    if (!SDDS_InitializeOutput(&(sddsFdTable[fd].table), dataMode, 1, NULL, NULL, fileName)) {
      sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
      Tcl_AppendResult(interp, "sdds open: ", sddsErrs[0], NULL);
      SDDS_ClearErrors();
      free(sddsErrs[0]);
      return TCL_ERROR;
    }
    strcpy(sddsFdTable[fd].fileName,fileName);
    sddsFdTable[fd].free = 0;
  }

  sprintf(buffer,"%d",fd);
  Tcl_SetResult(interp, buffer, TCL_VOLATILE);

  return TCL_OK;
}

/*****************************************
 *
 *****************************************/
int tclSDDSClose(Tcl_Interp *interp, int argc, char *argv[]) {
  char **sddsErrs;
  int32_t sddsNumErrs;
  int fd;
  char *sddsFileId = argv[2];

  if (argc != 3) {
    Tcl_SetResult(interp, "usage: sdds close <fd>",
		  NULL);
    return TCL_ERROR;    
  }

  fd = atoi(sddsFileId);
  if ((fd > MAX_OPEN_SDDS_FILES) || (sddsFdTable[fd].free == 1)) { 
    Tcl_SetResult(interp, "sdds close: unknown file descriptor", NULL);

    return TCL_ERROR;
  }
  if (!SDDS_Terminate(&(sddsFdTable[fd].table))) {
    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
    Tcl_AppendResult(interp, "sdds close: ", sddsErrs[0], NULL);
    SDDS_ClearErrors();
    free(sddsErrs[0]);
    return TCL_ERROR;
  }
  sddsFdTable[fd].free = 1;
  sddsFdTable[fd].currentPage = 0;
  return TCL_OK;
}

int tclSDDSGetRowCount(Tcl_Interp *interp, int argc, char *argv[]) {
  char **sddsErrs;
  int32_t sddsNumErrs;
  int fd;
  char *sddsFileId;
  int moreData;
  
  long nrows, i;
  long desiredPage = 1;
  int allPages = 0;
  long pagesToGo = 0;
  long tableRead;

  char buffer[tclSDDS_BUFSIZE];     /* for converting SDDS column to tcl string */
  Tcl_DString result;

  if ((argc != 3) && (argc != 5)) {  
    Tcl_SetResult(interp, "usage: sdds getRowCount <fd> [-page n]",
		  NULL);
    return TCL_ERROR;    
  }

  sddsFileId = argv[2];
  if (argc == 5 && !strcmp(argv[3],"-page")) {
    desiredPage = atoi(argv[4]);
    if (desiredPage < 0) {
      Tcl_SetResult(interp, "sdds getRowCount: page must be >=0", NULL);
      return TCL_ERROR;
    } else if (desiredPage == 0) {
      desiredPage = 1;
      allPages = 1;
    }
  } else if (argc == 3) {
    allPages = 1;   /* indicates we want all pages */
  }

  fd = atoi(sddsFileId);
  if ((fd > MAX_OPEN_SDDS_FILES) || (sddsFdTable[fd].free == 1)) { 
    Tcl_SetResult(interp, "sdds getRowCount: unknown file descriptor",
		  (Tcl_FreeProc *) NULL);
    return TCL_ERROR;
  }
  if (sddsFdTable[fd].mode != 'r') {
    Tcl_SetResult(interp, "sdds getRowCount: <fd> must be opened for reading",
		  NULL);
    return TCL_ERROR;
  }

  /* Find our current page location with respect to desired page */
  if ((allPages == 1 && sddsFdTable[fd].currentPage > 1) ||
      (allPages == 0 && desiredPage < sddsFdTable[fd].currentPage)) {
    if (tclSDDSReopenFd(fd)) {
      Tcl_SetResult(interp, 
		    "sdds getRowCount: unable to reopen file for page seek", 
		    NULL);
      return TCL_ERROR;
    }
  }
  if (desiredPage > sddsFdTable[fd].currentPage) {
    pagesToGo = desiredPage - sddsFdTable[fd].currentPage;
  }

  /* Read in until desired page */
  for (i=0 ; i < pagesToGo ; i++) {
    if ((tableRead = SDDS_ReadTable(&(sddsFdTable[fd].table))) <= 0) {
      if (tableRead == -1) {
	Tcl_SetResult(interp, "EOF", NULL);
	return TCL_ERROR;
      } else {
	sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	Tcl_AppendResult(interp, "sdds getRowCount: ", sddsErrs[0], NULL);
	SDDS_ClearErrors();
	free(sddsErrs[0]);
	return TCL_ERROR;	
      }
    }
    sddsFdTable[fd].currentPage++;
  }
  
  moreData = 1;

  Tcl_DStringInit(&result);

  while (moreData) {

    SDDS_SetColumnFlags(&(sddsFdTable[fd].table),1);
    SDDS_SetRowFlags(&(sddsFdTable[fd].table),1);
    
    if ((nrows = SDDS_CountRowsOfInterest(&(sddsFdTable[fd].table))) == -1) {
      sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
      Tcl_AppendResult(interp, "sdds getRowCount xx: ", sddsErrs[0], NULL);
      SDDS_ClearErrors();
      free(sddsErrs[0]);
      Tcl_DStringFree(&result);
      return TCL_ERROR;
    }
    sprintf(buffer,"%ld", nrows);
    Tcl_DStringAppendElement(&result,buffer);

    if (allPages) {
      if ((tableRead = SDDS_ReadTable(&(sddsFdTable[fd].table))) <= 0) {
	if (tableRead == -1) {
	  moreData = 0;
	  if (tclSDDSReopenFd(fd)) {
	    Tcl_SetResult(interp,"sdds getRowCount: unable to reopen file",NULL);
	    Tcl_DStringFree(&result);
	    return TCL_ERROR;
	  }	  
	} else {
	  sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	  Tcl_AppendResult(interp, "sdds getRowCount: ", sddsErrs[0], NULL);
	  SDDS_ClearErrors();
	  free(sddsErrs[0]);
	  Tcl_DStringFree(&result);
	  return TCL_ERROR;	
	}
      } else {
	sddsFdTable[fd].currentPage++;
      }
    } else {
      moreData = 0;
    }
  }
    
  Tcl_DStringResult(interp, &result);
  return TCL_OK;
}

/*****************************************
 *
 *****************************************/
int tclSDDSGetDescription(Tcl_Interp *interp, int argc, char *argv[]) {
  int fd;
  Tcl_DString result;

  if (argc != 3) {  
    Tcl_SetResult(interp, "usage: sdds getDescription <fd>", NULL);
    return TCL_ERROR;    
  }

  fd = atoi(argv[2]);
  if ((fd > MAX_OPEN_SDDS_FILES) || (sddsFdTable[fd].free == 1)) { 
    Tcl_SetResult(interp, "sdds getDescription: unknown file descriptor", NULL);
    return TCL_ERROR;
  }
  if (sddsFdTable[fd].mode != 'r') {
    Tcl_SetResult(interp, "sdds getDescription: <fd> must be opened for reading", NULL);
    return TCL_ERROR;
  }

  if (!SDDS_CheckDataset(&(sddsFdTable[fd].table), "SDDS_GetDescription")) {
    Tcl_SetResult(interp, "sdds getDescription: corrupted file", NULL);
  }

  Tcl_DStringInit(&result);
  Tcl_DStringAppendElement(&result,sddsFdTable[fd].table.layout.description);
  Tcl_DStringAppendElement(&result,sddsFdTable[fd].table.layout.contents);
  Tcl_DStringResult(interp, &result);
  return TCL_OK;
}

/*****************************************
 *
 *****************************************/
int tclSDDSSetDescription(Tcl_Interp *interp, int argc, char *argv[]) {
  char *descriptionText, *descriptionContents;
  int fd;

  if (argc != 5) {  
    Tcl_SetResult(interp, "usage: sdds setDescription <fd> <text> <contents>", NULL);
    return TCL_ERROR;    
  }

  fd = atoi(argv[2]);
  if ((fd > MAX_OPEN_SDDS_FILES) || (sddsFdTable[fd].free == 1)) { 
    Tcl_SetResult(interp, "sdds setDescription: unknown file descriptor", NULL);
    return TCL_ERROR;
  }
  descriptionText = argv[3];
  descriptionContents = argv[4];

  if (sddsFdTable[fd].mode != 'w') {
    Tcl_SetResult(interp, "sdds setDescription: <fd> must be opened for writing", NULL);
    return TCL_ERROR;
  }

  if (descriptionText && !SDDS_CopyString(&(sddsFdTable[fd].table.layout.description), descriptionText)) {
    Tcl_SetResult(interp, "Memory allocation failure initializing file", NULL);
    return TCL_ERROR;
  }
  if (descriptionContents && !SDDS_CopyString(&(sddsFdTable[fd].table.layout.contents), descriptionContents)) {
    Tcl_SetResult(interp, "Memory allocation failure initializing file", NULL);
    return TCL_ERROR;
  }
  return TCL_OK;
}

/*****************************************
 *
 *****************************************/
int tclSDDSGetColumn(Tcl_Interp *interp, int argc, char *argv[]) {
  char **sddsErrs;
  int32_t sddsNumErrs;
  int fd;
  char *sddsFileId;
  char *columnName;
  
  int32_t columnType;     /* for reading in SDDS columns */
  long nrows, i;
  long double *ldoubleData;
  double *doubleData;
  float *floatData;
  int64_t *long64Data;
  uint64_t *ulong64Data;
  int32_t *longData;
  uint32_t *ulongData;
  short *shortData;
  unsigned short *ushortData;
  char **stringData;
  char *charData;
  long desiredPage = 1;
  int allPages = 0;
  long pagesToGo = 0;
  long tableRead;
  int moreData;

  char buffer[tclSDDS_BUFSIZE];     /* for converting SDDS column to tcl string */
  Tcl_DString result;

  if (argc < 4 || ((argc%2) != 0)) {
    Tcl_SetResult(interp, "usage: sdds getColumn <fd> <columnName> [-page n]",
		  NULL);
    return TCL_ERROR;    
  }

  sddsFileId = argv[2];
  columnName = argv[3];
  if (argc > 4 && !strcmp(argv[4],"-page")) {
    desiredPage = atoi(argv[5]);
    if (desiredPage < 0) {
      Tcl_SetResult(interp, "sdds getColumn: page must be >=0", NULL);
      return TCL_ERROR;
    } else if (desiredPage == 0) {
      desiredPage = 1;
      allPages = 1;
    }
  } else if (argc == 4) {
    allPages = 1;   /* indicates we want all pages */
  }

  fd = atoi(sddsFileId);
  if ((fd > MAX_OPEN_SDDS_FILES) || (sddsFdTable[fd].free == 1)) { 
    Tcl_SetResult(interp, "sdds getColumn: unknown file descriptor",
		  (Tcl_FreeProc *) NULL);
    return TCL_ERROR;
  }
  if (sddsFdTable[fd].mode != 'r') {
    Tcl_SetResult(interp, "sdds getColumn: <fd> must be opened for reading",
		  NULL);
    return TCL_ERROR;
  }

  /* Find our current page location with respect to desired page */
  if ((allPages == 1 && sddsFdTable[fd].currentPage > 1) ||
      (allPages == 0 && desiredPage < sddsFdTable[fd].currentPage)) {
    if (tclSDDSReopenFd(fd)) {
      Tcl_SetResult(interp, 
		    "sdds getColumn: unable to reopen file for page seek", 
		    NULL);
      return TCL_ERROR;
    }
  }
  if (desiredPage > sddsFdTable[fd].currentPage) {
    pagesToGo = desiredPage - sddsFdTable[fd].currentPage;
  }

  /* Read in until desired page */
  for (i=0 ; i < pagesToGo ; i++) {
    if ((tableRead = SDDS_ReadTable(&(sddsFdTable[fd].table))) <= 0) {
      if (tableRead == -1) {
	Tcl_SetResult(interp, "EOF", NULL);
	return TCL_ERROR;
      } else {
	sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	Tcl_AppendResult(interp, "sdds getColumn: ", sddsErrs[0], NULL);
	SDDS_ClearErrors();
	free(sddsErrs[0]);
	return TCL_ERROR;	
      }
    }
    sddsFdTable[fd].currentPage++;
  }
  moreData = 1;

  if (SDDS_GetColumnInformation(&(sddsFdTable[fd].table), "type", 
				&columnType,SDDS_GET_BY_NAME, columnName) 
      == 0) {
    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
    Tcl_AppendResult(interp, "sdds getColumn: ", sddsErrs[0], NULL);
    SDDS_ClearErrors();
    free(sddsErrs[0]);
    return TCL_ERROR;
  }
  
  Tcl_DStringInit(&result);

  while (moreData) {

    SDDS_SetColumnFlags(&(sddsFdTable[fd].table),1);
    SDDS_SetRowFlags(&(sddsFdTable[fd].table),1);

    if ((nrows = SDDS_CountRowsOfInterest(&(sddsFdTable[fd].table))) == -1) {
      sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
      Tcl_AppendResult(interp, "sdds getColumn xx: ", sddsErrs[0], NULL);
      SDDS_ClearErrors();
      free(sddsErrs[0]);
      Tcl_DStringFree(&result);
      return TCL_ERROR;
    }

    switch (columnType) {
    case SDDS_LONGDOUBLE: {
      if ((ldoubleData = SDDS_GetColumn(&(sddsFdTable[fd].table), columnName))
	  == NULL) {
	sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	Tcl_AppendResult(interp, "sdds getColumn: ", sddsErrs[0], NULL);
	SDDS_ClearErrors();
	free(sddsErrs[0]);
	Tcl_DStringFree(&result);
	return TCL_ERROR;
      }
      for (i=0 ; i < nrows ; i++) {
	sprintf(buffer,"%23.20Le", ldoubleData[i]);
	Tcl_DStringAppendElement(&result,buffer);
      }
      free(ldoubleData);
      break;
    }
    case SDDS_DOUBLE: {
      if ((doubleData = SDDS_GetColumn(&(sddsFdTable[fd].table), columnName))
	  == NULL) {
	sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	Tcl_AppendResult(interp, "sdds getColumn: ", sddsErrs[0], NULL);
	SDDS_ClearErrors();
	free(sddsErrs[0]);
	Tcl_DStringFree(&result);
	return TCL_ERROR;
      }
      for (i=0 ; i < nrows ; i++) {
	sprintf(buffer,"%23.17e", doubleData[i]);
	Tcl_DStringAppendElement(&result,buffer);
      }
      free(doubleData);
      break;
    }
    case SDDS_FLOAT: {
      if ((floatData = SDDS_GetColumn(&(sddsFdTable[fd].table), columnName))
	  == NULL) {
      sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
      Tcl_AppendResult(interp, "sdds getColumn: ", sddsErrs[0], NULL);
      SDDS_ClearErrors();
      free(sddsErrs[0]);
      Tcl_DStringFree(&result);
      return TCL_ERROR;
      }
      for (i=0 ; i < nrows ; i++) {
	sprintf(buffer,"%23.17e", floatData[i]);
	Tcl_DStringAppendElement(&result,buffer);
      }
      free(floatData);
      break;
    }
    case SDDS_LONG64: {
      if ((long64Data = SDDS_GetColumn(&(sddsFdTable[fd].table), columnName))
	  == NULL) {
	sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	Tcl_AppendResult(interp, "sdds getColumn: ", sddsErrs[0], NULL);
	SDDS_ClearErrors();
	free(sddsErrs[0]);
	Tcl_DStringFree(&result);
	return TCL_ERROR;
      }
      for (i=0 ; i < nrows ; i++) {
	sprintf(buffer,"%" PRId64, long64Data[i]);
	Tcl_DStringAppendElement(&result,buffer);
      }
      free(long64Data);
      break;
    }
    case SDDS_ULONG64: {
      if ((ulong64Data = SDDS_GetColumn(&(sddsFdTable[fd].table), columnName))
	  == NULL) {
	sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	Tcl_AppendResult(interp, "sdds getColumn: ", sddsErrs[0], NULL);
	SDDS_ClearErrors();
	free(sddsErrs[0]);
	Tcl_DStringFree(&result);
	return TCL_ERROR;
      }
      for (i=0 ; i < nrows ; i++) {
	sprintf(buffer,"%" PRIu64, ulong64Data[i]);
	Tcl_DStringAppendElement(&result,buffer);
      }
      free(ulong64Data);
      break;
    }
    case SDDS_LONG: {
      if ((longData = SDDS_GetColumn(&(sddsFdTable[fd].table), columnName))
	  == NULL) {
	sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	Tcl_AppendResult(interp, "sdds getColumn: ", sddsErrs[0], NULL);
	SDDS_ClearErrors();
	free(sddsErrs[0]);
	Tcl_DStringFree(&result);
	return TCL_ERROR;
      }
      for (i=0 ; i < nrows ; i++) {
	sprintf(buffer,"%" PRId32, longData[i]);
	Tcl_DStringAppendElement(&result,buffer);
      }
      free(longData);
      break;
    }
    case SDDS_ULONG: {
      if ((ulongData = SDDS_GetColumn(&(sddsFdTable[fd].table), columnName))
	  == NULL) {
	sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	Tcl_AppendResult(interp, "sdds getColumn: ", sddsErrs[0], NULL);
	SDDS_ClearErrors();
	free(sddsErrs[0]);
	Tcl_DStringFree(&result);
	return TCL_ERROR;
      }
      for (i=0 ; i < nrows ; i++) {
	sprintf(buffer,"%" PRIu32, ulongData[i]);
	Tcl_DStringAppendElement(&result,buffer);
      }
      free(ulongData);
      break;
    }
    case SDDS_SHORT: {
      if ((shortData = SDDS_GetColumn(&(sddsFdTable[fd].table), columnName))
	  == NULL) {
	sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	Tcl_AppendResult(interp, "sdds getColumn: ", sddsErrs[0], NULL);
	SDDS_ClearErrors();
	free(sddsErrs[0]);
	Tcl_DStringFree(&result);
	return TCL_ERROR;
      }
      for (i=0 ; i < nrows ; i++) {
	sprintf(buffer,"%d", shortData[i]);
	Tcl_DStringAppendElement(&result,buffer);
      }
      free(shortData);
      break;
    }
    case SDDS_USHORT: {
      if ((ushortData = SDDS_GetColumn(&(sddsFdTable[fd].table), columnName))
	  == NULL) {
	sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	Tcl_AppendResult(interp, "sdds getColumn: ", sddsErrs[0], NULL);
	SDDS_ClearErrors();
	free(sddsErrs[0]);
	Tcl_DStringFree(&result);
	return TCL_ERROR;
      }
      for (i=0 ; i < nrows ; i++) {
	sprintf(buffer,"%u", ushortData[i]);
	Tcl_DStringAppendElement(&result,buffer);
      }
      free(ushortData);
      break;
    }
    case SDDS_STRING: {
      if ((stringData = SDDS_GetColumn(&(sddsFdTable[fd].table), columnName))
	  == NULL) {
	sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	Tcl_AppendResult(interp, "sdds getColumn: ", sddsErrs[0], NULL);
	SDDS_ClearErrors();
	free(sddsErrs[0]);
	Tcl_DStringFree(&result);
	return TCL_ERROR;
      }
      for (i=0 ; i < nrows ; i++)
	Tcl_DStringAppendElement(&result,stringData[i]);
      
      for (i=0 ; i < nrows ; i++)
	free(stringData[i]);
      free(stringData);
      break;
    }
    case SDDS_CHARACTER: {
      if ((charData = SDDS_GetColumn(&(sddsFdTable[fd].table), columnName))
	  == NULL) {
	sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	Tcl_AppendResult(interp, "sdds getColumn: ", sddsErrs[0], NULL);
	SDDS_ClearErrors();
	free(sddsErrs[0]);
	Tcl_DStringFree(&result);
	return TCL_ERROR;
      }
      for (i=0 ; i < nrows ; i++) {
	sprintf(buffer,"%c", charData[i]);
	Tcl_DStringAppendElement(&result,buffer);
      }
      free(charData);
      break;
    }}

    if (allPages) {
      if ((tableRead = SDDS_ReadTable(&(sddsFdTable[fd].table))) <= 0) {
	if (tableRead == -1) {
	  moreData = 0;
	  if (tclSDDSReopenFd(fd)) {
	    Tcl_SetResult(interp,"sdds getColumn: unable to reopen file",NULL);
	    Tcl_DStringFree(&result);
	    return TCL_ERROR;
	  }	  
	} else {
	  sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	  Tcl_AppendResult(interp, "sdds getColumn: ", sddsErrs[0], NULL);
	  SDDS_ClearErrors();
	  free(sddsErrs[0]);
	  Tcl_DStringFree(&result);
	  return TCL_ERROR;	
	}
      } else {
	sddsFdTable[fd].currentPage++;
      }
    } else {
      moreData = 0;
    }
    
  } /* end while(moreData) */
  
  Tcl_DStringResult(interp, &result);
  return TCL_OK;
}

/*****************************************
 *
 *****************************************/
int tclSDDSGetColumnInformation(Tcl_Interp *interp, int argc, char *argv[]) {
  char **sddsErrs;
  int32_t sddsNumErrs;
  int fd;
  char *sddsFileId;
  char *columnName;
  char *tclArrayName;
  
  int32_t type;     /* for reading in SDDS column information */
  char *name;
  char *symbol;
  char *units;
  char *description;
  char *format_string;
  int32_t field_length;

  char valueBuf[tclSDDS_BUFSIZE];    

  if (argc != 5) {
    Tcl_SetResult(interp, "usage: sdds getColumnInformation <fd> <columnName> <tclArrayName>",
		  NULL);
    return TCL_ERROR;    
  }

  sddsFileId = argv[2];
  columnName = argv[3];
  tclArrayName = argv[4];

  fd = atoi(sddsFileId);
  if ((fd > MAX_OPEN_SDDS_FILES) || (sddsFdTable[fd].free == 1)) { 
    Tcl_SetResult(interp, "sdds getColumnInformation: unknown file descriptor",
		  (Tcl_FreeProc *) NULL);
    return TCL_ERROR;
  }
  if (sddsFdTable[fd].mode != 'r') {
    Tcl_SetResult(interp, "sdds getColumnInformation: <fd> must be opened for reading",
		  NULL);
    return TCL_ERROR;
  }

  if (SDDS_GetColumnInformation(&(sddsFdTable[fd].table), "name", 
				&name,SDDS_GET_BY_NAME, columnName) 
      == 0) {
    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
    Tcl_AppendResult(interp, "sdds getColumnInformation: ", sddsErrs[0], NULL);
    SDDS_ClearErrors();
    free(sddsErrs[0]);
    return TCL_ERROR;
  }

  if (SDDS_GetColumnInformation(&(sddsFdTable[fd].table), "symbol", 
				&symbol,SDDS_GET_BY_NAME, columnName) 
      == 0) {
    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
    Tcl_AppendResult(interp, "sdds getColumnInformation: ", sddsErrs[0], NULL);
    SDDS_ClearErrors();
    free(sddsErrs[0]);
    if (name) free(name);
    return TCL_ERROR;
  }

  if (SDDS_GetColumnInformation(&(sddsFdTable[fd].table), "units", 
				&units,SDDS_GET_BY_NAME, columnName) 
      == 0) {
    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
    Tcl_AppendResult(interp, "sdds getColumnInformation: ", sddsErrs[0], NULL);
    SDDS_ClearErrors();
    free(sddsErrs[0]);
    if (name) free(name);
    if (symbol) free(symbol);
    return TCL_ERROR;
  }

  if (SDDS_GetColumnInformation(&(sddsFdTable[fd].table), "description", 
				&description,SDDS_GET_BY_NAME, columnName) 
      == 0) {
    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
    Tcl_AppendResult(interp, "sdds getColumnInformation: ", sddsErrs[0], NULL);
    SDDS_ClearErrors();
    free(sddsErrs[0]);
    if (name) free(name);
    if (symbol) free(symbol);
    if (units) free(units);
    return TCL_ERROR;
  }

  if (SDDS_GetColumnInformation(&(sddsFdTable[fd].table), "format_string", 
				&format_string,SDDS_GET_BY_NAME, columnName) 
      == 0) {
    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
    Tcl_AppendResult(interp, "sdds getColumnInformation: ", sddsErrs[0], NULL);
    SDDS_ClearErrors();
    free(sddsErrs[0]);
    if (name) free(name);
    if (symbol) free(symbol);
    if (units) free(units);
    if (description) free(description);
    return TCL_ERROR;
  }

  if (SDDS_GetColumnInformation(&(sddsFdTable[fd].table), "type", 
				&type,SDDS_GET_BY_NAME, columnName) 
      == 0) {
    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
    Tcl_AppendResult(interp, "sdds getColumnInformation: ", sddsErrs[0], NULL);
    SDDS_ClearErrors();
    free(sddsErrs[0]);
    if (name) free(name);
    if (symbol) free(symbol);
    if (units) free(units);
    if (description) free(description);
    if (format_string) free(format_string);
    return TCL_ERROR;
  }

  if (SDDS_GetColumnInformation(&(sddsFdTable[fd].table), "field_length", 
				&field_length,SDDS_GET_BY_NAME, columnName) 
      == 0) {
    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
    Tcl_AppendResult(interp, "sdds getColumnInformation: ", sddsErrs[0], NULL);
    SDDS_ClearErrors();
    free(sddsErrs[0]);
    if (name) free(name);
    if (symbol) free(symbol);
    if (units) free(units);
    if (description) free(description);
    if (format_string) free(format_string);
    return TCL_ERROR;
  }

  if (Tcl_SetVar2(interp,tclArrayName,"name",name==NULL?"":name,0) == NULL) {
    Tcl_SetResult(interp,"sdds getColumnInformation: unable to set tcl array element", NULL);
    if (name) free(name);
    if (symbol) free(symbol);
    if (units) free(units);
    if (description) free(description);
    if (format_string) free(format_string);
    return TCL_ERROR;
  }

  if (Tcl_SetVar2(interp,tclArrayName,"symbol",symbol==NULL?"":symbol,0) == NULL) {
    Tcl_SetResult(interp,"sdds getColumnInformation: unable to set tcl array element", NULL);
    if (name) free(name);
    if (symbol) free(symbol);
    if (units) free(units);
    if (description) free(description);
    if (format_string) free(format_string);
    return TCL_ERROR;
  }

  if (Tcl_SetVar2(interp,tclArrayName,"units",units==NULL?"":units,0) == NULL) {
    Tcl_SetResult(interp,"sdds getColumnInformation: unable to set tcl array element", NULL);
    if (name) free(name);
    if (symbol) free(symbol);
    if (units) free(units);
    if (description) free(description);
    if (format_string) free(format_string);
    return TCL_ERROR;
  }

  if (Tcl_SetVar2(interp,tclArrayName,"description",description==NULL?"":description,0) == NULL) {
    Tcl_SetResult(interp,"sdds getColumnInformation: unable to set tcl array element", NULL);
    if (name) free(name);
    if (symbol) free(symbol);
    if (units) free(units);
    if (description) free(description);
    if (format_string) free(format_string);
    return TCL_ERROR;
  }

  if (Tcl_SetVar2(interp,tclArrayName,"format_string",format_string==NULL?"":format_string,0) == NULL) {
    Tcl_SetResult(interp,"sdds getColumnInformation: unable to set tcl array element", NULL);
    if (name) free(name);
    if (symbol) free(symbol);
    if (units) free(units);
    if (description) free(description);
    if (format_string) free(format_string);
    return TCL_ERROR;
  }

  if (Tcl_SetVar2(interp,tclArrayName,"type",
		  convertNumericToTypeString(type),0) == NULL) {
    Tcl_SetResult(interp,"sdds getColumnInformation: unable to set tcl array element", NULL);
    if (name) free(name);
    if (symbol) free(symbol);
    if (units) free(units);
    if (description) free(description);
    if (format_string) free(format_string);
    return TCL_ERROR;
  }

  sprintf(valueBuf,"%" PRId32,field_length);
  if (Tcl_SetVar2(interp,tclArrayName,"field_length",valueBuf,0) == NULL) {
    Tcl_SetResult(interp,"sdds getColumnInformation: unable to set tcl array element", NULL);
    if (name) free(name);
    if (symbol) free(symbol);
    if (units) free(units);
    if (description) free(description);
    if (format_string) free(format_string);
    return TCL_ERROR;
  }
    
  return TCL_OK;
}

/*****************************************
 *
 *****************************************/
int tclSDDSGetParameter(Tcl_Interp *interp, int argc, char *argv[]) {
  char **sddsErrs;
  int32_t sddsNumErrs;
  int fd;
  char *sddsFileId;
  char *parameterName;
  
  int32_t parameterType;     /* for reading in SDDS parameters */
  long i;
  long double ldoubleData;
  double doubleData;
  float floatData;
  int64_t long64Data;
  uint64_t ulong64Data;
  int32_t longData;
  uint32_t ulongData;
  short shortData;
  unsigned short ushortData;
  char *stringData[1];
  char charData;
  long desiredPage = 1;
  int allPages = 0;
  long pagesToGo = 0;
  long tableRead;
  int moreData;

  char buffer[tclSDDS_BUFSIZE];     /* for converting SDDS parameter to tcl string */
  Tcl_DString result;

  if (argc < 4 || ((argc%2) != 0)) {
    Tcl_SetResult(interp, 
		  "usage: sdds getParameter <fd> <parameterName> [-page n]",
		  NULL);
    return TCL_ERROR;    
  }
  sddsFileId = argv[2];
  parameterName = argv[3];
  if (argc > 4 && !strcmp(argv[4],"-page")) {
    desiredPage = atoi(argv[5]);
    if (desiredPage < 0) {
      Tcl_SetResult(interp, "sdds getParameter: page must be >=0", NULL);
      return TCL_ERROR;
    } else if (desiredPage == 0) {
      desiredPage = 1;
      allPages = 1;
    }
  } else if (argc == 4) {
    allPages = 1;
  }


  fd = atoi(sddsFileId);
  if ((fd > MAX_OPEN_SDDS_FILES) || (sddsFdTable[fd].free == 1)) { 
    Tcl_SetResult(interp, "sdds getParameter: unknown file descriptor", NULL);
    return TCL_ERROR;
  }
  if (sddsFdTable[fd].mode != 'r') {
    Tcl_SetResult(interp, "sdds getParameter: <fd> must be opened for reading",
		  NULL);
    return TCL_ERROR;
  }

  /* Find our current page location with respect to desired page */
  if ((allPages == 1 && sddsFdTable[fd].currentPage > 1) ||
      (allPages == 0 && desiredPage < sddsFdTable[fd].currentPage)) {
    if (tclSDDSReopenFd(fd)) {
      Tcl_SetResult(interp, 
		    "sdds getParameter: unable to reopen file for page seek", 
		    NULL);
      return TCL_ERROR;
    }
  }
  if (desiredPage > sddsFdTable[fd].currentPage) {
    pagesToGo = desiredPage - sddsFdTable[fd].currentPage;
  }

  /* Read in until desired page */
  for (i=0 ; i < pagesToGo ; i++) {
    if ((tableRead = SDDS_ReadTable(&(sddsFdTable[fd].table))) <= 0) {
      if (tableRead == -1) {
	Tcl_SetResult(interp, "EOF", NULL);
	return TCL_ERROR;
      } else {
	sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	Tcl_AppendResult(interp, "sdds getParameter: ", sddsErrs[0], NULL);
	SDDS_ClearErrors();
	free(sddsErrs[0]);
	return TCL_ERROR;	
      }
    }
    sddsFdTable[fd].currentPage++;
  }

  moreData = 1;

  if (SDDS_GetParameterInformation(&(sddsFdTable[fd].table), "type", 
				   &parameterType, SDDS_GET_BY_NAME, 
				   parameterName) == 0) {
    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
    Tcl_AppendResult(interp, "sdds getParameter: ", sddsErrs[0], NULL);
    SDDS_ClearErrors();
    free(sddsErrs[0]);
    return TCL_ERROR;
  }

  Tcl_DStringInit(&result);
  
  while (moreData) {

    SDDS_SetColumnFlags(&(sddsFdTable[fd].table),1);
    SDDS_SetRowFlags(&(sddsFdTable[fd].table),1);

    switch (parameterType) {
    case SDDS_LONGDOUBLE: {
      if (SDDS_GetParameter(&(sddsFdTable[fd].table), parameterName, &ldoubleData)
	  == NULL) {
	sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	Tcl_AppendResult(interp, "sdds getParameter: ", sddsErrs[0], NULL);
	SDDS_ClearErrors();
	free(sddsErrs[0]);
	Tcl_DStringFree(&result);
	return TCL_ERROR;
      }
      sprintf(buffer,"%23.20Le", ldoubleData);
      Tcl_DStringAppendElement(&result,buffer);
      break;
    }
    case SDDS_DOUBLE: {
      if (SDDS_GetParameter(&(sddsFdTable[fd].table), parameterName, &doubleData)
	  == NULL) {
	sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	Tcl_AppendResult(interp, "sdds getParameter: ", sddsErrs[0], NULL);
	SDDS_ClearErrors();
	free(sddsErrs[0]);
	Tcl_DStringFree(&result);
	return TCL_ERROR;
      }
      sprintf(buffer,"%23.17e", doubleData);
      Tcl_DStringAppendElement(&result,buffer);
      break;
    }
    case SDDS_FLOAT: {
      if (SDDS_GetParameter(&(sddsFdTable[fd].table), parameterName, &floatData)
	  == NULL) {
	sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	Tcl_AppendResult(interp, "sdds getParameter: ", sddsErrs[0], NULL);
	SDDS_ClearErrors();
	free(sddsErrs[0]);
	Tcl_DStringFree(&result);
	return TCL_ERROR;
      }
      sprintf(buffer,"%23.17e", floatData);
      Tcl_DStringAppendElement(&result,buffer);
      break;
    }
    case SDDS_LONG64: {
      if (SDDS_GetParameter(&(sddsFdTable[fd].table), parameterName, &long64Data)
	  == NULL) {
	sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	Tcl_AppendResult(interp, "sdds getParameter: ", sddsErrs[0], NULL);
	SDDS_ClearErrors();
	free(sddsErrs[0]);
	Tcl_DStringFree(&result);
	return TCL_ERROR;
      }
      sprintf(buffer,"%" PRId64, long64Data);
      Tcl_DStringAppendElement(&result,buffer);
      break;
    }
    case SDDS_ULONG64: {
      if (SDDS_GetParameter(&(sddsFdTable[fd].table), parameterName, &ulong64Data)
	  == NULL) {
	sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	Tcl_AppendResult(interp, "sdds getParameter: ", sddsErrs[0], NULL);
	SDDS_ClearErrors();
	free(sddsErrs[0]);
	Tcl_DStringFree(&result);
	return TCL_ERROR;
      }
      sprintf(buffer,"%" PRIu64, ulong64Data);
      Tcl_DStringAppendElement(&result,buffer);
      break;
    }
    case SDDS_LONG: {
      if (SDDS_GetParameter(&(sddsFdTable[fd].table), parameterName, &longData)
	  == NULL) {
	sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	Tcl_AppendResult(interp, "sdds getParameter: ", sddsErrs[0], NULL);
	SDDS_ClearErrors();
	free(sddsErrs[0]);
	Tcl_DStringFree(&result);
	return TCL_ERROR;
      }
      sprintf(buffer,"%" PRId32, longData);
      Tcl_DStringAppendElement(&result,buffer);
      break;
    }
    case SDDS_ULONG: {
      if (SDDS_GetParameter(&(sddsFdTable[fd].table), parameterName, &ulongData)
	  == NULL) {
	sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	Tcl_AppendResult(interp, "sdds getParameter: ", sddsErrs[0], NULL);
	SDDS_ClearErrors();
	free(sddsErrs[0]);
	Tcl_DStringFree(&result);
	return TCL_ERROR;
      }
      sprintf(buffer,"%" PRIu32, ulongData);
      Tcl_DStringAppendElement(&result,buffer);
      break;
    }
    case SDDS_SHORT: {
      if (SDDS_GetParameter(&(sddsFdTable[fd].table), parameterName, &shortData)
	  == NULL) {
	sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	Tcl_AppendResult(interp, "sdds getParameter: ", sddsErrs[0], NULL);
	SDDS_ClearErrors();
	free(sddsErrs[0]);
	Tcl_DStringFree(&result);
	return TCL_ERROR;
      }
      sprintf(buffer,"%d", shortData);
      Tcl_DStringAppendElement(&result,buffer);
      break;
    }
    case SDDS_USHORT: {
      if (SDDS_GetParameter(&(sddsFdTable[fd].table), parameterName, &ushortData)
	  == NULL) {
	sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	Tcl_AppendResult(interp, "sdds getParameter: ", sddsErrs[0], NULL);
	SDDS_ClearErrors();
	free(sddsErrs[0]);
	Tcl_DStringFree(&result);
	return TCL_ERROR;
      }
      sprintf(buffer,"%u", ushortData);
      Tcl_DStringAppendElement(&result,buffer);
      break;
    }
    case SDDS_STRING: {
      if (SDDS_GetParameter(&(sddsFdTable[fd].table), parameterName, stringData)
	  == NULL) {
	sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	Tcl_AppendResult(interp, "sdds getParameter: ", sddsErrs[0], NULL);
	SDDS_ClearErrors();
	free(sddsErrs[0]);
	Tcl_DStringFree(&result);
	return TCL_ERROR;
      }
      Tcl_DStringAppendElement(&result,stringData[0]);
      free(stringData[0]);
      break;
    }
    case SDDS_CHARACTER: {
      if (SDDS_GetParameter(&(sddsFdTable[fd].table), parameterName, &charData)
	  == NULL) {
	sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	Tcl_AppendResult(interp, "sdds getParameter: ", sddsErrs[0], NULL);
	SDDS_ClearErrors();
	free(sddsErrs[0]);
	Tcl_DStringFree(&result);
	return TCL_ERROR;
      }
      sprintf(buffer,"%c", charData);
      Tcl_DStringAppendElement(&result,buffer);
      break;
    }}

    if (allPages) {
      if ((tableRead = SDDS_ReadTable(&(sddsFdTable[fd].table))) <= 0) {
	if (tableRead == -1) {
	  moreData = 0;
	  if (tclSDDSReopenFd(fd)) {
	    Tcl_SetResult(interp,"sdds getParameter: unable to reopen file",NULL);
	    Tcl_DStringFree(&result);
	    return TCL_ERROR;
	  }	  
	} else {
	  sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	  Tcl_AppendResult(interp, "sdds getParameter: ", sddsErrs[0], NULL);
	  SDDS_ClearErrors();
	  free(sddsErrs[0]);
	  Tcl_DStringFree(&result);
	  return TCL_ERROR;	
	}
      } else {
	sddsFdTable[fd].currentPage++;
      }
    } else {
      moreData = 0;
    }

  } /* end while(moreData) */  

  Tcl_DStringResult(interp, &result);
  return TCL_OK;
}

/*****************************************
 *
 *****************************************/
int tclSDDSGetParameterInformation(Tcl_Interp *interp, int argc, char *argv[]) {
  char **sddsErrs;
  int32_t sddsNumErrs;
  int fd;
  char *sddsFileId;
  char *parameterName;
  char *tclArrayName;
  
  int32_t type;     /* for reading in SDDS Parameter information */
  char *name;
  char *symbol;
  char *units;
  char *description;
  char *format_string;
  char *fixed_value;

  if (argc != 5) {
    Tcl_SetResult(interp, "usage: sdds getParameterInformation <fd> <parameterName> <tclArrayName>",
		  NULL);
    return TCL_ERROR;    
  }

  sddsFileId = argv[2];
  parameterName = argv[3];
  tclArrayName = argv[4];

  fd = atoi(sddsFileId);
  if ((fd > MAX_OPEN_SDDS_FILES) || (sddsFdTable[fd].free == 1)) { 
    Tcl_SetResult(interp, "sdds getParameterInformation: unknown file descriptor",
		  (Tcl_FreeProc *) NULL);
    return TCL_ERROR;
  }
  if (sddsFdTable[fd].mode != 'r') {
    Tcl_SetResult(interp, "sdds getParameterInformation: <fd> must be opened for reading",
		  NULL);
    return TCL_ERROR;
  }

  if (SDDS_GetParameterInformation(&(sddsFdTable[fd].table), "name", 
				&name,SDDS_GET_BY_NAME, parameterName) 
      == 0) {
    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
    Tcl_AppendResult(interp, "sdds getParameterInformation: ", sddsErrs[0], NULL);
    SDDS_ClearErrors();
    free(sddsErrs[0]);
    return TCL_ERROR;
  }

  if (SDDS_GetParameterInformation(&(sddsFdTable[fd].table), "symbol", 
				&symbol,SDDS_GET_BY_NAME, parameterName) 
      == 0) {
    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
    Tcl_AppendResult(interp, "sdds getParameterInformation: ", sddsErrs[0], NULL);
    SDDS_ClearErrors();
    free(sddsErrs[0]);
    if (name) free(name);
    return TCL_ERROR;
  }

  if (SDDS_GetParameterInformation(&(sddsFdTable[fd].table), "units", 
				&units,SDDS_GET_BY_NAME, parameterName) 
      == 0) {
    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
    Tcl_AppendResult(interp, "sdds getParameterInformation: ", sddsErrs[0], NULL);
    SDDS_ClearErrors();
    free(sddsErrs[0]);
    if (name) free(name);
    if (symbol) free(symbol);
    return TCL_ERROR;
  }

  if (SDDS_GetParameterInformation(&(sddsFdTable[fd].table), "description", 
				&description,SDDS_GET_BY_NAME, parameterName) 
      == 0) {
    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
    Tcl_AppendResult(interp, "sdds getParameterInformation: ", sddsErrs[0], NULL);
    SDDS_ClearErrors();
    free(sddsErrs[0]);
    if (name) free(name);
    if (symbol) free(symbol);
    if (units) free(units);
    return TCL_ERROR;
  }

  if (SDDS_GetParameterInformation(&(sddsFdTable[fd].table), "format_string", 
				&format_string,SDDS_GET_BY_NAME, parameterName) 
      == 0) {
    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
    Tcl_AppendResult(interp, "sdds getParameterInformation: ", sddsErrs[0], NULL);
    SDDS_ClearErrors();
    free(sddsErrs[0]);
    if (name) free(name);
    if (symbol) free(symbol);
    if (units) free(units);
    if (description) free(description);
    return TCL_ERROR;
  }

  if (SDDS_GetParameterInformation(&(sddsFdTable[fd].table), "type", 
				&type,SDDS_GET_BY_NAME, parameterName) 
      == 0) {
    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
    Tcl_AppendResult(interp, "sdds getParameterInformation: ", sddsErrs[0], NULL);
    SDDS_ClearErrors();
    free(sddsErrs[0]);
    if (name) free(name);
    if (symbol) free(symbol);
    if (units) free(units);
    if (description) free(description);
    if (format_string) free(format_string);
    return TCL_ERROR;
  }

  if (SDDS_GetParameterInformation(&(sddsFdTable[fd].table), "fixed_value", 
				&fixed_value,SDDS_GET_BY_NAME, parameterName) 
      == 0) {
    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
    Tcl_AppendResult(interp, "sdds getParameterInformation: ", sddsErrs[0], NULL);
    SDDS_ClearErrors();
    free(sddsErrs[0]);
    if (name) free(name);
    if (symbol) free(symbol);
    if (units) free(units);
    if (description) free(description);
    if (format_string) free(format_string);
    return TCL_ERROR;
  }

  if (Tcl_SetVar2(interp,tclArrayName,"name",name==NULL?"":name,0) == NULL) {
    Tcl_SetResult(interp,"sdds getParameterInformation: unable to set tcl array element", NULL);
    if (name) free(name);
    if (symbol) free(symbol);
    if (units) free(units);
    if (description) free(description);
    if (format_string) free(format_string);
    if (fixed_value) free(fixed_value);
    return TCL_ERROR;
  }

  if (Tcl_SetVar2(interp,tclArrayName,"symbol",symbol==NULL?"":symbol,0) == NULL) {
    Tcl_SetResult(interp,"sdds getParameterInformation: unable to set tcl array element", NULL);
    if (name) free(name);
    if (symbol) free(symbol);
    if (units) free(units);
    if (description) free(description);
    if (format_string) free(format_string);
    if (fixed_value) free(fixed_value);
    return TCL_ERROR;
  }

  if (Tcl_SetVar2(interp,tclArrayName,"units",units==NULL?"":units,0) == NULL) {
    Tcl_SetResult(interp,"sdds getParameterInformation: unable to set tcl array element", NULL);
    if (name) free(name);
    if (symbol) free(symbol);
    if (units) free(units);
    if (description) free(description);
    if (format_string) free(format_string);
    if (fixed_value) free(fixed_value);
    return TCL_ERROR;
  }

  if (Tcl_SetVar2(interp,tclArrayName,"description",description==NULL?"":description,0) == NULL) {
    Tcl_SetResult(interp,"sdds getParameterInformation: unable to set tcl array element", NULL);
    if (name) free(name);
    if (symbol) free(symbol);
    if (units) free(units);
    if (description) free(description);
    if (format_string) free(format_string);
    if (fixed_value) free(fixed_value);
    return TCL_ERROR;
  }

  if (Tcl_SetVar2(interp,tclArrayName,"format_string",format_string==NULL?"":format_string,0) == NULL) {
    Tcl_SetResult(interp,"sdds getParameterInformation: unable to set tcl array element", NULL);
    if (name) free(name);
    if (symbol) free(symbol);
    if (units) free(units);
    if (description) free(description);
    if (format_string) free(format_string);
    if (fixed_value) free(fixed_value);
    return TCL_ERROR;
  }

  if (Tcl_SetVar2(interp,tclArrayName,"type",
		  convertNumericToTypeString(type),0) == NULL) {
    Tcl_SetResult(interp,"sdds getParameterInformation: unable to set tcl array element", NULL);
    if (name) free(name);
    if (symbol) free(symbol);
    if (units) free(units);
    if (description) free(description);
    if (format_string) free(format_string);
    if (fixed_value) free(fixed_value);
    return TCL_ERROR;
  }

  if (Tcl_SetVar2(interp,tclArrayName,"fixed_value",fixed_value==NULL?"":fixed_value,0) == NULL) {
    Tcl_SetResult(interp,"sdds getParameterInformation: unable to set tcl array element", NULL);
    if (name) free(name);
    if (symbol) free(symbol);
    if (units) free(units);
    if (description) free(description);
    if (format_string) free(format_string);
    if (fixed_value) free(fixed_value);
    return TCL_ERROR;
  }
    
  return TCL_OK;
}

/*****************************************
 *
 *****************************************/
int tclSDDSGetNames(Tcl_Interp *interp, int argc, char *argv[]) {
  char **sddsErrs;
  int32_t sddsNumErrs;
  int fd;
  char *sddsFileId;
  char *class;
  int32_t number;
  long i;
  char **nameData;
  Tcl_DString result;

  if (argc < 3 || argc > 4) {
    Tcl_SetResult(interp, "usage: sdds getNames <fd> [<class>]", NULL);
    return TCL_ERROR;    
  }
  sddsFileId = argv[2];
  if (argc == 4) {
    class = argv[3];
  } else {
    class = "column";
  }

  fd = atoi(sddsFileId);
  if ((fd > MAX_OPEN_SDDS_FILES) || (sddsFdTable[fd].free == 1)) { 
    Tcl_SetResult(interp, "sdds getNames: unknown file descriptor", NULL);
    return TCL_ERROR;
  }
  if (sddsFdTable[fd].mode != 'r') {
    Tcl_SetResult(interp, "sdds getNames: <fd> must be opened for reading",
		  NULL);
    return TCL_ERROR;
  }

  if (!strcmp(class,"column")) {
    if ((nameData=SDDS_GetColumnNames(&(sddsFdTable[fd].table), &number)) 
	== NULL) {
      sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
      Tcl_AppendResult(interp, "sdds getNames: ", sddsErrs[0], NULL);
      SDDS_ClearErrors();
      free(sddsErrs[0]);
      return TCL_ERROR;
    }
    Tcl_DStringInit(&result);
    for (i=0 ; i < number ; i++)
      Tcl_DStringAppendElement(&result,nameData[i]);

    Tcl_DStringResult(interp, &result);
    for (i=0 ; i < number ; i++)
      free(nameData[i]);
    free(nameData);

  } else if (!strcmp(class,"parameter")) {
    if ((nameData=SDDS_GetParameterNames(&(sddsFdTable[fd].table), &number)) 
	== NULL) {
      sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
      Tcl_AppendResult(interp, "sdds getNames: ", sddsErrs[0], NULL);
      SDDS_ClearErrors();
      free(sddsErrs[0]);
      return TCL_ERROR;
    }
    Tcl_DStringInit(&result);
    for (i=0 ; i < number ; i++)
      Tcl_DStringAppendElement(&result,nameData[i]);

    Tcl_DStringResult(interp, &result);
    for (i=0 ; i < number ; i++)
      free(nameData[i]);
    free(nameData);

  } else if (!strcmp(class,"array")) {
    if ((nameData=SDDS_GetArrayNames(&(sddsFdTable[fd].table), &number)) 
	== NULL) {
      sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
      Tcl_AppendResult(interp, "sdds getNames: ", sddsErrs[0], NULL);
      SDDS_ClearErrors();
      free(sddsErrs[0]);
      return TCL_ERROR;
    }
    Tcl_DStringInit(&result);
    for (i=0 ; i < number ; i++)
      Tcl_DStringAppendElement(&result,nameData[i]);

    Tcl_DStringResult(interp, &result);
    for (i=0 ; i < number ; i++)
      free(nameData[i]);
    free(nameData);

  } else {
    Tcl_SetResult(interp, 
		  "sdds getNames: class must be column, parameter, or array", 
		  NULL);
    return TCL_ERROR;    
  }
  
  return TCL_OK;
}

/*****************************************
 *
 *****************************************/
int tclSDDSGetUnits(Tcl_Interp *interp, int argc, char *argv[]) {
  char **sddsErrs;
  int32_t sddsNumErrs;
  int fd;
  char *sddsFileId;
  char *class;
  long number, i;
  Tcl_DString result;

  if (argc < 3 || argc > 4) {
    Tcl_SetResult(interp, "usage: sdds getUnits <fd> [<class>]", NULL);
    return TCL_ERROR;    
  }
  sddsFileId = argv[2];
  if (argc == 4) {
    class = argv[3];
  } else {
    class = "column";
  }

  fd = atoi(sddsFileId);
  if ((fd > MAX_OPEN_SDDS_FILES) || (sddsFdTable[fd].free == 1)) { 
    Tcl_SetResult(interp, "sdds getUnits: unknown file descriptor", NULL);
    return TCL_ERROR;
  }
  if (sddsFdTable[fd].mode != 'r') {
    Tcl_SetResult(interp, "sdds getUnits: <fd> must be opened for reading",
		  NULL);
    return TCL_ERROR;
  }

  if (!strcmp(class,"column")) {
    char *units;
    Tcl_DStringInit(&result);
    number = SDDS_ColumnCount(&(sddsFdTable[fd].table));
    for (i=0; i<number; i++) {
      if (SDDS_GetColumnInformation(&(sddsFdTable[fd].table), "units", &units, SDDS_GET_BY_INDEX,
                                    i)!=SDDS_STRING) {
        sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
        Tcl_AppendResult(interp, "sdds getUnits: ", sddsErrs[0], NULL);
        SDDS_ClearErrors();
        free(sddsErrs[0]);
        return TCL_ERROR;
      }
      Tcl_DStringAppendElement(&result,units);
      free(units);
    }
    Tcl_DStringResult(interp, &result);
  } else if (!strcmp(class,"parameter")) {
    char *units;
    Tcl_DStringInit(&result);
    number = SDDS_ParameterCount(&(sddsFdTable[fd].table));
    for (i=0; i<number; i++) {
      if (SDDS_GetParameterInformation(&(sddsFdTable[fd].table), "units", &units, SDDS_GET_BY_INDEX,
                                    i)!=SDDS_STRING) {
        sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
        Tcl_AppendResult(interp, "sdds getUnits: ", sddsErrs[0], NULL);
        SDDS_ClearErrors();
        free(sddsErrs[0]);
        return TCL_ERROR;
      }
      Tcl_DStringAppendElement(&result,units);
      free(units);
    }
    Tcl_DStringResult(interp, &result);
  } else if (!strcmp(class,"array")) {
    char *units;
    Tcl_DStringInit(&result);
    number = SDDS_ArrayCount(&(sddsFdTable[fd].table));
    for (i=0; i<number; i++) {
      if (SDDS_GetArrayInformation(&(sddsFdTable[fd].table), "units", &units, SDDS_GET_BY_INDEX,
                                    i)!=SDDS_STRING) {
        sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
        Tcl_AppendResult(interp, "sdds getUnits: ", sddsErrs[0], NULL);
        SDDS_ClearErrors();
        free(sddsErrs[0]);
        return TCL_ERROR;
      }
      Tcl_DStringAppendElement(&result,units);
      free(units);
    }
    Tcl_DStringResult(interp, &result);
  } else {
    Tcl_SetResult(interp, 
		  "sdds getUnits: class must be column, parameter, or array", 
		  NULL);
    return TCL_ERROR;    
  }
  
  return TCL_OK;
}

/*****************************************
 *
 *****************************************/
int tclSDDSGetArray(Tcl_Interp *interp, int argc, char *argv[]) {
  char **sddsErrs;
  int32_t sddsNumErrs;
  int fd;
  char *sddsFileId;
  char *tclArrayName;
  char *sddsArrayName;
  char indexBuf[256];
  char valueBuf[256];

  SDDS_ARRAY *sddsArray; /* for reading in SDDS arrays */
  long arrayType;     
  long arrayDimensions;
  long arrayElements;
  int32_t arrayDim[5];
  long i,j;
  long double *ldoubleDataArray;
  double *doubleDataArray;
  float *floatDataArray;
  int64_t *long64DataArray;
  uint64_t *ulong64DataArray;
  int32_t *longDataArray;
  uint32_t *ulongDataArray;
  short *shortDataArray;
  unsigned short *ushortDataArray;
  char **stringDataArray;
  char *charDataArray;

  long desiredPage = 1; /* for keeping track of page in file */
  int allPages = 0;
  long pagesToGo = 0;
  long tableRead;

  if (argc != 7) {
    Tcl_SetResult(interp, "usage: sdds getArray <fd> <tclArrayName> <sddsArrayName> -page <n>",
		  NULL);
    return TCL_ERROR;    
  }

  sddsFileId = argv[2];
  tclArrayName = argv[3];
  sddsArrayName = argv[4];
  desiredPage = atoi(argv[6]);
  if (desiredPage <= 0) {
    Tcl_SetResult(interp, "sdds getArray: page must be > 0", NULL);
    return TCL_ERROR;
  }

  fd = atoi(sddsFileId);
  if ((fd > MAX_OPEN_SDDS_FILES) || (sddsFdTable[fd].free == 1)) { 
    Tcl_SetResult(interp, "sdds getArray: unknown file descriptor",
		  (Tcl_FreeProc *) NULL);
    return TCL_ERROR;
  }
  if (sddsFdTable[fd].mode != 'r') {
    Tcl_SetResult(interp, "sdds getArray: <fd> must be opened for reading",
		  NULL);
    return TCL_ERROR;
  }

  /* Find our current page location with respect to desired page */
  if ((allPages == 1 && sddsFdTable[fd].currentPage > 1) ||
      (allPages == 0 && desiredPage < sddsFdTable[fd].currentPage)) {
    if (tclSDDSReopenFd(fd)) {
      Tcl_SetResult(interp, 
		    "sdds getArray: unable to reopen file for page seek", 
		    NULL);
      return TCL_ERROR;
    }
  }
  if (desiredPage > sddsFdTable[fd].currentPage) {
    pagesToGo = desiredPage - sddsFdTable[fd].currentPage;
  }

  /* Read in until desired page */
  for (i=0 ; i < pagesToGo ; i++) {
    if ((tableRead = SDDS_ReadTable(&(sddsFdTable[fd].table))) <= 0) {
      if (tableRead == -1) {
	Tcl_SetResult(interp, "EOF", NULL);
	return TCL_ERROR;
      } else {
	sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	Tcl_AppendResult(interp, "sdds getArray: ", sddsErrs[0], NULL);
	SDDS_ClearErrors();
	free(sddsErrs[0]);
	return TCL_ERROR;	
      }
    }
    sddsFdTable[fd].currentPage++;
  }

  if (!(sddsArray=SDDS_GetArray(&(sddsFdTable[fd].table), sddsArrayName, NULL))) {
    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
    Tcl_AppendResult(interp, "sdds getArray: ", sddsErrs[0], NULL);
    SDDS_ClearErrors();
    free(sddsErrs[0]);
    return TCL_ERROR;
  }
  
  arrayType = sddsArray->definition->type;
  arrayDimensions = sddsArray->definition->dimensions;
  arrayElements = sddsArray->elements;
  if (arrayDimensions > 4) {
    Tcl_SetResult(interp, "sdds getArray: unable to handle array dimensions greater then 4", NULL);
    return TCL_ERROR;
  }
  for (i=0 ; i < arrayDimensions ; i++) {
    arrayDim[i] = sddsArray->dimension[i];
  }
  switch (arrayType) {
  case SDDS_LONGDOUBLE: {
    ldoubleDataArray = (long double *)sddsArray->data;
    for (i=0 ; i < arrayElements ; i++) {
      constructIndex(i, arrayDimensions, arrayDim, indexBuf);
      sprintf(valueBuf,"%23.20Le",ldoubleDataArray[i]);
      if (Tcl_SetVar2(interp,tclArrayName,indexBuf,valueBuf,0) == NULL) {
	Tcl_SetResult(interp,"sdds getArray: unable to set tcl array element", 
		      NULL);
	free(sddsArray->data);
	free(sddsArray->pointer);
	free(sddsArray->dimension);
	return TCL_ERROR;	
      }
    }
    free(sddsArray->data);
    free(sddsArray->pointer);
    free(sddsArray->dimension);
    break;
  }
  case SDDS_DOUBLE: {
    doubleDataArray = (double *)sddsArray->data;
    for (i=0 ; i < arrayElements ; i++) {
      constructIndex(i, arrayDimensions, arrayDim, indexBuf);
      sprintf(valueBuf,"%23.17e",doubleDataArray[i]);
      if (Tcl_SetVar2(interp,tclArrayName,indexBuf,valueBuf,0) == NULL) {
	Tcl_SetResult(interp,"sdds getArray: unable to set tcl array element", 
		      NULL);
	free(sddsArray->data);
	free(sddsArray->pointer);
	free(sddsArray->dimension);
	return TCL_ERROR;	
      }
    }
    free(sddsArray->data);
    free(sddsArray->pointer);
    free(sddsArray->dimension);
    break;
  }
  case SDDS_FLOAT: {
    floatDataArray = (float *)sddsArray->data;
    for (i=0 ; i < arrayElements ; i++) {
      constructIndex(i, arrayDimensions, arrayDim, indexBuf);
      sprintf(valueBuf,"%23.17e",floatDataArray[i]);
      if (Tcl_SetVar2(interp,tclArrayName,indexBuf,valueBuf,0) == NULL) {
	Tcl_SetResult(interp,"sdds getArray: unable to set tcl array element", 
		      NULL);
	free(sddsArray->data);
	free(sddsArray->pointer);
	free(sddsArray->dimension);
	return TCL_ERROR;	
      }
    }
    free(sddsArray->data);
    free(sddsArray->pointer);
    free(sddsArray->dimension);
    break;
  }
  case SDDS_LONG64: {
    long64DataArray = (int64_t *)sddsArray->data;
    for (i=0 ; i < arrayElements ; i++) {
      constructIndex(i, arrayDimensions, arrayDim, indexBuf);
      sprintf(valueBuf,"%" PRId64,long64DataArray[i]);
      if (Tcl_SetVar2(interp,tclArrayName,indexBuf,valueBuf,0) == NULL) {
	Tcl_SetResult(interp,"sdds getArray: unable to set tcl array element", 
		      NULL);
	free(sddsArray->data);
	free(sddsArray->pointer);
	free(sddsArray->dimension);
	return TCL_ERROR;	
      }
    }
    free(sddsArray->data);
    free(sddsArray->pointer);
    free(sddsArray->dimension);
    break;
  }
  case SDDS_ULONG64: {
    ulong64DataArray = (uint64_t *)sddsArray->data;
    for (i=0 ; i < arrayElements ; i++) {
      constructIndex(i, arrayDimensions, arrayDim, indexBuf);
      sprintf(valueBuf,"%" PRIu64,ulong64DataArray[i]);
      if (Tcl_SetVar2(interp,tclArrayName,indexBuf,valueBuf,0) == NULL) {
	Tcl_SetResult(interp,"sdds getArray: unable to set tcl array element", 
		      NULL);
	free(sddsArray->data);
	free(sddsArray->pointer);
	free(sddsArray->dimension);
	return TCL_ERROR;	
      }
    }
    free(sddsArray->data);
    free(sddsArray->pointer);
    free(sddsArray->dimension);
    break;
  }
  case SDDS_LONG: {
    longDataArray = (int32_t *)sddsArray->data;
    for (i=0 ; i < arrayElements ; i++) {
      constructIndex(i, arrayDimensions, arrayDim, indexBuf);
      sprintf(valueBuf,"%" PRId32,longDataArray[i]);
      if (Tcl_SetVar2(interp,tclArrayName,indexBuf,valueBuf,0) == NULL) {
	Tcl_SetResult(interp,"sdds getArray: unable to set tcl array element", 
		      NULL);
	free(sddsArray->data);
	free(sddsArray->pointer);
	free(sddsArray->dimension);
	return TCL_ERROR;	
      }
    }
    free(sddsArray->data);
    free(sddsArray->pointer);
    free(sddsArray->dimension);
    break;
  }
  case SDDS_ULONG: {
    ulongDataArray = (uint32_t *)sddsArray->data;
    for (i=0 ; i < arrayElements ; i++) {
      constructIndex(i, arrayDimensions, arrayDim, indexBuf);
      sprintf(valueBuf,"%" PRIu32,ulongDataArray[i]);
      if (Tcl_SetVar2(interp,tclArrayName,indexBuf,valueBuf,0) == NULL) {
	Tcl_SetResult(interp,"sdds getArray: unable to set tcl array element", 
		      NULL);
	free(sddsArray->data);
	free(sddsArray->pointer);
	free(sddsArray->dimension);
	return TCL_ERROR;	
      }
    }
    free(sddsArray->data);
    free(sddsArray->pointer);
    free(sddsArray->dimension);
    break;
  }
  case SDDS_SHORT: {
    shortDataArray = (short *)sddsArray->data;
    for (i=0 ; i < arrayElements ; i++) {
      constructIndex(i, arrayDimensions, arrayDim, indexBuf);
      sprintf(valueBuf,"%d",shortDataArray[i]);
      if (Tcl_SetVar2(interp,tclArrayName,indexBuf,valueBuf,0) == NULL) {
	Tcl_SetResult(interp,"sdds getArray: unable to set tcl array element", 
		      NULL);
	free(sddsArray->data);
	free(sddsArray->pointer);
	free(sddsArray->dimension);
	return TCL_ERROR;	
      }
    }
    free(sddsArray->data);
    free(sddsArray->pointer);
    free(sddsArray->dimension);
    break;
  }
  case SDDS_USHORT: {
    ushortDataArray = (unsigned short *)sddsArray->data;
    for (i=0 ; i < arrayElements ; i++) {
      constructIndex(i, arrayDimensions, arrayDim, indexBuf);
      sprintf(valueBuf,"%u",ushortDataArray[i]);
      if (Tcl_SetVar2(interp,tclArrayName,indexBuf,valueBuf,0) == NULL) {
	Tcl_SetResult(interp,"sdds getArray: unable to set tcl array element", 
		      NULL);
	free(sddsArray->data);
	free(sddsArray->pointer);
	free(sddsArray->dimension);
	return TCL_ERROR;	
      }
    }
    free(sddsArray->data);
    free(sddsArray->pointer);
    free(sddsArray->dimension);
    break;
  }
  case SDDS_STRING: {
    stringDataArray = (char **)sddsArray->data;
    for (i=0 ; i < arrayElements ; i++) {
      constructIndex(i, arrayDimensions, arrayDim, indexBuf);
      if (Tcl_SetVar2(interp,tclArrayName,indexBuf,stringDataArray[i],0) == NULL) {
	Tcl_SetResult(interp,"sdds getArray: unable to set tcl array element", 
		      NULL);
	for (j=0 ; j < arrayElements ; j++) 
	  free(stringDataArray[i]);
	free(sddsArray->data);
	free(sddsArray->pointer);
	free(sddsArray->dimension);
	return TCL_ERROR;	
      }
    }
    for (j=0 ; j < arrayElements ; j++) 
      free(stringDataArray[i]);
    free(sddsArray->data);
    free(sddsArray->pointer);
    free(sddsArray->dimension);
    break;
  }
  case SDDS_CHARACTER: {
    charDataArray = (char *)sddsArray->data;
    for (i=0 ; i < arrayElements ; i++) {
      constructIndex(i, arrayDimensions, arrayDim, indexBuf);
      sprintf(valueBuf,"%c",charDataArray[i]);
      if (Tcl_SetVar2(interp,tclArrayName,indexBuf,valueBuf,0) == NULL) {
	Tcl_SetResult(interp,"sdds getArray: unable to set tcl array element", 
		      NULL);
	free(sddsArray->data);
	free(sddsArray->pointer);
	free(sddsArray->dimension);
	return TCL_ERROR;	
      }
    }
    free(sddsArray->data);
    free(sddsArray->pointer);
    free(sddsArray->dimension);
    break;
  }}

  return TCL_OK;
}

/*****************************************
 *
 *****************************************/
int tclSDDSGetArrayInformation(Tcl_Interp *interp, int argc, char *argv[]) {
  char **sddsErrs;
  int32_t sddsNumErrs;
  int fd;
  char *sddsFileId;
  char *arrayName;
  char *tclArrayName;
  
  int32_t type;     /* for reading in SDDS Array information */
  char *name;
  char *symbol;
  char *units;
  char *description;
  char *format_string;
  char *group_name;
  int32_t field_length;
  int32_t dimensions;

  char valueBuf[tclSDDS_BUFSIZE];    

  if (argc != 5) {
    Tcl_SetResult(interp, "usage: sdds getArrayInformation <fd> <arrayName> <tclArrayName>",
		  NULL);
    return TCL_ERROR;    
  }

  sddsFileId = argv[2];
  arrayName = argv[3];
  tclArrayName = argv[4];

  fd = atoi(sddsFileId);
  if ((fd > MAX_OPEN_SDDS_FILES) || (sddsFdTable[fd].free == 1)) { 
    Tcl_SetResult(interp, "sdds getArrayInformation: unknown file descriptor",
		  (Tcl_FreeProc *) NULL);
    return TCL_ERROR;
  }
  if (sddsFdTable[fd].mode != 'r') {
    Tcl_SetResult(interp, "sdds getArrayInformation: <fd> must be opened for reading",
		  NULL);
    return TCL_ERROR;
  }

  if (SDDS_GetArrayInformation(&(sddsFdTable[fd].table), "name", 
				&name,SDDS_GET_BY_NAME, arrayName) 
      == 0) {
    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
    Tcl_AppendResult(interp, "sdds getArrayInformation: ", sddsErrs[0], NULL);
    SDDS_ClearErrors();
    free(sddsErrs[0]);
    return TCL_ERROR;
  }

  if (SDDS_GetArrayInformation(&(sddsFdTable[fd].table), "symbol", 
				&symbol,SDDS_GET_BY_NAME, arrayName) 
      == 0) {
    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
    Tcl_AppendResult(interp, "sdds getArrayInformation: ", sddsErrs[0], NULL);
    SDDS_ClearErrors();
    free(sddsErrs[0]);
    if (name) free(name);
    return TCL_ERROR;
  }

  if (SDDS_GetArrayInformation(&(sddsFdTable[fd].table), "units", 
				&units,SDDS_GET_BY_NAME, arrayName) 
      == 0) {
    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
    Tcl_AppendResult(interp, "sdds getArrayInformation: ", sddsErrs[0], NULL);
    SDDS_ClearErrors();
    free(sddsErrs[0]);
    if (name) free(name);
    if (symbol) free(symbol);
    return TCL_ERROR;
  }

  if (SDDS_GetArrayInformation(&(sddsFdTable[fd].table), "description", 
				&description,SDDS_GET_BY_NAME, arrayName) 
      == 0) {
    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
    Tcl_AppendResult(interp, "sdds getArrayInformation: ", sddsErrs[0], NULL);
    SDDS_ClearErrors();
    free(sddsErrs[0]);
    if (name) free(name);
    if (symbol) free(symbol);
    if (units) free(units);
    return TCL_ERROR;
  }

  if (SDDS_GetArrayInformation(&(sddsFdTable[fd].table), "format_string", 
				&format_string,SDDS_GET_BY_NAME, arrayName) 
      == 0) {
    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
    Tcl_AppendResult(interp, "sdds getArrayInformation: ", sddsErrs[0], NULL);
    SDDS_ClearErrors();
    free(sddsErrs[0]);
    if (name) free(name);
    if (symbol) free(symbol);
    if (units) free(units);
    if (description) free(description);
    return TCL_ERROR;
  }

  if (SDDS_GetArrayInformation(&(sddsFdTable[fd].table), "group_name", 
				&group_name,SDDS_GET_BY_NAME, arrayName) 
      == 0) {
    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
    Tcl_AppendResult(interp, "sdds getArrayInformation: ", sddsErrs[0], NULL);
    SDDS_ClearErrors();
    free(sddsErrs[0]);
    if (name) free(name);
    if (symbol) free(symbol);
    if (units) free(units);
    if (description) free(description);
    if (format_string) free(format_string);
    return TCL_ERROR;
  }

  if (SDDS_GetArrayInformation(&(sddsFdTable[fd].table), "type", 
				&type,SDDS_GET_BY_NAME, arrayName) 
      == 0) {
    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
    Tcl_AppendResult(interp, "sdds getArrayInformation: ", sddsErrs[0], NULL);
    SDDS_ClearErrors();
    free(sddsErrs[0]);
    if (name) free(name);
    if (symbol) free(symbol);
    if (units) free(units);
    if (description) free(description);
    if (format_string) free(format_string);
    if (group_name) free(group_name);
    return TCL_ERROR;
  }

  if (SDDS_GetArrayInformation(&(sddsFdTable[fd].table), "field_length", 
				&field_length,SDDS_GET_BY_NAME, arrayName) 
      == 0) {
    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
    Tcl_AppendResult(interp, "sdds getArrayInformation: ", sddsErrs[0], NULL);
    SDDS_ClearErrors();
    free(sddsErrs[0]);
    if (name) free(name);
    if (symbol) free(symbol);
    if (units) free(units);
    if (description) free(description);
    if (format_string) free(format_string);
    if (group_name) free(group_name);
    return TCL_ERROR;
  }

  if (SDDS_GetArrayInformation(&(sddsFdTable[fd].table), "dimensions", 
				&dimensions,SDDS_GET_BY_NAME, arrayName) 
      == 0) {
    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
    Tcl_AppendResult(interp, "sdds getArrayInformation: ", sddsErrs[0], NULL);
    SDDS_ClearErrors();
    free(sddsErrs[0]);
    if (name) free(name);
    if (symbol) free(symbol);
    if (units) free(units);
    if (description) free(description);
    if (format_string) free(format_string);
    if (group_name) free(group_name);
    return TCL_ERROR;
  }

  if (Tcl_SetVar2(interp,tclArrayName,"name",name==NULL?"":name,0) == NULL) {
    Tcl_SetResult(interp,"sdds getArrayInformation: unable to set tcl array element", NULL);
    if (name) free(name);
    if (symbol) free(symbol);
    if (units) free(units);
    if (description) free(description);
    if (format_string) free(format_string);
    if (group_name) free(group_name);
    return TCL_ERROR;
  }

  if (Tcl_SetVar2(interp,tclArrayName,"symbol",symbol==NULL?"":symbol,0) == NULL) {
    Tcl_SetResult(interp,"sdds getArrayInformation: unable to set tcl array element", NULL);
    if (name) free(name);
    if (symbol) free(symbol);
    if (units) free(units);
    if (description) free(description);
    if (format_string) free(format_string);
    if (group_name) free(group_name);
    return TCL_ERROR;
  }

  if (Tcl_SetVar2(interp,tclArrayName,"units",units==NULL?"":units,0) == NULL) {
    Tcl_SetResult(interp,"sdds getArrayInformation: unable to set tcl array element", NULL);
    if (name) free(name);
    if (symbol) free(symbol);
    if (units) free(units);
    if (description) free(description);
    if (format_string) free(format_string);
    if (group_name) free(group_name);
    return TCL_ERROR;
  }

  if (Tcl_SetVar2(interp,tclArrayName,"description",description==NULL?"":description,0) == NULL) {
    Tcl_SetResult(interp,"sdds getArrayInformation: unable to set tcl array element", NULL);
    if (name) free(name);
    if (symbol) free(symbol);
    if (units) free(units);
    if (description) free(description);
    if (format_string) free(format_string);
    if (group_name) free(group_name);
    return TCL_ERROR;
  }

  if (Tcl_SetVar2(interp,tclArrayName,"format_string",format_string==NULL?"":format_string,0) == NULL) {
    Tcl_SetResult(interp,"sdds getArrayInformation: unable to set tcl array element", NULL);
    if (name) free(name);
    if (symbol) free(symbol);
    if (units) free(units);
    if (description) free(description);
    if (format_string) free(format_string);
    if (group_name) free(group_name);
    return TCL_ERROR;
  }

  if (Tcl_SetVar2(interp,tclArrayName,"group_name",group_name==NULL?"":group_name,0) == NULL) {
    Tcl_SetResult(interp,"sdds getArrayInformation: unable to set tcl array element", NULL);
    if (name) free(name);
    if (symbol) free(symbol);
    if (units) free(units);
    if (description) free(description);
    if (format_string) free(format_string);
    if (group_name) free(group_name);
    return TCL_ERROR;
  }

  if (Tcl_SetVar2(interp,tclArrayName,"type",
		  convertNumericToTypeString(type),0) == NULL) {
    Tcl_SetResult(interp,"sdds getArrayInformation: unable to set tcl array element", NULL);
    if (name) free(name);
    if (symbol) free(symbol);
    if (units) free(units);
    if (description) free(description);
    if (format_string) free(format_string);
    if (group_name) free(group_name);
    return TCL_ERROR;
  }

  sprintf(valueBuf,"%" PRId32,field_length);
  if (Tcl_SetVar2(interp,tclArrayName,"field_length",valueBuf,0) == NULL) {
    Tcl_SetResult(interp,"sdds getArrayInformation: unable to set tcl array element", NULL);
    if (name) free(name);
    if (symbol) free(symbol);
    if (units) free(units);
    if (description) free(description);
    if (format_string) free(format_string);
    if (group_name) free(group_name);
    return TCL_ERROR;
  }

  sprintf(valueBuf,"%" PRId32,dimensions);
  if (Tcl_SetVar2(interp,tclArrayName,"dimensions",valueBuf,0) == NULL) {
    Tcl_SetResult(interp,"sdds getArrayInformation: unable to set tcl array element", NULL);
    if (name) free(name);
    if (symbol) free(symbol);
    if (units) free(units);
    if (description) free(description);
    if (format_string) free(format_string);
    if (group_name) free(group_name);
    return TCL_ERROR;
  }
    
  return TCL_OK;
}


/*****************************************
 *
 *****************************************/
int tclSDDSDefineColumn(Tcl_Interp *interp, int argc, char *argv[]) {
  char **sddsErrs;
  int32_t sddsNumErrs;
  int fd, i;
  char buffer[tclSDDS_BUFSIZE];
  long ntype;        /* numeric version of type */
  long nfieldLength; /* numeric verison of fieldLength */

  /* Required arguments */
  char *sddsFileId;
  char *columnName;
  
  /* Optional argument defaults */
  char *type = "SDDS_STRING";
  char *symbol = NULL;
  char *units = NULL;
  char *description = NULL;
  char *formatString = NULL;
  char *fieldLength = NULL;

  if (argc < 4 || ((argc%2) != 0)) {
    Tcl_SetResult(interp, 
		  "usage: sdds defineColumn <fd> <columnName> [-type <string>] [-symbol <string>] [-units <string>] [-description <string>] [-formatString <string>] [-fieldLength <int>]",
		  NULL);
    return TCL_ERROR;    
  }
  sddsFileId = argv[2];
  columnName = argv[3];

  /* Process optional arguments */
  for (i=4 ; i < argc ; i+=2) {
    if (!strcmp(argv[i],"-type")) {
      type = argv[i+1];
    } else if (!strcmp(argv[i],"-symbol")) {
      symbol = argv[i+1];
    } else if (!strcmp(argv[i],"-units")) {
      units = argv[i+1];
    } else if (!strcmp(argv[i],"-description")) {
      description = argv[i+1];
    } else if (!strcmp(argv[i],"-formatString")) {
      formatString = argv[i+1];
    } else if (!strcmp(argv[i],"-fieldLength")) {
      fieldLength = argv[i+1];
    } else {
      sprintf(buffer,"sdds defineColumn: unknown option %s",argv[i]);
      Tcl_SetResult(interp, buffer, NULL);
      return TCL_ERROR;
    }
  }

  fd = atoi(sddsFileId);
  if ((fd > MAX_OPEN_SDDS_FILES) || (sddsFdTable[fd].free == 1)) { 
    Tcl_SetResult(interp, "sdds defineColumn: unknown file descriptor", NULL);
    return TCL_ERROR;
  }
  if (sddsFdTable[fd].mode != 'w') {
    Tcl_SetResult(interp, "sdds defineColumn: <fd> must be opened for writing",
		  NULL);
    return TCL_ERROR;
  }
  /* Convert type and fieldLength arguments to integers */
  if ((ntype = convertTypeStringToNumeric(type)) == -1) {
    Tcl_SetResult(interp, "sdds defineColumn: invalid type given",NULL);
    return TCL_ERROR;
  }
  if (fieldLength != NULL) {
    nfieldLength = atoi(fieldLength);
  } else {
    nfieldLength = 0;
  }

  /* define column */
  if (SDDS_DefineColumn(&(sddsFdTable[fd].table), columnName, symbol, units,
			description, formatString, ntype, nfieldLength)
      == -1) {
    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
    Tcl_AppendResult(interp, "sdds defineColumn: ", sddsErrs[0], NULL);
    SDDS_ClearErrors();
    free(sddsErrs[0]);
    return TCL_ERROR;
  }
  return TCL_OK;
}

/*****************************************
 *
 *****************************************/
int tclSDDSDefineParameter(Tcl_Interp *interp, int argc, char *argv[]) {
  char **sddsErrs;
  int32_t sddsNumErrs;
  int fd, i;
  char buffer[tclSDDS_BUFSIZE];
  long ntype;        /* numeric version of type */

  /* Required arguments */
  char *sddsFileId;
  char *parameterName;
  
  /* Optional argument defaults */
  char *type = "SDDS_STRING";
  char *symbol = NULL;
  char *units = NULL;
  char *description = NULL;
  char *formatString = NULL;
  char *fixedValue = NULL;

  if (argc < 4 || ((argc%2) != 0)) {
    Tcl_SetResult(interp, 
		  "usage: sdds defineParameter <fd> <parameterName> [-type <string>] [-symbol <string>] [-units <string>] [-description <string>] [-formatString <string>] [-fixedValue <string>]",
		  NULL);
    return TCL_ERROR;    
  }
  sddsFileId = argv[2];
  parameterName = argv[3];

  /* Process optional arguments */
  for (i=4 ; i < argc ; i+=2) {
    if (!strcmp(argv[i],"-type")) {
      type = argv[i+1];
    } else if (!strcmp(argv[i],"-symbol")) {
      symbol = argv[i+1];
    } else if (!strcmp(argv[i],"-units")) {
      units = argv[i+1];
    } else if (!strcmp(argv[i],"-description")) {
      description = argv[i+1];
    } else if (!strcmp(argv[i],"-formatString")) {
      formatString = argv[i+1];
    } else if (!strcmp(argv[i],"-fixedValue")) {
      fixedValue = argv[i+1];
    } else {
      sprintf(buffer,"sdds defineParameter: unknown option %s",argv[i]);
      Tcl_SetResult(interp, buffer, NULL);
      return TCL_ERROR;
    }
  }

  fd = atoi(sddsFileId);
  if ((fd > MAX_OPEN_SDDS_FILES) || (sddsFdTable[fd].free == 1)) { 
    Tcl_SetResult(interp, "sdds defineParameter: unknown file descriptor", NULL);
    return TCL_ERROR;
  }
  if (sddsFdTable[fd].mode != 'w') {
    Tcl_SetResult(interp, "sdds defineParameter: <fd> must be opened for writing",
		  NULL);
    return TCL_ERROR;
  }
  /* Convert type argument to integer */
  if ((ntype = convertTypeStringToNumeric(type)) == -1) {
    Tcl_SetResult(interp, "sdds defineParameter: invalid type given",NULL);
    return TCL_ERROR;
  }

  /* define parameter */
  if (SDDS_DefineParameter(&(sddsFdTable[fd].table), parameterName, symbol, 
			   units, description, formatString, ntype, 
			   fixedValue)
      == -1) {
    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
    Tcl_AppendResult(interp, "sdds defineParameter: ", sddsErrs[0], NULL);
    SDDS_ClearErrors();
    free(sddsErrs[0]);
    return TCL_ERROR;
  }
  return TCL_OK;
}


/*****************************************
 *
 *****************************************/
int tclSDDSDefineArray(Tcl_Interp *interp, int argc, char *argv[]) {
  char **sddsErrs;
  int32_t sddsNumErrs;
  int fd, i;
  char buffer[tclSDDS_BUFSIZE];
  long ntype;        /* numeric version of type */
  long nfieldLength; /* numeric verison of fieldLength */
  long ndimensions;  /* numeric version of dimensions */

  /* Required arguments */
  char *sddsFileId;
  char *arrayName;
  
  /* Optional argument defaults */
  char *type = "SDDS_STRING";
  char *symbol = NULL;
  char *units = NULL;
  char *description = NULL;
  char *formatString = NULL;
  char *fieldLength = NULL;
  char *dimensions = NULL;
  char *groupName = NULL;

  if (argc < 4 || ((argc%2) != 0)) {
    Tcl_SetResult(interp, 
		  "usage: sdds defineArray <fd> <arrayName> [-type <string>] [-symbol <string>] [-units <string>] [-description <string>] [-formatString <string>] [-fieldLength <int>] [-dimensions <int>] [-groupName <string>]",
		  NULL);
    return TCL_ERROR;    
  }
  sddsFileId = argv[2];
  arrayName = argv[3];

  /* Process optional arguments */
  for (i=4 ; i < argc ; i+=2) {
    if (!strcmp(argv[i],"-type")) {
      type = argv[i+1];
    } else if (!strcmp(argv[i],"-symbol")) {
      symbol = argv[i+1];
    } else if (!strcmp(argv[i],"-units")) {
      units = argv[i+1];
    } else if (!strcmp(argv[i],"-description")) {
      description = argv[i+1];
    } else if (!strcmp(argv[i],"-formatString")) {
      formatString = argv[i+1];
    } else if (!strcmp(argv[i],"-fieldLength")) {
      fieldLength = argv[i+1];
    } else if (!strcmp(argv[i],"-dimensions")) {
      dimensions = argv[i+1];
    } else if (!strcmp(argv[i],"-groupName")) {
      groupName = argv[i+1];
    } else {
      sprintf(buffer,"sdds defineArray: unknown option %s",argv[i]);
      Tcl_SetResult(interp, buffer, NULL);
      return TCL_ERROR;
    }
  }

  fd = atoi(sddsFileId);
  if ((fd > MAX_OPEN_SDDS_FILES) || (sddsFdTable[fd].free == 1)) { 
    Tcl_SetResult(interp, "sdds defineArray: unknown file descriptor", NULL);
    return TCL_ERROR;
  }
  if (sddsFdTable[fd].mode != 'w') {
    Tcl_SetResult(interp, "sdds defineArray: <fd> must be opened for writing",
		  NULL);
    return TCL_ERROR;
  }
  /* Convert string arguments to integer */
  if ((ntype = convertTypeStringToNumeric(type)) == -1) {
    Tcl_SetResult(interp, "sdds defineArray: invalid type given",NULL);
    return TCL_ERROR;
  }
  if (fieldLength != NULL) {
    nfieldLength = atoi(fieldLength);
  } else {
    nfieldLength = 0;
  }
  if (dimensions != NULL) {
    ndimensions = atoi(dimensions);
    if (ndimensions > 4) {
      Tcl_SetResult(interp, "sdds defineArray: max dimension is 4",NULL);
      return TCL_ERROR;
    }
  } else {
    ndimensions = 1;
  }

  /* define array */
  if (SDDS_DefineArray(&(sddsFdTable[fd].table), arrayName, symbol, units,
		       description, formatString, ntype, nfieldLength,
		       ndimensions, groupName)
      == -1) {
    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
    Tcl_AppendResult(interp, "sdds defineArray: ", sddsErrs[0], NULL);
    SDDS_ClearErrors();
    free(sddsErrs[0]);
    return TCL_ERROR;
  }
  return TCL_OK;
}

/*****************************************
 *
 *****************************************/
int tclSDDSStartPage(Tcl_Interp *interp, int argc, char *argv[]) {
  char **sddsErrs;
  int32_t sddsNumErrs;
  int fd;
  long nexpectedRows;

  /* Required arguments */
  char *sddsFileId;
  char *expectedRows;
  
  if (argc != 4) {
    Tcl_SetResult(interp, "usage: sdds startPage <fd> <expectedRows>",NULL);
    return TCL_ERROR;    
  }
  sddsFileId = argv[2];
  fd = atoi(sddsFileId);
  expectedRows = argv[3];
  
  if (expectedRows != NULL) {
    nexpectedRows = atoi(expectedRows);
  } else {
    nexpectedRows = 100;
  }

  if (!SDDS_StartPage(&(sddsFdTable[fd].table), nexpectedRows)) {
    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
    Tcl_AppendResult(interp, "sdds startPage: ", sddsErrs[0], NULL);
    SDDS_ClearErrors();
    free(sddsErrs[0]);
    return TCL_ERROR;
  }
  sddsFdTable[fd].pageStarted = 1;
  return TCL_OK;
}

/*****************************************
 *
 *****************************************/
int tclSDDSWritePage(Tcl_Interp *interp, int argc, char *argv[]) {
  char **sddsErrs;
  int32_t sddsNumErrs;
  int fd;

  /* Required arguments */
  char *sddsFileId;
  
  if (argc != 3) {
    Tcl_SetResult(interp, "usage: sdds writePage <fd>",NULL);
    return TCL_ERROR;    
  }
  sddsFileId = argv[2];
  fd = atoi(sddsFileId);
  
  if (!SDDS_WritePage(&(sddsFdTable[fd].table))) {
    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
    Tcl_AppendResult(interp, "sdds writePage: ", sddsErrs[0], NULL);
    SDDS_ClearErrors();
    free(sddsErrs[0]);
    return TCL_ERROR;
  }
  sddsFdTable[fd].pageStarted = 0;
  return TCL_OK;
}


/*****************************************
 *
 *****************************************/
int tclSDDSWriteLayout(Tcl_Interp *interp, int argc, char *argv[]) {
  char **sddsErrs;
  int32_t sddsNumErrs;
  int fd;

  /* Required arguments */
  char *sddsFileId;
  
  if (argc != 3) {
    Tcl_SetResult(interp, "usage: sdds writeLayout <fd>",NULL);
    return TCL_ERROR;    
  }
  sddsFileId = argv[2];
  fd = atoi(sddsFileId);
  
  if (!SDDS_WriteLayout(&(sddsFdTable[fd].table))) {
    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
    Tcl_AppendResult(interp, "sdds writeLayout: ", sddsErrs[0], NULL);
    SDDS_ClearErrors();
    free(sddsErrs[0]);
    return TCL_ERROR;
  }
  return TCL_OK;
}

/*****************************************
 *
 *****************************************/
int tclSDDSSetParameter(Tcl_Interp *interp, int argc, char *argv[]) {
  char **sddsErrs;
  int32_t sddsNumErrs;
  int fd;
  
  long setMode = (SDDS_SET_BY_NAME | SDDS_PASS_BY_VALUE);

  int32_t parameterType;
  long double ldoubleData;
  double doubleData;
  float floatData;
  int64_t long64Data;
  uint64_t ulong64Data;
  int32_t longData;
  uint32_t ulongData;
  int intData;
  short shortData;
  unsigned short ushortData;

  /* Required arguments */
  char *sddsFileId;
  char *parameterName;
  char *parameterValue;
  
  if (argc != 5) {
    Tcl_SetResult(interp, 
		  "usage: sdds setParameter <fd> <parameterName> <parameterValue>", NULL);
    return TCL_ERROR;    
  }
  sddsFileId = argv[2];
  parameterName = argv[3];
  parameterValue = argv[4];

  fd = atoi(sddsFileId);
  if ((fd > MAX_OPEN_SDDS_FILES) || (sddsFdTable[fd].free == 1)) { 
    Tcl_SetResult(interp, "sdds setParameter: unknown file descriptor", NULL);
    return TCL_ERROR;
  }
  if (sddsFdTable[fd].mode != 'w') {
    Tcl_SetResult(interp, "sdds setParameter: <fd> must be opened for writing",
		  NULL);
    return TCL_ERROR;
  }
  if (!sddsFdTable[fd].pageStarted) {
    Tcl_SetResult(interp, "sdds setParameter: you must call startPage first",
		  NULL);
    return TCL_ERROR;
  }

  /* Get native data type of parameter, as given from DefineParameter call */
  if (SDDS_GetParameterInformation(&(sddsFdTable[fd].table), "type", 
				   &parameterType, SDDS_GET_BY_NAME, 
				   parameterName) == 0) {
    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
    Tcl_AppendResult(interp, "sdds setParameter: ", sddsErrs[0], NULL);
    SDDS_ClearErrors();
    free(sddsErrs[0]);
    return TCL_ERROR;
  }  

  /* Convert tcl string to native data type, and set parameter value */
  switch (parameterType) {
  case SDDS_LONGDOUBLE: {
    ldoubleData = strtold(parameterValue, NULL);
    if (!SDDS_SetParameters(&(sddsFdTable[fd].table),setMode,parameterName,
			    ldoubleData, NULL)) {
      sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
      Tcl_AppendResult(interp, "sdds setParameter: ", sddsErrs[0], NULL);
      SDDS_ClearErrors();
      free(sddsErrs[0]);
      return TCL_ERROR;
    }
    break;
  }
  case SDDS_DOUBLE: {
    if (Tcl_GetDouble(interp,parameterValue,&doubleData) != TCL_OK) {
      Tcl_SetResult(interp, "sdds setParameter:  value cannot be converted to native data type (SDDS_DOUBLE)",NULL);
      return TCL_ERROR;
    }
    if (!SDDS_SetParameters(&(sddsFdTable[fd].table),setMode,parameterName,
			    doubleData, NULL)) {
      sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
      Tcl_AppendResult(interp, "sdds setParameter: ", sddsErrs[0], NULL);
      SDDS_ClearErrors();
      free(sddsErrs[0]);
      return TCL_ERROR;
    }
    break;
  }
  case SDDS_FLOAT: {
    if (Tcl_GetDouble(interp,parameterValue,&doubleData) != TCL_OK) {
      Tcl_SetResult(interp, "sdds setParameter:  value cannot be converted to native data type (SDDS_FLOAT)",NULL);
      return TCL_ERROR;
    }
    floatData = doubleData;
    if (!SDDS_SetParameters(&(sddsFdTable[fd].table),setMode,parameterName,
			    floatData, NULL)) {
      sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
      Tcl_AppendResult(interp, "sdds setParameter: ", sddsErrs[0], NULL);
      SDDS_ClearErrors();
      free(sddsErrs[0]);
      return TCL_ERROR;
    }
    break;
  }
  case SDDS_LONG64: {
    long64Data = (int64_t)atoll(parameterValue);
    if (!SDDS_SetParameters(&(sddsFdTable[fd].table),setMode,parameterName,
			    long64Data, NULL)) {
      sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
      Tcl_AppendResult(interp, "sdds setParameter: ", sddsErrs[0], NULL);
      SDDS_ClearErrors();
      free(sddsErrs[0]);
      return TCL_ERROR;
    }
    break;
  }
  case SDDS_ULONG64: {
    ulong64Data = (uint64_t)strtoull(parameterValue, NULL, 10);
    if (!SDDS_SetParameters(&(sddsFdTable[fd].table),setMode,parameterName,
			    ulong64Data, NULL)) {
      sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
      Tcl_AppendResult(interp, "sdds setParameter: ", sddsErrs[0], NULL);
      SDDS_ClearErrors();
      free(sddsErrs[0]);
      return TCL_ERROR;
    }
    break;
  }
  case SDDS_LONG: {
    if (Tcl_GetInt(interp,parameterValue,&intData) != TCL_OK) {
      Tcl_SetResult(interp, "sdds setParameter:  value cannot be converted to native data type (SDDS_LONG)",NULL);
      return TCL_ERROR;
    }
    longData = intData;
    if (!SDDS_SetParameters(&(sddsFdTable[fd].table),setMode,parameterName,
			    longData, NULL)) {
      sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
      Tcl_AppendResult(interp, "sdds setParameter: ", sddsErrs[0], NULL);
      SDDS_ClearErrors();
      free(sddsErrs[0]);
      return TCL_ERROR;
    }
    break;
  }
  case SDDS_ULONG: {
    if (Tcl_GetInt(interp,parameterValue,&intData) != TCL_OK) {
      Tcl_SetResult(interp, "sdds setParameter:  value cannot be converted to native data type (SDDS_ULONG)",NULL);
      return TCL_ERROR;
    }
    ulongData = intData;
    if (!SDDS_SetParameters(&(sddsFdTable[fd].table),setMode,parameterName,
			    ulongData, NULL)) {
      sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
      Tcl_AppendResult(interp, "sdds setParameter: ", sddsErrs[0], NULL);
      SDDS_ClearErrors();
      free(sddsErrs[0]);
      return TCL_ERROR;
    }
    break;
  }
  case SDDS_SHORT: {
    if (Tcl_GetInt(interp,parameterValue,&intData) != TCL_OK) {
      Tcl_SetResult(interp, "sdds setParameter:  value cannot be converted to native data type (SDDS_SHORT)",NULL);
      return TCL_ERROR;
    }
    shortData = intData;
    if (!SDDS_SetParameters(&(sddsFdTable[fd].table),setMode,parameterName,
			    shortData, NULL)) {
      sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
      Tcl_AppendResult(interp, "sdds setParameter: ", sddsErrs[0], NULL);
      SDDS_ClearErrors();
      free(sddsErrs[0]);
      return TCL_ERROR;
    }
    break;
  }
  case SDDS_USHORT: {
    if (Tcl_GetInt(interp,parameterValue,&intData) != TCL_OK) {
      Tcl_SetResult(interp, "sdds setParameter:  value cannot be converted to native data type (SDDS_USHORT)",NULL);
      return TCL_ERROR;
    }
    ushortData = intData;
    if (!SDDS_SetParameters(&(sddsFdTable[fd].table),setMode,parameterName,
			    ushortData, NULL)) {
      sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
      Tcl_AppendResult(interp, "sdds setParameter: ", sddsErrs[0], NULL);
      SDDS_ClearErrors();
      free(sddsErrs[0]);
      return TCL_ERROR;
    }
    break;
  }
  case SDDS_STRING: {
    if (!SDDS_SetParameters(&(sddsFdTable[fd].table),setMode,parameterName,
			    parameterValue, NULL)) {
      sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
      Tcl_AppendResult(interp, "sdds setParameter: ", sddsErrs[0], NULL);
      SDDS_ClearErrors();
      free(sddsErrs[0]);
      return TCL_ERROR;
    }
    break;
  }
  case SDDS_CHARACTER: {
    if (!SDDS_SetParameters(&(sddsFdTable[fd].table),setMode,parameterName,
			    parameterValue[0], NULL)) {
      sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
      Tcl_AppendResult(interp, "sdds setParameter: ", sddsErrs[0], NULL);
      SDDS_ClearErrors();
      free(sddsErrs[0]);
      return TCL_ERROR;
    }
    break;
  }}

  return TCL_OK;
}

/*****************************************
 *
 *****************************************/
int tclSDDSSetArray(Tcl_Interp *interp, int argc, char *argv[]) {
  char **sddsErrs;
  int32_t sddsNumErrs;
  int fd;
  long i,j;
  int32_t dim[4];
  int intDim;
  char indexBuf[tclSDDS_BUFSIZE];
  char cmdBuf[tclSDDS_BUFSIZE];
  char *elementValue;
  int elements;
  long setMode = SDDS_CONTIGUOUS_DATA;

  int32_t arrayType;
  int32_t arrayDim;
  long double *ldoubleDataArray;
  double *doubleDataArray;
  float *floatDataArray;
  int64_t *long64DataArray;
  uint64_t *ulong64DataArray;
  int32_t *longDataArray;
  uint32_t *ulongDataArray;
  short *shortDataArray;
  unsigned short *ushortDataArray;
  char **stringDataArray;
  char *charDataArray;

  double doubleData;
  int intData;

  /* Required arguments */
  char *sddsFileId;
  char *sddsArrayName;
  char *tclArrayName;
  
  if (argc < 6) {
    Tcl_SetResult(interp, 
		  "usage: sdds setArray <fd> <tclArrayName> <sddsArrayName> <dim0Range> ... <dimnRange>",NULL);
    return TCL_ERROR;    
  }
  sddsFileId = argv[2];
  tclArrayName = argv[3];
  sddsArrayName = argv[4];

  fd = atoi(sddsFileId);
  if ((fd > MAX_OPEN_SDDS_FILES) || (sddsFdTable[fd].free == 1)) { 
    Tcl_SetResult(interp, "sdds setArray: unknown file descriptor", NULL);
    return TCL_ERROR;
  }
  if (sddsFdTable[fd].mode != 'w') {
    Tcl_SetResult(interp, "sdds setArray: <fd> must be opened for writing",
		  NULL);
    return TCL_ERROR;
  }
  if (!sddsFdTable[fd].pageStarted) {
    Tcl_SetResult(interp, "sdds setArray: you must call startPage first",
		  NULL);
    return TCL_ERROR;
  }

  /* Get native data type of array, as given from DefineArray call */
  if (SDDS_GetArrayInformation(&(sddsFdTable[fd].table), "type", 
			       &arrayType, SDDS_GET_BY_NAME, 
			       sddsArrayName) == 0) {
    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
    Tcl_AppendResult(interp, "sdds setArray: ", sddsErrs[0], NULL);
    SDDS_ClearErrors();
    free(sddsErrs[0]);
    return TCL_ERROR;
  }  

  /* Get dimension of array, as given from DefineArray call */
  if (SDDS_GetArrayInformation(&(sddsFdTable[fd].table), "dimensions", 
			       &arrayDim, SDDS_GET_BY_NAME, 
			       sddsArrayName) == 0) {
    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
    Tcl_AppendResult(interp, "sdds setArray: ", sddsErrs[0], NULL);
    SDDS_ClearErrors();
    free(sddsErrs[0]);
    return TCL_ERROR;
  }  

  /* Get dimension information from command line */
  if ((argc - 5) != arrayDim) {
    Tcl_SetResult(interp, "sdds setArray: you must supply the range of each array dimension",NULL);
    return TCL_ERROR;
  }
  for (i=0 ; i < arrayDim ; i++) {
    if (Tcl_GetInt(interp,argv[i+5],&intDim) != TCL_OK) {
      Tcl_SetResult(interp, "sdds setArray: unable to read dimension range",NULL);
      return TCL_ERROR;
    }
    dim[i] = intDim;
  }

  /* Verify that at least element 0 of array exists. This provides
     a crude check that user has supplied an array of correct arity.
     */
  indexBuf[0] = '\0';
  strcpy(indexBuf,"0");   /* Construct index */
  for (i=1 ; i < arrayDim ; i++) {
    strcat(indexBuf,",0");
  }
  if (Tcl_GetVar2(interp,tclArrayName,indexBuf,0) == NULL) {
    Tcl_SetResult(interp, "sdds setArray: array is missing elements or its arity does not match SDDS array definition", NULL);
    return TCL_ERROR;
  }

  /* Get total number of elements so we can preallocate space for the
     conversion from string to native SDDS array type.
     */
  sprintf(cmdBuf,"array size %s",tclArrayName);
  if (Tcl_Eval(interp,cmdBuf) != TCL_OK) {
    Tcl_SetResult(interp, "sdds setArray: unable to get size of array",NULL);
    return TCL_ERROR;
  }
  if (Tcl_GetInt(interp,interp->result,&elements) != TCL_OK) {
    Tcl_SetResult(interp, "sdds setArray: unable to convert size of array",NULL);
    return TCL_ERROR;
  }

  /* Convert string data to native SDDS array type, and set SDDS array */
  switch (arrayType) {
  case SDDS_LONGDOUBLE: {
    ldoubleDataArray = (long double *)malloc(sizeof(long double)*elements);

    /* Extract and convert array elements one by one */
    for (i=0 ; i < elements ; i++) {
      constructIndex(i,arrayDim,dim,indexBuf);
      if ((elementValue=(char*)Tcl_GetVar2(interp,tclArrayName,indexBuf,0)) == NULL) {
	free(ldoubleDataArray);
	Tcl_SetResult(interp, "sdds setArray:  unable to extract all elements",NULL);
	return TCL_ERROR;
      }
      ldoubleDataArray[i] = strtold(elementValue, NULL);
    }

    if (!SDDS_SetArray(&(sddsFdTable[fd].table),sddsArrayName,setMode,
			    ldoubleDataArray, dim)) {
      sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
      Tcl_AppendResult(interp, "sdds setArray: ", sddsErrs[0], NULL);
      SDDS_ClearErrors();
      free(sddsErrs[0]);
      free(ldoubleDataArray);
      return TCL_ERROR;
    }
    free(ldoubleDataArray);
    break;
  }
  case SDDS_DOUBLE: {
    doubleDataArray = (double *)malloc(sizeof(double)*elements);

    /* Extract and convert array elements one by one */
    for (i=0 ; i < elements ; i++) {
      constructIndex(i,arrayDim,dim,indexBuf);
      if ((elementValue=(char*)Tcl_GetVar2(interp,tclArrayName,indexBuf,0)) == NULL) {
	free(doubleDataArray);
	Tcl_SetResult(interp, "sdds setArray:  unable to extract all elements",NULL);
	return TCL_ERROR;
      }
      if (Tcl_GetDouble(interp,elementValue,&(doubleDataArray[i])) != TCL_OK) {
	free(doubleDataArray);
	Tcl_SetResult(interp, "sdds setArray:  value cannot be converted to native data type (SDDS_DOUBLE)",NULL);
	return TCL_ERROR;
      }
    }

    if (!SDDS_SetArray(&(sddsFdTable[fd].table),sddsArrayName,setMode,
			    doubleDataArray, dim)) {
      sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
      Tcl_AppendResult(interp, "sdds setArray: ", sddsErrs[0], NULL);
      SDDS_ClearErrors();
      free(sddsErrs[0]);
      free(doubleDataArray);
      return TCL_ERROR;
    }
    free(doubleDataArray);
    break;
  }
  case SDDS_FLOAT: {
    floatDataArray = (float *)malloc(sizeof(float)*elements);

    /* Extract and convert array elements one by one */
    for (i=0 ; i < elements ; i++) {
      constructIndex(i,arrayDim,dim,indexBuf);
      if ((elementValue=(char*)Tcl_GetVar2(interp,tclArrayName,indexBuf,0)) == NULL) {
	free(floatDataArray);
	Tcl_SetResult(interp, "sdds setArray:  unable to extract all elements",NULL);
	return TCL_ERROR;
      }
      if (Tcl_GetDouble(interp,elementValue,&doubleData) != TCL_OK) {
	free(floatDataArray);
	Tcl_SetResult(interp, "sdds setArray:  value cannot be converted to native data type (SDDS_FLOAT)",NULL);
	return TCL_ERROR;
      }
      floatDataArray[i] = doubleData;
    }

    if (!SDDS_SetArray(&(sddsFdTable[fd].table),sddsArrayName,setMode,
			    floatDataArray, dim)) {
      sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
      Tcl_AppendResult(interp, "sdds setArray: ", sddsErrs[0], NULL);
      SDDS_ClearErrors();
      free(sddsErrs[0]);
      free(floatDataArray);
      return TCL_ERROR;
    }
    free(floatDataArray);
    break;
  }
  case SDDS_LONG64: {
    long64DataArray = (int64_t *)malloc(sizeof(int64_t)*elements);

    /* Extract and convert array elements one by one */
    for (i=0 ; i < elements ; i++) {
      constructIndex(i,arrayDim,dim,indexBuf);
      if ((elementValue=(char*)Tcl_GetVar2(interp,tclArrayName,indexBuf,0)) == NULL) {
	free(long64DataArray);
	Tcl_SetResult(interp, "sdds setArray:  unable to extract all elements",NULL);
	return TCL_ERROR;
      }
      long64DataArray[i] = atoll(elementValue);
    }

    if (!SDDS_SetArray(&(sddsFdTable[fd].table),sddsArrayName,setMode,
			    long64DataArray, dim)) {
      sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
      Tcl_AppendResult(interp, "sdds setArray: ", sddsErrs[0], NULL);
      SDDS_ClearErrors();
      free(sddsErrs[0]);
      free(long64DataArray);
      return TCL_ERROR;
    }
    free(long64DataArray);
    break;
  }
  case SDDS_ULONG64: {
    ulong64DataArray = (uint64_t *)malloc(sizeof(uint64_t)*elements);

    /* Extract and convert array elements one by one */
    for (i=0 ; i < elements ; i++) {
      constructIndex(i,arrayDim,dim,indexBuf);
      if ((elementValue=(char*)Tcl_GetVar2(interp,tclArrayName,indexBuf,0)) == NULL) {
	free(ulong64DataArray);
	Tcl_SetResult(interp, "sdds setArray:  unable to extract all elements",NULL);
	return TCL_ERROR;
      }
      ulong64DataArray[i] = strtoull(elementValue, NULL, 10);
    }

    if (!SDDS_SetArray(&(sddsFdTable[fd].table),sddsArrayName,setMode,
			    ulong64DataArray, dim)) {
      sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
      Tcl_AppendResult(interp, "sdds setArray: ", sddsErrs[0], NULL);
      SDDS_ClearErrors();
      free(sddsErrs[0]);
      free(ulong64DataArray);
      return TCL_ERROR;
    }
    free(ulong64DataArray);
    break;
  }
  case SDDS_LONG: {
    longDataArray = (int32_t *)malloc(sizeof(int32_t)*elements);

    /* Extract and convert array elements one by one */
    for (i=0 ; i < elements ; i++) {
      constructIndex(i,arrayDim,dim,indexBuf);
      if ((elementValue=(char*)Tcl_GetVar2(interp,tclArrayName,indexBuf,0)) == NULL) {
	free(longDataArray);
	Tcl_SetResult(interp, "sdds setArray:  unable to extract all elements",NULL);
	return TCL_ERROR;
      }
      if (Tcl_GetInt(interp,elementValue,&intData) != TCL_OK) {
	free(longDataArray);
	Tcl_SetResult(interp, "sdds setArray:  value cannot be converted to native data type (SDDS_LONG)",NULL);
	return TCL_ERROR;
      }
      longDataArray[i] = intData;
    }

    if (!SDDS_SetArray(&(sddsFdTable[fd].table),sddsArrayName,setMode,
			    longDataArray, dim)) {
      sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
      Tcl_AppendResult(interp, "sdds setArray: ", sddsErrs[0], NULL);
      SDDS_ClearErrors();
      free(sddsErrs[0]);
      free(longDataArray);
      return TCL_ERROR;
    }
    free(longDataArray);
    break;
  }
  case SDDS_ULONG: {
    ulongDataArray = (uint32_t *)malloc(sizeof(uint32_t)*elements);

    /* Extract and convert array elements one by one */
    for (i=0 ; i < elements ; i++) {
      constructIndex(i,arrayDim,dim,indexBuf);
      if ((elementValue=(char*)Tcl_GetVar2(interp,tclArrayName,indexBuf,0)) == NULL) {
	free(ulongDataArray);
	Tcl_SetResult(interp, "sdds setArray:  unable to extract all elements",NULL);
	return TCL_ERROR;
      }
      if (Tcl_GetInt(interp,elementValue,&intData) != TCL_OK) {
	free(ulongDataArray);
	Tcl_SetResult(interp, "sdds setArray:  value cannot be converted to native data type (SDDS_ULONG)",NULL);
	return TCL_ERROR;
      }
      ulongDataArray[i] = intData;
    }

    if (!SDDS_SetArray(&(sddsFdTable[fd].table),sddsArrayName,setMode,
			    ulongDataArray, dim)) {
      sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
      Tcl_AppendResult(interp, "sdds setArray: ", sddsErrs[0], NULL);
      SDDS_ClearErrors();
      free(sddsErrs[0]);
      free(ulongDataArray);
      return TCL_ERROR;
    }
    free(ulongDataArray);
    break;
  }
  case SDDS_SHORT: {
    shortDataArray = (short *)malloc(sizeof(short)*elements);

    /* Extract and convert array elements one by one */
    for (i=0 ; i < elements ; i++) {
      constructIndex(i,arrayDim,dim,indexBuf);
      if ((elementValue=(char*)Tcl_GetVar2(interp,tclArrayName,indexBuf,0)) == NULL) {
	free(shortDataArray);
	Tcl_SetResult(interp, "sdds setArray:  unable to extract all elements",NULL);
	return TCL_ERROR;
      }
      if (Tcl_GetInt(interp,elementValue,&intData) != TCL_OK) {
	free(shortDataArray);
	Tcl_SetResult(interp, "sdds setArray:  value cannot be converted to native data type (SDDS_SHORT)",NULL);
	return TCL_ERROR;
      }
      shortDataArray[i] = intData;
    }

    if (!SDDS_SetArray(&(sddsFdTable[fd].table),sddsArrayName,setMode,
			    shortDataArray, dim)) {
      sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
      Tcl_AppendResult(interp, "sdds setArray: ", sddsErrs[0], NULL);
      SDDS_ClearErrors();
      free(sddsErrs[0]);
      free(shortDataArray);
      return TCL_ERROR;
    }
    free(shortDataArray);
    break;
  }
  case SDDS_USHORT: {
    ushortDataArray = (unsigned short *)malloc(sizeof(unsigned short)*elements);

    /* Extract and convert array elements one by one */
    for (i=0 ; i < elements ; i++) {
      constructIndex(i,arrayDim,dim,indexBuf);
      if ((elementValue=(char*)Tcl_GetVar2(interp,tclArrayName,indexBuf,0)) == NULL) {
	free(ushortDataArray);
	Tcl_SetResult(interp, "sdds setArray:  unable to extract all elements",NULL);
	return TCL_ERROR;
      }
      if (Tcl_GetInt(interp,elementValue,&intData) != TCL_OK) {
	free(ushortDataArray);
	Tcl_SetResult(interp, "sdds setArray:  value cannot be converted to native data type (SDDS_USHORT)",NULL);
	return TCL_ERROR;
      }
      ushortDataArray[i] = intData;
    }

    if (!SDDS_SetArray(&(sddsFdTable[fd].table),sddsArrayName,setMode,
			    ushortDataArray, dim)) {
      sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
      Tcl_AppendResult(interp, "sdds setArray: ", sddsErrs[0], NULL);
      SDDS_ClearErrors();
      free(sddsErrs[0]);
      free(ushortDataArray);
      return TCL_ERROR;
    }
    free(ushortDataArray);
    break;
  }
  case SDDS_STRING: {
    stringDataArray = (char **)malloc(sizeof(char*)*elements);
    for (i=0 ; i < elements ; i++)
      stringDataArray[i] = (char *)malloc(sizeof(char)*tclSDDS_BUFSIZE);

    /* Extract strings from tcl array var one by one */
    for (i=0 ; i < elements ; i++) {
      constructIndex(i,arrayDim,dim,indexBuf);
      if ((elementValue=(char*)Tcl_GetVar2(interp,tclArrayName,indexBuf,0)) == NULL) {
	for (j=0 ; j < elements ; j++)
	  free(stringDataArray[i]);
	free(stringDataArray);
	Tcl_SetResult(interp, "sdds setArray:  unable to extract all elements",NULL);
	return TCL_ERROR;
      }
      strcpy(stringDataArray[i],elementValue);
    }

    if (!SDDS_SetArray(&(sddsFdTable[fd].table),sddsArrayName,setMode,
			    stringDataArray, dim)) {
      sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
      Tcl_AppendResult(interp, "sdds setArray: ", sddsErrs[0], NULL);
      SDDS_ClearErrors();
      free(sddsErrs[0]);
      for (j=0 ; j < elements ; j++)
	free(stringDataArray[i]);
      free(stringDataArray);
      return TCL_ERROR;
    }
    for (j=0 ; j < elements ; j++)
      free(stringDataArray[j]);
    free(stringDataArray);
    break;
  }
  case SDDS_CHARACTER: {
    charDataArray = (char *)malloc(sizeof(char)*elements);

    /* Extract and convert array elements one by one */
    for (i=0 ; i < elements ; i++) {
      constructIndex(i,arrayDim,dim,indexBuf);
      if ((elementValue=(char*)Tcl_GetVar2(interp,tclArrayName,indexBuf,0)) == NULL) {
	free(charDataArray);
	Tcl_SetResult(interp, "sdds setArray:  unable to extract all elements",NULL);
	return TCL_ERROR;
      }
      charDataArray[i] = elementValue[0];
    }

    if (!SDDS_SetArray(&(sddsFdTable[fd].table),sddsArrayName,setMode,
			    charDataArray, dim)) {
      sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
      Tcl_AppendResult(interp, "sdds setArray: ", sddsErrs[0], NULL);
      SDDS_ClearErrors();
      free(sddsErrs[0]);
      free(charDataArray);
      return TCL_ERROR;
    }
    free(charDataArray);
    break;
  }}
  return TCL_OK;
}

/*****************************************
 *
 *****************************************/
int tclSDDSSetRowValues(Tcl_Interp *interp, int argc, char *argv[]) {
  char **sddsErrs;
  int32_t sddsNumErrs;
  int fd, i;
  
  long setMode = (SDDS_SET_BY_NAME | SDDS_PASS_BY_VALUE);
  int32_t columnType;
  long double ldoubleData;
  double doubleData;
  float floatData;
  int64_t long64Data;
  uint64_t ulong64Data;
  int32_t longData;
  uint32_t ulongData;
  int intData;
  short shortData;
  unsigned short ushortData;

  /* Required arguments */
  char *sddsFileId;
  char *rowNumber;
  long nrowNumber;
  char *columnName;
  char *columnValue;
  
  if (argc < 6 || ((argc%2)!=0)) {
    Tcl_SetResult(interp, 
		  "usage: sdds setRowValues <fd> <rowNumber> <columnName> <columnValue> [<columnName columnValue ...]", NULL);
    return TCL_ERROR;    
  }
  sddsFileId = argv[2];
  rowNumber = argv[3];
  nrowNumber = atoi(rowNumber);

  fd = atoi(sddsFileId);
  if ((fd > MAX_OPEN_SDDS_FILES) || (sddsFdTable[fd].free == 1)) { 
    Tcl_SetResult(interp, "sdds setRowValues: unknown file descriptor", NULL);
    return TCL_ERROR;
  }
  if (sddsFdTable[fd].mode != 'w') {
    Tcl_SetResult(interp, "sdds setRowValues: <fd> must be opened for writing",
		  NULL);
    return TCL_ERROR;
  }
  if (!sddsFdTable[fd].pageStarted) {
    Tcl_SetResult(interp, "sdds setRowValues: you must call startPage first",
		  NULL);
    return TCL_ERROR;
  }

  /* Process column name/value arguments */
  for (i=4 ; i < argc ; i+=2) {
    columnName = argv[i];
    columnValue = argv[i+1];

    if (SDDS_GetColumnInformation(&(sddsFdTable[fd].table), "type", 
				  &columnType,SDDS_GET_BY_NAME, columnName) 
	== 0) {
      sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
      Tcl_AppendResult(interp, "sdds setRowValues: ", sddsErrs[0], NULL);
      SDDS_ClearErrors();
      free(sddsErrs[0]);
      return TCL_ERROR;
    }
    
    /* Convert tcl string to native data type, and set parameter value */
    switch (columnType) {
    case SDDS_LONGDOUBLE: {
      ldoubleData = strtold(columnValue, NULL);
      if (!SDDS_SetRowValues(&(sddsFdTable[fd].table),setMode,nrowNumber,
			     columnName, ldoubleData, NULL)) {
	sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	Tcl_AppendResult(interp, "sdds setRowValues: ", sddsErrs[0], NULL);
	SDDS_ClearErrors();
	free(sddsErrs[0]);
	return TCL_ERROR;
      }
      break;
    }
    case SDDS_DOUBLE: {
      if (Tcl_GetDouble(interp,columnValue,&doubleData) != TCL_OK) {
	Tcl_SetResult(interp, "sdds setRowValues:  value cannot be converted to native data type (SDDS_DOUBLE)",NULL);
	return TCL_ERROR;
      }
      if (!SDDS_SetRowValues(&(sddsFdTable[fd].table),setMode,nrowNumber,
			     columnName, doubleData, NULL)) {
	sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	Tcl_AppendResult(interp, "sdds setRowValues: ", sddsErrs[0], NULL);
	SDDS_ClearErrors();
	free(sddsErrs[0]);
	return TCL_ERROR;
      }
      break;
    }
    case SDDS_FLOAT: {
      if (Tcl_GetDouble(interp,columnValue,&doubleData) != TCL_OK) {
	Tcl_SetResult(interp, "sdds setRowValues:  value cannot be converted to native data type (SDDS_FLOAT)",NULL);
	return TCL_ERROR;
      }
      floatData = doubleData;
      if (!SDDS_SetRowValues(&(sddsFdTable[fd].table),setMode,nrowNumber,
			     columnName,floatData, NULL)) {
	sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	Tcl_AppendResult(interp, "sdds setRowValues: ", sddsErrs[0], NULL);
	SDDS_ClearErrors();
	free(sddsErrs[0]);
	return TCL_ERROR;
      }
      break;
    }
    case SDDS_LONG64: {
      long64Data = atoll(columnValue);
      if (!SDDS_SetRowValues(&(sddsFdTable[fd].table),setMode,nrowNumber,
			     columnName,long64Data, NULL)) {
	sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	Tcl_AppendResult(interp, "sdds setRowValues: ", sddsErrs[0], NULL);
	SDDS_ClearErrors();
	free(sddsErrs[0]);
	return TCL_ERROR;
      }
      break;
    }
    case SDDS_ULONG64: {
      ulong64Data = strtoull(columnValue, NULL, 10);
      if (!SDDS_SetRowValues(&(sddsFdTable[fd].table),setMode,nrowNumber,
			     columnName,ulong64Data, NULL)) {
	sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	Tcl_AppendResult(interp, "sdds setRowValues: ", sddsErrs[0], NULL);
	SDDS_ClearErrors();
	free(sddsErrs[0]);
	return TCL_ERROR;
      }
      break;
    }
    case SDDS_LONG: {
      if (Tcl_GetInt(interp,columnValue,&intData) != TCL_OK) {
	Tcl_SetResult(interp, "sdds setRowValues:  value cannot be converted to native data type (SDDS_LONG)",NULL);
	return TCL_ERROR;
      }
      longData = intData;
      if (!SDDS_SetRowValues(&(sddsFdTable[fd].table),setMode,nrowNumber,
			     columnName,longData, NULL)) {
	sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	Tcl_AppendResult(interp, "sdds setRowValues: ", sddsErrs[0], NULL);
	SDDS_ClearErrors();
	free(sddsErrs[0]);
	return TCL_ERROR;
      }
      break;
    }
    case SDDS_ULONG: {
      if (Tcl_GetInt(interp,columnValue,&intData) != TCL_OK) {
	Tcl_SetResult(interp, "sdds setRowValues:  value cannot be converted to native data type (SDDS_ULONG)",NULL);
	return TCL_ERROR;
      }
      ulongData = intData;
      if (!SDDS_SetRowValues(&(sddsFdTable[fd].table),setMode,nrowNumber,
			     columnName,ulongData, NULL)) {
	sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	Tcl_AppendResult(interp, "sdds setRowValues: ", sddsErrs[0], NULL);
	SDDS_ClearErrors();
	free(sddsErrs[0]);
	return TCL_ERROR;
      }
      break;
    }
    case SDDS_SHORT: {
      if (Tcl_GetInt(interp,columnValue,&intData) != TCL_OK) {
	Tcl_SetResult(interp, "sdds setRowValues:  value cannot be converted to native data type (SDDS_SHORT)",NULL);
	return TCL_ERROR;
      }
      shortData = intData;
      if (!SDDS_SetRowValues(&(sddsFdTable[fd].table),setMode,nrowNumber,
			     columnName,shortData, NULL)) {
	sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	Tcl_AppendResult(interp, "sdds setRowValues: ", sddsErrs[0], NULL);
	SDDS_ClearErrors();
	free(sddsErrs[0]);
	return TCL_ERROR;
      }
      break;
    }
    case SDDS_USHORT: {
      if (Tcl_GetInt(interp,columnValue,&intData) != TCL_OK) {
	Tcl_SetResult(interp, "sdds setRowValues:  value cannot be converted to native data type (SDDS_USHORT)",NULL);
	return TCL_ERROR;
      }
      ushortData = intData;
      if (!SDDS_SetRowValues(&(sddsFdTable[fd].table),setMode,nrowNumber,
			     columnName,ushortData, NULL)) {
	sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	Tcl_AppendResult(interp, "sdds setRowValues: ", sddsErrs[0], NULL);
	SDDS_ClearErrors();
	free(sddsErrs[0]);
	return TCL_ERROR;
      }
      break;
    }
    case SDDS_STRING: {
      if (!SDDS_SetRowValues(&(sddsFdTable[fd].table),setMode,nrowNumber,
			     columnName,columnValue, NULL)) {
	sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	Tcl_AppendResult(interp, "sdds setRowValues: ", sddsErrs[0], NULL);
	SDDS_ClearErrors();
	free(sddsErrs[0]);
	return TCL_ERROR;
      }
      break;
    }
    case SDDS_CHARACTER: {
      if (!SDDS_SetRowValues(&(sddsFdTable[fd].table),setMode,nrowNumber,
			     columnName, columnValue[0], NULL)) {
	sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	Tcl_AppendResult(interp, "sdds setRowValues: ", sddsErrs[0], NULL);
	SDDS_ClearErrors();
	free(sddsErrs[0]);
	return TCL_ERROR;
      }
      break;
    }}

  } /* end for colName/colValue arguments */

  return TCL_OK;
}

/*****************************************
 *
 *****************************************/
int tclSDDSSetColumn(Tcl_Interp *interp, int argc, char *argv[]) {
  char **sddsErrs;
  int32_t sddsNumErrs;
  int fd,i,j;
  long elements;
  long setMode = (SDDS_SET_BY_NAME | SDDS_PASS_BY_VALUE);

  int32_t columnType;
  long double *ldoubleDataArray;
  double *doubleDataArray;
  float *floatDataArray;
  int64_t *long64DataArray;
  uint64_t *ulong64DataArray;
  int32_t *longDataArray;
  uint32_t *ulongDataArray;
  short *shortDataArray;
  unsigned short *ushortDataArray;
  char **stringDataArray;
  char *charDataArray;

  double doubleData;
  int intData;

  /* Required arguments */
  char *sddsFileId;
  char *columnName;
  
  if (argc < 5) {
    Tcl_SetResult(interp, 
		  "usage: sdds setColumn <fd> <columnName> <columnValue> [columnValue ...]", NULL);
    return TCL_ERROR;    
  }
  sddsFileId = argv[2];
  columnName = argv[3];

  fd = atoi(sddsFileId);
  if ((fd > MAX_OPEN_SDDS_FILES) || (sddsFdTable[fd].free == 1)) { 
    Tcl_SetResult(interp, "sdds setColumn: unknown file descriptor", NULL);
    return TCL_ERROR;
  }
  if (sddsFdTable[fd].mode != 'w') {
    Tcl_SetResult(interp, "sdds setColumn: <fd> must be opened for writing",
		  NULL);
    return TCL_ERROR;
  }
  if (!sddsFdTable[fd].pageStarted) {
    Tcl_SetResult(interp, "sdds setColumn: you must call startPage first",
		  NULL);
    return TCL_ERROR;
  }

  /* Get native data type of column, as given from DefineColumn call */
  if (SDDS_GetColumnInformation(&(sddsFdTable[fd].table), "type", 
				   &columnType, SDDS_GET_BY_NAME, 
				   columnName) == 0) {
    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
    Tcl_AppendResult(interp, "sdds setColumn: ", sddsErrs[0], NULL);
    SDDS_ClearErrors();
    free(sddsErrs[0]);
    return TCL_ERROR;
  }  

  elements = argc - 4;

  /* Convert tcl strings to native data type, and set column */
  switch (columnType) {
  case SDDS_LONGDOUBLE: {
    ldoubleDataArray = (long double *)malloc(sizeof(long double)*elements);

    for (i=4,j=0 ; i < argc ; i++,j++) {
      ldoubleDataArray[j] = strtold(argv[i], NULL);
    }

    if (!SDDS_SetColumn(&(sddsFdTable[fd].table),setMode, ldoubleDataArray, 
			elements, columnName)) {
      sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
      Tcl_AppendResult(interp, "sdds setColumn: ", sddsErrs[0], NULL);
      SDDS_ClearErrors();
      free(sddsErrs[0]);
      free(ldoubleDataArray);
      return TCL_ERROR;
    }
    free(ldoubleDataArray);
    break;
  }
  case SDDS_DOUBLE: {
    doubleDataArray = (double *)malloc(sizeof(double)*elements);

    for (i=4, j=0 ; i < argc ; i++,j++) {
      if (Tcl_GetDouble(interp,argv[i],&(doubleDataArray[j])) != TCL_OK) {
	free(doubleDataArray);
	Tcl_SetResult(interp, "sdds setColumn:  value cannot be converted to native data type (SDDS_DOUBLE)",NULL);
	return TCL_ERROR;
      }
    }

    if (!SDDS_SetColumn(&(sddsFdTable[fd].table),setMode, doubleDataArray, 
			elements, columnName)) {
      sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
      Tcl_AppendResult(interp, "sdds setColumn: ", sddsErrs[0], NULL);
      SDDS_ClearErrors();
      free(sddsErrs[0]);
      free(doubleDataArray);
      return TCL_ERROR;
    }
    free(doubleDataArray);
    break;
  }
  case SDDS_FLOAT: {
    floatDataArray = (float *)malloc(sizeof(float)*elements);

    for (i=4,j=0 ; i < argc ; i++,j++) {
      if (Tcl_GetDouble(interp,argv[i],&doubleData) != TCL_OK) {
	free(floatDataArray);
	Tcl_SetResult(interp, "sdds setColumn:  value cannot be converted to native data type (SDDS_FLOAT)",NULL);
	return TCL_ERROR;
      }
      floatDataArray[j] = doubleData;
    }

    if (!SDDS_SetColumn(&(sddsFdTable[fd].table),setMode, floatDataArray, 
			elements, columnName)) {
      sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
      Tcl_AppendResult(interp, "sdds setColumn: ", sddsErrs[0], NULL);
      SDDS_ClearErrors();
      free(sddsErrs[0]);
      free(floatDataArray);
      return TCL_ERROR;
    }
    free(floatDataArray);
    break;
  }
  case SDDS_LONG64: {
    long64DataArray = (int64_t *)malloc(sizeof(int64_t)*elements);

    for (i=4,j=0 ; i < argc ; i++,j++) {
      long64DataArray[j] = atoll(argv[i]);
    }
    if (!SDDS_SetColumn(&(sddsFdTable[fd].table),setMode, long64DataArray, 
			elements, columnName)) {
      sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
      Tcl_AppendResult(interp, "sdds setColumn: ", sddsErrs[0], NULL);
      SDDS_ClearErrors();
      free(sddsErrs[0]);
      free(long64DataArray);
      return TCL_ERROR;
    }
    free(long64DataArray);
    break;
  }
  case SDDS_ULONG64: {
    ulong64DataArray = (uint64_t *)malloc(sizeof(uint64_t)*elements);

    for (i=4,j=0 ; i < argc ; i++,j++) {
      ulong64DataArray[j] = strtoull(argv[i], NULL, 10);;
    }
    if (!SDDS_SetColumn(&(sddsFdTable[fd].table),setMode, ulong64DataArray, 
			elements, columnName)) {
      sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
      Tcl_AppendResult(interp, "sdds setColumn: ", sddsErrs[0], NULL);
      SDDS_ClearErrors();
      free(sddsErrs[0]);
      free(ulong64DataArray);
      return TCL_ERROR;
    }
    free(ulong64DataArray);
    break;
  }
  case SDDS_LONG: {
    longDataArray = (int32_t *)malloc(sizeof(int32_t)*elements);

    for (i=4,j=0 ; i < argc ; i++,j++) {
      if (Tcl_GetInt(interp,argv[i],&intData) != TCL_OK) {
	free(longDataArray);
	Tcl_SetResult(interp, "sdds setColumn:  value cannot be converted to native data type (SDDS_LONG)",NULL);
	return TCL_ERROR;
      }
      longDataArray[j] = intData;
    }
    if (!SDDS_SetColumn(&(sddsFdTable[fd].table),setMode, longDataArray, 
			elements, columnName)) {
      sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
      Tcl_AppendResult(interp, "sdds setColumn: ", sddsErrs[0], NULL);
      SDDS_ClearErrors();
      free(sddsErrs[0]);
      free(longDataArray);
      return TCL_ERROR;
    }
    free(longDataArray);
    break;
  }
  case SDDS_ULONG: {
    ulongDataArray = (uint32_t *)malloc(sizeof(uint32_t)*elements);

    for (i=4,j=0 ; i < argc ; i++,j++) {
      if (Tcl_GetInt(interp,argv[i],&intData) != TCL_OK) {
	free(ulongDataArray);
	Tcl_SetResult(interp, "sdds setColumn:  value cannot be converted to native data type (SDDS_ULONG)",NULL);
	return TCL_ERROR;
      }
      ulongDataArray[j] = intData;
    }
    if (!SDDS_SetColumn(&(sddsFdTable[fd].table),setMode, ulongDataArray, 
			elements, columnName)) {
      sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
      Tcl_AppendResult(interp, "sdds setColumn: ", sddsErrs[0], NULL);
      SDDS_ClearErrors();
      free(sddsErrs[0]);
      free(ulongDataArray);
      return TCL_ERROR;
    }
    free(ulongDataArray);
    break;
  }
  case SDDS_SHORT: {
    shortDataArray = (short *)malloc(sizeof(short)*elements);

    for (i=4,j=0 ; i < argc ; i++,j++) {
      if (Tcl_GetInt(interp,argv[i],&intData) != TCL_OK) {
	free(shortDataArray);
	Tcl_SetResult(interp, "sdds setColumn:  value cannot be converted to native data type (SDDS_SHORT)",NULL);
	return TCL_ERROR;
      }
      shortDataArray[j] = intData;
    }

    if (!SDDS_SetColumn(&(sddsFdTable[fd].table),setMode, shortDataArray, 
			elements, columnName)) {
      sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
      Tcl_AppendResult(interp, "sdds setColumn: ", sddsErrs[0], NULL);
      SDDS_ClearErrors();
      free(sddsErrs[0]);
      free(shortDataArray);
      return TCL_ERROR;
    }
    free(shortDataArray);
    break;
  }
  case SDDS_USHORT: {
    ushortDataArray = (unsigned short *)malloc(sizeof(unsigned short)*elements);

    for (i=4,j=0 ; i < argc ; i++,j++) {
      if (Tcl_GetInt(interp,argv[i],&intData) != TCL_OK) {
	free(ushortDataArray);
	Tcl_SetResult(interp, "sdds setColumn:  value cannot be converted to native data type (SDDS_USHORT)",NULL);
	return TCL_ERROR;
      }
      ushortDataArray[j] = intData;
    }

    if (!SDDS_SetColumn(&(sddsFdTable[fd].table),setMode, ushortDataArray, 
			elements, columnName)) {
      sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
      Tcl_AppendResult(interp, "sdds setColumn: ", sddsErrs[0], NULL);
      SDDS_ClearErrors();
      free(sddsErrs[0]);
      free(ushortDataArray);
      return TCL_ERROR;
    }
    free(ushortDataArray);
    break;
  }
  case SDDS_STRING: {
    stringDataArray = (char **)malloc(sizeof(char*)*elements);
    for (i=4,j=0 ; i < argc ; i++,j++) 
      SDDS_CopyString(stringDataArray+j, argv[i]);

    if (!SDDS_SetColumn(&(sddsFdTable[fd].table),setMode, stringDataArray, 
			elements, columnName)) {
      sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
      Tcl_AppendResult(interp, "sdds setColumn: ", sddsErrs[0], NULL);
      SDDS_ClearErrors();
      free(sddsErrs[0]);
      for (j=0 ; j < elements ; j++)
	free(stringDataArray[j]);
      free(stringDataArray);
      return TCL_ERROR;
    }
    for (j=0 ; j < elements ; j++)
      free(stringDataArray[j]);
    free(stringDataArray);
    break;
  }
  case SDDS_CHARACTER: {
    charDataArray = (char *)malloc(sizeof(char)*elements);

    for (i=4,j=0 ; i < argc ; i++,j++) {
      charDataArray[j] = *(argv[i]);
    }

    if (!SDDS_SetColumn(&(sddsFdTable[fd].table),setMode, charDataArray, 
			elements, columnName)) {
      sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
      Tcl_AppendResult(interp, "sdds setColumn: ", sddsErrs[0], NULL);
      SDDS_ClearErrors();
      free(sddsErrs[0]);
      free(charDataArray);
      return TCL_ERROR;
    }
    free(charDataArray);
    break;
  }}

  return TCL_OK;
}

/******************************************
 *
 *****************************************/
int tclSDDSCheck(Tcl_Interp *interp, int argc, char *argv[]) {
  char **sddsErrs;
  int32_t sddsNumErrs;
  int fd;
  char *sddsFileId;
  long printErrors;
  long pageRead;
  printErrors = 0;

  if ((argc != 3) && (argc != 4)) {  
    Tcl_SetResult(interp, "usage: sdds check <fd> [-printErrors]", NULL);
    return TCL_ERROR;    
  }
  sddsFileId = argv[2];
  if (argc == 4) {
    if (!strcmp(argv[3],"-printErrors")) {
      printErrors = 1;
    } else {
      Tcl_SetResult(interp, "usage: sdds check <fd> [-printErrors]", NULL);
      return TCL_ERROR;    
    }
  }
  fd = atoi(sddsFileId);
  if ((fd > MAX_OPEN_SDDS_FILES) || (sddsFdTable[fd].free == 1)) { 
    Tcl_SetResult(interp, "sdds check: unknown file descriptor", (Tcl_FreeProc *) NULL);
    return TCL_ERROR;
  }
  if (sddsFdTable[fd].mode != 'r') {
    Tcl_SetResult(interp, "sdds check: <fd> must be opened for reading", NULL);
    return TCL_ERROR;
  }

  /* currently reopens the file but this may be changed in the future */
  if (tclSDDSReopenFd(fd)) {
    Tcl_SetResult(interp, 
		  "sdds check: unable to reopen file for page seek", NULL);
    return TCL_ERROR;
  }

  while ((pageRead = SDDS_ReadPage(&(sddsFdTable[fd].table))) > 0) {
  }
  if (pageRead == -1) {
    Tcl_SetResult(interp, "ok", NULL); 
  } else {
    if (printErrors) {
      sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
      Tcl_AppendResult(interp, "Error for sdds check:\n", sddsErrs[0],"\n", NULL); 
      free(sddsErrs[0]);
    }
    Tcl_AppendResult(interp, "corrupted", NULL);       
    SDDS_ClearErrors();
  }
  return TCL_OK;
}

/******************************************
 *
 *****************************************/
int tclSDDSCollapse(Tcl_Interp *interp, int argc, char *argv[]) {
  char **sddsErrs;
  int32_t sddsNumErrs;
  int fdInput, fdOutput;
  char *sddsFileId;
  int32_t number;
  long i;
  char **nameData;
  long page_number, allocated_rows, setPageNumber;
  char s[SDDS_MAXLINE];
  long buffer[16], long_max;
  long_max = 2147483647;

  if (argc != 4) {  
    Tcl_SetResult(interp, "usage: sdds collapse <fd input> <fd output>", NULL);
    return TCL_ERROR;    
  }
  sddsFileId = argv[2];
  fdInput = atoi(sddsFileId);
  sddsFileId = argv[3];
  fdOutput = atoi(sddsFileId);
  if ((fdInput  > MAX_OPEN_SDDS_FILES) || (sddsFdTable[fdInput].free  == 1) ||
      (fdOutput > MAX_OPEN_SDDS_FILES) || (sddsFdTable[fdOutput].free == 1)) { 
    Tcl_SetResult(interp, "sdds collapse: unknown file descriptor", (Tcl_FreeProc *) NULL);
    return TCL_ERROR;
  }
  if (sddsFdTable[fdInput].mode != 'r') {
    Tcl_SetResult(interp, "sdds collapse: <fd input> must be opened for reading", NULL);
    return TCL_ERROR;
  }
  if (sddsFdTable[fdOutput].mode != 'w') {
    Tcl_SetResult(interp, "sdds collapse: <fd output> must be opened for writing", NULL);
    return TCL_ERROR;
  }
  /* currently reopens the input file but this may be changed in the future */
  if (tclSDDSReopenFd(fdInput)) {
    Tcl_SetResult(interp, 
		  "sdds collapse: unable to reopen input file", NULL);
    return TCL_ERROR;
  }
  
  if ((nameData=SDDS_GetParameterNames(&(sddsFdTable[fdInput].table), &number)) == NULL) {
    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
    Tcl_AppendResult(interp, "sdds collapse: ", sddsErrs[0], NULL);
    SDDS_ClearErrors();
    free(sddsErrs[0]);
    return TCL_ERROR;
  }
  for (i=0 ; i < number ; i++) {
    if (!SDDS_DefineColumnLikeParameter(&(sddsFdTable[fdOutput].table),
					&(sddsFdTable[fdInput].table), nameData[i], NULL)) {
      sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
      Tcl_AppendResult(interp, "sdds collapse: ", sddsErrs[0], NULL);
      SDDS_ClearErrors();
      free(sddsErrs[0]);
      return TCL_ERROR;
    }
  }
    
  sprintf(s, "corresponding page number of %s for this row", sddsFdTable[fdInput].fileName); 

  if (SDDS_GetColumnIndex(&(sddsFdTable[fdOutput].table), "PageNumber")<0) {
    if (SDDS_DefineColumn(&(sddsFdTable[fdOutput].table), "PageNumber", NULL, NULL, s,
			  NULL, SDDS_LONG, 0)<0) {
      sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
      Tcl_AppendResult(interp, "sdds collapse: ", sddsErrs[0], NULL);
      SDDS_ClearErrors();
      free(sddsErrs[0]);
      return TCL_ERROR;
    }
    setPageNumber = 1;
  } else {
    setPageNumber = 0;
  }

  if (!SDDS_WriteLayout(&(sddsFdTable[fdOutput].table)) ||
      !SDDS_StartPage(&(sddsFdTable[fdOutput].table), allocated_rows=100)) {
    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
    Tcl_AppendResult(interp, "sdds collapse: ", sddsErrs[0], NULL);
    SDDS_ClearErrors();
    free(sddsErrs[0]);
    return TCL_ERROR;
  }

  while ((page_number=SDDS_ReadPageSparse(&(sddsFdTable[fdInput].table), 0, long_max-1, 0, 0))>0) {
    if (page_number>allocated_rows) {
      if (!SDDS_LengthenTable(&(sddsFdTable[fdOutput].table), 100)) {
	sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	Tcl_AppendResult(interp, "sdds collapse: ", sddsErrs[0], NULL);
	SDDS_ClearErrors();
	free(sddsErrs[0]);
	return TCL_ERROR;
      }
      allocated_rows += 100;
    }
    for (i=0; i<number; i++) {
      if (!SDDS_GetParameter(&(sddsFdTable[fdInput].table), nameData[i], buffer)) {
	sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	Tcl_AppendResult(interp, "sdds collapse: ", sddsErrs[0], NULL);
	SDDS_ClearErrors();
	free(sddsErrs[0]);
	return TCL_ERROR;
      }
      if (!SDDS_SetRowValues(&(sddsFdTable[fdOutput].table),
			     SDDS_SET_BY_NAME|SDDS_PASS_BY_REFERENCE, page_number-1,
			     nameData[i], buffer, NULL)) {
	sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	Tcl_AppendResult(interp, "sdds collapse: ", sddsErrs[0], NULL);
	SDDS_ClearErrors();
	free(sddsErrs[0]);
	return TCL_ERROR;
      }
    }
    if (setPageNumber &&
	!SDDS_SetRowValues(&(sddsFdTable[fdOutput].table), SDDS_SET_BY_NAME|SDDS_PASS_BY_VALUE, 
			   page_number-1, "PageNumber", page_number, NULL)) {
      sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
      Tcl_AppendResult(interp, "sdds collapse: ", sddsErrs[0], NULL);
      SDDS_ClearErrors();
      free(sddsErrs[0]);
      return TCL_ERROR;
    }
  }

  if (!SDDS_WritePage(&(sddsFdTable[fdOutput].table))) {
    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
    Tcl_AppendResult(interp, "sdds expand: ", sddsErrs[0], NULL);
    SDDS_ClearErrors();
    free(sddsErrs[0]);
    return TCL_ERROR;
  }
  return TCL_OK;
}

/******************************************
 *
 *****************************************/
int tclSDDSExpand(Tcl_Interp *interp, int argc, char *argv[]) {
  typedef struct {
    char *name;
    long size;
    long index;  /* index in the target data set */
    short doCopy;
  } SOURCE_DATA;
  SOURCE_DATA *columnSource, *parameterSource;
  char **sddsErrs, **nameData;
  int32_t sddsNumErrs;
  long rows, irow, noWarnings, i;
  int32_t columnSources, parameterSources;
  int fdInput, fdOutput;
  char *sddsFileId;
  void **data;
  long buffer[32];
  noWarnings = 0;

  if ((argc != 4) && (argc != 5)) {  
    Tcl_SetResult(interp, "usage: sdds expand <fd input> <fd output> [-noWarnings]", NULL);
    return TCL_ERROR;    
  }
  sddsFileId = argv[2];
  fdInput = atoi(sddsFileId);
  sddsFileId = argv[3];
  fdOutput = atoi(sddsFileId);
  if (argc == 5) {
    if (!strcmp(argv[4],"-noWarnings")) {
      noWarnings = 1;
    } else {
      Tcl_SetResult(interp, "usage: sdds expand <fd input> <fd output> [-noWarnings]", NULL);
      return TCL_ERROR;    
    }
  }
  if ((fdInput  > MAX_OPEN_SDDS_FILES) || (sddsFdTable[fdInput].free  == 1) ||
      (fdOutput > MAX_OPEN_SDDS_FILES) || (sddsFdTable[fdOutput].free == 1)) { 
    Tcl_SetResult(interp, "sdds expand: unknown file descriptor", (Tcl_FreeProc *) NULL);
    return TCL_ERROR;
  }
  if (sddsFdTable[fdInput].mode != 'r') {
    Tcl_SetResult(interp, "sdds expand: <fd input> must be opened for reading", NULL);
    return TCL_ERROR;
  }
  if (sddsFdTable[fdOutput].mode != 'w') {
    Tcl_SetResult(interp, "sdds expand: <fd output> must be opened for writing", NULL);
    return TCL_ERROR;
  }
  /* currently reopens the input file but this may be changed in the future */
  if (tclSDDSReopenFd(fdInput)) {
    Tcl_SetResult(interp, 
		  "sdds expand: unable to reopen input file", NULL);
    return TCL_ERROR;
  }

  if (((nameData = SDDS_GetColumnNames(&(sddsFdTable[fdInput].table), &columnSources)) == NULL) ||
     (!(columnSource = malloc(sizeof(*columnSource)*columnSources)))) {
    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
    Tcl_AppendResult(interp, "sdds expand: ", sddsErrs[0], NULL);
    SDDS_ClearErrors();
    free(sddsErrs[0]);
    return TCL_ERROR;
  }

  for (i=0 ; i < columnSources ; i++) {
    columnSource[i].name = nameData[i];
    if (!SDDS_DefineParameterLikeColumn(&(sddsFdTable[fdOutput].table), 
					&(sddsFdTable[fdInput].table), columnSource[i].name, NULL) ||
        (columnSource[i].index = SDDS_GetParameterIndex(&(sddsFdTable[fdOutput].table)
							, columnSource[i].name))<0) {
      sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
      Tcl_AppendResult(interp, "sdds expand: ", sddsErrs[0], NULL);
      SDDS_ClearErrors();
      free(sddsErrs[0]);
      return TCL_ERROR;
    }
    columnSource[i].size = SDDS_GetTypeSize(SDDS_GetParameterType(&(sddsFdTable[fdOutput].table), 
								  columnSource[i].index));
  }

  if (((nameData = SDDS_GetParameterNames(&(sddsFdTable[fdInput].table), &parameterSources)) == NULL) ||
      (!(parameterSource = malloc(sizeof(*parameterSource)*parameterSources)))) {
    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
    Tcl_AppendResult(interp, "sdds expand: ", sddsErrs[0], NULL);
    SDDS_ClearErrors();
    free(sddsErrs[0]);
    return TCL_ERROR;
  }

  for (i=0 ; i < parameterSources ; i++) {
    parameterSource[i].name = nameData[i];
    if (SDDS_GetParameterIndex(&(sddsFdTable[fdOutput].table), parameterSource[i].name)>=0) {
      if (!noWarnings) {
	Tcl_AppendResult(interp, "Warning (sddsexpand): name ", parameterSource[i].name, " used for parameter and column in input file. Column data used.\n", NULL);
      }
      parameterSource[i].doCopy = 0;
      continue;
    }
    parameterSource[i].doCopy = 1;
    if (!SDDS_TransferParameterDefinition(&(sddsFdTable[fdOutput].table), &(sddsFdTable[fdInput].table), 
                                          parameterSource[i].name, NULL) ||
        (parameterSource[i].index = SDDS_GetParameterIndex(&(sddsFdTable[fdOutput].table), 
							   parameterSource[i].name))<0) {
      sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
      Tcl_AppendResult(interp, "sdds expand: ", sddsErrs[0], NULL);
      SDDS_ClearErrors();
      free(sddsErrs[0]);
      return TCL_ERROR;
    }
    parameterSource[i].size = SDDS_GetTypeSize(SDDS_GetParameterType(&(sddsFdTable[fdOutput].table), 
								     parameterSource[i].index));
  }

  if (!SDDS_WriteLayout(&(sddsFdTable[fdOutput].table)) ||
      (!(data=malloc(sizeof(*data)*columnSources)))) {
    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
    Tcl_AppendResult(interp, "sdds expand: ", sddsErrs[0], NULL);
    SDDS_ClearErrors();
    free(sddsErrs[0]);
    return TCL_ERROR;
  }

  while (SDDS_ReadPage(&(sddsFdTable[fdInput].table))>0) {
    if ((rows = SDDS_CountRowsOfInterest(&(sddsFdTable[fdInput].table))) == -1) {
      continue;
    }
    for (i=0; i<columnSources; i++) 
      if (!(data[i] = SDDS_GetInternalColumn(&(sddsFdTable[fdInput].table), columnSource[i].name))) {
	sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	Tcl_AppendResult(interp, "sdds expand: ", sddsErrs[0], NULL);
	SDDS_ClearErrors();
	free(sddsErrs[0]);
	return TCL_ERROR;
      }
    for (irow=0; irow<rows; irow++) {
      if (!SDDS_StartPage(&(sddsFdTable[fdOutput].table), 0)) {
	sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	Tcl_AppendResult(interp, "sdds expand: ", sddsErrs[0], NULL);
	SDDS_ClearErrors();
	free(sddsErrs[0]);
	return TCL_ERROR;
      }
      for (i=0; i<parameterSources; i++) {
        if (!parameterSource[i].doCopy)
          continue;
        if (!SDDS_GetParameter(&(sddsFdTable[fdInput].table), parameterSource[i].name, buffer) ||
            !SDDS_SetParameters(&(sddsFdTable[fdOutput].table), SDDS_SET_BY_INDEX|SDDS_PASS_BY_REFERENCE, 
                                parameterSource[i].index, buffer, -1)) {
	  sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	  Tcl_AppendResult(interp, "sdds expand: ", sddsErrs[0], NULL);
	  SDDS_ClearErrors();
	  free(sddsErrs[0]);
	  return TCL_ERROR;
	}
      }
      for (i=0; i<columnSources; i++) {
        if (!SDDS_SetParameters(&(sddsFdTable[fdOutput].table), SDDS_SET_BY_INDEX|SDDS_PASS_BY_REFERENCE,
                                columnSource[i].index, (((char*)data[i])+irow*columnSource[i].size), -1)) {
	  sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	  Tcl_AppendResult(interp, "sdds expand: ", sddsErrs[0], NULL);
	  SDDS_ClearErrors();
	  free(sddsErrs[0]);
	  return TCL_ERROR;
	}
      }
      if (!SDDS_WritePage(&(sddsFdTable[fdOutput].table))) {
	sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	Tcl_AppendResult(interp, "sdds expand: ", sddsErrs[0], NULL);
	SDDS_ClearErrors();
	free(sddsErrs[0]);
	return TCL_ERROR;
      }
    }
  }
  return TCL_OK;
}

/******************************************
 *
 *****************************************/
int tclSDDSConvert(Tcl_Interp *interp, int argc, char *argv[]) {
#define COLUMN_MODE 0
#define PARAMETER_MODE 1
#define ARRAY_MODE 2
#define MODES 3
#define SET_DELETE 0
#define SET_RETAIN 1
#define SET_RENAME 2
#define SET_EDIT_NAMES 3
#define SET_RECOVER 4
#define SET_FROMPAGE 5
#define SET_TOPAGE 6
#define SET_ACCEPT_ALL_NAMES 7
#define N_OPTIONS 8

  char **retain_column, **delete_column;
  long retain_columns, delete_columns, rename_columns, edit_column_requests;
  EDIT_NAME_REQUEST *edit_column_request;
  STRING_PAIR *rename_column;
  char **orig_column_name, **new_column_name = NULL;
  long *orig_column_flag;
  int32_t orig_column_names;
  
  char **retain_parameter, **delete_parameter;
  long retain_parameters, delete_parameters, rename_parameters, edit_parameter_requests;
  EDIT_NAME_REQUEST *edit_parameter_request;
  STRING_PAIR *rename_parameter;
  char **orig_parameter_name, **new_parameter_name = NULL;
  long *orig_parameter_flag;
  int32_t orig_parameter_names;
  
  char **retain_array, **delete_array;
  long retain_arrays, delete_arrays, rename_arrays, edit_array_requests;
  EDIT_NAME_REQUEST *edit_array_request;
  STRING_PAIR *rename_array;
  char **orig_array_name, **new_array_name = NULL;
  long *orig_array_flag;
  int32_t orig_array_names;

  char *ptr, *input, *output, *buffer;
  char **sddsErrs;
  long i, i_arg, pageNumber, fromPage, toPage, recover, fdInput, fdOutput;
  int32_t sddsNumErrs;
  long output_columns, max_size;
  long recovered, rows;
  SCANNED_ARG *s_arg;

  static char *mode_name[MODES] = {
    "column", "parameter", "array",
  };
  char *option[N_OPTIONS] = {
    "delete", "retain", "rename",
    "editnames", "recover",
    "frompage", "topage", "acceptallnames",
  };

  pageNumber = fromPage = toPage = recover = 0;
  input = output = NULL;
  fdInput = fdOutput = 0;

  retain_column = delete_column = NULL;
  retain_columns = delete_columns = rename_columns = edit_column_requests = 0;
  rename_column = NULL;
  edit_column_request = NULL;
  
  retain_parameter = delete_parameter = NULL;
  retain_parameters = delete_parameters = rename_parameters = edit_parameter_requests = 0;
  rename_parameter = NULL;
  edit_parameter_request = NULL;
  
  retain_array = delete_array = NULL;
  retain_arrays = delete_arrays = rename_arrays = edit_array_requests = 0;
  rename_array = NULL;
  edit_array_request = NULL;
  

  argc = scanargs(&s_arg, argc, argv);
  if (argc<4) {
    Tcl_SetResult(interp, "usage: sdds convert <fd input> <fd output>\n[-fromPage=<pageNumber>] [-toPage=<pageNumber>] [-recover[=clip]]\n[-delete={column | parameter | array},<matching-string>[,...]]\n[-retain={column | parameter | array},<matching-string>[,...]]\n[-rename={column | parameter | array},<oldname>=<newname>[,...]]\n[-editnames={column | parameter | array},<wildcard-string>,<edit-string>]\n[-acceptAllNames]", NULL);
    return TCL_ERROR;    
  }
  
  for (i_arg=2; i_arg<argc; i_arg++) {
    if (s_arg[i_arg].arg_type==OPTION) {
      delete_chars(s_arg[i_arg].list[0], "_");
      switch (match_string(s_arg[i_arg].list[0], option, N_OPTIONS, 0)) {
      case SET_DELETE:
	if (s_arg[i_arg].n_items<3) {
	  Tcl_SetResult(interp, "sdds convert: invalid -delete syntax", NULL);
	  return TCL_ERROR;    
	}
	switch (match_string(s_arg[i_arg].list[1], mode_name, MODES, 0)) {
	case COLUMN_MODE:
	  delete_column = trealloc(delete_column, 
				   sizeof(*delete_column)*(delete_columns+s_arg[i_arg].n_items-2));
	  for (i=2; i<s_arg[i_arg].n_items; i++)
	    delete_column[i-2+delete_columns] = s_arg[i_arg].list[i];
	  delete_columns += s_arg[i_arg].n_items-2;
	  break;
	case PARAMETER_MODE:
	  delete_parameter = trealloc(delete_parameter, 
				      sizeof(*delete_parameter)*(delete_parameters+s_arg[i_arg].n_items-2));
	  for (i=2; i<s_arg[i_arg].n_items; i++)
	    delete_parameter[i-2+delete_parameters] = s_arg[i_arg].list[i];
	  delete_parameters += s_arg[i_arg].n_items-2;
	  break;
	case ARRAY_MODE:
	  delete_array = trealloc(delete_array, 
				  sizeof(*delete_array)*(delete_arrays+s_arg[i_arg].n_items-2));
	  for (i=2; i<s_arg[i_arg].n_items; i++)
	    delete_array[i-2+delete_arrays] = s_arg[i_arg].list[i];
	  delete_arrays += s_arg[i_arg].n_items-2;
	  break;
	default:
	  Tcl_SetResult(interp, "sdds convert: invalid -delete syntax, specify column or parameter keyword", NULL);
	  return TCL_ERROR;    
	}
	break;
      case SET_RETAIN:
	if (s_arg[i_arg].n_items<3) {
	  Tcl_SetResult(interp, "sdds convert: invalid -retain syntax", NULL);
	  return TCL_ERROR;    
	}
	switch (match_string(s_arg[i_arg].list[1], mode_name, MODES, 0)) {
	case COLUMN_MODE:
	  retain_column = trealloc(retain_column, 
				   sizeof(*retain_column)*(retain_columns+s_arg[i_arg].n_items-2));
	  for (i=2; i<s_arg[i_arg].n_items; i++)
	    retain_column[i-2+retain_columns] = s_arg[i_arg].list[i];
	  retain_columns += s_arg[i_arg].n_items-2;
	  break;
	case PARAMETER_MODE:
	  retain_parameter = trealloc(retain_parameter, 
				      sizeof(*retain_parameter)*(retain_parameters+s_arg[i_arg].n_items-2));
	  for (i=2; i<s_arg[i_arg].n_items; i++)
	    retain_parameter[i-2+retain_parameters] = s_arg[i_arg].list[i];
	  retain_parameters += s_arg[i_arg].n_items-2;
	  break;
	case ARRAY_MODE:
	  retain_array = trealloc(retain_array, 
				  sizeof(*retain_array)*(retain_arrays+s_arg[i_arg].n_items-2));
	  for (i=2; i<s_arg[i_arg].n_items; i++)
	    retain_array[i-2+retain_arrays] = s_arg[i_arg].list[i];
	  retain_arrays += s_arg[i_arg].n_items-2;
	  break;
	default:
	  Tcl_SetResult(interp, "sdds convert: invalid -retain syntax, specify column or parameter keyword", NULL);
	  return TCL_ERROR;    
	}
	break;
      case SET_RENAME:
	if (s_arg[i_arg].n_items<3) {
	  Tcl_SetResult(interp, "sdds convert: invalid -rename syntax", NULL);
	  return TCL_ERROR;    
	}
	switch (match_string(s_arg[i_arg].list[1], mode_name, MODES, 0)) {
	case COLUMN_MODE:
	  rename_column = trealloc(rename_column, 
				   sizeof(*rename_column)*(rename_columns+s_arg[i_arg].n_items-2));
	  for (i=2; i<s_arg[i_arg].n_items; i++) {
	    if (!(ptr=strchr(s_arg[i_arg].list[i], '='))) {
	      Tcl_SetResult(interp, "sdds convert: invalid -rename syntax", NULL);
	      return TCL_ERROR;    
	    }
	    *ptr++ = 0;
	    rename_column[i-2+rename_columns][0] = s_arg[i_arg].list[i];
	    rename_column[i-2+rename_columns][1] = ptr;
	  }
	  rename_columns += s_arg[i_arg].n_items-2;
	  break;
	case PARAMETER_MODE:
	  rename_parameter = trealloc(rename_parameter, 
				      sizeof(*rename_parameter)*(rename_parameters+s_arg[i_arg].n_items-2));
	  for (i=2; i<s_arg[i_arg].n_items; i++) {
	    if (!(ptr=strchr(s_arg[i_arg].list[i], '='))) {
	      Tcl_SetResult(interp, "sdds convert: invalid -rename syntax", NULL);
	      return TCL_ERROR;    
	    }
	    *ptr++ = 0;
	    rename_parameter[i-2+rename_parameters][0] = s_arg[i_arg].list[i];
	    rename_parameter[i-2+rename_parameters][1] = ptr;
	  }
	  rename_parameters += s_arg[i_arg].n_items-2;
	  break;
	case ARRAY_MODE:
	  rename_array = trealloc(rename_array, 
				  sizeof(*rename_array)*(rename_arrays+s_arg[i_arg].n_items-2));
	  for (i=2; i<s_arg[i_arg].n_items; i++) {
	    if (!(ptr=strchr(s_arg[i_arg].list[i], '='))) {
	      Tcl_SetResult(interp, "sdds convert: invalid -rename syntax", NULL);
	      return TCL_ERROR;    
	    }
	    *ptr++ = 0;
	    rename_array[i-2+rename_arrays][0] = s_arg[i_arg].list[i];
	    rename_array[i-2+rename_arrays][1] = ptr;
	  }
	  rename_arrays += s_arg[i_arg].n_items-2;
	  break;
	default:
	  Tcl_SetResult(interp, "sdds convert: invalid -rename syntax, specify column or parameter keyword", NULL);
	  return TCL_ERROR;    
	}
	break;
      case SET_FROMPAGE:
	if (s_arg[i_arg].n_items<2) {
	  Tcl_SetResult(interp, "sdds convert: invalid -fromPage syntax", NULL);
	  return TCL_ERROR;    
	}
	if (fromPage!=0) {
	  Tcl_SetResult(interp, "sdds convert: specify -fromPage once only", NULL);
	  return TCL_ERROR;    
	}
	if (sscanf(s_arg[i_arg].list[1], "%ld", &fromPage)!=1 || fromPage<=0) {
	  Tcl_SetResult(interp, "sdds convert: invalid -fromPage syntax or value", NULL);
	  return TCL_ERROR;    
	}
	break;
      case SET_TOPAGE:
	if (s_arg[i_arg].n_items<2) {
	  Tcl_SetResult(interp, "sdds convert: invalid -toPage syntax", NULL);
	  return TCL_ERROR;    
	}
	if (toPage!=0) {
	  Tcl_SetResult(interp, "sdds convert: invalid syntax, specify -toPage once only", NULL);
	  return TCL_ERROR;    
	}
	if (sscanf(s_arg[i_arg].list[1], "%ld", &toPage)!=1 || toPage<=0) {
	  Tcl_SetResult(interp, "sdds convert: invalid -toPage syntax or value", NULL);
	  return TCL_ERROR;    
	}
	break;
      case SET_EDIT_NAMES: 
	if (s_arg[i_arg].n_items<4) {
	  Tcl_SetResult(interp, "sdds convert: invalid -editnames syntax", NULL);
	  return TCL_ERROR;    
	}
	switch (match_string(s_arg[i_arg].list[1], mode_name, MODES, 0)) {
	case COLUMN_MODE:
	  edit_column_request = trealloc(edit_column_request, sizeof(*edit_column_request)*(edit_column_requests+1));
	  edit_column_request[edit_column_requests].match_string = s_arg[i_arg].list[2];
	  edit_column_request[edit_column_requests].edit_string  = s_arg[i_arg].list[3];
	  edit_column_requests++;
	  break;
	case PARAMETER_MODE:
	  edit_parameter_request = trealloc(edit_parameter_request, sizeof(*edit_parameter_request)*(edit_parameter_requests+1));
	  edit_parameter_request[edit_parameter_requests].match_string = s_arg[i_arg].list[2];
	  edit_parameter_request[edit_parameter_requests].edit_string  = s_arg[i_arg].list[3];
	  edit_parameter_requests++;
	  break;
	case ARRAY_MODE:
	  edit_array_request = trealloc(edit_array_request, sizeof(*edit_array_request)*(edit_array_requests+1));
	  edit_array_request[edit_array_requests].match_string = s_arg[i_arg].list[2];
	  edit_array_request[edit_array_requests].edit_string  = s_arg[i_arg].list[3];
	  edit_array_requests++;
	  break;
	default:
	  Tcl_SetResult(interp, "sdds convert: invalid -editnames syntax, specify column or parameter keyword", NULL);
	  return TCL_ERROR;    
	}
	break;
      case SET_RECOVER:
	recover = 1;
	if (s_arg[i_arg].n_items!=1) {
	  recover = 2;
	  if (s_arg[i_arg].n_items>2 ||
	      strncmp(s_arg[i_arg].list[1], "clip", strlen(s_arg[i_arg].list[1]))!=0) {
	    Tcl_SetResult(interp, "sdds convert: invalid -recover syntax", NULL);
	    return TCL_ERROR;    
	  }
	}
	break;
      case SET_ACCEPT_ALL_NAMES:
	SDDS_SetNameValidityFlags(SDDS_ALLOW_ANY_NAME);
	break; 
      default:
	Tcl_AppendResult(interp, "sdds convert: unknown switch ", s_arg[i_arg].list[0], NULL);
	return TCL_ERROR;    
      }
    }
    else {
      if (input==NULL)
	input = s_arg[i_arg].list[0];
      else if (output==NULL)
	output = s_arg[i_arg].list[0];
      else {
	Tcl_SetResult(interp, "sdds convert: too many file descriptors", NULL);
	return TCL_ERROR;    
      }
    }
  }
  if (fromPage && toPage && fromPage>toPage) {
    Tcl_SetResult(interp, "sdds convert: invalid -fromPage and -toPage", NULL);
    return TCL_ERROR;    
  }

  if (input==NULL) {
    Tcl_SetResult(interp, "sdds convert: no input file descriptor found", NULL);
    return TCL_ERROR;    
  }    
  if (output==NULL) {
    Tcl_SetResult(interp, "sdds convert: no output file descriptor found", NULL);
    return TCL_ERROR;    
  }    
  fdInput = atoi(input);
  fdOutput = atoi(output);
  if ((fdInput  > MAX_OPEN_SDDS_FILES) || (sddsFdTable[fdInput].free  == 1) ||
      (fdOutput > MAX_OPEN_SDDS_FILES) || (sddsFdTable[fdOutput].free == 1)) {
    Tcl_SetResult(interp, "sdds convert: unknown file descriptor", (Tcl_FreeProc *) NULL);
    return TCL_ERROR;
  }
  if (sddsFdTable[fdInput].mode != 'r') {
    Tcl_SetResult(interp, "sdds convert: <fd input> must be opened for reading", NULL);
    return TCL_ERROR;
  }
  if (sddsFdTable[fdOutput].mode != 'w') {
    Tcl_SetResult(interp, "sdds convert: <fd output> must be opened for writing", NULL);
    return TCL_ERROR;
  }
  /* currently reopens the input file but this may be changed in the future */
  if (tclSDDSReopenFd(fdInput)) {
    Tcl_SetResult(interp, "sdds convert: unable to reopen input file", NULL);
    return TCL_ERROR;
  }

  /*Getting column, parameter, and array names from input file*/
  if (!(orig_column_name = SDDS_GetColumnNames(&(sddsFdTable[fdInput].table), &orig_column_names))) {
    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
    Tcl_AppendResult(interp, "sdds convert: ", sddsErrs[0], NULL);
    SDDS_ClearErrors();
    free(sddsErrs[0]);
    return TCL_ERROR;
  }
  if (orig_column_names && 
      !(new_column_name=process_name_options(orig_column_name, &orig_column_flag, orig_column_names,
					     delete_column, delete_columns,
					     retain_column, retain_columns,
					     rename_column, rename_columns,
					     edit_column_request, edit_column_requests))) 
    return TCL_ERROR;
  
  if (!(orig_parameter_name = SDDS_GetParameterNames(&(sddsFdTable[fdInput].table), &orig_parameter_names))) {
    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
    Tcl_AppendResult(interp, "sdds convert: ", sddsErrs[0], NULL);
    SDDS_ClearErrors();
    free(sddsErrs[0]);
    return TCL_ERROR;
  }
  
  /*processing name options*/
  if (orig_parameter_names && 
      !(new_parameter_name=process_name_options(orig_parameter_name, &orig_parameter_flag, orig_parameter_names,
						delete_parameter, delete_parameters,
						retain_parameter, retain_parameters,
						rename_parameter, rename_parameters,
						edit_parameter_request, edit_parameter_requests))) 
    return TCL_ERROR;
  
  if (!(orig_array_name = SDDS_GetArrayNames(&(sddsFdTable[fdInput].table), &orig_array_names))) {
    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
    Tcl_AppendResult(interp, "sdds convert: ", sddsErrs[0], NULL);
    SDDS_ClearErrors();
    free(sddsErrs[0]);
    return TCL_ERROR;
  }
  if (orig_array_names && 
      !(new_array_name=process_name_options(orig_array_name, &orig_array_flag, orig_array_names,
					    delete_array, delete_arrays,
					    retain_array, retain_arrays,
					    rename_array, rename_arrays,
					    edit_array_request, edit_array_requests))) 
    return TCL_ERROR;
    
  /*Transferring definitions to new file*/
  for (i=0; i<orig_parameter_names; i++) {
    if (orig_parameter_flag[i]) {
      if (!SDDS_TransferParameterDefinition(&(sddsFdTable[fdOutput].table), &(sddsFdTable[fdInput].table),
					    orig_parameter_name[i], new_parameter_name[i])) {
	Tcl_AppendResult(interp, "unable to transfer parameter ", orig_parameter_name[i],
			 " to ", new_parameter_name[i], NULL);
	return TCL_ERROR;
      }
    }
  }
  for (i=0; i<orig_array_names; i++) {
    if (orig_array_flag[i]) {
      if (!SDDS_TransferArrayDefinition(&(sddsFdTable[fdOutput].table), &(sddsFdTable[fdInput].table),
					orig_array_name[i], new_array_name[i])) {
	Tcl_AppendResult(interp, "unable to transfer array ", orig_array_name[i],
			 " to ", new_array_name[i], NULL);
	return TCL_ERROR;
      }
    }
  }
  output_columns = 0;
  for (i=0; i<orig_column_names; i++) {
    if (orig_column_flag[i]) {
      output_columns++;
      if (!SDDS_TransferColumnDefinition(&(sddsFdTable[fdOutput].table), &(sddsFdTable[fdInput].table),
					 orig_column_name[i], new_column_name[i])) {
	Tcl_AppendResult(interp, "unable to transfer column ", orig_column_name[i],
			 " to ", new_column_name[i], NULL);
	return TCL_ERROR;
      }
    }
  }

  /*Saving layout*/
  if (!SDDS_SaveLayout(&(sddsFdTable[fdOutput].table))) {
    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
    Tcl_AppendResult(interp, "sdds convert: ", sddsErrs[0], NULL);
    SDDS_ClearErrors();
    free(sddsErrs[0]);
    return TCL_ERROR;
  }
  /*Writing layout*/
  if (!SDDS_WriteLayout(&(sddsFdTable[fdOutput].table))) {
    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
    Tcl_AppendResult(interp, "sdds convert: ", sddsErrs[0], NULL);
    SDDS_ClearErrors();
    free(sddsErrs[0]);
    return TCL_ERROR;
  }  
  
  max_size = 0;
  for (i=0; i<SDDS_NUM_TYPES; i++)
    if (max_size<SDDS_type_size[i])
      max_size = SDDS_type_size[i];
  buffer = tmalloc(max_size*sizeof(char));
  
  recovered = 0;
  /*Reading file*/
  while (!recovered && (pageNumber=SDDS_ReadPage(&(sddsFdTable[fdInput].table)))>=0) {
    if (pageNumber==0) {
      if (!recover) {
	/* user did not ask to recover garbled page, so clip it */
	Tcl_AppendResult(interp, "sdds convert: SDDS data garbled--consider using -recover option\n", NULL);
	Tcl_AppendResult(interp, "sdds convert: one or more data pages may be missing\n", NULL);
	break;
      }
      else {
	if (recover!=2 && SDDS_ReadRecoveryPossible(&(sddsFdTable[fdInput].table))) {
	  /* user wants to recover bad page */
	  recovered = 1;
	}
	else {
	  if (recover!=2) {
	    Tcl_AppendResult(interp, "sdds convert: unable to recover garbled data--one or more data pages may be missing\n", NULL);
	  }
	  break;
	}
      }
    }
    if (fromPage && pageNumber<fromPage)
      continue;
    if ((rows = SDDS_CountRowsOfInterest(&(sddsFdTable[fdInput].table)))<0) {
      Tcl_AppendResult(interp, "sdds convert: problem counting rows in input page", NULL);
      return TCL_ERROR;
    }
    if (!SDDS_StartPage(&(sddsFdTable[fdOutput].table), rows)) {
      Tcl_AppendResult(interp, "sdds convert: problem starting output page", NULL);
      return TCL_ERROR;
    }
    for (i=0; i<orig_parameter_names; i++) {
      if (orig_parameter_flag[i]) {
	if (!SDDS_GetParameter(&(sddsFdTable[fdInput].table), orig_parameter_name[i], buffer)) {
	  Tcl_AppendResult(interp, "sdds convert:  problem getting parameter ", orig_parameter_name[i], NULL);
	  return TCL_ERROR;
	}
	if (!SDDS_SetParameters(&(sddsFdTable[fdOutput].table), SDDS_SET_BY_NAME|SDDS_PASS_BY_REFERENCE,
				new_parameter_name[i], buffer, NULL)) {
	  Tcl_AppendResult(interp, "sdds convert:  problem setting parameter ", new_parameter_name[i], NULL);
	  return TCL_ERROR;
	}
	/* need to free string data here */
      }
    }
    for (i=0; i<orig_array_names; i++) {
      SDDS_ARRAY *array;
      if (orig_array_flag[i]) {
	if (!(array=SDDS_GetArray(&(sddsFdTable[fdInput].table), orig_array_name[i], NULL))) {
	  Tcl_AppendResult(interp, "sdds convert:  problem getting array ", orig_array_name[i], NULL);
	  return TCL_ERROR;
	}
	if (!SDDS_SetArray(&(sddsFdTable[fdOutput].table), new_array_name[i], SDDS_CONTIGUOUS_DATA,
			   array->data, array->dimension)) {
	  Tcl_AppendResult(interp, "sdds convert:  problem setting array ", new_array_name[i], NULL);
	  return TCL_ERROR;
	}
      }
    }
    if (SDDS_CountRowsOfInterest(&(sddsFdTable[fdInput].table))) {
      for (i=0; i<orig_column_names; i++) {
	if (orig_column_flag[i]) {
	  if (!(ptr=SDDS_GetInternalColumn(&(sddsFdTable[fdInput].table), orig_column_name[i]))) {
	    Tcl_AppendResult(interp, "sdds convert:  problem getting column ", orig_column_name[i], NULL);
	    return TCL_ERROR;
	  }
	  if (!SDDS_SetColumn(&(sddsFdTable[fdOutput].table), SDDS_SET_BY_NAME,
			      ptr, rows,  new_column_name[i])) {
	    Tcl_AppendResult(interp, "sdds convert:  problem setting column ", new_column_name[i], NULL);
	    return TCL_ERROR;
	  }
	}
      }
    }
    if (!SDDS_WritePage(&(sddsFdTable[fdOutput].table))) {
      Tcl_AppendResult(interp, "sdds convert:  problem writing page to file ", 
		       sddsFdTable[fdOutput].fileName, NULL);
      return TCL_ERROR;
    }
    if (toPage && pageNumber>=toPage)
      break;
  }
  return TCL_OK;
}

int tclSDDSSave(Tcl_Interp *interp, int argc, char *argv[]) {
  int32_t sddsNumErrs;
  long i, j, k, n, ntype, nfieldLength = 0, ndimensions = 1, *types[3];
  int32_t dim[4];
  int32_t arrayDim;
  int fd, listArgc, listArgc2, objcPtr, page, length, result = 0, numColumns, elements;
  char **sddsErrs, *fileName, *tclArrayName, buffer[tclSDDS_BUFSIZE], *arrayBuffer=NULL, *tempBuffer;
  char *description_text, *description_contents, **listArgv, **listArgv2;
  char *symbol, *units, *description, *format_string, *type, *fixed_value;
  char *field_length, *dimensions, *groupName;
  Tcl_Obj *arrayName, *arraySubName, **data[3], *names[3], *info[3], **objvPtr, *obj;
  long setMode = (SDDS_SET_BY_NAME | SDDS_PASS_BY_VALUE);
  long rows = -1;
  long lines_per_row = 1;
  long no_row_count = 0;
  int pages = -1;
  long dataMode = SDDS_ASCII;
  if (argc != 4) {
    Tcl_SetResult(interp, "usage: sdds save <filename> <tclArrayName>",NULL);
    return TCL_ERROR;    
  }
  
  fileName = argv[2];
  tclArrayName = argv[3];

  if ((fd = tclSDDSGetFreeFd()) == -1) {
    Tcl_SetResult(interp, "sdds save: too many SDDS files open", NULL);
    return TCL_ERROR;
  }

  /* Create Array Object That Will Hold TCL Variable */
  arrayName = Tcl_NewStringObj(tclArrayName, -1);

  /* Read in the Description */
  description_text = (char*)Tcl_GetVar2(interp, tclArrayName, "Description.Text", 0);
  description_contents = (char*)Tcl_GetVar2(interp, tclArrayName, "Description.Contents", 0);
  if ((description_text == NULL) || 
      (strlen(description_text) == 0)) {
    description_text = NULL;
  }
  if ((description_contents == NULL) || 
      (strlen(description_contents) == 0)) {
    description_contents = NULL;
  }

  /* Read in the Data Mode */
  tempBuffer = (char*)Tcl_GetVar2(interp, tclArrayName, "Layout.DataMode.Mode", 0);
  if (tempBuffer) {
      if (!strcmp(tempBuffer,"binary")) {
	dataMode = SDDS_BINARY;
      }
  }

  /* Read in Layout.DataMode.LinesPerRow */
  arraySubName = Tcl_NewStringObj("Layout.DataMode.LinesPerRow", -1);
  obj = Tcl_ObjGetVar2(interp, arrayName, arraySubName, 0);
  if (obj) {
    if (Tcl_GetLongFromObj(interp, obj, &lines_per_row) != TCL_OK) {
      lines_per_row = 1;
    }
  }

  /* Read in Layout.DataMode.NoRowCount */
  arraySubName = Tcl_NewStringObj("Layout.DataMode.NoRowCount", -1);
  obj = Tcl_ObjGetVar2(interp, arrayName, arraySubName, 0);
  if (obj) {
    if (Tcl_GetLongFromObj(interp, obj, &no_row_count) != TCL_OK) {
      no_row_count = 0;
    }
  }

  /* Open File */
  sddsFdTable[fd].mode = 'w';
  if (!SDDS_InitializeOutput(&(sddsFdTable[fd].table), dataMode, lines_per_row, 
			     description_text, description_contents, fileName)) {
    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
    Tcl_AppendResult(interp, "sdds save: ", sddsErrs[0], NULL);
    SDDS_ClearErrors();
    free(sddsErrs[0]);
    return TCL_ERROR;
  }
  strcpy(sddsFdTable[fd].fileName,fileName);
  sddsFdTable[fd].free = 0;

  if (no_row_count) {
    if (!SDDS_SetRowCountMode(&(sddsFdTable[fd].table), SDDS_NOROWCOUNT)) {
      sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
      Tcl_AppendResult(interp, "sdds save: ", sddsErrs[0], NULL);
      SDDS_ClearErrors();
      free(sddsErrs[0]);
      return TCL_ERROR;
    }
  }

  /* Define Parameters, Arrays, and Columns */
  for (k = 0; k < 3; k++) {
    types[k] = NULL;
  }
  for (k = 0; k < 3; k++) {
    if (k == 0) { arraySubName = Tcl_NewStringObj("ParameterNames", -1);
    } else if (k == 1) { arraySubName = Tcl_NewStringObj("ArrayNames", -1);
    } else { arraySubName = Tcl_NewStringObj("ColumnNames", -1);
    }
    names[k] = Tcl_ObjGetVar2(interp, arrayName, arraySubName, 0);
    if (names[k]) {
      if (Tcl_SplitList(interp, Tcl_GetStringFromObj(names[k], NULL), &listArgc, (SDDSCONST char***)&listArgv) != TCL_OK) {
	Tcl_SetResult(interp,"sdds save:splitList: ",NULL);
	if (!SDDS_Terminate(&(sddsFdTable[fd].table))) {
	  sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	  Tcl_AppendResult(interp, ": Unable to close file", sddsErrs[0], NULL);
	  SDDS_ClearErrors();
	  free(sddsErrs[0]);
	  return TCL_ERROR;
	}
	sddsFdTable[fd].free = 1;
	sddsFdTable[fd].currentPage = 0;
	return TCL_ERROR;
      }
      
      types[k] = malloc(sizeof(long)*listArgc);
      for (i = 0 ; i < listArgc; i++) {
	symbol = units = description = format_string = fixed_value = field_length = dimensions = groupName = NULL;
	type = "SDDS_STRING";
	if (k == 0) { sprintf(buffer, "ParameterInfo.%s", listArgv[i]);
	} else if (k == 1) { sprintf(buffer, "ArrayInfo.%s", listArgv[i]);
	} else { sprintf(buffer, "ColumnInfo.%s", listArgv[i]);
	}
	arraySubName = Tcl_NewStringObj(buffer, -1);
	info[k] = Tcl_ObjGetVar2(interp, arrayName, arraySubName, 0);
	if (info[k]) {
	  if (Tcl_SplitList(interp, Tcl_GetStringFromObj(info[k], NULL), &listArgc2, (SDDSCONST char***)&listArgv2) != TCL_OK) {
	    Tcl_SetResult(interp,"sdds save:splitList: ",NULL);
	    Tcl_Free((char *) listArgv);
	    for (j = 0; j < 3; j++) {
	      if (types[j]) free(types[j]);
	    }
	    if (!SDDS_Terminate(&(sddsFdTable[fd].table))) {
	      sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	      Tcl_AppendResult(interp, ": Unable to close file", sddsErrs[0], NULL);
	      SDDS_ClearErrors();
	      free(sddsErrs[0]);
	      return TCL_ERROR;
	    }
	    sddsFdTable[fd].free = 1;
	    sddsFdTable[fd].currentPage = 0;
	    return TCL_ERROR;
	  }
	  for (j = 0; j < listArgc2; j += 2) {
	    if (strlen(listArgv2[j+1]) == 0) {
	      continue;
	    }
	    if (!strcmp(listArgv2[j],"symbol")) {
	      symbol = listArgv2[j+1];
	    } else if (!strcmp(listArgv2[j],"units")) {
	      units = listArgv2[j+1];
	    } else if (!strcmp(listArgv2[j],"description")) {
	      description = listArgv2[j+1];
	    } else if (!strcmp(listArgv2[j],"format_string")) {
	      format_string = listArgv2[j+1];
	    } else if (!strcmp(listArgv2[j],"type")) {
	      type = listArgv2[j+1];
	    } else if (!strcmp(listArgv2[j],"fixed_value")) {
	      fixed_value = listArgv2[j+1];
	    } else if (!strcmp(listArgv2[j],"field_length")) {
	      field_length = listArgv2[j+1];
	    } else if (!strcmp(listArgv2[j],"dimensions")) {
	      dimensions = listArgv2[j+1];
	    } else if (!strcmp(listArgv2[j],"groupName")) {
	      groupName = listArgv2[j+1];
	    }
	  }
	  /*Tcl_Free((char *) listArgv2);*/
	}
	if ((ntype = convertTypeStringToNumeric(type)) == -1) {
	  Tcl_SetResult(interp, "sdds save: invalid type given",NULL);
	  Tcl_Free((char *) listArgv);
	  for (j = 0; j < 3; j++) {
	    if (types[j]) free(types[j]);
	  }
	  if (!SDDS_Terminate(&(sddsFdTable[fd].table))) {
	    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	    Tcl_AppendResult(interp, ": Unable to close file", sddsErrs[0], NULL);
	    SDDS_ClearErrors();
	    free(sddsErrs[0]);
	    return TCL_ERROR;
	  }
	  sddsFdTable[fd].free = 1;
	  sddsFdTable[fd].currentPage = 0;
	  return TCL_ERROR;
	}
	types[k][i] = ntype;
	if (k != 0) {
	  if (field_length != NULL) {
	    nfieldLength = atoi(field_length);
	  } else {
	    nfieldLength = 0;
	  }
	}
	if (k == 1) {
	  if (dimensions != NULL) {
	    ndimensions = atoi(dimensions);
	    if (ndimensions > 4) {
	      Tcl_SetResult(interp, "sdds save: max dimension is 4",NULL);
	      Tcl_Free((char *) listArgv);
	      for (j = 0; j < 3; j++) {
		if (types[j]) free(types[j]);
	      }
	      if (!SDDS_Terminate(&(sddsFdTable[fd].table))) {
		sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
		Tcl_AppendResult(interp, ": Unable to close file", sddsErrs[0], NULL);
		SDDS_ClearErrors();
		free(sddsErrs[0]);
		return TCL_ERROR;
	      }
	      sddsFdTable[fd].free = 1;
	      sddsFdTable[fd].currentPage = 0;
	      return TCL_ERROR;
	    }
	  } else {
	    ndimensions = 1;
	  }
	}
	if (k == 0) {
	  result = SDDS_DefineParameter(&(sddsFdTable[fd].table), listArgv[i], symbol, 
					units, description, format_string, ntype, 
					fixed_value);
	} else if (k == 1) {
	  result = SDDS_DefineArray(&(sddsFdTable[fd].table), listArgv[i], symbol, units,
				    description, format_string, ntype, nfieldLength,
				    ndimensions, groupName);
	} else {
	  result = SDDS_DefineColumn(&(sddsFdTable[fd].table), listArgv[i], symbol, units,
				     description, format_string, ntype, nfieldLength);
	}
	if (result == -1) {
	  sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	  Tcl_AppendResult(interp, "sdds save: ", sddsErrs[0], NULL);
	  SDDS_ClearErrors();
	  free(sddsErrs[0]);
	  Tcl_Free((char *) listArgv);
	  for (j = 0; j < 3; j++) {
	    if (types[j]) free(types[j]);
	  }
	  if (!SDDS_Terminate(&(sddsFdTable[fd].table))) {
	    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	    Tcl_AppendResult(interp, ": Unable to close file", sddsErrs[0], NULL);
	    SDDS_ClearErrors();
	    free(sddsErrs[0]);
	    return TCL_ERROR;
	  }
	  sddsFdTable[fd].free = 1;
	  sddsFdTable[fd].currentPage = 0;
	  return TCL_ERROR;	
	}	
      }
      Tcl_Free((char *) listArgv);
    }
  }

  /* Write Layout */
  if (!SDDS_WriteLayout(&(sddsFdTable[fd].table))) {
    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
    Tcl_AppendResult(interp, "sdds save: ", sddsErrs[0], NULL);
    SDDS_ClearErrors();
    free(sddsErrs[0]);
    for (j = 0; j < 3; j++) {
      if (types[j]) free(types[j]);
    }
    if (!SDDS_Terminate(&(sddsFdTable[fd].table))) {
      sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
      Tcl_AppendResult(interp, ": Unable to close file", sddsErrs[0], NULL);
      SDDS_ClearErrors();
      free(sddsErrs[0]);
      return TCL_ERROR;
    }
    sddsFdTable[fd].free = 1;
    sddsFdTable[fd].currentPage = 0;
    return TCL_ERROR;
  }
  
  /* Check for equal number of pages */
  for (k = 0; k < 3; k++) {
    data[k] = NULL;
  }
  for (k = 0; k < 3; k++) {
    if (names[k]) {
      Tcl_SplitList(interp, Tcl_GetStringFromObj(names[k], NULL), &listArgc, (SDDSCONST char***)&listArgv);
      data[k] = malloc(sizeof(Tcl_Obj)*listArgc);
      for (i = 0 ; i < listArgc; i++) {
	if (k == 0) { sprintf(buffer, "Parameter.%s", listArgv[i]);
	} else if (k == 1) { sprintf(buffer, "Array.%s", listArgv[i]);
	} else { sprintf(buffer, "Column.%s", listArgv[i]);
	}
	arraySubName = Tcl_NewStringObj(buffer, -1);
	data[k][i] = Tcl_ObjGetVar2(interp, arrayName, arraySubName, 0);
	if (data[k][i] == NULL) {
	  Tcl_AppendResult(interp,"sdds save: ", Tcl_GetStringFromObj(arraySubName, NULL), " element is missing",NULL);
	  for (j = 0; j <= k; j++) {
	    if (data[j]) free(data[j]);
	    if (types[j]) free(types[j]);
	  }
	  Tcl_Free((char *) listArgv);
	  if (!SDDS_Terminate(&(sddsFdTable[fd].table))) {
	    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	    Tcl_AppendResult(interp, ": Unable to close file", sddsErrs[0], NULL);
	    SDDS_ClearErrors();
	    free(sddsErrs[0]);
	    return TCL_ERROR;
	  }
	  sddsFdTable[fd].free = 1;
	  sddsFdTable[fd].currentPage = 0;
	  return TCL_ERROR;
	}
	Tcl_ListObjLength(interp, data[k][i], &length); 
	if (pages == -1) {
	  pages = length;
	} else if (pages != length) {
	  Tcl_SetResult(interp,"sdds save: Number of pages not equal",NULL);
	  for (j = 0; j <= k; j++) {
	    if (data[j]) free(data[j]);
	    if (types[j]) free(types[j]);
	  }
	  Tcl_Free((char *) listArgv);
	  if (!SDDS_Terminate(&(sddsFdTable[fd].table))) {
	    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	    Tcl_AppendResult(interp, ": Unable to close file", sddsErrs[0], NULL);
	    SDDS_ClearErrors();
	    free(sddsErrs[0]);
	    return TCL_ERROR;
	  }
	  sddsFdTable[fd].free = 1;
	  sddsFdTable[fd].currentPage = 0;
	  return TCL_ERROR;	
	}
      }
      Tcl_Free((char *) listArgv);
    }
  }

  /* Check for equal number of rows */
  for (page = 0; page < pages; page++) {
    rows = -1;
    if (names[2]) {
      Tcl_ListObjLength(interp, names[2], &numColumns);
      for (i = 0; i < numColumns; i++) {
	Tcl_ListObjGetElements(interp, data[2][i], &objcPtr, &objvPtr);
	Tcl_ListObjLength(interp, objvPtr[page], &length);
	if ((rows = -1)) {
	  rows = length;
	} else if (rows != length) {
	  Tcl_SetResult(interp,"sdds save: Number of rows not equal",NULL);
	  for (j = 0; j < 3; j++) {
	    if (data[j]) free(data[j]);
	    if (types[j]) free(types[j]);
	  }
	  if (!SDDS_Terminate(&(sddsFdTable[fd].table))) {
	    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	    Tcl_AppendResult(interp, ": Unable to close file", sddsErrs[0], NULL);
	    SDDS_ClearErrors();
	    free(sddsErrs[0]);
	    return TCL_ERROR;
	  }
	  sddsFdTable[fd].free = 1;
	  sddsFdTable[fd].currentPage = 0;
	  return TCL_ERROR;	
	}
      }
    } else {
      rows = 0;
    }
    /* Start Page */
    if (!SDDS_StartPage(&(sddsFdTable[fd].table), rows)) {
      sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
      Tcl_AppendResult(interp, "sdds save: ", sddsErrs[0], NULL);
      SDDS_ClearErrors();
      free(sddsErrs[0]);
      for (j = 0; j < 3; j++) {
	if (data[j]) free(data[j]);
	if (types[j]) free(types[j]);
      }
      if (!SDDS_Terminate(&(sddsFdTable[fd].table))) {
	sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	Tcl_AppendResult(interp, ": Unable to close file", sddsErrs[0], NULL);
	SDDS_ClearErrors();
	free(sddsErrs[0]);
	return TCL_ERROR;
      }
      sddsFdTable[fd].free = 1;
      sddsFdTable[fd].currentPage = 0;
      return TCL_ERROR;	
    }
    sddsFdTable[fd].pageStarted = 1;
    
    for (k = 0; k < 3; k++) {
      if (names[k]) {
	Tcl_SplitList(interp, Tcl_GetStringFromObj(names[k], NULL), &listArgc, (SDDSCONST char***)&listArgv);
	for (i = 0 ; i < listArgc; i++) {
	  Tcl_ListObjGetElements(interp, data[k][i], &objcPtr, &objvPtr);
	  if (k == 0) {
	    /* Set Parameters */
	    switch (types[k][i]) {
	    case SDDS_LONGDOUBLE: {
	      long double res;
	      res = strtold(Tcl_GetStringFromObj(objvPtr[page], NULL), NULL);
	      result = SDDS_SetParameters(&(sddsFdTable[fd].table),setMode, listArgv[i], res, NULL);
	      break;
	    }
	    case SDDS_DOUBLE: {
	      double res;
	      if (Tcl_GetDoubleFromObj(interp, objvPtr[page], &res) != TCL_OK) {
		res = 0.0;
	      }
	      result = SDDS_SetParameters(&(sddsFdTable[fd].table),setMode, listArgv[i], res, NULL);
	      break;
	    }
	    case SDDS_FLOAT: {
	      double res;
	      float res2;
	      if (Tcl_GetDoubleFromObj(interp, objvPtr[page], &res) != TCL_OK) {
		res = 0.0;
	      }
	      res2 = res;
	      result = SDDS_SetParameters(&(sddsFdTable[fd].table),setMode, listArgv[i], res2, NULL);
	      break;
	    }
	    case SDDS_LONG64: {
	      long res;
              int64_t res2;
	      if (Tcl_GetLongFromObj(interp, objvPtr[page], &res) != TCL_OK) {
		res = 0;
	      }
              res2 = res;
	      result = SDDS_SetParameters(&(sddsFdTable[fd].table),setMode, listArgv[i], res2, NULL);
	      break;
	    }
	    case SDDS_ULONG64: {
	      uint64_t res;
              res = strtoull(Tcl_GetStringFromObj(objvPtr[page], NULL), NULL, 10);
	      result = SDDS_SetParameters(&(sddsFdTable[fd].table),setMode, listArgv[i], res, NULL);
	      break;
	    }
	    case SDDS_LONG: {
	      long res;
              int32_t res2;
	      if (Tcl_GetLongFromObj(interp, objvPtr[page], &res) != TCL_OK) {
		res = 0;
	      }
              res2 = res;
	      result = SDDS_SetParameters(&(sddsFdTable[fd].table),setMode, listArgv[i], res2, NULL);
	      break;
	    }
	    case SDDS_ULONG: {
	      Tcl_WideInt res;
              uint32_t res2;
	      if (Tcl_GetWideIntFromObj(interp, objvPtr[page], &res) != TCL_OK) {
		res = 0;
	      }
              res2 = res;
	      result = SDDS_SetParameters(&(sddsFdTable[fd].table),setMode, listArgv[i], res2, NULL);
	      break;
	    }
	    case SDDS_SHORT: {
	      int res;
              short res2;
	      if (Tcl_GetIntFromObj(interp, objvPtr[page], &res) != TCL_OK) {
		res = 0;
	      }
              res2 = res;
	      result = SDDS_SetParameters(&(sddsFdTable[fd].table),setMode, listArgv[i], res2, NULL);
	      break;
	    }
	    case SDDS_USHORT: {
	      int res;
              unsigned short res2;
	      if (Tcl_GetIntFromObj(interp, objvPtr[page], &res) != TCL_OK) {
		res = 0;
	      }
              res2 = res;
	      result = SDDS_SetParameters(&(sddsFdTable[fd].table),setMode, listArgv[i], res2, NULL);
	      break;
	    }
	    case SDDS_STRING: {
	      result = SDDS_SetParameters(&(sddsFdTable[fd].table),setMode, listArgv[i], 
					  Tcl_GetStringFromObj(objvPtr[page], NULL), NULL);
	      break;
	    }
	    case SDDS_CHARACTER: {
	      result = SDDS_SetParameters(&(sddsFdTable[fd].table),setMode, listArgv[i],
					  (Tcl_GetStringFromObj(objvPtr[page], NULL))[0], NULL);
	      break;
	    }
	    default: {
	      result = 0;
	      break;
	    }
	    }
	    if (!result) {
		sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
		Tcl_AppendResult(interp, "sdds save: ", sddsErrs[0], NULL);
		SDDS_ClearErrors();
		free(sddsErrs[0]);
		for (j = 0; j < 3; j++) {
		  if (data[j]) free(data[j]);
		  if (types[j]) free(types[j]);
		}
		Tcl_Free((char *) listArgv);
		if (!SDDS_Terminate(&(sddsFdTable[fd].table))) {
		  sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
		  Tcl_AppendResult(interp, ": Unable to close file", sddsErrs[0], NULL);
		  SDDS_ClearErrors();
		  free(sddsErrs[0]);
		  return TCL_ERROR;
		}
		sddsFdTable[fd].free = 1;
		sddsFdTable[fd].currentPage = 0;
		return TCL_ERROR;
	    }
	  } else if (k == 1) { /* Set Arrays */
	    int dimElement;
	    long count;
	    Tcl_Obj *tempObj, *tempObjElement, *obj;
	    tempObj = Tcl_NewStringObj("TempArrayDataStorageVariable", -1);

	    SDDS_GetArrayInformation(&(sddsFdTable[fd].table), "dimensions", 
				     &arrayDim, SDDS_GET_BY_NAME, listArgv[i]);
	    tempBuffer = Tcl_GetStringFromObj(objvPtr[page], NULL);
	    arrayBuffer = (char *)malloc(sizeof(char*)*strlen(tempBuffer)+100);
	    sprintf(arrayBuffer, "array set TempArrayDataStorageVariable {%s} ", 
		    tempBuffer);
	    /*
	    sprintf(buffer, "array set TempArrayDataStorageVariable {%s} ", 
		    Tcl_GetStringFromObj(objvPtr[page], NULL));
	    */
	    Tcl_UnsetVar2(interp, "TempArrayDataStorageVariable",NULL, 0);
	    if ((Tcl_Eval(interp, arrayBuffer) != TCL_OK) ||
		(Tcl_Eval(interp,"array size TempArrayDataStorageVariable") != TCL_OK) ||
		(Tcl_GetInt(interp,interp->result,&elements) != TCL_OK)) {
	      Tcl_SetResult(interp, "sdds save: error occured reading array data", NULL);
	      for (j = 0; j < 3; j++) {
		if (data[j]) free(data[j]);
		if (types[j]) free(types[j]);
	      }
	      if (arrayBuffer) free(arrayBuffer);
	      Tcl_Free((char *) listArgv);
	      if (!SDDS_Terminate(&(sddsFdTable[fd].table))) {
		sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
		Tcl_AppendResult(interp, ": Unable to close file", sddsErrs[0], NULL);
		SDDS_ClearErrors();
		free(sddsErrs[0]);
		return TCL_ERROR;
	      }
	      sddsFdTable[fd].free = 1;
	      sddsFdTable[fd].currentPage = 0;
	      return TCL_ERROR;
	    }
	    if (arrayBuffer) free(arrayBuffer);
	    Tcl_SetResult(interp,"",NULL);
	    for (j = 0; j < arrayDim; j++) {
	      dim[j] = elements;
	    }
	    
	    dimElement = arrayDim - 1;
	    j = count = 0;
	    switch (types[k][i]) {
	    case SDDS_LONGDOUBLE: {
	      long double *res = (long double *)malloc(sizeof(long double)*elements);
	      while (j < elements) {
		constructIndex(j,arrayDim,dim,buffer);
		tempObjElement = Tcl_NewStringObj(buffer, -1);
		obj = Tcl_ObjGetVar2(interp, tempObj, tempObjElement, 0);
		if (obj == NULL) {
		  dim[dimElement] = constructIndex2(dimElement, arrayDim, dim, count);
		  dimElement--;
		  if ((dimElement == -1) || (count == 0)) {
		    Tcl_SetResult(interp, "sdds save: unable to extract all elements from array",NULL);
		    count = -1;
		    break;
		  }
		  count = 0;
		  continue;
		}
                res[j] = strtold(Tcl_GetStringFromObj(obj, NULL), NULL);
		j++;
		count++;
	      }
	      if (count == -1) {
		free(res);
		break;
	      }
	      while (dimElement >= 0) {
		dim[dimElement] = constructIndex2(dimElement, arrayDim, dim, count);
		dimElement--;
		count = 0;
	      }
	      result = SDDS_SetArray(&(sddsFdTable[fd].table),listArgv[i], SDDS_CONTIGUOUS_DATA,
				     res, dim);
	      free(res);
	      break;
	    }
	    case SDDS_DOUBLE: {
	      double *res = (double *)malloc(sizeof(double)*elements);
	      while (j < elements) {
		constructIndex(j,arrayDim,dim,buffer);
		tempObjElement = Tcl_NewStringObj(buffer, -1);
		obj = Tcl_ObjGetVar2(interp, tempObj, tempObjElement, 0);
		if (obj == NULL) {
		  dim[dimElement] = constructIndex2(dimElement, arrayDim, dim, count);
		  dimElement--;
		  if ((dimElement == -1) || (count == 0)) {
		    Tcl_SetResult(interp, "sdds save: unable to extract all elements from array",NULL);
		    count = -1;
		    break;
		  }
		  count = 0;
		  continue;
		}
		if (Tcl_GetDoubleFromObj(interp, obj, &(res[j])) != TCL_OK) {
		  Tcl_SetResult(interp, "sdds save: array value cannot be converted to native data type",NULL);
		  count = -1;
		  break;
		}
		j++;
		count++;
	      }
	      if (count == -1) {
		free(res);
		break;
	      }
	      while (dimElement >= 0) {
		dim[dimElement] = constructIndex2(dimElement, arrayDim, dim, count);
		dimElement--;
		count = 0;
	      }
	      result = SDDS_SetArray(&(sddsFdTable[fd].table),listArgv[i], SDDS_CONTIGUOUS_DATA,
				     res, dim);
	      free(res);
	      break;
	    }
	    case SDDS_FLOAT: {
	      float *res = (float *)malloc(sizeof(float)*elements);
	      double res2;
	      while (j < elements) {
		constructIndex(j,arrayDim,dim,buffer);
		tempObjElement = Tcl_NewStringObj(buffer, -1);
		obj = Tcl_ObjGetVar2(interp, tempObj, tempObjElement, 0);
		if (obj == NULL) {
		  dim[dimElement] = constructIndex2(dimElement, arrayDim, dim, count);
		  dimElement--;
		  if ((dimElement == -1) || (count == 0)) {
		    Tcl_SetResult(interp, "sdds save: unable to extract all elements from array",NULL);
		    count = -1;
		    break;
		  }
		  count = 0;
		  continue;
		}
		if (Tcl_GetDoubleFromObj(interp, obj, &res2) != TCL_OK) {
		  Tcl_SetResult(interp, "sdds save: array value cannot be converted to native data type",NULL);
		  count = -1;
		  break;
		}
		res[j] = res2;
		j++;
		count++;
	      }
	      if (count == -1) {
		free(res);
		break;
	      }
	      while (dimElement >= 0) {
		dim[dimElement] = constructIndex2(dimElement, arrayDim, dim, count);
		dimElement--;
		count = 0;
	      }
	      result = SDDS_SetArray(&(sddsFdTable[fd].table),listArgv[i], SDDS_CONTIGUOUS_DATA,
				     res, dim);
	      free(res);
	      break;
	    }
	    case SDDS_LONG64: {
	      int64_t *res = (int64_t *)malloc(sizeof(int64_t)*elements);
              long res2;
	      while (j < elements) {
		constructIndex(j,arrayDim,dim,buffer);
		tempObjElement = Tcl_NewStringObj(buffer, -1);
		obj = Tcl_ObjGetVar2(interp, tempObj, tempObjElement, 0);
		if (obj == NULL) {
		  dim[dimElement] = constructIndex2(dimElement, arrayDim, dim, count);
		  dimElement--;
		  if ((dimElement == -1) || (count == 0)) {
		    Tcl_SetResult(interp, "sdds save: unable to extract all elements from array",NULL);
		    count = -1;
		    break;
		  }
		  count = 0;
		  continue;
		}
		if (Tcl_GetLongFromObj(interp, obj, &res2) != TCL_OK) {
		  Tcl_SetResult(interp, "sdds save: array value cannot be converted to native data type",NULL);
		  count = -1;
		  break;
		}
                res[j] = res2;
		j++;
		count++;
	      }
	      if (count == -1) {
		free(res);
		break;
	      }
	      while (dimElement >= 0) {
		dim[dimElement] = constructIndex2(dimElement, arrayDim, dim, count);
		dimElement--;
		count = 0;
	      }
	      result = SDDS_SetArray(&(sddsFdTable[fd].table),listArgv[i], SDDS_CONTIGUOUS_DATA,
				     res, dim);
	      free(res);
	      break;
	    }
	    case SDDS_ULONG64: {
	      uint64_t *res = (uint64_t *)malloc(sizeof(uint64_t)*elements);
	      while (j < elements) {
		constructIndex(j,arrayDim,dim,buffer);
		tempObjElement = Tcl_NewStringObj(buffer, -1);
		obj = Tcl_ObjGetVar2(interp, tempObj, tempObjElement, 0);
		if (obj == NULL) {
		  dim[dimElement] = constructIndex2(dimElement, arrayDim, dim, count);
		  dimElement--;
		  if ((dimElement == -1) || (count == 0)) {
		    Tcl_SetResult(interp, "sdds save: unable to extract all elements from array",NULL);
		    count = -1;
		    break;
		  }
		  count = 0;
		  continue;
		}
                res[j] = strtoull(Tcl_GetStringFromObj(obj, NULL), NULL, 10);
		j++;
		count++;
	      }
	      if (count == -1) {
		free(res);
		break;
	      }
	      while (dimElement >= 0) {
		dim[dimElement] = constructIndex2(dimElement, arrayDim, dim, count);
		dimElement--;
		count = 0;
	      }
	      result = SDDS_SetArray(&(sddsFdTable[fd].table),listArgv[i], SDDS_CONTIGUOUS_DATA,
				     res, dim);
	      free(res);
	      break;
	    }
	    case SDDS_LONG: {
	      int32_t *res = (int32_t *)malloc(sizeof(int32_t)*elements);
              long res2;
	      while (j < elements) {
		constructIndex(j,arrayDim,dim,buffer);
		tempObjElement = Tcl_NewStringObj(buffer, -1);
		obj = Tcl_ObjGetVar2(interp, tempObj, tempObjElement, 0);
		if (obj == NULL) {
		  dim[dimElement] = constructIndex2(dimElement, arrayDim, dim, count);
		  dimElement--;
		  if ((dimElement == -1) || (count == 0)) {
		    Tcl_SetResult(interp, "sdds save: unable to extract all elements from array",NULL);
		    count = -1;
		    break;
		  }
		  count = 0;
		  continue;
		}
		if (Tcl_GetLongFromObj(interp, obj, &res2) != TCL_OK) {
		  Tcl_SetResult(interp, "sdds save: array value cannot be converted to native data type",NULL);
		  count = -1;
		  break;
		}
                res[j] = res2;
		j++;
		count++;
	      }
	      if (count == -1) {
		free(res);
		break;
	      }
	      while (dimElement >= 0) {
		dim[dimElement] = constructIndex2(dimElement, arrayDim, dim, count);
		dimElement--;
		count = 0;
	      }
	      result = SDDS_SetArray(&(sddsFdTable[fd].table),listArgv[i], SDDS_CONTIGUOUS_DATA,
				     res, dim);
	      free(res);
	      break;
	    }
	    case SDDS_ULONG: {
	      uint32_t *res = (uint32_t *)malloc(sizeof(uint32_t)*elements);
              Tcl_WideInt res2;
	      while (j < elements) {
		constructIndex(j,arrayDim,dim,buffer);
		tempObjElement = Tcl_NewStringObj(buffer, -1);
		obj = Tcl_ObjGetVar2(interp, tempObj, tempObjElement, 0);
		if (obj == NULL) {
		  dim[dimElement] = constructIndex2(dimElement, arrayDim, dim, count);
		  dimElement--;
		  if ((dimElement == -1) || (count == 0)) {
		    Tcl_SetResult(interp, "sdds save: unable to extract all elements from array",NULL);
		    count = -1;
		    break;
		  }
		  count = 0;
		  continue;
		}
		if (Tcl_GetWideIntFromObj(interp, obj, &res2) != TCL_OK) {
		  Tcl_SetResult(interp, "sdds save: array value cannot be converted to native data type",NULL);
		  count = -1;
		  break;
		}
                res[j] = res2;
		j++;
		count++;
	      }
	      if (count == -1) {
		free(res);
		break;
	      }
	      while (dimElement >= 0) {
		dim[dimElement] = constructIndex2(dimElement, arrayDim, dim, count);
		dimElement--;
		count = 0;
	      }
	      result = SDDS_SetArray(&(sddsFdTable[fd].table),listArgv[i], SDDS_CONTIGUOUS_DATA,
				     res, dim);
	      free(res);
	      break;
	    }
	    case SDDS_SHORT: {
	      short *res = (short *)malloc(sizeof(short)*elements);
	      int res2;
	      while (j < elements) {
		constructIndex(j,arrayDim,dim,buffer);
		tempObjElement = Tcl_NewStringObj(buffer, -1);
		obj = Tcl_ObjGetVar2(interp, tempObj, tempObjElement, 0);
		if (obj == NULL) {
		  dim[dimElement] = constructIndex2(dimElement, arrayDim, dim, count);
		  dimElement--;
		  if ((dimElement == -1) || (count == 0)) {
		    Tcl_SetResult(interp, "sdds save: unable to extract all elements from array",NULL);
		    count = -1;
		    break;
		  }
		  count = 0;
		  continue;
		}
		if (Tcl_GetIntFromObj(interp, obj, &res2) != TCL_OK) {
		  Tcl_SetResult(interp, "sdds save: array value cannot be converted to native data type",NULL);
		  count = -1;
		  break;
		}
		res[j] = res2;
		j++;
		count++;
	      }
	      if (count == -1) {
		free(res);
		break;
	      }
	      while (dimElement >= 0) {
		dim[dimElement] = constructIndex2(dimElement, arrayDim, dim, count);
		dimElement--;
		count = 0;
	      }
	      result = SDDS_SetArray(&(sddsFdTable[fd].table),listArgv[i], SDDS_CONTIGUOUS_DATA,
				     res, dim);
	      free(res);
	      break;
	    }
	    case SDDS_USHORT: {
	      unsigned short *res = (unsigned short *)malloc(sizeof(unsigned short)*elements);
	      int res2;
	      while (j < elements) {
		constructIndex(j,arrayDim,dim,buffer);
		tempObjElement = Tcl_NewStringObj(buffer, -1);
		obj = Tcl_ObjGetVar2(interp, tempObj, tempObjElement, 0);
		if (obj == NULL) {
		  dim[dimElement] = constructIndex2(dimElement, arrayDim, dim, count);
		  dimElement--;
		  if ((dimElement == -1) || (count == 0)) {
		    Tcl_SetResult(interp, "sdds save: unable to extract all elements from array",NULL);
		    count = -1;
		    break;
		  }
		  count = 0;
		  continue;
		}
		if (Tcl_GetIntFromObj(interp, obj, &res2) != TCL_OK) {
		  Tcl_SetResult(interp, "sdds save: array value cannot be converted to native data type",NULL);
		  count = -1;
		  break;
		}
		res[j] = res2;
		j++;
		count++;
	      }
	      if (count == -1) {
		free(res);
		break;
	      }
	      while (dimElement >= 0) {
		dim[dimElement] = constructIndex2(dimElement, arrayDim, dim, count);
		dimElement--;
		count = 0;
	      }
	      result = SDDS_SetArray(&(sddsFdTable[fd].table),listArgv[i], SDDS_CONTIGUOUS_DATA,
				     res, dim);
	      free(res);
	      break;
	    }
	    case SDDS_STRING: {
	      char **res = (char **)malloc(sizeof(char*)*elements);
	      /*	      for (n=0 ; n < elements ; n++)
		res[n] = (char *)malloc(sizeof(char)*tclSDDS_BUFSIZE);*/
	      while (j < elements) {
		constructIndex(j,arrayDim,dim,buffer);
		tempObjElement = Tcl_NewStringObj(buffer, -1);
		obj = Tcl_ObjGetVar2(interp, tempObj, tempObjElement, 0);
		if (obj == NULL) {
		  dim[dimElement] = constructIndex2(dimElement, arrayDim, dim, count);
		  dimElement--;
		  if ((dimElement == -1) || (count == 0)) {
		    Tcl_SetResult(interp, "sdds save: unable to extract all elements from array",NULL);
		    count = -1;
		    break;
		  }
		  count = 0;
		  continue;
		}
		res[j] = Tcl_GetStringFromObj(obj, NULL);
		if (res[j] == NULL) {
		  Tcl_SetResult(interp, "sdds save: array value cannot be converted to native data type",NULL);
		  count = -1;
		  break;
		}
		j++;
		count++;
	      }
	      if (count == -1) {
		/*	for (j=0 ; j < elements ; j++)
		  free(res[j]);*/
		free(res);
		break;
	      }
	      while (dimElement >= 0) {
		dim[dimElement] = constructIndex2(dimElement, arrayDim, dim, count);
		dimElement--;
		count = 0;
	      }
	      result = SDDS_SetArray(&(sddsFdTable[fd].table),listArgv[i], SDDS_CONTIGUOUS_DATA,
				     res, dim);
	      /*  for (j=0 ; j < elements ; j++)
		free(res[j]);*/
	      free(res);
	      break;
	    }
	    case SDDS_CHARACTER: {
	      char *res = (char *)malloc(sizeof(char)*elements);
	      while (j < elements) {
		constructIndex(j,arrayDim,dim,buffer);
		tempObjElement = Tcl_NewStringObj(buffer, -1);
		obj = Tcl_ObjGetVar2(interp, tempObj, tempObjElement, 0);
		if (obj == NULL) {
		  dim[dimElement] = constructIndex2(dimElement, arrayDim, dim, count);
		  dimElement--;
		  if ((dimElement == -1) || (count == 0)) {
		    Tcl_SetResult(interp, "sdds save: unable to extract all elements from array",NULL);
		    count = -1;
		    break;
		  }
		  count = 0;
		  continue;
		}
		if (Tcl_GetStringFromObj(obj, NULL) == NULL) {
		  Tcl_SetResult(interp, "sdds save: array value cannot be converted to native data type",NULL);
		  count = -1;
		  break;
		}
		res[j] = (Tcl_GetStringFromObj(obj, NULL))[0];
		j++;
		count++;
	      }
	      if (count == -1) {
		free(res);
		break;
	      }
	      while (dimElement >= 0) {
		dim[dimElement] = constructIndex2(dimElement, arrayDim, dim, count);
		dimElement--;
		count = 0;
	      }
	      result = SDDS_SetArray(&(sddsFdTable[fd].table),listArgv[i], SDDS_CONTIGUOUS_DATA,
				     res, dim);
	      free(res);
	      break;
	    }
	    default: {
	      result = 0;
	      break;
	    }
	    }
	    if (count == -1) {
	      for (n = 0; n < 3; n++) {
		if (data[n]) free(data[n]);
		if (types[j]) free(types[j]);
	      }
	      Tcl_Free((char *) listArgv);
	      if (!SDDS_Terminate(&(sddsFdTable[fd].table))) {
		sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
		Tcl_AppendResult(interp, ": Unable to close file", sddsErrs[0], NULL);
		SDDS_ClearErrors();
		free(sddsErrs[0]);
		return TCL_ERROR;
	      }
	      sddsFdTable[fd].free = 1;
	      sddsFdTable[fd].currentPage = 0;
	      return TCL_ERROR;
	    }
	    if (!result) {
	      sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	      Tcl_AppendResult(interp, "sdds save: ", sddsErrs[0], NULL);
	      SDDS_ClearErrors();
	      free(sddsErrs[0]);
	      for (j = 0; j < 3; j++) {
		if (data[j]) free(data[j]);
		if (types[j]) free(types[j]);
	      }
	      Tcl_Free((char *) listArgv);
	      if (!SDDS_Terminate(&(sddsFdTable[fd].table))) {
		sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
		Tcl_AppendResult(interp, ": Unable to close file", sddsErrs[0], NULL);
		SDDS_ClearErrors();
		free(sddsErrs[0]);
		return TCL_ERROR;
	      }
	      sddsFdTable[fd].free = 1;
	      sddsFdTable[fd].currentPage = 0;
	      return TCL_ERROR;
	    }
	  } else { /* Set Columns */
	    Tcl_Obj **objvRowPtr;
	    int objcRowPtr;
	    Tcl_ListObjGetElements(interp, objvPtr[page], &objcRowPtr, &objvRowPtr);
	    switch (types[k][i]) {
	    case SDDS_LONGDOUBLE: {
	      long double *res = (long double *)malloc(sizeof(long double)*objcRowPtr);
	      for (j = 0; j < objcRowPtr; j++) {
                res[j] = strtold(Tcl_GetStringFromObj(objvRowPtr[j], NULL), NULL);
	      }
	      result = SDDS_SetColumn(&(sddsFdTable[fd].table),setMode, res, 
				      objcRowPtr, listArgv[i]);
	      free(res);
	      break;
	    }
	    case SDDS_DOUBLE: {
	      double *res = (double *)malloc(sizeof(double)*objcRowPtr);
	      for (j = 0; j < objcRowPtr; j++) {
		if (Tcl_GetDoubleFromObj(interp, objvRowPtr[j], &(res[j])) != TCL_OK) {
		  res[j] = 0.0;
		}
	      }
	      result = SDDS_SetColumn(&(sddsFdTable[fd].table),setMode, res, 
				      objcRowPtr, listArgv[i]);
	      free(res);
	      break;
	    }
	    case SDDS_FLOAT: {
	      float *res = (float *)malloc(sizeof(float)*objcRowPtr);
	      double res2;
	      for (j = 0; j < objcRowPtr; j++) {
		if (Tcl_GetDoubleFromObj(interp, objvRowPtr[j], &res2) != TCL_OK) {
		  res2 = 0.0;
		}
		res[j] = res2;
	      }
	      result = SDDS_SetColumn(&(sddsFdTable[fd].table),setMode, res, 
				      objcRowPtr, listArgv[i]);
	      free(res);
	      break;
	    }
	    case SDDS_LONG64: {
	      int64_t *res = (int64_t *)malloc(sizeof(int64_t)*objcRowPtr);
              long res2;
	      for (j = 0; j < objcRowPtr; j++) {
		if (Tcl_GetLongFromObj(interp, objvRowPtr[j], &res2) != TCL_OK) {
                  res2 = 0;
                }
                res[j] = res2;
              }
	      result = SDDS_SetColumn(&(sddsFdTable[fd].table),setMode, res, 
				      objcRowPtr, listArgv[i]);
	      break;
	    }
	    case SDDS_ULONG64: {
	      uint64_t *res = (uint64_t *)malloc(sizeof(uint64_t)*objcRowPtr);
	      for (j = 0; j < objcRowPtr; j++) {
                res[j] = strtoull(Tcl_GetStringFromObj(objvRowPtr[j], NULL), NULL, 10);
	      }
	      result = SDDS_SetColumn(&(sddsFdTable[fd].table),setMode, res, 
				      objcRowPtr, listArgv[i]);
	      free(res);
	      break;
	    }
	    case SDDS_LONG: {
	      int32_t *res = (int32_t *)malloc(sizeof(int32_t)*objcRowPtr);
              long res2;
	      for (j = 0; j < objcRowPtr; j++) {
		if (Tcl_GetLongFromObj(interp, objvRowPtr[j], &res2) != TCL_OK) {
                  res2 = 0;
                }
                res[j] = res2;
              }
	      result = SDDS_SetColumn(&(sddsFdTable[fd].table),setMode, res, 
				      objcRowPtr, listArgv[i]);
	      break;
	    }
	    case SDDS_ULONG: {
	      uint32_t *res = (uint32_t *)malloc(sizeof(uint32_t)*objcRowPtr);
              Tcl_WideInt res2;
	      for (j = 0; j < objcRowPtr; j++) {
		if (Tcl_GetWideIntFromObj(interp, objvRowPtr[j], &res2) != TCL_OK) {
                  res2 = 0;
                }
                res[j] = res2;
              }
	      result = SDDS_SetColumn(&(sddsFdTable[fd].table),setMode, res, 
				      objcRowPtr, listArgv[i]);
	      break;
	    }
	    case SDDS_SHORT: {
	      short *res = (short *)malloc(sizeof(short)*objcRowPtr);
	      int res2;
	      for (j = 0; j < objcRowPtr; j++) {
		if (Tcl_GetIntFromObj(interp, objvRowPtr[j], &res2) != TCL_OK) {
		  res2 = 0;
		}
		res[j] = res2;
	      }
	      result = SDDS_SetColumn(&(sddsFdTable[fd].table),setMode, res, 
				      objcRowPtr, listArgv[i]);
	      free(res);
	      break;
	    }
	    case SDDS_USHORT: {
	      unsigned short *res = (unsigned short *)malloc(sizeof(unsigned short)*objcRowPtr);
	      int res2;
	      for (j = 0; j < objcRowPtr; j++) {
		if (Tcl_GetIntFromObj(interp, objvRowPtr[j], &res2) != TCL_OK) {
		  res2 = 0;
		}
		res[j] = res2;
	      }
	      result = SDDS_SetColumn(&(sddsFdTable[fd].table),setMode, res, 
				      objcRowPtr, listArgv[i]);
	      free(res);
	      break;
	    }
	    case SDDS_STRING: {
	      char **res = (char **)malloc(sizeof(char*)*objcRowPtr);
	      for (j=0 ; j < objcRowPtr ; j++) {
		res[j] = Tcl_GetStringFromObj(objvRowPtr[j], NULL);
		if (res[j] == NULL) {
		  res[j] = "";
		}
	      }
	      result = SDDS_SetColumn(&(sddsFdTable[fd].table),setMode, res, 
				      objcRowPtr, listArgv[i]);
	      free(res);
	      break;
	    }
	    case SDDS_CHARACTER: {
	      char *res = (char *)malloc(sizeof(char)*objcRowPtr);
	      for (j = 0; j < objcRowPtr; j++) {
		if (Tcl_GetStringFromObj(objvRowPtr[j], NULL) == NULL) {
		  res[j] = '?';
		} else {
		  res[j] = (Tcl_GetStringFromObj(objvRowPtr[j], NULL))[0];
		}
	      }
	      result = SDDS_SetColumn(&(sddsFdTable[fd].table),setMode, res, 
				      objcRowPtr, listArgv[i]);
	      free(res);
	      break;
	    }	  
	    default: {
	      result = 0;
	      break;
	    }
	    }
	    if (!result) {
		sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
		Tcl_AppendResult(interp, "sdds save: ", sddsErrs[0], NULL);
		SDDS_ClearErrors();
		free(sddsErrs[0]);
		for (j = 0; j < 3; j++) {
		  if (data[j]) free(data[j]);
		  if (types[j]) free(types[j]);
		}
		Tcl_Free((char *) listArgv);
		if (!SDDS_Terminate(&(sddsFdTable[fd].table))) {
		  sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
		  Tcl_AppendResult(interp, ": Unable to close file", sddsErrs[0], NULL);
		  SDDS_ClearErrors();
		  free(sddsErrs[0]);
		  return TCL_ERROR;
		}
		sddsFdTable[fd].free = 1;
		sddsFdTable[fd].currentPage = 0;
		return TCL_ERROR;
	    }
	  }
	}
	Tcl_Free((char *) listArgv);
      }
    }

    /* Write Page */
    if (!SDDS_WritePage(&(sddsFdTable[fd].table))) {
      sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
      Tcl_AppendResult(interp, "sdds save: ", sddsErrs[0], NULL);
      SDDS_ClearErrors();
      free(sddsErrs[0]);
      for (j = 0; j < 3; j++) {
	if (data[j]) free(data[j]);
	if (types[j]) free(types[j]);
      }
      if (!SDDS_Terminate(&(sddsFdTable[fd].table))) {
	sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	Tcl_AppendResult(interp, ": Unable to close file", sddsErrs[0], NULL);
	SDDS_ClearErrors();
	free(sddsErrs[0]);
	return TCL_ERROR;
      }
      sddsFdTable[fd].free = 1;
      sddsFdTable[fd].currentPage = 0;
      return TCL_ERROR;
    }
    sddsFdTable[fd].pageStarted = 0;
  }

  for (j = 0; j < 3; j++) {
    if (data[j]) free(data[j]);
    if (types[j]) free(types[j]);
  }

  /* Close File */
  if (!SDDS_Terminate(&(sddsFdTable[fd].table))) {
    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
    Tcl_AppendResult(interp, "sdds save: Unable to close file", sddsErrs[0], NULL);
    SDDS_ClearErrors();
    free(sddsErrs[0]);
    return TCL_ERROR;
  }
  sddsFdTable[fd].free = 1;
  sddsFdTable[fd].currentPage = 0;

  return TCL_OK;
}

int tclSDDSLoad(Tcl_Interp *interp, int argc, char *argv[]) {
  int32_t sddsNumErrs;
  long i, nrows, tableRead;
  int32_t parameter_number, column_number, array_number;
  int fd, moreData;
  char **sddsErrs, *fileName, *tclArrayName, buffer[tclSDDS_BUFSIZE];
  char **parameter_nameData, **column_nameData, **array_nameData;
  SDDS_ARRAY *sddsArray;
  Tcl_Obj *arrayName, *arraySubName, *obj;
  Tcl_DString DString;

  if (argc != 4) {
    Tcl_SetResult(interp, "usage: sdds load <filename> <tclArrayName>",NULL);
    return TCL_ERROR;    
  }
  
  fileName = argv[2];
  tclArrayName = argv[3];

  if ((fd = tclSDDSGetFreeFd()) == -1) {
    Tcl_SetResult(interp, "sdds load: too many SDDS files open", NULL);
    return TCL_ERROR;
  }

  /* Open File */
  sddsFdTable[fd].mode = 'r';
  if (!SDDS_InitializeInput(&(sddsFdTable[fd].table), fileName)) {
    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
    Tcl_AppendResult(interp, "sdds load: ", sddsErrs[0], NULL);
    SDDS_ClearErrors();
    free(sddsErrs[0]);
    return TCL_ERROR;
  }
  strcpy(sddsFdTable[fd].fileName,fileName);
  sddsFdTable[fd].free = 0;

  /* Check Dataset For Errors */
  if (!SDDS_CheckDataset(&(sddsFdTable[fd].table), "tclSDDSLoad")) {
    Tcl_SetResult(interp, "sdds load: corrupted file", NULL);
    if (!SDDS_Terminate(&(sddsFdTable[fd].table))) {
      sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
      Tcl_AppendResult(interp, ": Unable to close file", sddsErrs[0], NULL);
      SDDS_ClearErrors();
      free(sddsErrs[0]);
      return TCL_ERROR;
    }
    sddsFdTable[fd].free = 1;
    sddsFdTable[fd].currentPage = 0;
    return TCL_ERROR;
  }

  /* Read Parameter, Array, and Column Names */
  parameter_number = array_number = column_number = 0; 
  parameter_nameData = array_nameData = column_nameData = NULL;
  if (((parameter_nameData=SDDS_GetParameterNames(&(sddsFdTable[fd].table), &parameter_number)) == NULL) ||
      ((array_nameData=SDDS_GetArrayNames(&(sddsFdTable[fd].table), &array_number)) == NULL) ||
      ((column_nameData=SDDS_GetColumnNames(&(sddsFdTable[fd].table), &column_number)) == NULL))  {
    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
    Tcl_AppendResult(interp, "sdds load: ", sddsErrs[0], NULL);
    SDDS_ClearErrors();
    free(sddsErrs[0]);
    if (!SDDS_Terminate(&(sddsFdTable[fd].table))) {
      sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
      Tcl_AppendResult(interp, ": Unable to close file", sddsErrs[0], NULL);
      SDDS_ClearErrors();
      free(sddsErrs[0]);
      return TCL_ERROR;
    }
    sddsFdTable[fd].free = 1;
    sddsFdTable[fd].currentPage = 0;
    return TCL_ERROR;
  }

  /* Create Array Object That Will Hold TCL Variable */
  arrayName = Tcl_NewStringObj(tclArrayName, -1);
  Tcl_UnsetVar2(interp, tclArrayName,NULL, 0);

  /* Create Layout.DataMode.Mode Element */
  arraySubName = Tcl_NewStringObj("Layout.DataMode.Mode", -1);
  if (sddsFdTable[fd].table.layout.data_mode.mode == SDDS_BINARY) {
    obj = Tcl_NewStringObj("binary", -1);
  } else {
    obj = Tcl_NewStringObj("ascii", -1);
  }
  Tcl_ObjSetVar2(interp, arrayName, arraySubName, obj, TCL_LIST_ELEMENT);

  /* Create Layout.DataMode.LinesPerRow Element */
  arraySubName = Tcl_NewStringObj("Layout.DataMode.LinesPerRow", -1);
  if (sddsFdTable[fd].table.layout.data_mode.lines_per_row > 0) {
    obj = Tcl_NewLongObj(sddsFdTable[fd].table.layout.data_mode.lines_per_row);
  } else {
    obj = Tcl_NewLongObj(1);
  }
  Tcl_ObjSetVar2(interp, arrayName, arraySubName, obj, TCL_LIST_ELEMENT);

  /* Create Description.Text Element */
  arraySubName = Tcl_NewStringObj("Description.Text", -1);
  if (sddsFdTable[fd].table.layout.description != NULL) {
    obj = Tcl_NewStringObj(sddsFdTable[fd].table.layout.description, -1);
    Tcl_ObjSetVar2(interp, arrayName, arraySubName, obj, TCL_LIST_ELEMENT);
  } else {
    obj = Tcl_NewStringObj("", -1);
    Tcl_ObjSetVar2(interp, arrayName, arraySubName, obj, 0);
  }
  
  /* Create Description.Contents Element */
  arraySubName = Tcl_NewStringObj("Description.Contents", -1);
  if (sddsFdTable[fd].table.layout.contents != NULL) {
    obj = Tcl_NewStringObj(sddsFdTable[fd].table.layout.contents, -1);
    Tcl_ObjSetVar2(interp, arrayName, arraySubName, obj, TCL_LIST_ELEMENT);
  } else {
    obj = Tcl_NewStringObj("", -1);
    Tcl_ObjSetVar2(interp, arrayName, arraySubName, obj, 0);
  }
  
  /* Create ParameterNames Element */
  arraySubName = Tcl_NewStringObj("ParameterNames", -1);
  obj = Tcl_NewStringObj(Tcl_Merge(parameter_number, (SDDSCONST2)parameter_nameData), -1);
  Tcl_ObjSetVar2(interp, arrayName, arraySubName, obj, 0);
  
  /* Create ArrayNames Element */
  arraySubName = Tcl_NewStringObj("ArrayNames", -1);
  obj = Tcl_NewStringObj(Tcl_Merge(array_number, (SDDSCONST2)array_nameData), -1);
  Tcl_ObjSetVar2(interp, arrayName, arraySubName, obj, 0);

  /* Create ColumnNames Element */
  arraySubName = Tcl_NewStringObj("ColumnNames", -1);
  obj = Tcl_NewStringObj(Tcl_Merge(column_number, (SDDSCONST2)column_nameData), -1);
  Tcl_ObjSetVar2(interp, arrayName, arraySubName, obj, 0);

  /* Read First Page of Data File */
  if ((tableRead = SDDS_ReadTable(&(sddsFdTable[fd].table))) <= 0) {
    if (tableRead == -1) {
      Tcl_SetResult(interp, "EOF", NULL);
    } else {
      sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
      Tcl_AppendResult(interp, "sdds load: ", sddsErrs[0], NULL);
      SDDS_ClearErrors();
      free(sddsErrs[0]);
    }
    if (!SDDS_Terminate(&(sddsFdTable[fd].table))) {
      sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
      Tcl_AppendResult(interp, ": Unable to close file", sddsErrs[0], NULL);
      SDDS_ClearErrors();
      free(sddsErrs[0]);
      return TCL_ERROR;
    }
    sddsFdTable[fd].free = 1;
    sddsFdTable[fd].currentPage = 0;
    return TCL_ERROR;
  }
  sddsFdTable[fd].currentPage++;

  moreData = 1;

  /* Create ParameterInfo Element */
  for (i=0 ; i < parameter_number ; i++) {
    PARAMETER_DEFINITION *parameter = SDDS_GetParameterDefinition(&(sddsFdTable[fd].table), parameter_nameData[i]);
    Tcl_DStringInit(&DString);
    Tcl_DStringAppendElement(&DString,"name");
    Tcl_DStringAppendElement(&DString,parameter->name);
    Tcl_DStringAppendElement(&DString,"symbol");
    Tcl_DStringAppendElement(&DString,parameter->symbol==NULL?"":parameter->symbol);
    Tcl_DStringAppendElement(&DString,"units");
    Tcl_DStringAppendElement(&DString,parameter->units==NULL?"":parameter->units);
    Tcl_DStringAppendElement(&DString,"description");
    Tcl_DStringAppendElement(&DString,parameter->description==NULL?"":parameter->description);
    Tcl_DStringAppendElement(&DString,"format_string");
    Tcl_DStringAppendElement(&DString,parameter->format_string==NULL?"":parameter->format_string);
    Tcl_DStringAppendElement(&DString,"type");
    Tcl_DStringAppendElement(&DString,convertNumericToTypeString(parameter->type));
    Tcl_DStringAppendElement(&DString,"fixed_value");
    Tcl_DStringAppendElement(&DString,parameter->fixed_value==NULL?"":parameter->fixed_value);
    
    sprintf(buffer, "ParameterInfo.%s", parameter_nameData[i]);
    arraySubName = Tcl_NewStringObj(buffer, -1);
    obj = Tcl_NewStringObj(Tcl_DStringValue(&DString), -1);
    Tcl_DStringFree(&DString);
    Tcl_ObjSetVar2(interp, arrayName, arraySubName, obj, 0);
    
    SDDS_FreeParameterDefinition(parameter);
  }
  
  /* Create ArrayInfo Element */
  for (i=0 ; i < array_number ; i++) {
    ARRAY_DEFINITION *array = SDDS_GetArrayDefinition(&(sddsFdTable[fd].table), array_nameData[i]);
    Tcl_DStringInit(&DString);
    Tcl_DStringAppendElement(&DString,"name");
    Tcl_DStringAppendElement(&DString,array->name);
    Tcl_DStringAppendElement(&DString,"symbol");
    Tcl_DStringAppendElement(&DString,array->symbol==NULL?"":array->symbol);
    Tcl_DStringAppendElement(&DString,"units");
    Tcl_DStringAppendElement(&DString,array->units==NULL?"":array->units);
    Tcl_DStringAppendElement(&DString,"description");
    Tcl_DStringAppendElement(&DString,array->description==NULL?"":array->description);
    Tcl_DStringAppendElement(&DString,"format_string");
    Tcl_DStringAppendElement(&DString,array->format_string==NULL?"":array->format_string);
    Tcl_DStringAppendElement(&DString,"group_name");
    Tcl_DStringAppendElement(&DString,array->group_name==NULL?"":array->group_name);
    Tcl_DStringAppendElement(&DString,"type");
    Tcl_DStringAppendElement(&DString,convertNumericToTypeString(array->type));
    Tcl_DStringAppendElement(&DString,"field_length");
    sprintf(buffer, "%" PRId32, array->field_length);
    Tcl_DStringAppendElement(&DString,buffer);
    Tcl_DStringAppendElement(&DString,"dimensions");
    sprintf(buffer, "%" PRId32, array->dimensions);
    Tcl_DStringAppendElement(&DString,buffer);
    
    sprintf(buffer, "ArrayInfo.%s", array_nameData[i]);
    arraySubName = Tcl_NewStringObj(buffer, -1);
    obj = Tcl_NewStringObj(Tcl_DStringValue(&DString), -1);
    Tcl_DStringFree(&DString);
    Tcl_ObjSetVar2(interp, arrayName, arraySubName, obj, 0);

    SDDS_FreeArrayDefinition(array);
  }

  /* Create ColumnInfo Elements */
  for (i=0 ; i < column_number ; i++) {
    COLUMN_DEFINITION *column = SDDS_GetColumnDefinition(&(sddsFdTable[fd].table), column_nameData[i]);
    Tcl_DStringInit(&DString);
    Tcl_DStringAppendElement(&DString,"name");
    Tcl_DStringAppendElement(&DString,column->name);
    Tcl_DStringAppendElement(&DString,"symbol");
    Tcl_DStringAppendElement(&DString,column->symbol==NULL?"":column->symbol);
    Tcl_DStringAppendElement(&DString,"units");
    Tcl_DStringAppendElement(&DString,column->units==NULL?"":column->units);
    Tcl_DStringAppendElement(&DString,"description");
    Tcl_DStringAppendElement(&DString,column->description==NULL?"":column->description);
    Tcl_DStringAppendElement(&DString,"format_string");
    Tcl_DStringAppendElement(&DString,column->format_string==NULL?"":column->format_string);
    Tcl_DStringAppendElement(&DString,"type");
    Tcl_DStringAppendElement(&DString,convertNumericToTypeString(column->type));
    Tcl_DStringAppendElement(&DString,"field_length");
    sprintf(buffer, "%" PRId32, column->field_length);
    Tcl_DStringAppendElement(&DString,buffer);
    
    sprintf(buffer, "ColumnInfo.%s", column_nameData[i]);
    arraySubName = Tcl_NewStringObj(buffer, -1);
    obj = Tcl_NewStringObj(Tcl_DStringValue(&DString), -1);
    Tcl_DStringFree(&DString);
    Tcl_ObjSetVar2(interp, arrayName, arraySubName, obj, 0);

    SDDS_FreeColumnDefinition(column);
  }
  
  while (moreData) {

    SDDS_SetColumnFlags(&(sddsFdTable[fd].table),1);
    SDDS_SetRowFlags(&(sddsFdTable[fd].table),1);

    if ((nrows = SDDS_CountRowsOfInterest(&(sddsFdTable[fd].table))) == -1) {
      sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
      Tcl_AppendResult(interp, "sdds load: ", sddsErrs[0], NULL);
      SDDS_ClearErrors();
      free(sddsErrs[0]);
      if (!SDDS_Terminate(&(sddsFdTable[fd].table))) {
	sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	Tcl_AppendResult(interp, ": Unable to close file", sddsErrs[0], NULL);
	SDDS_ClearErrors();
	free(sddsErrs[0]);
	return TCL_ERROR;
      }
      sddsFdTable[fd].free = 1;
      sddsFdTable[fd].currentPage = 0;
      return TCL_ERROR;
    }

    /* Create Parameter Elements */
    for (i=0 ; i < parameter_number ; i++) {
      PARAMETER_DEFINITION *parameter = SDDS_GetParameterDefinition(&(sddsFdTable[fd].table), parameter_nameData[i]);
      obj = Tcl_SDDS_HandleParameter(&(sddsFdTable[fd].table), parameter);
      SDDS_FreeParameterDefinition(parameter);
      if (obj == NULL) {
	  Tcl_SetResult(interp,"sdds load: Invalid Parameter Data",NULL);
	  if (!SDDS_Terminate(&(sddsFdTable[fd].table))) {
	    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	    Tcl_AppendResult(interp, ": Unable to close file", sddsErrs[0], NULL);
	    SDDS_ClearErrors();
	    free(sddsErrs[0]);
	    return TCL_ERROR;
	  }
	  sddsFdTable[fd].free = 1;
	  sddsFdTable[fd].currentPage = 0;
	  return TCL_ERROR;
      }

      sprintf(buffer, "Parameter.%s", parameter_nameData[i]);
      arraySubName = Tcl_NewStringObj(buffer, -1);
      Tcl_ObjSetVar2(interp, arrayName, arraySubName, obj, TCL_LIST_ELEMENT | TCL_APPEND_VALUE);
    }

    /* Create Array Elements */
    for (i=0 ; i < array_number ; i++) {
      if (!(sddsArray=SDDS_GetArray(&(sddsFdTable[fd].table), array_nameData[i], NULL))) {
	sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	Tcl_AppendResult(interp, "sdds load: ", sddsErrs[0], NULL);
	SDDS_ClearErrors();
	free(sddsErrs[0]);
	if (!SDDS_Terminate(&(sddsFdTable[fd].table))) {
	  sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	  Tcl_AppendResult(interp, ": Unable to close file", sddsErrs[0], NULL);
	  SDDS_ClearErrors();
	  free(sddsErrs[0]);
	  return TCL_ERROR;
	}
	sddsFdTable[fd].free = 1;
	sddsFdTable[fd].currentPage = 0;
	return TCL_ERROR;
      }
      if (sddsArray->definition->dimensions > 4) {
	Tcl_SetResult(interp, "sdds load: unable to handle array dimensions greater then 4", NULL);
	if (!SDDS_Terminate(&(sddsFdTable[fd].table))) {
	  sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	  Tcl_AppendResult(interp, ": Unable to close file", sddsErrs[0], NULL);
	  SDDS_ClearErrors();
	  free(sddsErrs[0]);
	  return TCL_ERROR;
	}
	sddsFdTable[fd].free = 1;
	sddsFdTable[fd].currentPage = 0;
	return TCL_ERROR;
      }
      
      obj = Tcl_SDDS_HandleArray(sddsArray);
      SDDS_FreeArray(sddsArray);
      if (obj == NULL) {
	  Tcl_SetResult(interp,"sdds load: Invalid Array Data",NULL);
	  if (!SDDS_Terminate(&(sddsFdTable[fd].table))) {
	    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	    Tcl_AppendResult(interp, ": Unable to close file", sddsErrs[0], NULL);
	    SDDS_ClearErrors();
	    free(sddsErrs[0]);
	    return TCL_ERROR;
	  }
	  sddsFdTable[fd].free = 1;
	  sddsFdTable[fd].currentPage = 0;
	  return TCL_ERROR;
      }
      sprintf(buffer, "Array.%s", array_nameData[i]);
      arraySubName = Tcl_NewStringObj(buffer, -1);
      Tcl_ObjSetVar2(interp, arrayName, arraySubName, obj, TCL_LIST_ELEMENT | TCL_APPEND_VALUE);
    }
    
    /* Create Column Elements */
    for (i=0 ; i < column_number ; i++) {
      COLUMN_DEFINITION *column = SDDS_GetColumnDefinition(&(sddsFdTable[fd].table), column_nameData[i]);
      obj = Tcl_SDDS_HandleColumn(&(sddsFdTable[fd].table), column, nrows);
      SDDS_FreeColumnDefinition(column);
      if (obj == NULL) {
	  Tcl_SetResult(interp,"sdds load: Invalid Column Data",NULL);
	  if (!SDDS_Terminate(&(sddsFdTable[fd].table))) {
	    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	    Tcl_AppendResult(interp, ": Unable to close file", sddsErrs[0], NULL);
	    SDDS_ClearErrors();
	    free(sddsErrs[0]);
	    return TCL_ERROR;
	  }
	  sddsFdTable[fd].free = 1;
	  sddsFdTable[fd].currentPage = 0;
	  return TCL_ERROR;
      }
      sprintf(buffer, "Column.%s", column_nameData[i]);
      arraySubName = Tcl_NewStringObj(buffer, -1);
      Tcl_ObjSetVar2(interp, arrayName, arraySubName, obj, TCL_LIST_ELEMENT | TCL_APPEND_VALUE);
    }

    /* Read Next Page */
    if ((tableRead = SDDS_ReadTable(&(sddsFdTable[fd].table))) <= 0) {
      if (tableRead == -1) {
	moreData = 0;
	if (tclSDDSReopenFd(fd)) {
	  Tcl_SetResult(interp,"sdds load: unable to reopen file",NULL);
	  if (!SDDS_Terminate(&(sddsFdTable[fd].table))) {
	    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	    Tcl_AppendResult(interp, ": Unable to close file", sddsErrs[0], NULL);
	    SDDS_ClearErrors();
	    free(sddsErrs[0]);
	    return TCL_ERROR;
	  }
	  sddsFdTable[fd].free = 1;
	  sddsFdTable[fd].currentPage = 0;
	  return TCL_ERROR;
	}	  
      } else {
	sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	Tcl_AppendResult(interp, "sdds load: ", sddsErrs[0], NULL);
	SDDS_ClearErrors();
	free(sddsErrs[0]);
	if (!SDDS_Terminate(&(sddsFdTable[fd].table))) {
	  sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
	  Tcl_AppendResult(interp, ": Unable to close file", sddsErrs[0], NULL);
	  SDDS_ClearErrors();
	  free(sddsErrs[0]);
	  return TCL_ERROR;
	}
	sddsFdTable[fd].free = 1;
	sddsFdTable[fd].currentPage = 0;
	return TCL_ERROR;	
      }
    } else {
      sddsFdTable[fd].currentPage++;
    }
  }

  for (i=0 ; i < array_number ; i++)
    free(array_nameData[i]);
  free(array_nameData);
  for (i=0 ; i < column_number ; i++)
    free(column_nameData[i]);
  free(column_nameData);
  for (i=0 ; i < parameter_number ; i++)
    free(parameter_nameData[i]);
  free(parameter_nameData);

  if (!SDDS_Terminate(&(sddsFdTable[fd].table))) {
    sddsErrs = SDDS_GetErrorMessages(&sddsNumErrs, SDDS_ERROR_MODE);
    Tcl_AppendResult(interp, "sdds load: ", sddsErrs[0], NULL);
    SDDS_ClearErrors();
    free(sddsErrs[0]);
    return TCL_ERROR;
  }
  sddsFdTable[fd].free = 1;
  sddsFdTable[fd].currentPage = 0;

  return TCL_OK;

}

Tcl_Obj *Tcl_SDDS_HandleParameter(SDDS_TABLE *Table, PARAMETER_DEFINITION *def) {
  switch (def->type) {
  case SDDS_LONGDOUBLE: {
    double long result;
    char buffer[SDDS_MAXLINE];
    SDDS_GetParameter(Table, def->name, (void *) &result);
    sprintf(buffer, "%21.18Le", result);
    return Tcl_NewStringObj(buffer, -1);
  }
  case SDDS_DOUBLE: {
    double result;
    SDDS_GetParameter(Table, def->name, (void *) &result);
    return Tcl_NewDoubleObj(result);
  }
  case SDDS_FLOAT: {
    float result;
    SDDS_GetParameter(Table, def->name, (void *) &result);
    return Tcl_NewDoubleObj((double)result);
  }
  case SDDS_LONG: {
    int32_t result;
    SDDS_GetParameter(Table, def->name, (void *) &result);
    return Tcl_NewLongObj((long)result);
  }
  case SDDS_LONG64: {
    int64_t result;
    SDDS_GetParameter(Table, def->name, (void *) &result);
    return Tcl_NewLongObj((long)result);
  }
  case SDDS_ULONG64: {
    uint64_t result;
    char buffer[SDDS_MAXLINE];
    SDDS_GetParameter(Table, def->name, (void *) &result);
    sprintf(buffer, "%" PRId64, result);
    return Tcl_NewStringObj(buffer, -1);
  }
  case SDDS_ULONG: {
    uint32_t result;
    SDDS_GetParameter(Table, def->name, (void *) &result);
    return Tcl_NewWideIntObj((long)result);
  }
  case SDDS_SHORT: {
    short result;
    SDDS_GetParameter(Table, def->name, (void *) &result);
    return Tcl_NewIntObj((int)result);
  }
  case SDDS_USHORT: {
    unsigned short result;
    SDDS_GetParameter(Table, def->name, (void *) &result);
    return Tcl_NewIntObj((int)result);
  }
  case SDDS_STRING: {
    char* result = NULL;
    Tcl_Obj* s;
    SDDS_GetParameter(Table, def->name, (void *) &result);
    s = Tcl_NewStringObj(result, -1);
    free(result);
    return s;
  }
  case SDDS_CHARACTER: {
    char result;
    SDDS_GetParameter(Table, def->name, (void *) &result);
    return Tcl_NewStringObj(&result, 1);
  }
  }
  return NULL; 
}

Tcl_Obj *Tcl_SDDS_HandleColumn(SDDS_TABLE *Table, COLUMN_DEFINITION *def, long len) {
  Tcl_Obj **list, *obj;
  int j;
  list = malloc(sizeof(Tcl_Obj)*len);
  switch (def->type) {
  case SDDS_LONGDOUBLE: {
    long double *result = (long double *)SDDS_GetColumn(Table, def->name);
    char buffer[SDDS_MAXLINE];
    for (j=0 ; j < len ; j++) {
      sprintf(buffer, "%23.20Le", result[j]);
      list[j] = Tcl_NewStringObj(buffer, -1);
    }
    free(result);
    break;
  }
  case SDDS_DOUBLE: {
    double *result = (double *)SDDS_GetColumn(Table, def->name);
    /*
    char buffer[SDDS_MAXLINE];
    for (j=0 ; j < len ; j++) {
      sprintf(buffer, "%22.15g", result[j]);
      list[j] = Tcl_NewStringObj(buffer, -1);
    }
    */
    
    for (j=0 ; j < len ; j++) {
      list[j] = Tcl_NewDoubleObj(result[j]);
    }
    
    free(result);
    break;
  }
  case SDDS_FLOAT: {
    float *result = (float *)SDDS_GetColumn(Table, def->name);
    for (j=0 ; j < len ; j++) {
      list[j] = Tcl_NewDoubleObj((double)result[j]);
    }	
    free(result);
    break;
  }
  case SDDS_LONG64: {
    int64_t *result = (int64_t *)SDDS_GetColumn(Table, def->name);
    for (j=0 ; j < len ; j++) {
      list[j] = Tcl_NewLongObj(result[j]);
    }	
    free(result);
    break;
  }
  case SDDS_ULONG64: {
    uint64_t *result = (uint64_t *)SDDS_GetColumn(Table, def->name);
    char buffer[SDDS_MAXLINE];
    for (j=0 ; j < len ; j++) {
      sprintf(buffer, "%" PRId64, result[j]);
      list[j] = Tcl_NewStringObj(buffer, -1);
    }
    free(result);
    break;
  }
  case SDDS_LONG: {
    int32_t *result = (int32_t *)SDDS_GetColumn(Table, def->name);
    for (j=0 ; j < len ; j++) {
      list[j] = Tcl_NewLongObj(result[j]);
    }	
    free(result);
    break;
  }
  case SDDS_ULONG: {
    uint32_t *result = (uint32_t *)SDDS_GetColumn(Table, def->name);
    for (j=0 ; j < len ; j++) {
      list[j] = Tcl_NewWideIntObj(result[j]);
    }	
    free(result);
    break;
  }
  case SDDS_SHORT: {
    short *result = (short *)SDDS_GetColumn(Table, def->name);
    for (j=0 ; j < len ; j++) {
      list[j] = Tcl_NewIntObj(result[j]);
    }	
    free(result);
    break;
  }
  case SDDS_USHORT: {
    unsigned short *result = (unsigned short *)SDDS_GetColumn(Table, def->name);
    for (j=0 ; j < len ; j++) {
      list[j] = Tcl_NewIntObj(result[j]);
    }	
    free(result);
    break;
  }
  case SDDS_STRING: {
    char **result = (char **)SDDS_GetColumn(Table, def->name);
    for (j=0 ; j < len ; j++) {
      list[j] = Tcl_NewStringObj(result[j], -1);
      free(result[j]);
    }	
    free(result);
    break;
  }
  case SDDS_CHARACTER: {
    char *result = (char *)SDDS_GetColumn(Table, def->name);
    for (j=0 ; j < len ; j++) {
      list[j] = Tcl_NewStringObj(&result[j], 1);
    }
    free(result);
    break;
  }
  default: {
    free(list);
    return NULL; 
  }   
  }
  obj = Tcl_NewListObj(len, list);
  free(list);
  return obj;
}

Tcl_Obj *Tcl_SDDS_HandleArray(SDDS_ARRAY *array) {
  Tcl_Obj **list, *obj;
  int j;
  long len;
  char indexBuf[256];

  len = 2 * array->elements;
  list = malloc(sizeof(Tcl_Obj)*len);

  switch (array->definition->type) {
  case SDDS_LONGDOUBLE: {
    long double *result = (long double *)array->data;
    char buffer[SDDS_MAXLINE];
    for (j=0 ; j < array->elements ; j++) {
      constructIndex(j, array->definition->dimensions, array->dimension, indexBuf);
      list[j*2] = Tcl_NewStringObj(indexBuf, -1);
      sprintf(buffer, "%21.18Le", result[j]);
      list[j*2+1] = Tcl_NewStringObj(buffer, -1);
    }
    break;
  }
  case SDDS_DOUBLE: {
    double *result = (double *)array->data;
    for (j=0 ; j < array->elements ; j++) {
      constructIndex(j, array->definition->dimensions, array->dimension, indexBuf);
      list[j*2] = Tcl_NewStringObj(indexBuf, -1);
      list[j*2+1] = Tcl_NewDoubleObj(result[j]);
    }
    break;
  }
  case SDDS_FLOAT: {
    float *result = (float *)array->data;
    for (j=0 ; j < array->elements ; j++) {
      constructIndex(j, array->definition->dimensions, array->dimension, indexBuf);
      list[j*2] = Tcl_NewStringObj(indexBuf, -1);
      list[j*2+1] = Tcl_NewDoubleObj((double)result[j]);
    }
    break;
  }
  case SDDS_LONG64: {
    int64_t *result = (int64_t *)array->data;
    for (j=0 ; j < array->elements ; j++) {
      constructIndex(j, array->definition->dimensions, array->dimension, indexBuf);
      list[j*2] = Tcl_NewStringObj(indexBuf, -1);
      list[j*2+1] = Tcl_NewLongObj(result[j]);
    }
    break;
  }
  case SDDS_ULONG64: {
    uint64_t *result = (uint64_t *)array->data;
    char buffer[SDDS_MAXLINE];
    for (j=0 ; j < array->elements ; j++) {
      constructIndex(j, array->definition->dimensions, array->dimension, indexBuf);
      list[j*2] = Tcl_NewStringObj(indexBuf, -1);
      sprintf(buffer, "%" PRId64, result[j]);
      list[j*2+1] = Tcl_NewStringObj(buffer, -1);
    }
    break;
  }
  case SDDS_LONG: {
    int32_t *result = (int32_t *)array->data;
    for (j=0 ; j < array->elements ; j++) {
      constructIndex(j, array->definition->dimensions, array->dimension, indexBuf);
      list[j*2] = Tcl_NewStringObj(indexBuf, -1);
      list[j*2+1] = Tcl_NewLongObj(result[j]);
    }
    break;
  }
  case SDDS_ULONG: {
    uint32_t *result = (uint32_t *)array->data;
    for (j=0 ; j < array->elements ; j++) {
      constructIndex(j, array->definition->dimensions, array->dimension, indexBuf);
      list[j*2] = Tcl_NewStringObj(indexBuf, -1);
      list[j*2+1] = Tcl_NewWideIntObj(result[j]);
    }
    break;
  }
  case SDDS_SHORT: {
    short *result = (short *)array->data;
    for (j=0 ; j < array->elements ; j++) {
      constructIndex(j, array->definition->dimensions, array->dimension, indexBuf);
      list[j*2] = Tcl_NewStringObj(indexBuf, -1);
      list[j*2+1] = Tcl_NewIntObj(result[j]);
    }
    break;
  }
  case SDDS_USHORT: {
    unsigned short *result = (unsigned short *)array->data;
    for (j=0 ; j < array->elements ; j++) {
      constructIndex(j, array->definition->dimensions, array->dimension, indexBuf);
      list[j*2] = Tcl_NewStringObj(indexBuf, -1);
      list[j*2+1] = Tcl_NewIntObj(result[j]);
    }
    break;
  }
  case SDDS_STRING: {
    char **result = (char **)array->data;
    for (j=0 ; j < array->elements ; j++) {
      constructIndex(j, array->definition->dimensions, array->dimension, indexBuf);
      list[j*2] = Tcl_NewStringObj(indexBuf, -1);
      list[j*2+1] = Tcl_NewStringObj(result[j], -1);
    }
    break;
  }
  case SDDS_CHARACTER: {
    char *result = (char *)array->data;
    for (j=0 ; j < array->elements ; j++) {
      constructIndex(j, array->definition->dimensions, array->dimension, indexBuf);
      list[j*2] = Tcl_NewStringObj(indexBuf, -1);
      list[j*2+1] = Tcl_NewStringObj(&result[j], 1);
    }
    break;
  }
  default: {
    free(list);
    return NULL; 
  }   
  }
  obj = Tcl_NewListObj(len, list);
  free(list);
  return obj;
}


char **process_name_options(char **orig_name, long **orig_flag, long orig_names, 
                            char **delete, long deletes,
                            char **retain, long retains,
                            STRING_PAIR *rename, long renames,
                            EDIT_NAME_REQUEST *edit_request, long edit_requests)
{
  long i, j;
  char **new_name;
  char *ptr;
  
  *orig_flag = tmalloc(sizeof(**orig_flag)*orig_names);
  for (i=0; i<orig_names; i++)
    (*orig_flag)[i] = 1;
  
  if (deletes) {
    for (i=0; i<deletes; i++) {
      ptr = expand_ranges(delete[i]);
      free(delete[i]);
      delete[i] = ptr;
    }
    for (j=0; j<orig_names; j++) {
      for (i=0; i<deletes; i++) {
	if (wild_match(orig_name[j], delete[i])) {
	  (*orig_flag)[j] = 0;
	  break;
	}
      }
    }
  }
  
  if (retains) {
    for (i=0; i<retains; i++) {
      ptr = expand_ranges(retain[i]);
      free(retain[i]);
      retain[i] = ptr;
    }
    if (!deletes)
      for (j=0; j<orig_names; j++)
	(*orig_flag)[j] = 0;
    for (j=0; j<orig_names; j++) {
      if ((*orig_flag)[j])
	continue;
      for (i=0; i<retains; i++) {
	if (wild_match(orig_name[j], retain[i])) {
	  (*orig_flag)[j] = 1;
	  break;
	}
      }
    }
  }
  
  new_name = tmalloc(sizeof(*new_name)*orig_names);
  for (j=0; j<orig_names; j++) {
    for (i=0; i<renames; i++) {
      if (strcmp(rename[i][0], orig_name[j])==0) {
	SDDS_CopyString(new_name+j, rename[i][1]);
	break;
      }
    }
    if (i==renames)
      SDDS_CopyString(new_name+j, orig_name[j]);
    for (i=0; i<edit_requests; i++) {
      char edit_buffer[256];
      ptr = expand_ranges(edit_request[i].match_string);
      free(edit_request[i].match_string);
      edit_request[i].match_string = ptr;
      if (wild_match(new_name[j], edit_request[i].match_string)) {
	strcpy(edit_buffer, new_name[j]);
	if (!edit_string(edit_buffer, edit_request[i].edit_string))
	  SDDS_Bomb("error editing name");
	free(new_name[j]);
	SDDS_CopyString(&new_name[j], edit_buffer);
      }
    }
  }
  
  return(new_name);
}

/******************************************
 *
 *****************************************/
static long convertTypeStringToNumeric(char *type) {
  if (!strcmp(type,"SDDS_LONGDOUBLE")) {
    return 1;
  } else if (!strcmp(type,"SDDS_DOUBLE")) {
    return 2;
  } else if (!strcmp(type,"SDDS_FLOAT")) {
    return 3;
  } else if (!strcmp(type,"SDDS_LONG64")) {
    return 4;
  } else if (!strcmp(type,"SDDS_ULONG64")) {
    return 5;
  } else if (!strcmp(type,"SDDS_LONG")) {
    return 6;
  } else if (!strcmp(type,"SDDS_ULONG")) {
    return 7;
  } else if (!strcmp(type,"SDDS_SHORT")) {
    return 8;
  } else if (!strcmp(type,"SDDS_USHORT")) {
    return 9;
  } else if (!strcmp(type,"SDDS_STRING")) {
    return 10;
  } else if (!strcmp(type,"SDDS_CHARACTER")) {
    return 11;
  } else {
    return -1;
  }
}

/******************************************
 *
 *****************************************/
static char *convertNumericToTypeString(long type) {
  switch (type) {
  case 1:
    return("SDDS_LONGDOUBLE");
  case 2:
    return("SDDS_DOUBLE");
  case 3:
    return("SDDS_FLOAT");
  case 4:
    return("SDDS_LONG64");
  case 5:
    return("SDDS_ULONG64");
  case 6:
    return("SDDS_LONG");
  case 7:
    return("SDDS_ULONG");
  case 8:
    return("SDDS_SHORT");
  case 9:
    return("SDDS_USHORT");
  case 10:
    return("SDDS_STRING");
  case 11:
    return("SDDS_CHARACTER");
  default:
    return("SDDS_UNKNOWN");
  }
}

/******************************************
 *
 *****************************************/
static long constructIndex(int element, long dimensions, 
			   int32_t dim[], char *indexBuf) {

  switch (dimensions) {
  case 1: {
    sprintf(indexBuf,"%d",element);
    return 0;
  }
  case 2: {
    sprintf(indexBuf,"%ld,%ld",(long)(element/dim[1]),(long)(element%dim[1]));
    return 0;
  }
  case 3: {
    sprintf(indexBuf,"%ld,%ld,%ld",(long)(element/(dim[1]*dim[2])),
	    (long)(element/dim[2]%dim[1]),(long)(element%dim[2]));
    return 0;
  }
  case 4: {
    sprintf(indexBuf,"%ld,%ld,%ld,%ld",(long)(element/(dim[1]*dim[2]*dim[3])),
	    (long)(element/(dim[2]*dim[3])%dim[1]),
	    (long)(element/dim[3]%dim[2]),
	    (long)(element%dim[3]));
    return 0;
  }
  default:
    return -1;
  }
}

long constructIndex2(int element, long dimensions, int32_t dim[], long count) {
  if (element == dimensions-1) {
    return count;
  } else if (element == dimensions-2) {
    return (count / dim[element+1]) + 1;
  } else if (element == dimensions-3) {
    return (count / (dim[element+1] * dim[element+2])) + 1;
  } else if (element == dimensions-4) {
    return (count / (dim[element+1] * dim[element+2] * dim[element+3])) + 1;
  } else {
    return 0;
  }
}

/******************************************
 *
 *****************************************/
int tclSDDSInit(Tcl_Interp *interp) {
  int i;

  for (i=0 ; i < MAX_OPEN_SDDS_FILES ; i++) {
    sddsFdTable[i].free = 1;
    sddsFdTable[i].currentPage = 0;
    sddsFdTable[i].fileName[0] = '\0';
    sddsFdTable[i].mode = 'r';
    sddsFdTable[i].pageStarted = 0;
  }
  return TCL_OK;
}


