summaryrefslogtreecommitdiffstats
path: root/funtools/funcol.c
diff options
context:
space:
mode:
Diffstat (limited to 'funtools/funcol.c')
-rw-r--r--funtools/funcol.c1461
1 files changed, 1461 insertions, 0 deletions
diff --git a/funtools/funcol.c b/funtools/funcol.c
new file mode 100644
index 0000000..277cc86
--- /dev/null
+++ b/funtools/funcol.c
@@ -0,0 +1,1461 @@
+/*
+ * Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory
+ */
+
+#include <funtoolsP.h>
+
+/*
+ *
+ * private routines
+ *
+ */
+
+/*
+ *
+ * _FunColCmp -- compare routine for qsort
+ *
+ */
+#ifdef ANSI_FUNC
+static int
+_FunColCmp(const void *s1, const void *s2)
+#else
+static int _FunColCmp(s1, s2)
+ const void *s1;
+ const void *s2;
+#endif
+{
+ FunCol *f1 = (FunCol *)s1;
+ FunCol *f2 = (FunCol *)s2;
+
+ /* user order flag */
+ if( (*f1)->order > (*f2)->order )
+ return -1;
+ if( (*f1)->order < (*f2)->order )
+ return 1;
+ else
+ return 0;
+}
+
+#ifdef ANSI_FUNC
+static int
+mparse (char *mode)
+#else
+static int mparse(mode)
+ char *mode;
+#endif
+{
+ int xmode = 0;
+ xmode |= ( strpbrk(mode, "a") != NULL ? COL_ACTIVE : 0 );
+ xmode |= ( strpbrk(mode, "i") != NULL ? COL_IBUF : 0 );
+ xmode |= ( strpbrk(mode, "p") != NULL ? COL_PTR : 0 );
+ xmode |= ( strpbrk(mode, "r") != NULL ? COL_READ : 0 );
+ xmode |= ( strpbrk(mode, "w") != NULL ? COL_WRITE : 0 );
+ return xmode;
+}
+
+#ifdef ANSI_FUNC
+static void
+_FunGetAlias(Fun fun, char *iname, char *oname)
+#else
+static void _FunGetAlias(fun, iname, oname)
+ Fun fun;
+ char *iname;
+ char *oname;
+#endif
+{
+ strcpy(oname, iname);
+ if( !strcasecmp(iname, "$x") ){
+ if( fun->bin[0] >= 0 ){
+ strcpy(oname, fun->header->table->col[fun->bin[0]].name);
+ }
+ }
+ else if( !strcasecmp(iname, "$y") ){
+ if( fun->bin[1] >= 0 ){
+ strcpy(oname, fun->header->table->col[fun->bin[1]].name);
+ }
+ }
+}
+
+
+/*
+ *
+ * _FunColumnAddRegion -- primitive to add region to a list of columns
+ *
+ */
+#ifdef ANSI_FUNC
+static int
+_FunColumnAddRegion(Fun fun, int dopad, char *mode, int *rgot, size_t *rsize)
+#else
+static int
+_FunColumnAddRegion(fun, dopad, mode, rgot, rsize)
+ Fun fun;
+ int dopad;
+ char *mode;
+ int *rgot;
+ size_t *rsize;
+#endif
+{
+ int got=*rgot;
+ size_t tsize=*rsize;
+ size_t pad;
+
+ /* only add region if we do not have it already, but don't activate it */
+ if( !FunColumnLookup(fun, COL_REGION_NAME, 0,
+ NULL, NULL, NULL, NULL, NULL, NULL) ){
+ /* allocate a new column struct */
+ if( !(fun->cols[got] = (FunCol)xcalloc(1, sizeof(FunColRec))) ){
+ gerror(stderr, "can't allocate FunCol struct\n");
+ return 0;
+ }
+ /* fill in the blanks with the known info */
+ fun->cols[got]->tcol = COL_REGION_ID;
+ fun->cols[got]->name = xstrdup(COL_REGION_NAME);
+ fun->cols[got]->type = 'J';
+ fun->cols[got]->from = -1;
+ fun->cols[got]->mode = mparse(mode);
+ fun->cols[got]->mode &= ~COL_ACTIVE;
+ fun->cols[got]->n = 1;
+ fun->cols[got]->width = ft_sizeof(fun->cols[got]->type);
+ /* pad for alignment */
+ if( dopad ){
+ pad = (sizeof(int) - (tsize % sizeof(int)));
+ if( pad != sizeof(int) )
+ tsize += pad;
+ }
+ fun->cols[got]->offset = tsize;
+ tsize += sizeof(int);
+ got++;
+
+ /* reset return values */
+ *rgot = got;
+ *rsize = tsize;
+ /* return the news */
+ return got;
+ }
+ else
+ return 0;
+}
+
+/*
+ *
+ * _FunColumnAddNum -- primitive to add num to a list of columns
+ *
+ */
+#ifdef ANSI_FUNC
+static int
+_FunColumnAddNum(Fun fun, int dopad, char *mode, int *rgot, size_t *rsize)
+#else
+static int
+_FunColumnAddNum(fun, dopad, mode, rgot, rsize)
+ Fun fun;
+ int dopad;
+ char *mode;
+ int *rgot;
+ size_t *rsize;
+#endif
+{
+ int got=*rgot;
+ size_t tsize=*rsize;
+ size_t pad;
+
+ /* only add num if we do not have it already, but don't activate it */
+ if( !FunColumnLookup(fun, COL_NUM_NAME, 0,
+ NULL, NULL, NULL, NULL, NULL, NULL) ){
+ /* allocate a new column struct */
+ if( !(fun->cols[got] = (FunCol)xcalloc(1, sizeof(FunColRec))) ){
+ gerror(stderr, "can't allocate FunCol struct\n");
+ return 0;
+ }
+ /* fill in the blanks with the known info */
+ fun->cols[got]->tcol = COL_NUM_ID;
+ fun->cols[got]->name = xstrdup(COL_NUM_NAME);
+ fun->cols[got]->type = 'J';
+ fun->cols[got]->from = -1;
+ fun->cols[got]->mode = mparse(mode);
+ fun->cols[got]->mode &= ~COL_ACTIVE;
+ fun->cols[got]->n = 1;
+ fun->cols[got]->width = ft_sizeof(fun->cols[got]->type);
+ /* pad for alignment */
+ if( dopad ){
+ pad = (sizeof(int) - (tsize % sizeof(int)));
+ if( pad != sizeof(int) )
+ tsize += pad;
+ }
+ fun->cols[got]->offset = tsize;
+ tsize += sizeof(int);
+ got++;
+
+ /* reset return values */
+ *rgot = got;
+ *rsize = tsize;
+ /* return the news */
+ return got;
+ }
+ else
+ return 0;
+}
+
+/*
+ *
+ * _FunColumnAddTable -- primitive to add entries from a binary table to list
+ *
+ */
+#ifdef ANSI_FUNC
+static int
+_FunColumnAddTable(Fun fun, FITSHead header, char *mode,
+ int dopad, int *got, size_t *size)
+#else
+static int
+_FunColumnAddTable(fun, header, mode, dopad, got, size)
+ Fun fun;
+ FITSHead header;
+ char *mode;
+ int dopad;
+ int *got;
+ size_t *size;
+#endif
+{
+ int i;
+ int pad;
+ int fsize;
+ FITSCard card1, card2, card3;
+
+ for(i=0; (i<header->table->tfields) && (*got<FUN_MAXCOL) ; i++){
+ /* sanity check */
+ if( !ft_sizeof(header->table->col[i].type) ){
+ gwarning(stderr,
+ "skipping column %s with no width (FITS TFORM%d is probably unknown)\n",
+ header->table->col[i].name, i+1);
+ continue;
+ }
+ /* allocate a new column struct */
+ if( !(fun->cols[*got] = (FunCol)xcalloc(1, sizeof(FunColRec))) ){
+ gerror(stderr, "can't allocate FunCol struct\n");
+ return 0;
+ }
+ /* fill in the blanks with the info directly from the table */
+ fun->cols[*got]->tcol = i;
+ fun->cols[*got]->name = xstrdup(header->table->col[i].name);
+
+ fun->cols[*got]->from = -1;
+ fun->cols[*got]->mode = mparse(mode);
+ fun->cols[*got]->n = header->table->col[i].n;
+ fun->cols[*got]->tblank = header->table->col[i].dblank;
+ fun->cols[*got]->doblank = header->table->col[i].has_blank;
+ fun->cols[*got]->tlmin = ft_headgetr(header, "TLMIN", i+1, 0.0, &card1);
+ fun->cols[*got]->tlmax = ft_headgetr(header, "TLMAX", i+1, 0.0, &card2);
+ fun->cols[*got]->binsiz = ft_headgetr(header, "TDBIN", i+1, 0.0, &card3);
+ fun->cols[*got]->type = header->table->col[i].type;
+ if( header->table->col[i].scaled && (header->table->col[i].type != 'X')){
+ /* for input data, just set the scale values */
+ if( fun->cols[*got]->mode & COL_IBUF ){
+ fun->cols[*got]->tzero = header->table->col[i].zero;
+ fun->cols[*got]->tscale = header->table->col[i].scale;
+ fun->cols[*got]->scaled = FUN_SCALE_EXISTS;
+ }
+ /* otherwise, change type of column to double */
+ else{
+ switch(header->table->col[i].type){
+ case 'B':
+ fun->cols[*got]->type = 'I';
+ break;
+ case 'I':
+ case 'U':
+ fun->cols[*got]->type = 'J';
+ break;
+ default:
+ fun->cols[*got]->type = 'D';
+ break;
+ }
+ }
+ }
+ /* save wcs keywords */
+ fun->cols[*got]->tctyp = ft_headgets(header, "TCTYP",
+ i+1, NULL, &card1);
+ fun->cols[*got]->tcrvl = ft_headgets(header, "TCRVL",
+ i+1, NULL, &card1);
+ fun->cols[*got]->tcdlt = ft_headgets(header, "TCDLT",
+ i+1, NULL, &card1);
+ fun->cols[*got]->tcrpx = ft_headgets(header, "TCRPX",
+ i+1, NULL, &card1);
+ fun->cols[*got]->tcrot = ft_headgets(header, "TCROT",
+ i+1, NULL, &card1);
+ fun->cols[*got]->tunit = ft_headgets(header, "TUNIT",
+ i+1, NULL, &card1);
+ fun->cols[*got]->vla = xstrdup(header->table->col[i].vla);
+ /* now that we have the type, calculate offset, width, etc. */
+ fsize = ft_sizeof(fun->cols[*got]->type);
+ /* pad for alignment, if necessary */
+ if( dopad ){
+ pad = (fsize - (*size % fsize));
+ if( pad != fsize ) *size += pad;
+ }
+ fun->cols[*got]->offset = *size;
+ fun->cols[*got]->width = fsize * fun->cols[*got]->n;
+ /* size of bitfield adjusted specially */
+ if( fun->cols[*got]->type == 'X' )
+ fun->cols[*got]->width = (fun->cols[*got]->width + 7) / 8;
+ *size += fun->cols[*got]->width;
+ /* make column active */
+ fun->cols[*got]->mode |= COL_ACTIVE;
+ *got += 1;
+ }
+ /* add special columns, if necessary */
+ _FunColumnAddRegion(fun, dopad, "rw", got, size);
+ _FunColumnAddNum(fun, dopad, "rw", got, size);
+ return *got;
+}
+
+/*
+ *
+ * _FunColumnSelect -- primitive to add columns to the selected column list
+ *
+ */
+#ifdef ANSI_FUNC
+static int
+_FunColumnSelect(Fun fun, size_t size, char *mode, char **names, char **types,
+ char **modes, int *offsets, int nargs)
+#else
+static int
+_FunColumnSelect(fun, size, mode, names, types, modes, offsets, nargs)
+ Fun fun;
+ size_t size;
+ char *mode;
+ char **names;
+ char **types;
+ char **modes;
+ int *offsets;
+ int nargs;
+#endif
+{
+ int i;
+ int got;
+ int flag;
+ int type;
+ int ptype;
+ int poff;
+ int n;
+ int narg;
+ int offset;
+ int dopad;
+ int doselect;
+ int doref;
+ int idx;
+ int dims;
+ int scaled;
+ size_t pad;
+ size_t tsize;
+ char *mbuf;
+ char name[SZ_LINE];
+ char tbuf[SZ_LINE];
+ char *s, *t, *m;
+ char *activate=NULL;
+ double tlmin;
+ double tlmax;
+ double binsiz;
+ double tscale;
+ double tzero;
+ FITSHead header;
+
+ /* make sure we have something */
+ if( !_FunValid(fun) )
+ return 0;
+
+ /* make sure we have something like a table */
+ if( fun->header && fun->header->table ){
+ header = fun->header;
+ activate = NULL;
+ }
+ /* if not, we can use the input fun handle's table */
+ else if( fun->ifun && fun->ifun->header && fun->ifun->header->table ){
+ header = fun->ifun->header;
+ activate = fun->ifun->activate;
+ }
+ /* else die */
+ else{
+ header = NULL;
+ activate = NULL;
+ }
+
+ /* this extension must be a table */
+ fun->type = FUN_TABLE;
+ /* reset the io flag, since we are presumably preparing a new table */
+ fun->io = 0;
+ /* assume array of structs */
+ fun->org = FUN_ORG_AOS;
+ /* init flag */
+ flag = 0;
+
+ /* process mode string */
+ doselect = 0;
+ doref = 0;
+ mbuf = xstrdup(mode);
+ if( _FunKeyword(mbuf, "pad", NULL, tbuf, SZ_LINE) )
+ dopad = istrue(tbuf);
+ else
+ dopad = 1;
+ if( _FunKeyword(mbuf, "copy", NULL, tbuf, SZ_LINE) ){
+ doselect = !strcasecmp(tbuf, "select") && (fun->ifun && fun->ifun->ncol);
+ doref = !strcasecmp(tbuf, "reference");
+ }
+ if( _FunKeyword(mbuf, "org", NULL, tbuf, SZ_LINE) ){
+ if( !strcasecmp(tbuf, "soa") || !strcasecmp(tbuf, "structofarrays") )
+ fun->org = FUN_ORG_SOA;
+ else if( !strcasecmp(tbuf, "aos") || !strcasecmp(tbuf, "arrayofstructs") )
+ fun->org = FUN_ORG_AOS;
+ }
+ if( mbuf ) xfree(mbuf);
+
+ /* process the argument list */
+ tsize = 0;
+ for(narg=0, got=fun->ncol; (narg<nargs) && (got<FUN_MAXCOL); narg++){
+ /* we got info from the routine call, not from the FITS file */
+ flag = 1;
+ /* get name, type, and mode, and make sure they are valid */
+ s = names[narg];
+ t = types[narg];
+ m = modes[narg];
+ if( !s || !*s || !t || !*t || !m || !*m )
+ continue;
+ offset = offsets[narg];
+ _FunGetAlias(fun, s, name);
+ _FunColumnType(t, &type, &n, &tlmin, &tlmax, &binsiz, &dims,
+ &tscale, &tzero, &scaled, &ptype, &poff);
+ /* allocate a new column struct */
+ if( !(fun->cols[got] = (FunCol)xcalloc(1, sizeof(FunColRec))) ){
+ gerror(stderr, "can't allocate FunCol struct\n");
+ return 0;
+ }
+ /* if we have a header, look for the specified column */
+ if( header ){
+ for(i=0; i<header->table->tfields; i++){
+ if( !header->table->col[i].name ) continue;
+ if( !strcasecmp(header->table->col[i].name, name) ){
+ fun->cols[got]->tcol = i;
+ fun->cols[got]->name = xstrdup(header->table->col[i].name);
+ break;
+ }
+ }
+ }
+ /* if we did not find the name in the header, maybe its "$region" */
+ if( !fun->cols[got]->name && !strcasecmp(name, COL_REGION_NAME) ){
+ fun->cols[got]->tcol = COL_REGION_ID;
+ fun->cols[got]->name = xstrdup(COL_REGION_NAME);
+ }
+ if( !fun->cols[got]->name && !strcasecmp(name, COL_NUM_NAME) ){
+ fun->cols[got]->tcol = COL_NUM_ID;
+ fun->cols[got]->name = xstrdup(COL_NUM_NAME);
+ }
+ /* for reading, make sure we found it */
+ if( !fun->cols[got]->name ){
+ if( strchr(m, 'w') ){
+ fun->cols[got]->tcol = COL_UNKNOWN_ID;
+ fun->cols[got]->name = xstrdup(name);
+ }
+ else{
+ gerror(stderr,
+ "selected column '%s' does not exist in table\n", name);
+ return 0;
+ }
+
+ }
+ /* fill in the remaining info */
+ fun->cols[got]->type = type;
+ fun->cols[got]->from = -1;
+ fun->cols[got]->mode = mparse(m);
+ fun->cols[got]->mode |= COL_ACTIVE;
+ fun->cols[got]->mode |= ptype;
+ if( poff >= 0 )
+ /* offset is in units of data type */
+ fun->cols[got]->poff = poff*ft_sizeof(fun->cols[got]->type);
+ else
+ /* negative means its a byte offset */
+ fun->cols[got]->poff = -poff;
+ fun->cols[got]->n = n;
+ fun->cols[got]->offset = offset;
+ fun->cols[got]->tlmin = tlmin;
+ fun->cols[got]->tlmax = tlmax;
+ fun->cols[got]->binsiz = binsiz;
+ fun->cols[got]->tscale = tscale;
+ fun->cols[got]->tzero = tzero;
+ fun->cols[got]->scaled = scaled;
+ fun->cols[got]->width = fun->cols[got]->n*ft_sizeof(fun->cols[got]->type);
+ /* size of bitfield adjusted specially */
+ if( fun->cols[got]->type == 'X' )
+ fun->cols[got]->width = (fun->cols[got]->width + 7) / 8;
+ if( fun->cols[got]->mode & COL_PTR )
+ tsize += sizeof(char *);
+ else
+ tsize += fun->cols[got]->width;
+ /* if we are merging, we may have to set the mode on an original column */
+ switch( fun->merge ){
+ case MERGE_UPDATE:
+ /* for update, we change the value of the original column -- that is,
+ if this is a writable column itself */
+ if( fun->cols[got]->mode & COL_WRITE ){
+ if( (idx = FunColumnLookup(fun, fun->cols[got]->name, 0, NULL,
+ NULL, NULL, NULL, NULL, NULL)) ){
+ idx--;
+ /* we don't write the updating column */
+ fun->cols[got]->mode &= ~COL_WRITE;
+ /* instead we write the updated column with the updating info */
+ fun->cols[idx]->from = got;
+ }
+ }
+ break;
+ case MERGE_REPLACE:
+ /* for replace, we don't write the original column -- that is,
+ if this is a writable column itself */
+ if( fun->cols[got]->mode & COL_WRITE ){
+ if( (idx = FunColumnLookup(fun, fun->cols[got]->name, 0, NULL,
+ NULL, NULL, NULL, NULL, NULL)) ){
+ idx--;
+ fun->cols[idx]->mode |= COL_REPLACEME;
+ /* if the replacing column has no tlmin,tlmax, but the replaced
+ column does, we use the replaced column's values */
+ if( !fun->cols[got]->tlmin && !fun->cols[got]->tlmax ){
+ if( fun->cols[idx]->tlmin || fun->cols[idx]->tlmax ){
+ fun->cols[got]->tlmin = fun->cols[idx]->tlmin;
+ fun->cols[got]->tlmax = fun->cols[idx]->tlmax;
+ fun->cols[got]->binsiz = fun->cols[idx]->binsiz;
+ }
+ }
+
+ }
+ }
+ break;
+ case MERGE_APPEND:
+ /* for append, only write user columns if they are new */
+ if( (idx = FunColumnLookup(fun, fun->cols[got]->name, 0, NULL,
+ NULL, NULL, NULL, NULL, NULL)) ){
+ fun->cols[got]->mode &= ~COL_WRITE;
+ }
+ break;
+ }
+ got++;
+ }
+
+ /* if select, and no args, use the defaults from the FITS table itself or
+ from selected input columns */
+ if( !got ){
+ /* copy selected columns from input struct */
+ if( doselect ){
+ /* flag input from columns */
+ flag = 1;
+ /* copy column records */
+ memcpy(fun->cols, fun->ifun->cols, fun->ifun->ncol*sizeof(FunCol));
+ for(got=0; got<fun->ifun->ncol; got++){
+ if( !(fun->cols[got] = (FunCol)xcalloc(1, sizeof(FunColRec))) ){
+ gerror(stderr, "can't allocate FunCol struct\n");
+ return 0;
+ }
+ memcpy(fun->cols[got], fun->ifun->cols[got], sizeof(FunColRec));
+ fun->cols[got]->name = xstrdup(fun->ifun->cols[got]->name);
+ fun->cols[got]->tctyp = xstrdup(fun->ifun->cols[got]->tctyp);
+ fun->cols[got]->tcrvl = xstrdup(fun->ifun->cols[got]->tcrvl);
+ fun->cols[got]->tcdlt = xstrdup(fun->ifun->cols[got]->tcdlt);
+ fun->cols[got]->tcrpx = xstrdup(fun->ifun->cols[got]->tcrpx);
+ fun->cols[got]->tcrot = xstrdup(fun->ifun->cols[got]->tcrot);
+ fun->cols[got]->tunit = xstrdup(fun->ifun->cols[got]->tunit);
+ fun->cols[got]->vla = xstrdup(fun->ifun->cols[got]->vla);
+ }
+ size = fun->ifun->rowsize;
+ /* copy activation string */
+ fun->activate = xstrdup(fun->ifun->activate);
+ }
+ /* copy all of the columns from the reference file */
+ else if( doref ){
+ if( header ){
+ /* flag that we got info from FITS file, not from the routine call */
+ flag = 0;
+ /* add columns from table */
+ if( !_FunColumnAddTable(fun, header, "rw", dopad, &got, &tsize) )
+ return 0;
+ /* if we are copying raw columns from a reference file,
+ we have to call the reference activate routine */
+ if( activate ) FunColumnActivate(fun, activate, NULL);
+ }
+ else{
+ gerror(stderr, "no reference header passed to FunColumnSelect()\n");
+ return 0;
+ }
+ }
+ }
+
+ /* this is how many specified columns we have */
+ fun->ncol = got;
+
+ /* if we had input, we have to accept the size */
+ if( flag )
+ fun->rowsize = size;
+ else{
+ /* make sure we are padded properly */
+ if( dopad ){
+ pad = sizeof(double) - (tsize % sizeof(double));
+ if( pad != sizeof(double) )
+ tsize += pad;
+ }
+ fun->rowsize = tsize;
+ }
+ if( fun->rowsize < 0 ){
+ gerror(stderr, "invalid event record size in FunColumnSelect (%d)\n",
+ fun->rowsize);
+ return 0;
+ }
+
+ /* return the number of selected columns */
+ return fun->ncol;
+}
+
+/*
+ *
+ * semi-public routines
+ *
+ */
+
+/*
+ *
+ * _FunColumnHeader -- generate a fitsy header from the col array
+ *
+ */
+#ifdef ANSI_FUNC
+void
+_FunColumnHeader(Fun fun, FunCol *cols, int ncol)
+#else
+void _FunColumnHeader(fun, cols, ncol)
+ Fun fun;
+ FunCol *cols;
+ int ncol;
+#endif
+{
+ int i, j, k;
+ int width;
+ int acol;
+
+ char tbuf[SZ_LINE];
+ char *extname="EVENTS";
+ int extver = 1;
+ FITSHead old, merge;
+ FITSCard card;
+
+ /* make sure we have something to work with */
+ if( !_FunValid(fun) )
+ return;
+
+ /* create a fitsy header, if necessary */
+ if( !fun->header ){
+ if( (fun->header = ft_headinit(NULL, 0)) == NULL )
+ return;
+ }
+
+ /* get width of each row */
+ for(acol=0, width=0, i=0; i<ncol; i++){
+ if( (cols[i]->mode & COL_ACTIVE) &&
+ (cols[i]->mode & COL_WRITE) &&
+ !(cols[i]->mode & COL_REPLACEME) ){
+ width += cols[i]->width;
+ acol++;
+ }
+ }
+
+ /* if there is an input table, look for a name */
+ if( fun->ifun && fun->ifun->header && fun->ifun->header->basic ){
+ if( ft_name(fun->ifun->header) && *ft_name(fun->ifun->header) )
+ extname = ft_name(fun->ifun->header);
+ extver = MAX(1, ft_extn(fun->ifun->header));
+ }
+
+ /* fill in the header to this binary table */
+ ft_headsets(fun->header, "XTENSION", 0, "BINTABLE", "FITS BINARY TABLE", 1);
+ ft_headseti(fun->header, "BITPIX", 0, 8, "Binary data", 1);
+ ft_headseti(fun->header, "NAXIS", 0, 2, "Table is a matrix", 1);
+ ft_headseti(fun->header, "NAXIS", 1, width, "Width of table in bytes", 1);
+ ft_headseti(fun->header, "NAXIS", 2, -1, "Number of entries in table", 1);
+ ft_headseti(fun->header, "PCOUNT", 0, 0, "Random parameter count", 1);
+ ft_headseti(fun->header, "GCOUNT", 0, 1, "Group count", 1);
+ ft_headseti(fun->header, "TFIELDS", 0, acol, "Number of fields in row", 1);
+ if( !ft_headfind(fun->header, "EXTNAME", 0, 0) )
+ ft_headsets(fun->header, "EXTNAME", 0, extname, "Ext. name", 1);
+ if( !ft_headfind(fun->header, "EXTVER", 0, 0) )
+ ft_headseti(fun->header, "EXTVER", 0, extver, "Ext. version", 1);
+
+
+ /* now add the info for each active column */
+ for(i=0, j=1; i<ncol; i++){
+ if( !(cols[i]->mode & COL_ACTIVE) ||
+ !(cols[i]->mode & COL_WRITE) ||
+ (cols[i]->mode & COL_REPLACEME) )
+ continue;
+ if( cols[i]->vla ){
+ ft_headsets(fun->header, "TFORM", j, cols[i]->vla,
+ "Data type for field", 1);
+ }
+ else{
+ snprintf(tbuf, SZ_LINE-1, "%d%c", cols[i]->n, toupper(cols[i]->type));
+ ft_headsets(fun->header, "TFORM", j, tbuf, "Data type for field", 1);
+ }
+ /* name of column */
+ if( fun->cols[i]->name ){
+ /* we change "$region" to "region" */
+ if( !strcasecmp(cols[i]->name, COL_REGION_NAME) ){
+ /* best to use "region", if its not already used */
+ if( !FunColumnLookup(fun, COL_REGION_ONAME, 0,
+ NULL, NULL, NULL, NULL, NULL, NULL) )
+ ft_headsets(fun->header,
+ "TTYPE", j, COL_REGION_ONAME, "Label for field", 1);
+ /* otherwise use region[n], using the first free value for n */
+ else{
+ for(k=1; ; k++){
+ snprintf(tbuf, SZ_LINE-1, "%s%d", COL_REGION_ONAME, k);
+ if( !FunColumnLookup(fun, tbuf, 0,
+ NULL, NULL, NULL, NULL, NULL, NULL) ){
+ ft_headsets(fun->header, "TTYPE", j, tbuf, "Label for field", 1);
+ break;
+ }
+ }
+ }
+ }
+ /* might have to change "$n" to something else */
+ else if( !strcasecmp(cols[i]->name, COL_NUM_NAME) ){
+ /* best to use "n", if its not already used */
+ if( !FunColumnLookup(fun, COL_NUM_ONAME, 0,
+ NULL, NULL, NULL, NULL, NULL, NULL) )
+ ft_headsets(fun->header,
+ "TTYPE", j, COL_NUM_ONAME, "Label for field", 1);
+ /* otherwise use n[n], using the first free value for n */
+ else{
+ for(k=1; ; k++){
+ snprintf(tbuf, SZ_LINE-1, "%s%d", COL_NUM_ONAME, k);
+ if( !FunColumnLookup(fun, tbuf, 0,
+ NULL, NULL, NULL, NULL, NULL, NULL) ){
+ ft_headsets(fun->header, "TTYPE", j, tbuf, "Label for field", 1);
+ break;
+ }
+ }
+ }
+ }
+ /* not a special name, just use as is */
+ else{
+ ft_headsets(fun->header,
+ "TTYPE", j, cols[i]->name, "Label for field", 1);
+ }
+ }
+ /* write out tlmin/tlmax values if either is set */
+ if( cols[i]->tlmin || cols[i]->tlmax ){
+ /* match data type of number to data type of column */
+ switch(cols[i]->type){
+ case 'D':
+ case 'E':
+ if( !ft_headfind(fun->header, "TLMIN", j, 0) )
+ ft_headsetr(fun->header, "TLMIN", j, cols[i]->tlmin, 7,
+ "Min. axis value", 1);
+ if( !ft_headfind(fun->header, "TLMAX", j, 0) )
+ ft_headsetr(fun->header, "TLMAX", j, cols[i]->tlmax, 7,
+ "Max. axis value", 1);
+ if( cols[i]->binsiz != 0.0 ){
+ if( !ft_headfind(fun->header, "TDBIN", j, 0) )
+ ft_headsetr(fun->header, "TDBIN", j, cols[i]->binsiz, 7,
+ "Binsize", 1);
+ }
+ break;
+ default:
+ if( !ft_headfind(fun->header, "TLMIN", j, 0) )
+ ft_headseti(fun->header, "TLMIN", j, (int)cols[i]->tlmin,
+ "Min. axis value", 1);
+ if( !ft_headfind(fun->header, "TLMAX", j, 0) )
+ ft_headseti(fun->header, "TLMAX", j, (int)cols[i]->tlmax,
+ "Max. axis value", 1);
+ if( cols[i]->binsiz != 0.0 ){
+ if( !ft_headfind(fun->header, "TDBIN", j, 0) )
+ ft_headsetr(fun->header, "TDBIN", j, cols[i]->binsiz, 7,
+ "Binsize", 1);
+ }
+ break;
+ }
+ }
+ /* add wcs info */
+ if( cols[i]->tctyp && !ft_headfind(fun->header, "TCTYP", j, 0))
+ ft_headsets(fun->header,
+ "TCTYP", j, cols[i]->tctyp, "axis type (e.g. RA---TAN)", 1);
+ if( cols[i]->tcrvl && !ft_headfind(fun->header, "TCRVL", j, 0))
+ ft_headappv(fun->header,
+ "TCRVL", j, cols[i]->tcrvl, "sky coord (deg.)");
+ if( cols[i]->tcdlt && !ft_headfind(fun->header, "TCDLT", j, 0))
+ ft_headappv(fun->header,
+ "TCDLT", j, cols[i]->tcdlt, "degrees per pixel");
+ if( cols[i]->tcrpx && !ft_headfind(fun->header, "TCRPX", j, 0))
+ ft_headappv(fun->header,
+ "TCRPX", j, cols[i]->tcrpx, "pixel of tangent plane direc.");
+ if( cols[i]->tcrot && !ft_headfind(fun->header, "TCROT", j, 0))
+ ft_headappv(fun->header,
+ "TCROT", j, cols[i]->tcrot, "rotation angle (degrees)");
+ if( cols[i]->tunit && !ft_headfind(fun->header, "TUNIT", j, 0))
+ ft_headsets(fun->header,
+ "TUNIT", j, cols[i]->tunit, "axis units", 1);
+ if( cols[i]->tblank && !ft_headfind(fun->header, "TNULL", j, 0))
+ ft_headsetr(fun->header, "TNULL", j, (double)cols[i]->tblank, 7,
+ "undefined value", 1);
+ if( cols[i]->scaled & FUN_SCALE_APPLIED ){
+ if( ft_headfind(fun->header, "TZERO", j, 0) )
+ ft_headdel(fun->header, "TZERO", j);
+ if( ft_headfind(fun->header, "TSCAL", j, 0) )
+ ft_headdel(fun->header, "TSCAL", j);
+ }
+ else if( cols[i]->scaled & FUN_SCALE_EXISTS ){
+ ft_headsetr(fun->header, "TZERO", j, cols[i]->tzero, 7,
+ "phys_val = tzero + tscale * field_val", 1);
+ ft_headsetr(fun->header, "TSCAL", j, cols[i]->tscale, 7,
+ "phys_val = tzero + tscale * field_val", 1);
+ }
+ j++;
+ }
+
+ /* now turn this into a table header */
+ ft_syncdata(fun->header);
+
+ /* merge in params from original header, if they exist */
+ if( fun->ifun && fun->ifun->header && fun->ifun->header->table ){
+ old = ft_headcopy(fun->ifun->header);
+ i = ft_headgeti(old, "TFIELDS", 0, 0, &card);
+ _FunCopyBinDelete(old, i);
+ /* merge, but don't overwrite new with old */
+ merge = ft_headmerge(fun->header, old, 0);
+ ft_headfree(old, 1);
+ ft_headfree(fun->header, 1);
+ fun->header = merge;
+ ft_syncdata(fun->header);
+ }
+
+ /* merge in user-specified params with overwrite */
+ merge = ft_headmerge(fun->header, fun->theader, 1);
+ ft_headfree(fun->theader, 1);
+ fun->theader = NULL;
+ ft_headfree(fun->header, 1);
+ fun->header = merge;
+ ft_syncdata(fun->header);
+}
+
+/*
+ *
+ * _FunColumnReplace -- replace values from one set of columns into another
+ *
+ */
+#ifdef ANSI_FUNC
+int
+_FunColumnReplace(Fun fund, char *d, Fun funs, char *s,
+ int convert, int direction, int n)
+#else
+int _FunColumnReplace(fund, d, funs, s, convert, direction, n)
+ Fun fund;
+ char *d;
+ Fun funs;
+ char *s;
+ int convert;
+ int direction;
+ int n;
+#endif
+{
+ int i, j;
+ int got = 0;
+ char *ss, *dd;
+
+ n = MAX(1,n);
+ while( n-- ){
+ for(i=0; i<funs->ncol; i++){
+ for(j=0; j<fund->ncol; j++){
+ if( !strcasecmp(funs->cols[i]->name, fund->cols[j]->name) ){
+ /* determine addresses for pointers or offsets */
+ if( !(funs->cols[i]->mode & COL_PTR) )
+ ss = s+funs->cols[i]->offset;
+ else
+ ss = *((char **)(((char *)s)+funs->cols[i]->offset));
+ ss += funs->cols[i]->poff;
+ if( !(fund->cols[j]->mode & COL_PTR) )
+ dd = d+fund->cols[j]->offset;
+ else
+ dd = *((char **)(((char *)d)+fund->cols[j]->offset));
+ dd += fund->cols[i]->poff;
+ /* convert dest to source type and replace */
+ ft_acht2(fund->cols[j]->offset, dd, funs->cols[i]->offset, ss,
+ MIN(funs->cols[i]->n,fund->cols[j]->n),
+ convert, direction);
+ got++;
+ break;
+ }
+ }
+ }
+ s += funs->rowsize;
+ d += fund->rowsize;
+ }
+ return got;
+}
+
+#ifdef ANSI_FUNC
+void
+_FunColumnFree(Fun fun)
+#else
+void _FunColumnFree(fun)
+ Fun fun;
+#endif
+{
+ int i;
+
+ if( !_FunValid(fun) )
+ return;
+ if( fun->cols ){
+ for(i=0; i<fun->ncol; i++){
+ if( fun->cols[i] ){
+ if( fun->cols[i]->name ) xfree(fun->cols[i]->name);
+ if( fun->cols[i]->tctyp ) xfree(fun->cols[i]->tctyp);
+ if( fun->cols[i]->tcrvl ) xfree(fun->cols[i]->tcrvl);
+ if( fun->cols[i]->tcdlt ) xfree(fun->cols[i]->tcdlt);
+ if( fun->cols[i]->tcrpx ) xfree(fun->cols[i]->tcrpx);
+ if( fun->cols[i]->tcrot ) xfree(fun->cols[i]->tcrot);
+ if( fun->cols[i]->tunit ) xfree(fun->cols[i]->tunit);
+ if( fun->cols[i]->vla ) xfree(fun->cols[i]->vla);
+ xfree(fun->cols[i]);
+ }
+ }
+ xfree(fun->cols);
+ fun->cols = NULL;
+ }
+ fun->ncol = 0;
+ fun->rowsize = 0;
+ fun->merge = 0;
+}
+
+/*
+ *
+ * public routines
+ *
+ */
+
+/*
+ *
+ * FunColumnActivate -- activate/de-activate a list of columns
+ *
+ */
+#ifdef ANSI_FUNC
+void
+FunColumnActivate(Fun fun, char *s, char *mode)
+#else
+void FunColumnActivate(fun, s, mode)
+ Fun fun;
+ char *s;
+ char *mode;
+#endif
+{
+ int i, j;
+ int xmode;
+ int dosort;
+ int matches;
+ int ip=0;
+ int ncol=0;
+ int imodes=0;
+ int emodes=0;
+ int amode=0;
+ int modes[FUN_MAXCOL];
+ char *names[FUN_MAXCOL];
+ char tbuf[SZ_LINE];
+ char tbuf2[SZ_LINE];
+ char *t;
+ char *mbuf;
+
+ /* sanity check */
+ if( !fun ) return;
+
+ /* if no columns on the commmand line ... */
+ if( !s ){
+ /* check for existence of previously specified view cols */
+ if( fun->vcols ){
+ s = fun->vcols;
+ }
+ /* or look for environment variable */
+ else{
+ s = getenv("FUN_COLUMNS");
+ }
+ }
+
+ /* sanity check */
+ if( !s || !*s ) return;
+
+ /* process mode string */
+ mbuf = xstrdup(mode);
+ if( _FunKeyword(mbuf, "sort", NULL, tbuf, SZ_LINE) )
+ dosort = istrue(tbuf);
+ else
+ dosort = -1;
+ if( _FunKeyword(mbuf, "mode", NULL, tbuf, SZ_LINE) )
+ amode = mparse(tbuf);
+ if( mbuf ) xfree(mbuf);
+
+ /* parse entries and create a list of names/modes */
+ while( word(s, tbuf, &ip) ){
+ if( _FunKeyword(tbuf, "sort", NULL, tbuf2, SZ_LINE) ){
+ dosort = istrue(tbuf2);
+ continue;
+ }
+ /* convert to upper case */
+ t = tbuf;
+ /* set activate mode and get name without prefix */
+ if( *tbuf == '-' ){
+ t++;
+ xmode = 0;
+ }
+ else if( *tbuf == '+' ){
+ t++;
+ xmode = 1;
+ }
+ else
+ xmode = 1;
+ if( xmode )
+ imodes++;
+ else
+ emodes++;
+ /* look up aliases for this name */
+ _FunGetAlias(fun, t, tbuf2);
+ /* save this entry */
+ names[ncol] = xstrdup(tbuf2);
+ modes[ncol] = xmode;
+ ncol++;
+ }
+
+ /* loop through the (possible) list */
+ for(; fun != NULL; fun=fun->next){
+ if( !_FunValid(fun) )
+ return;
+
+ /* if we delayed the open for reading before, we have to open now */
+ if( !fun->header && strchr(fun->mode, 'r') )
+ _FunFITSOpen(fun, fun->fname, "r");
+
+ /* if we have no columns yet, try to get some from the assoc. input file */
+ if( !fun->ncol ){
+ /* if we have a header to copy from, that is */
+ if( fun->ifun && fun->ifun->header && fun->ifun->header->table ){
+ FunColumnSelect(fun, 0, "copy=select", NULL);
+ /* grab the copied merge value as well */
+ fun->merge = fun->ifun->merge;
+ }
+ /* else we lose */
+ else
+ return;
+ }
+
+ /* save activation string */
+ if( fun->activate ) xfree(fun->activate );
+ fun->activate = xstrdup(s);
+
+ /* handle the case of setting the mode specially */
+ if( amode ) goto doamode;
+
+ /* if we have excludes, activate all to start with */
+ if( emodes && !imodes ){
+ for(i=0; i<fun->ncol; i++){
+ if( !fun->cols[i]->name ) continue;
+ /* all except the special columns, that is! */
+ if( strcasecmp(fun->cols[i]->name, COL_REGION_NAME) &&
+ strcasecmp(fun->cols[i]->name, COL_NUM_NAME) )
+ fun->cols[i]->mode |= COL_ACTIVE;
+ }
+ }
+ /* otherwise, we de-activate all to start with */
+ else if( imodes ){
+ if( dosort < 0 )
+ dosort = 1;
+ for(i=0; i<fun->ncol; i++){
+ fun->cols[i]->mode &= ~COL_ACTIVE;
+ fun->cols[i]->order = 0;
+ }
+ }
+
+ /* process entries */
+ for(j=0; j<ncol; j++){
+ /* "+" means activate all, "-" means de-activate all,
+ (nb: we removed the +/i earlier, leaving no name) */
+ if( !*names[j] ){
+ for(i=0; i<fun->ncol; i++){
+ if( modes[j] ){
+ if( !fun->cols[i]->name ) continue;
+ /* all except the special columns, that is! */
+ if( strcasecmp(fun->cols[i]->name, COL_REGION_NAME) &&
+ strcasecmp(fun->cols[i]->name, COL_NUM_NAME) )
+ fun->cols[i]->mode |= COL_ACTIVE;
+ }
+ else{
+ fun->cols[i]->mode &= ~COL_ACTIVE;
+ fun->cols[i]->order = 0;
+ }
+ }
+ continue;
+ }
+ /* look for corresponding selected column and set status */
+ for(matches=0, i=0; i<fun->ncol; i++){
+ if( !fun->cols[i]->name ) continue;
+ if( !strcasecmp(fun->cols[i]->name, names[j]) ||
+ tmatch(fun->cols[i]->name, names[j]) ){
+ matches++;
+ if( modes[j] ){
+ fun->cols[i]->mode |= COL_ACTIVE;
+ if( dosort == 1 )
+ fun->cols[i]->order = ncol-j;
+ }
+ else{
+ fun->cols[i]->mode &= ~COL_ACTIVE;
+ }
+ }
+ }
+ /* can't activate a non-existent column, but ok to de-activate one */
+ if( !matches && modes[j] ){
+ gerror(stderr, "no column named '%s' in table\n", names[j]);
+ return;
+ }
+ }
+
+ /* re-sort, if necessary */
+ if( dosort == 1 ){
+ /* save current indexes to adjust the 'from' value after sorting */
+ for(i=0; i<fun->ncol; i++)
+ fun->cols[i]->ofrom = i;
+ /* sort the column records */
+ qsort(fun->cols, fun->ncol, sizeof(FunCol), _FunColCmp);
+ /* fix up the 'from' indices to reflect the new indexes */
+ for(i=0; i<fun->ncol; i++){
+ /* if 'from' is not 'self' ... */
+ if( fun->cols[i]->from >=0 ){
+ /* look through al columns ... */
+ for(j=0; j<fun->ncol; j++){
+ /* ... for the original index */
+ if( fun->cols[i]->from == fun->cols[j]->ofrom ){
+ /* reset the 'from' value to the new index of this column */
+ fun->cols[i]->from = j;
+ break;
+ }
+ }
+ }
+ }
+ }
+ continue;
+
+/* special code to activate and change access mode */
+doamode:
+ for(j=0; j<ncol; j++){
+ /* "+" means activate all, "-" means de-activate all,
+ (nb: we removed the +/i earlier, leaving no name) */
+ if( *names[j] ){
+ /* look for corresponding selected column and set status */
+ for(matches=0, i=0; i<fun->ncol; i++){
+ if( !fun->cols[i]->name ) continue;
+ if( !strcasecmp(fun->cols[i]->name, names[j]) ||
+ tmatch(fun->cols[i]->name, names[j]) ){
+ /* set the new mode */
+ fun->cols[i]->mode = amode;
+ if( modes[j] ){
+ fun->cols[i]->mode |= COL_ACTIVE;
+ }
+ else{
+ fun->cols[i]->mode &= ~COL_ACTIVE;
+ }
+ }
+ }
+ }
+ }
+ continue;
+ }
+
+ /* clean up */
+ for(j=0; j<ncol; j++){
+ /* done with this one */
+ if( names[j] ) xfree(names[j]);
+ }
+}
+
+/*
+ *
+ * FunColumnSelectArr -- non-varargs add columns to the selected column list
+ *
+ */
+#ifdef ANSI_FUNC
+int
+FunColumnSelectArr(Fun fun, size_t size, char *mode,
+ char **names, char **types,
+ char **modes, int *offsets, int nargs)
+#else
+int FunColumnSelectArr(fun, size, mode, names, types, modes, offsets, nargs)
+ Fun fun;
+ size_t size;
+ char *mode;
+ char **names;
+ char **types;
+ char **modes;
+ int *offsets;
+ int nargs;
+#endif
+{
+ int got, goterr;
+ int domerge;
+ size_t tsize;
+ char *mbuf;
+ char *activate;
+ char tbuf[SZ_LINE];
+ FITSHead header;
+
+ /* start out with no error */
+ goterr = 0;
+
+ /* how many args have we got? */
+ got = nargs;
+
+ /* look at keywords */
+ mbuf = xstrdup(mode);
+ if( _FunKeyword(mbuf, "merge", NULL, tbuf, SZ_LINE) ){
+ if( !strncasecmp(tbuf, "replace", 7) )
+ domerge = MERGE_REPLACE;
+ else if( !strncasecmp(tbuf, "append", 6) )
+ domerge = MERGE_APPEND;
+ else if( !strncasecmp(tbuf, "update", 6) )
+ domerge = MERGE_UPDATE;
+ else if( istrue(tbuf) )
+ domerge = MERGE_UPDATE;
+ else
+ domerge = 0;
+ }
+ else
+ domerge = 0;
+ if( mbuf ) xfree(mbuf);
+
+ /* loop through the (possible) list */
+ for(; fun != NULL; fun=fun->next){
+ /* make sure we have something */
+ if( !_FunValid(fun) ){
+ goterr = 1;
+ goto done;
+ }
+
+ /* if we delayed the open for reading before, we have to open now */
+ if( !fun->header && strchr(fun->mode, 'r') )
+ _FunFITSOpen(fun, fun->fname, "r");
+
+ /* free previous -- this is a new start */
+ _FunColumnFree(fun);
+ /* allocate space for these new columns */
+ if( !(fun->cols = (FunCol *)xcalloc(FUN_MAXCOL, sizeof(FunCol))) ){
+ gerror(stderr, "can't allocate FunCol array\n");
+ goterr = 1;
+ goto done;
+ }
+
+ /* if merging, we need to set up the raw input columns for writing */
+ if( (fun->merge=domerge) != 0 ){
+ if( fun->header && fun->header->table ){
+ header = fun->header;
+ activate = NULL;
+ }
+ /* if not, we can use the input fun handle's table */
+ else if( fun->ifun && fun->ifun->header && fun->ifun->header->table ){
+ header = fun->ifun->header;
+ activate = fun->ifun->activate;
+ }
+ /* else die */
+ else{
+ goterr = 1;
+ goto done;
+ }
+ /* set flag for writing, also flag this as input data, not user data */
+ tsize=0;
+ if( !_FunColumnAddTable(fun, header, "iw", 0, &(fun->ncol), &tsize) ){
+ goterr = 1;
+ goto done;
+ }
+ /* if we are copying raw columns from a reference file,
+ we have to call the reference activate routine */
+ if( activate ) FunColumnActivate(fun, activate, NULL);
+ }
+
+ /* we can't have no columns and no mode */
+ if( !got && !mode ){
+ gerror(stderr, "FunColumnSelect requires valid column(s) or mode\n");
+ goterr = 1;
+ goto done;
+ }
+
+ /* add columns (or add default columns if none were specified) */
+ _FunColumnSelect(fun, size, mode, names, types, modes, offsets, got);
+ }
+
+done:
+ /* return the news */
+ if( goterr )
+ got = 0;
+ return got;
+}
+
+/*
+ *
+ * FunColumnSelect -- select columns for extraction
+ *
+ */
+#ifdef __STDC__
+int FunColumnSelect(Fun fun, size_t size, char *mode, ...)
+{
+ int i;
+ int got, got2;
+ char *s;
+ char *names[FUN_MAXCOL];
+ char *types[FUN_MAXCOL];
+ char *modes[FUN_MAXCOL];
+ int offsets[FUN_MAXCOL];
+ va_list args;
+ va_start(args, mode);
+#else
+int FunColumnSelect(va_alist) va_dcl
+{
+ Fun fun;
+ size_t size;
+ int i;
+ int got, got2;
+ char *s;
+ char *mode;
+ char *names[FUN_MAXCOL];
+ char *types[FUN_MAXCOL];
+ char *modes[FUN_MAXCOL];
+ int offsets[FUN_MAXCOL];
+ va_list args;
+ va_start(args);
+ fun = va_arg(args, Fun);
+ size = va_arg(args, size_t);
+ mode = va_arg(args, char *);
+#endif
+
+ /* collect variable arguments */
+ for(got=0; (s=va_arg(args, char *)) && *s && (got<FUN_MAXCOL); got++ ){
+ names[got] = xstrdup(s);
+ s = va_arg(args, char *);
+ types[got] = xstrdup(s);
+ s = va_arg(args, char *);
+ modes[got] = xstrdup(s);
+ offsets[got] = va_arg(args, int);
+ }
+
+ /* call non-varargs version */
+ got2=FunColumnSelectArr(fun, size, mode, names, types, modes, offsets, got);
+
+ /* clean up */
+ for(i=0; i<got; i++){
+ if( names[i] ) xfree(names[i]);
+ if( types[i] ) xfree(types[i]);
+ if( modes[i] ) xfree(modes[i]);
+ }
+
+ /* return the news */
+ return got2;
+}
+
+#ifdef ANSI_FUNC
+int
+FunColumnLookup(Fun fun, char *s, int which, char **name,
+ int *type, int *mode, int *offset, int *n, int *width)
+#else
+int FunColumnLookup(fun, s, which, name, type, mode, offset, n, width)
+ Fun fun;
+ char *s;
+ int which;
+ char **name;
+ int *type;
+ int *mode;
+ int *offset;
+ int *n;
+ int *width;
+#endif
+{
+ int i;
+ int got = 0;
+
+ /* make sure we have something */
+ if( !_FunValid(fun) )
+ return 0;
+
+ /* if we delayed the open for reading before, we have to open now */
+ if( !fun->header && strchr(fun->mode, 'r') )
+ _FunFITSOpen(fun, fun->fname, "r");
+
+ /* if we were passed a string, use that as the name for the lookup */
+ if( s ){
+ for(i=0; i<fun->ncol; i++){
+ if( !fun->cols[i]->name ) continue;
+ if( !strcasecmp(s, fun->cols[i]->name) ){
+ got = i+1;
+ break;
+ }
+ }
+ }
+ /* otherwise, we got the zero-based index to lookup */
+ else
+ got = which+1;
+
+ /* if we have something to look up, do it */
+ if( got ){
+ i = got - 1;
+ if( name ) *name = fun->cols[i]->name;
+ if( type ) *type = fun->cols[i]->type;
+ if( mode ) *mode = fun->cols[i]->mode;
+ if( offset ) *offset = fun->cols[i]->offset;
+ if( n ) *n = fun->cols[i]->n;
+ if( width ) *width = fun->cols[i]->width;
+ }
+ return got;
+}
+
+#ifdef ANSI_FUNC
+int
+FunColumnLookup2(Fun fun, char *s, int which, double *tlmin, double *tlmax,
+ double *binsize, double *tscale, double *tzero)
+#else
+int FunColumnLookup2(fun, s, which, tlmin, tlmax, binsize, tscale, tzero)
+ Fun fun;
+ char *s;
+ int which;
+ double *tlmin;
+ double *tlmax;
+ double *binsize;
+ double *tscale;
+ double *tzero;
+#endif
+{
+ int i;
+ int got = 0;
+
+ /* make sure we have something */
+ if( !_FunValid(fun) )
+ return 0;
+
+ /* if we delayed the open for reading before, we have to open now */
+ if( !fun->header && strchr(fun->mode, 'r') )
+ _FunFITSOpen(fun, fun->fname, "r");
+
+ /* if we were passed a string, use that as the name for the lookup */
+ if( s ){
+ for(i=0; i<fun->ncol; i++){
+ if( !fun->cols[i]->name ) continue;
+ if( !strcasecmp(s, fun->cols[i]->name) ){
+ got = i+1;
+ break;
+ }
+ }
+ }
+ /* otherwise, we got the zero-based index to lookup */
+ else
+ got = which+1;
+
+ /* if we have something to look up, do it */
+ if( got ){
+ i = got - 1;
+ if( tlmin ) *tlmin = fun->cols[i]->tlmin;
+ if( tlmax ) *tlmax = fun->cols[i]->tlmax;
+ if( binsize ) *binsize = fun->cols[i]->binsiz;
+ if( tscale ) *tscale = fun->cols[i]->tscale;
+ if( tzero ) *tzero = fun->cols[i]->tzero;
+ }
+ return got;
+}
+