/* * Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory */ #include /* * * 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; (itable->tfields) && (*gottable->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; (nargcols[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; itable->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; gotifun->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; imode & 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; imode & 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; incol; i++){ for(j=0; jncol; 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; incol; 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; incol; 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; incol; i++){ fun->cols[i]->mode &= ~COL_ACTIVE; fun->cols[i]->order = 0; } } /* process entries */ for(j=0; jncol; 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; incol; 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; incol; 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; incol; i++){ /* if 'from' is not 'self' ... */ if( fun->cols[i]->from >=0 ){ /* look through al columns ... */ for(j=0; jncol; 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; jncol; 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; jnext){ /* 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 && (gotheader && 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; incol; 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; incol; 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; }