Index: /trunk/Ohana/src/libautocode/.cvsignore
===================================================================
--- /trunk/Ohana/src/libautocode/.cvsignore	(revision 3515)
+++ /trunk/Ohana/src/libautocode/.cvsignore	(revision 3515)
@@ -0,0 +1,3 @@
+include
+lib
+src
Index: /trunk/Ohana/src/libautocode/Makefile
===================================================================
--- /trunk/Ohana/src/libautocode/Makefile	(revision 3515)
+++ /trunk/Ohana/src/libautocode/Makefile	(revision 3515)
@@ -0,0 +1,94 @@
+default: autocode
+help:
+	@echo "make options: install autocode (default)"
+
+include ../../Configure
+
+HOME	=	$(ROOT)/src/libautocode
+SRC	=	$(HOME)/src
+BIN	=	$(HOME)/bin
+DEF	=	$(HOME)/def
+LIB	=	$(HOME)/lib
+INC	=	$(HOME)/include
+MAN	= 	$(HOME)/doc
+DESTLIB	=	$(LLIB)
+DESTINC	=	$(LINC)
+DESTMAN	=	$(LMAN)
+
+INCS	=	-I$(INC) -I$(LINC)
+LIBS	= 	-L$(LLIB)
+CFLAGS	=	$(INCS) -D$(ARCH)
+LFLAGS	=	$(LIBS)
+
+install: $(DESTINC)/autocode.h $(DESTLIB)/libautocode.a
+	@echo done install
+
+autocode: $(INC)/autocode.h $(LIB)/libautocode.$(ARCH).a 
+	@echo done autocode
+
+LIBOBJ = \
+$(SRC)/spectrum.$(ARCH).o \
+$(SRC)/spectrum-ascii.$(ARCH).o
+
+LIBINC = \
+$(INC)/spectrum.h \
+$(INC)/spectrum-ascii.h
+
+COMINC = \
+$(DEF)/common.h
+
+$(LIBOBJ): $(INC)/autocode.h
+
+$(INC)/autocode.h: $(LIBINC)
+	cat $(COMINC) $(LIBINC) > $(INC)/autocode.h
+	@echo done with libautocode.a:
+
+$(DESTINC)/autocode.h: $(INC)/autocode.h
+	@if [ ! -d $(DESTINC) ]; then mkdir -p $(DESTINC); fi
+	rm -f $(DESTINC)/autocode.h
+	cp $(INC)/autocode.h $(DESTINC)/
+	@echo installed autocode.h
+
+$(LIB)/libautocode.$(ARCH).a: $(LIBOBJ)
+	@if [ ! -d $(LIB) ]; then mkdir -p $(LIB); fi
+	rm -f $(LIB)/libautocode.$(ARCH).a
+	ar rcv $(LIB)/libautocode.$(ARCH).a $(LIBOBJ)
+	$(RANLIB) $(LIB)/libautocode.$(ARCH).a
+	@echo done with libautocode.$(ARCH).a
+
+$(DESTLIB)/libautocode.a: $(LIB)/libautocode.$(ARCH).a 
+	@if [ ! -d $(DESTLIB) ]; then mkdir -p $(DESTLIB); fi
+	rm -f  $(DESTLIB)/libautocode.a
+	cp $(LIB)/libautocode.$(ARCH).a $(DESTLIB)/libautocode.a
+	@echo installed libautocode.a
+
+$(INC)/%.h: $(DEF)/%.d $(DEF)/autocode.h
+	@if [ ! -d $(INC) ]; then mkdir -p $(INC); fi
+	generate $< $(DEF)/autocode.h $@
+	@echo done with $*.h
+
+$(SRC)/%.c: $(DEF)/%.d $(DEF)/autocode.c
+	@if [ ! -d $(SRC) ]; then mkdir -p $(SRC); fi
+	generate $< $(DEF)/autocode.c $@
+	@echo done with $*.c
+
+%.$(ARCH).o: %.c
+	$(CC) $(CFLAGS) -c $*.c -o $@
+	@echo done with $*.o
+
+%.$(ARCH).o: %.c
+	$(CC) $(CFLAGS) -c $*.c -o $@
+	@echo done with $*.o
+
+clean:	
+	rm -f `find . -name "*.o"`
+	rm -f `find . -name "*.a"`
+	rm -f `find . -name "*~"`
+	rm -f `find . -name "#*"`
+	rm -f `find src -name "*.c"`
+	rm -f `find include -name "*.h"`
+# 	this is an unusual target!  it deletes .c and .h files!
+
+.PRECIOUS: $(SRC)/%.c
+.PRECIOUS: %.$(ARCH).o
+.PRECIOUS: $(BIN)/%.$(ARCH)
Index: /trunk/Ohana/src/libautocode/def/autocode.c
===================================================================
--- /trunk/Ohana/src/libautocode/def/autocode.c	(revision 3515)
+++ /trunk/Ohana/src/libautocode/def/autocode.c	(revision 3515)
@@ -0,0 +1,60 @@
+# include "autocode.h"
+
+int fits_convert_$STRUCT ($STRUCT *data, int size, int nitems) {
+
+  int i;
+  unsigned char *byte, tmp;
+
+  if (size != $SIZE) { 
+    fprintf (stderr, "ERROR: mismatch in data types $STRUCT: %d vs %d\n",
+	     size, $SIZE);
+    exit (1);
+  }
+
+  /* provide initial values to avoid compiler warnings for non-BYTE_SWAP arch */
+  i = tmp = 0;
+  byte = NULL;
+
+# ifdef BYTE_SWAP
+  byte = (char *) data;
+  for (i = 0; i < nitems; i++, byte += $SIZE) {
+    /** BYTE SWAP **/
+  }
+# endif  
+
+  return (TRUE);
+} 
+
+/*** add test of EXTNAME and header-defined columns? ***/
+$STRUCT *fits_table_get_$STRUCT (FTable *ftable, int *Ndata) {
+
+  $STRUCT *data;
+
+  *Ndata = ftable[0].header[0].Naxis[1];
+  data = ($STRUCT *) ftable[0].buffer;
+  fits_convert_$STRUCT (data, sizeof ($STRUCT), *Ndata);
+  
+  return (data);
+}
+
+int fits_table_set_$STRUCT (FTable *ftable, $STRUCT *data, int Ndata) {
+
+  Header *header;
+
+  header = ftable[0].header;
+
+  /* create table header */
+  fits_create_table_header (header, "$TYPE", "$EXTNAME");
+
+  /* define table layout */
+  /** TABLE DEFINITION **/
+
+  /* create table */
+  fits_create_table (header, ftable);
+
+  /* add data values */
+  fits_convert_$STRUCT (data, sizeof ($STRUCT), Ndata);
+  fits_add_rows (ftable, (char *) data, Ndata, sizeof ($STRUCT));
+
+  return (TRUE);
+}
Index: /trunk/Ohana/src/libautocode/def/autocode.h
===================================================================
--- /trunk/Ohana/src/libautocode/def/autocode.h	(revision 3515)
+++ /trunk/Ohana/src/libautocode/def/autocode.h	(revision 3515)
@@ -0,0 +1,6 @@
+
+/** STRUCT DEFINITION **/
+
+$STRUCT *fits_table_get_$STRUCT (FTable *table, int *Ndata);
+int      fits_table_set_$STRUCT (FTable *ftable, $STRUCT *data, int Ndata);
+int      fits_convert_$STRUCT ($STRUCT *data, int size, int nitems);
Index: /trunk/Ohana/src/libautocode/def/common.h
===================================================================
--- /trunk/Ohana/src/libautocode/def/common.h	(revision 3515)
+++ /trunk/Ohana/src/libautocode/def/common.h	(revision 3515)
@@ -0,0 +1,25 @@
+# include <ohana.h>
+
+# define SWAP_BYTE(X) \
+  tmp = byte[X+0]; byte[X+0] = byte[X+1]; byte[X+1] = tmp;
+# define SWAP_WORD(X) \
+  tmp = byte[X+0]; byte[X+0] = byte[X+3]; byte[X+3] = tmp; \
+  tmp = byte[X+1]; byte[X+1] = byte[X+2]; byte[X+2] = tmp;
+# define SWAP_DBLE(X) \
+  tmp = byte[X+0]; byte[X+0] = byte[X+7]; byte[X+7] = tmp; \
+  tmp = byte[X+1]; byte[X+1] = byte[X+6]; byte[X+6] = tmp; \
+  tmp = byte[X+2]; byte[X+2] = byte[X+5]; byte[X+5] = tmp; \
+  tmp = byte[X+3]; byte[X+3] = byte[X+4]; byte[X+4] = tmp;
+
+# ifdef linux
+# define BYTE_SWAP
+# endif
+
+# ifdef sid
+# define BYTE_SWAP
+# endif
+
+# ifdef dec
+# define BYTE_SWAP
+# endif
+
Index: /trunk/Ohana/src/libautocode/def/smpdata.d
===================================================================
--- /trunk/Ohana/src/libautocode/def/smpdata.d	(revision 3515)
+++ /trunk/Ohana/src/libautocode/def/smpdata.d	(revision 3515)
@@ -0,0 +1,17 @@
+# name of structure type
+STRUCT  SMPData
+EXTNAME SMPFILE
+
+# elements of data structure / FITS table
+FIELD X,      X_PIX,      float,    x coord,              pixels
+FIELD Y,      Y_PIX,      float,    y coord,              pixels
+FIELD M,      MAG_RAW,    float,    inst mags,            mags
+FIELD dM,     MAG_ERR,    float,    inst mag error,       mags
+FIELD Mgal,   MAG_GAL,    float,    galaxy mag,           mags
+FIELD Map,    MAG_AP,     float,    aperture mag,         mags
+FIELD sky,    LOG_SKY,    float,    log-10 of sky,        cnts/sec
+FIELD fx,     FWHM_X,     float,    semi-major,           pixels
+FIELD fy,     FWHM_Y,     float,    semi-minor,           pixels
+FIELD df,     THETA,      float,    ellipse angle,        degrees
+FIELD dophot, DOPHOT,     char,     dophot type,          none
+FIELD dummy,  DUMMY,      char[3],  padding,              none
Index: /trunk/Ohana/src/libautocode/def/spectrum-ascii.d
===================================================================
--- /trunk/Ohana/src/libautocode/def/spectrum-ascii.d	(revision 3515)
+++ /trunk/Ohana/src/libautocode/def/spectrum-ascii.d	(revision 3515)
@@ -0,0 +1,29 @@
+# name of structure type
+STRUCT  SpectrumASCII
+EXTNAME SPECTRUM
+TYPE    TABLE
+SIZE    328
+
+# elements of data structure / FITS table
+FIELD filename,   FILENAME,   char[32],    filename in db,        
+FIELD pathname,   PATHNAME,   char[64],    fullpath in db,        
+FIELD instrument, INSTRUMENT, char[16],    instrument,            
+FIELD telescope,  TELESCOPE,  char[16],    telescope,             
+FIELD objname,    OBJNAME,    char[16],    object name,           
+FIELD extname,    EXTNAME,    char[16],    extname in file,       
+
+FIELD ra,         RA,         float[10.6], ra,                    degrees
+FIELD dec,        DEC,        float[10.6], dec,                   degrees
+FIELD exptime,    EXPTIME,    float[6.1],  exposure time,         seconds
+FIELD airmass,    AIRMASS,    float[5.3],  airmass,               none
+FIELD Ws,         Ws,         float[7.2],  spectral range start,  Angstrom
+FIELD We,         We,         float[7.2],  spectral range end,    Angstrom
+FIELD dW,         dW,         float[7.2],  spectral resolution,   Angstrom / pix
+	       			      
+FIELD Nspec,      NSPECTRA,   int[3],      number of spectra,     none
+FIELD obstime,    OBS_TIME,   char[20],    time of measurement,   yyyy/mm/dd
+FIELD regtime,    REG_TIME,   char[20],    time of registration,  yyyy/mm/dd
+	       			      
+FIELD mode,       MODE,       int[2],      phu/mef/ext,           
+FIELD state,      STATE,      int[2],      raw/wav/flx/etc,       
+FIELD flag,       FLAG,       int[3],      status flags,          
Index: /trunk/Ohana/src/libautocode/def/spectrum.d
===================================================================
--- /trunk/Ohana/src/libautocode/def/spectrum.d	(revision 3515)
+++ /trunk/Ohana/src/libautocode/def/spectrum.d	(revision 3515)
@@ -0,0 +1,32 @@
+# name of structure type
+STRUCT  Spectrum
+EXTNAME SPECTRUM_DATABASE
+TYPE    BINTABLE
+SIZE    216
+
+# elements of data structure / FITS table
+	       			      
+FIELD ra,         RA,         float,     ra,                    degrees
+FIELD dec,        DEC,        float,     dec,                   degrees
+FIELD exptime,    EXPTIME,    float,     exposure time,         seconds
+FIELD airmass,    AIRMASS,    float,     airmass,               
+FIELD Ws,         Ws,         float,     spectral range start,  Angstrom
+FIELD We,         We,         float,     spectral range end,    Angstrom
+FIELD dW,         dW,         float,     spectral resolution,   Angstrom / pix
+	       			      
+FIELD Nspec,      NSPECTRA,   int,       number of spectra,     
+FIELD obstime,    OBS_TIME,   int,       time of measurement,   seconds since 1 Jan 1970 UT
+FIELD regtime,    REG_TIME,   int,       time of registration,  seconds since 1 Jan 1970 UT
+	       			      
+FIELD mode,       MODE,       char,      phu/mef/ext           
+FIELD state,      STATE,      char,      raw/wav/flx/etc       
+FIELD flag,       FLAG,       char,      status flags
+FIELD extra,      EXTRA,      char[13],  room for expansion
+
+FIELD pathname,   PATHNAME,   char[64],  fullpath in db
+FIELD filename,   FILENAME,   char[32],  filename in db
+FIELD extname,    EXTNAME,    char[16],  extname in file,       
+
+FIELD instrument, INSTRUMENT, char[16],  instrument,            
+FIELD telescope,  TELESCOPE,  char[16],  telescope,             
+FIELD objname,    OBJNAME,    char[16],  object name,           
Index: /trunk/Ohana/src/libautocode/doc/autocode.txt
===================================================================
--- /trunk/Ohana/src/libautocode/doc/autocode.txt	(revision 3515)
+++ /trunk/Ohana/src/libautocode/doc/autocode.txt	(revision 3515)
@@ -0,0 +1,71 @@
+
+This directory contains a collection of autocoded FITS I/O routines
+used to define FITS Table DB functions.  
+
+The autocoder program is a perl script 'generate'.  This scripts takes
+as input a schema file and a template source code file, and produces
+an output file from these two inputs.  A single schema file is meant
+to be associated with a single data concept which is being coded.  For
+example, in the case of the FITS DB tables, a single schema file
+defines a single FITS table, or equivalently, a single C structure
+representing a row in that FITS table.
+
+Schema File
+
+The schema file currently consists of two types of information.
+
+First, there are simple keyword / name pairs which the autocoder
+simply applies as a direct replacement anywhere in the template.  For
+example, the keyword NAME replaces any instance of "$NAME" in the
+template with the corresponding value.  
+
+Second, there is a special type of keyword: FIELD.  The FIELD entry
+defines an entry in the data structure.  The FIELD entry is followed
+by the following comma-separated pieces of information:
+
+- the element name
+- the element data type
+- the element description
+- the element physical unit
+
+Template File
+
+The template file is a source code in whatever language is desired.
+Within the template, the defined keywords may be used as desired,
+wherever needed.  In addition, there are special directives which
+invoke additional special behavior.  All special directives have the
+form of comments within their target language.  They are replaced with
+a block of code in that target language, normally one which iterates
+over the FIELD elements of the schema file.  As such, the directive
+appropriate for one language should not be used within code for a
+different language.  Here is a list of existing special directives:
+
+/** STRUCT DEFINITION **/
+
+This tells the autocoder to create a structure definition for the
+schema.  The structure definition creates a structure with elements
+based on the FIELD entries, with the name $NAME (NOTE: this is perhaps
+making too much of an assumption.  we could require the template to
+provide the wrapper: "typedef struct { } $NAME;" and have the
+autocoder only insert the field lines).  
+
+/** TABLE DEFINITION **/
+
+This tells the autocoder to output the lines which add a column to an
+exiting empty table.  The assumption is that the template contains
+code to initialize a table.  It then invokes the table definition
+code, which defines each of the appropriate columns.  This is perhaps
+followed by some code which finalizes the table definition.  (Note:
+the code output by the autocoder in this block is not very flexible:
+it the current example, it explicitly uses the Elixir FITS Table
+functions, and refers to some data elements in the template code.  The
+latter could possibly be more abstracted with the keyword / value
+pairs, but in any case, the autocoded lines will have to be
+constructed somewhat by hand for a specific API set.
+
+/** BYTE SWAP **/
+
+This tells the autocoder to output code defining the byte swaps
+appropriat to the data structure.  Again, the resulting code depends a
+bit on the intended use and API set.
+
Index: /trunk/Ohana/src/libautocode/doc/notes.txt
===================================================================
--- /trunk/Ohana/src/libautocode/doc/notes.txt	(revision 3515)
+++ /trunk/Ohana/src/libautocode/doc/notes.txt	(revision 3515)
@@ -0,0 +1,113 @@
+
+FITS I/O APIs
+
+  - I/O to a binary FITS table
+  - one extension per file?
+  - no locking
+  - always read/write to/from matched structure
+  - user needs to supply idiosyncratic conversions
+
+  - basic APIs:
+    - fits_read_datatable_NAME
+    - fits_write_datatable_NAME
+    - fits_IO_convert_NAME
+    - fits_fread_datatable_NAME
+    - fits_fwrite_datatable_NAME
+
+  
+
+FITS db APIs
+
+Basic Rules:
+
+  - All db files are Binary FITS tables
+  - There is only one extension per file
+  - The PHU contains basic information like status & date
+  - There is no data array for the PHU (NAXIS = 0)
+
+typedef struct {
+  FILE *f;
+  char *filename;
+  Header header;
+  FTable ftable;
+  int Nrows;
+  int Ncols;
+  int Nbyte;
+  int lockstate;
+  int lockreq;
+  NAME *data;
+} NAME_DB;
+
+NAME_DB *NAME_DB_Init (NAME_DB *db);
+
+  - 
+
+NAME_DB *NAME_DB_Load (char *filename, int lockreq);
+
+  - lock the database file
+  - load PHU
+  - load the header
+  - validate the EXTNAME
+  - validate the header
+  - load the data into ftable
+  - convert to memory format
+
+  * if SOFT & database file does not exist (file is empty), 
+    - return structure w/ 0 entries
+
+  * if HARD & database file does not exist (file is empty), 
+    - open, lock, return structure w/ 0 entries
+
+  * if database file cannot be locked
+    - return an error (NULL)
+
+  * if header does not validate: 
+    - unlock file
+    - return an error (NULL)
+
+NAME_DB *NAME_DB_Loadset (char *filename, int lockreq, int start, int Nrows);
+
+  - lock the database file
+  - load PHU
+  - load the header
+  - validate the EXTNAME
+  - validate the header
+  - load the data into vtable
+  - convert to memory format
+
+  * if database file does not exist (file is empty), 
+    - open, lock, return structure w/ 0 entries
+  * if requested entries don't exist
+    - unlock file
+    - return an error (NULL)
+
+NAME_DB *NAME_DB_Save ();
+
+  - if Nrows = 0, delete the file
+
+  - write PHU
+  - write header
+  - write ftable
+
+  - if vtable: 
+    - update 
+  - if ftable: 
+    - update 
+
+NAME_DB *NAME_DB_Saveset ();
+
+  - if Nrows = 0, delete the file
+
+  - write PHU
+  - write header
+  - write ftable
+
+  - if vtable: 
+    - update 
+  - if ftable: 
+    - update 
+
+NAME_DB *NAME_DB_Free ();
+
+  - unlock file
+
Index: /trunk/Ohana/src/libautocode/generate
===================================================================
--- /trunk/Ohana/src/libautocode/generate	(revision 3515)
+++ /trunk/Ohana/src/libautocode/generate	(revision 3515)
@@ -0,0 +1,277 @@
+#!/usr/bin/env perl
+
+if (@ARGV != 3) { die "generate (schema) (template) (output)\n"; }
+
+$schema   = $ARGV[0];
+$template = $ARGV[1];
+$output   = $ARGV[2];
+
+&parse_schema;
+&parse_template;
+exit 0;
+
+sub parse_schema {
+    open (FILE, "$schema");
+    @list = <FILE>;
+    close (FILE);
+
+    $NAME    = "";
+    $FILE    = "";
+    $Nfield  = 0;
+    $TIMEOUT = 0;
+
+    &init_key ("TIMEOUT");
+    &init_key ("NAME");
+    &init_key ("EXTNAME");
+    &init_key ("STRUCT");
+    &init_key ("FILE");
+    &init_key ("SIZE");
+    &init_key ("TYPE");
+
+    foreach $line (@list) {
+	chop $line;
+	($key, $value) = split (" ", $line, 2);
+	
+	&set_keypair ($key, $value);
+
+	# there are used internally (not just a replacement)
+	if ($key eq "TYPE") { $TYPE = $value; }
+	if ($key eq "STRUCT") { $STRUCT = $value; }
+
+	# not a simple key/value entry
+	if ($key eq "FIELD") {
+	    ($element, $field, $format, $comment, $unit) = split (/,\s+/, $value);
+	    push @element, $element;
+	    push @field,   $field;
+	    push @format,  $format;
+	    push @comment, $comment;
+	    push @unit,    $unit;
+	}
+    }
+    if ($TYPE eq "BINTABLE") { &count_bintablesize; }
+    if ($TYPE eq "TABLE") { &count_tablesize; }
+}
+
+sub parse_template {
+    open (FILE, $template);
+    @list = <FILE>;
+    close (FILE);
+
+    open (FILE, ">$output");
+
+    foreach $line (@list) {
+	
+	&check_keypairs;
+
+	print FILE $line;
+
+	# fill in structure
+	if ($line =~ m|/\*\* STRUCT DEFINITION \*\*/|) {
+	    &write_structure;
+	}
+
+	# fill in structure
+	if ($line =~ m|/\*\* TABLE DEFINITION \*\*/|) {
+	    if ($TYPE eq "BINTABLE") { &write_bintabledefs; }
+	    if ($TYPE eq "TABLE")    { &write_tabledefs; }
+	}
+
+	# fill in swaps
+	if ($line =~ m|/\*\* BYTE SWAP \*\*/|) {
+	    &write_byteswaps;
+	}
+    }
+    close (FILE);
+}
+
+sub write_bintabledefs {
+
+    for ($i = 0; $i < @field; $i++) {
+	# add [\d\.] to match ascii-type formats
+	($type, $length) = $format[$i] =~ m|^(\w+)\[(\d+)\]|;
+	if (!$type && !$length) { $type = $format[$i]; }
+
+	if ($type eq "char") {
+	    if ($length == 0) { 
+		$pt1 = sprintf "A";
+	    } else {
+		$pt1 = sprintf "%dA", $length;
+	    }
+	}
+
+	if ($type eq "byte")   { $pt1 = "B"; }
+	if ($type eq "short")  { $pt1 = "I"; }
+	if ($type eq "int")    { $pt1 = "J"; }
+	if ($type eq "float")  { $pt1 = "E"; }
+	if ($type eq "double") { $pt1 = "D"; }
+
+	printf FILE "  fits_define_bintable_column (header, ";
+	printf FILE "\"%s\",   ", $pt1;
+	printf FILE "\"%s\",   ", $field[$i];
+	printf FILE "\"%s\", ",   $comment[$i];
+	printf FILE "\"%s\", 1.0, 0.0);\n", $unit[$i];
+    }
+
+}
+
+sub write_tabledefs {
+
+    for ($i = 0; $i < @field; $i++) {
+	($type, $length) = $format[$i] =~ m|^(\w+)\[([\d\.]+)\]|;
+	if (!$type && !$length) { die "format must be specified for ASCII table"; }
+
+	if ($type eq "char")   { $pt1 = sprintf "A%s", $length; }
+	if ($type eq "byte")   { $pt1 = sprintf "I%s", $length; }
+	if ($type eq "short")  { $pt1 = sprintf "I%s", $length; }
+	if ($type eq "int")    { $pt1 = sprintf "I%s", $length; }
+	if ($type eq "float")  { $pt1 = sprintf "F%s", $length; }
+	if ($type eq "double") { $pt1 = sprintf "F%s", $length; }
+
+	printf FILE "  fits_define_table_column (header, ";
+	printf FILE "\"%s\", ",   $pt1;
+	printf FILE "\"%s\", ",   $field[$i];
+	printf FILE "\"%s\", ",   $comment[$i];
+	printf FILE "\"%s\");\n", $unit[$i];
+    }
+
+}
+
+sub write_structure {
+    print FILE "typedef struct {\n";
+    for ($i = 0; $i < @element; $i++) {
+	($type, $length) = $format[$i] =~ m|^(\w+)\[([\d\.]+)\]|;
+	if (!$type && !$length) { $type = $format[$i]; }
+
+	if (($type eq "char") && ($length != 0)) { 
+	    $pt2 = sprintf "%s[%d];", $element[$i], $length;
+	} else {
+	    $pt2 = sprintf "%s;", $element[$i];
+	}
+
+	if ($unit[$i] eq "") {
+	    $pt3 = sprintf "// %s", $comment[$i];
+	} else {
+	    $pt3 = sprintf "// %s (%s)", $comment[$i], $unit[$i];
+	}
+	printf FILE "  %-16s %-21s %s\n", $type, $pt2, $pt3;
+    }    
+    print FILE "} $STRUCT;\n";
+}
+
+sub write_byteswaps {
+    $N = 0;
+    for ($i = 0; $i < @field; $i++) {
+	($type, $length) = $format[$i] =~ m|^(\w+)\[([\d\.]+)\]|;
+	if (!$type && !$length) { $type = $format[$i]; }
+
+	if ($type eq "char") {
+	    if ($length == 0) { 
+		$N ++;
+	    } else {
+		$N += $length;
+	    }
+	    next;   # skip byte swap command
+	}
+	if ($type eq "byte")  {
+	    $N ++;
+	    next;
+	}
+	if ($type eq "short")  {
+	    $T = "BYTE";
+	    $n = 2;
+	}
+	if ($type eq "float")  {
+	    $T = "WORD";
+	    $n = 4;
+	}
+	if ($type eq "int")    {
+	    $T = "WORD";
+	    $n = 4;
+	}
+	if ($type eq "double") { 
+	    $T = "DBLE";
+	    $n = 8;
+	}
+	printf FILE "    SWAP_%s (%d); // %s\n", $T, $N, $field[$i];
+	$N += $n;
+    }
+}
+
+sub count_bintablesize {
+
+    $Nbytes = 0;
+    for ($i = 0; $i < @field; $i++) {
+
+	# add [\d\.] to match ascii-type formats
+	($type, $length) = $format[$i] =~ m|^(\w+)\[(\d+)\]|;
+	if (!$type && !$length) { 
+	    $type = $format[$i]; 
+	    $length = 0;
+	}
+
+	if ($type eq "char") {
+	    if ($length) {
+		$Nbytes += $length;
+	    } else {
+		$Nbytes ++;
+	    }
+	}
+	if ($type eq "double") { $Nbytes += 8; }
+	if ($type eq "int")    { $Nbytes += 4; }
+	if ($type eq "short")  { $Nbytes += 2; }
+	if ($type eq "float")  { $Nbytes += 4; }
+    }
+    return ($Nbytes);
+}
+
+sub count_tablesize {
+
+    $Nbytes = 0;
+    for ($i = 0; $i < @field; $i++) {
+	($length) = $format[$i] =~ m|^\w+\[([\d\.]+)\]|;
+	if ($length == 0) { die "ASCII table format requires field size"; }
+	$Nbytes += $length;
+    }
+    return ($Nbytes);
+}
+
+sub init_key {
+    my ($key)   = $_[0];
+
+    push @key, $key;
+    push @value, "";
+}
+
+sub set_keypair {
+    my ($i);
+    my ($key)   = $_[0];
+    my ($value) = $_[1];
+
+    for ($i = 0; $i < @key; $i++) {
+	if ($key eq $key[$i]) {
+	    if ($value[$i] ne "") { die "key is multiply defined\n"; }
+	    $value[$i] = $value;
+	    return;
+	}
+    }
+}
+
+sub check_keypairs {
+    my ($i);
+    for ($i = 0; $i < @key; $i++) {
+	if ($line =~ m|\$$key[$i]|) {
+#	    print "$key[$i]  -- $value[$i]\n";
+	    if ($value[$i] eq "") { die "missing value for required key $key[$i]\n"; }
+	    $line =~ s|\$$key[$i]|$value[$i]|g;
+	}
+    }
+}
+
+# we need to find the structure size, including padding 
+# i'm not sure I know the answer to this: it is probably 
+# the total number of bytes rounded up to the largest 
+# data item in the structure (ie, 8 for a double, etc)
+# if we have the size, then we can double check the structure
+# against the expectation at runtime.  for the moment,
+# calculate by hand and add to def.d file 
+
