diff options
Diffstat (limited to 'ast/fitstable.c')
-rw-r--r-- | ast/fitstable.c | 3006 |
1 files changed, 3006 insertions, 0 deletions
diff --git a/ast/fitstable.c b/ast/fitstable.c new file mode 100644 index 0000000..148431c --- /dev/null +++ b/ast/fitstable.c @@ -0,0 +1,3006 @@ +/* +*class++ +* Name: +* FitsTable + +* Purpose: +* A representation of a FITS binary table. + +* Constructor Function: +c astFitsTable +f AST_FITSTABLE + +* Description: +* The FitsTable class is a representation of a FITS binary table. It +* inherits from the Table class. The parent Table is used to hold the +* binary data of the main table, and a FitsChan (encapsulated within +* the FitsTable) is used to hold the FITS header. +* +* Note - it is not recommended to use the FitsTable class to store +* very large tables. +* +* FitsTables are primarily geared towards the needs of the "-TAB" +* algorithm defined in FITS-WCS paper 2, and so do not support all +* features of FITS binary tables. In particularly, they do not +* provide any equivalent to the following features of FITS binary +* tables: "heap" data (i.e. binary data following the main table), +* columns holding complex values, columns holding variable length +* arrays, scaled columns, column formats, columns holding bit values, +* 8-byte integer values or logical values. + +* Inheritance: +* The FitsTable class inherits from the Table class. + +* Attributes: +* The FitsTable class does not define any new attributes beyond +* those which are applicable to all Tables. + +* Functions: +c In addition to those functions applicable to all Tables, the +c following functions may also be applied to all FitsTables: +f In addition to those routines applicable to all Tables, the +f following routines may also be applied to all FitsTables: +* +c - astColumnNull: Get/set the null value for a column of a FitsTable +c - astColumnSize: Get number of bytes needed to hold a full column of data +c - astGetColumnData: Retrieve all the data values stored in a column +c - astGetTableHeader: Get the FITS headers from a FitsTable +c - astPutColumnData: Store data values in a column +c - astPutTableHeader: Store FITS headers within a FitsTable +f - AST_COLUMNNULL: Get/set the null value for a column of a FitsTable +f - AST_COLUMNSIZE: Get number of bytes needed to hold a full column of data +f - AST_GETCOLUMNDATA: Retrieve all the data values stored in a column +f - AST_GETTABLEHEADER: Get the FITS headers from a FitsTable +f - AST_PUTCOLUMNDATA: Store data values in a column +f - AST_PUTTABLEHEADER: Store FITS headers within a FitsTable + +* Copyright: +* Copyright (C) 2010 Science & Technology Facilities Council. +* All Rights Reserved. + +* Licence: +* This program is free software: you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation, either +* version 3 of the License, or (at your option) any later +* version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General +* License along with this program. If not, see +* <http://www.gnu.org/licenses/>. + +* Authors: +* DSB: David S. Berry (Starlink) + +* History: +* 25-NOV-2010 (DSB): +* Original version. +* 2-OCT-2012 (DSB): +* Check for Infs as well as NaNs. +*class-- +*/ + +/* Module Macros. */ +/* ============== */ +/* Set the name of the class we are implementing. This indicates to + the header files that define class interfaces that they should make + "protected" symbols available. */ +#define astCLASS FitsTable + +/* The KeyMap key use to store the null value for a column. */ +#define NULLKEY "Null" + +/* Include files. */ +/* ============== */ +/* Interface definitions. */ +/* ---------------------- */ + +#include "globals.h" /* Thread-safe global data access */ +#include "error.h" /* Error reporting facilities */ +#include "memory.h" /* Memory allocation facilities */ +#include "object.h" /* Base Object class */ +#include "table.h" /* Tables (parent class) */ +#include "channel.h" /* I/O channels */ +#include "pointset.h" /* For astCheckNaN(F) functions */ +#include "fitstable.h" /* Interface definition for this class */ + + +/* Error code definitions. */ +/* ----------------------- */ +#include "ast_err.h" /* AST error codes */ + +/* C header files. */ +/* --------------- */ +#include <limits.h> +#include <stdio.h> +#include <string.h> + + +/* Module Variables. */ +/* ================= */ + +/* Address of this static variable is used as a unique identifier for + member of this class. */ +static int class_check; + +/* Pointers to parent class methods which are extended by this class. */ +static int (* parent_equal)( AstObject *, AstObject *, int * ); +static int (* parent_getobjsize)( AstObject *, int * ); +static void (* parent_addcolumn)( AstTable *, const char *, int, int, int *, const char *, int * ); + +#if defined(THREAD_SAFE) +static int (* parent_managelock)( AstObject *, int, int, AstObject **, int * ); +#endif + + +/* Define macros for accessing each item of thread specific global data. */ +#ifdef THREAD_SAFE + +/* Define how to initialise thread-specific globals. */ +#define GLOBAL_inits \ + globals->Class_Init = 0; + +/* Create the function that initialises global data for this module. */ +astMAKE_INITGLOBALS(FitsTable) + +/* Define macros for accessing each item of thread specific global data. */ +#define class_init astGLOBAL(FitsTable,Class_Init) +#define class_vtab astGLOBAL(FitsTable,Class_Vtab) + + +/* If thread safety is not needed, declare and initialise globals at static + variables. */ +#else + +/* Define the class virtual function table and its initialisation flag + as static variables. */ +static AstFitsTableVtab class_vtab; /* Virtual function table */ +static int class_init = 0; /* Virtual function table initialised? */ + +#endif + +/* External Interface Function Prototypes. */ +/* ======================================= */ +/* The following functions have public prototypes only (i.e. no + protected prototypes), so we must provide local prototypes for use + within this module. */ +AstFitsTable *astFitsTableId_( void *, const char *, ... ); + +/* Prototypes for Private Member Functions. */ +/* ======================================== */ +static AstFitsChan *GetTableHeader( AstFitsTable *, int * ); +static char *MakeKey( const char *, int, char *, int, int * ); +static int ColumnNull( AstFitsTable *, const char *, int, int, int *, int *, int * ); +static int Equal( AstObject *, AstObject *, int * ); +static int GetObjSize( AstObject *, int * ); +static size_t ColumnSize( AstFitsTable *, const char *, int * ); +static void AddColumn( AstTable *, const char *, int, int, int *, const char *, int * ); +static void Copy( const AstObject *, AstObject *, int * ); +static void CopyStrings( int, size_t, const char *, char *, int * ); +static void Delete( AstObject *, int * ); +static void Dump( AstObject *, AstChannel *, int * ); +static void GenerateColumns( AstFitsTable *, AstFitsChan *, int * ); +static void GetColumnData( AstFitsTable *, const char *, float, double, size_t, void *, int *, int * ); +static void PurgeHeader( AstFitsTable *, int * ); +static void PutColumnData( AstFitsTable *, const char *, int, size_t, void *, int * ); +static void PutTableHeader( AstFitsTable *, AstFitsChan *, int * ); +static void UpdateHeader( AstFitsTable *, const char *, int * ); + +#if defined(THREAD_SAFE) +static int ManageLock( AstObject *, int, int, AstObject **, int * ); +#endif + +/* Member functions. */ +/* ================= */ + +static void AddColumn( AstTable *this, const char *name, int type, + int ndim, int *dims, const char *unit, int *status ) { +/* +* Name: +* AddColumn + +* Purpose: +* Add a new column definition to a FitsTable. + +* Type: +* Private function. + +* Synopsis: +* #include "table.h" +* void AddColumn( AstTable *this, const char *name, int type, int ndim, +* int *dims, const char *unit, int *status ) + +* Class Membership: +* FitsTable member function (over-rides the astAddColumn method +* inherited from the Table class). + +* Description: +* Adds the definition of a new column to the supplied table. Initially, +* the column contains a null value for every row. Values may be added +* subsequently using the methods of the KeyMap class. +* +* The FitsTable class extend the method inherited from the parent +* Table class in order to prevent the addition of columns with properties +* not supported by FITS binary tables. + +* Parameters: +* this +* Pointer to the Table. +* name +* The column name. Trailing spaces are ignored (all other spaces +* are significant). The supplied string is converted to upper case. +* type +* The data type associated with the column. One of AST__INTTYPE +* (for integer), AST__SINTTYPE (for short int), AST__BYTETYPE (for +* unsigned bytes - i.e. unsigned chars), AST__DOUBLETYPE (for double +* precision floating point), AST__FLOATTYPE (for single precision +* floating point), AST__STRINGTYPE (for character string). Note, +* pointers and undefined values cannot be stored in a FitsTable +* column. +* ndim +* The number of dimensions spanned by the values stored in a single +* cell of the column. Zero if the column holds scalar values. +* dims +* An array holding the the lengths of each of the axes spanned by +* the values stored in a single cell of the column. Ignored if the +* column holds scalara values. +* unit +* A string specifying the units of the column. Supply a blank +* string if the column is unitless. +* status +* Pointer to the inherited status. + +* Notes: +* - This function returns without action if a column already exists in +* the Table with the supplied name and properties. However an error is +* reported if any of the properties differ. +*/ + +/* Local Variables: */ + const char *text; /* Data type string */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Report an error if the supplied data type is supported by the Table + class but not by the FitsTable class. */ + if( type == AST__OBJECTTYPE ) { + text = "Object pointer"; + + } else if( type == AST__POINTERTYPE ) { + text = "generic pointer"; + + } else if( type == AST__UNDEFTYPE ) { + text = "undefined type"; + + } else { + text = NULL; + } + + if( text ) { + astError( AST__NAXIN, "astAddColumn(%s): Bad data type (%s) supplied " + "for new column %s. The %s class does not support %s " + "columns.", status, astGetClass( this ), text, name, + astGetClass( this ), text ); + +/* Otherwise, invoke the parent method to add the column. */ + } else { + (*parent_addcolumn)( this, name, type, ndim, dims, unit, status ); + } +} + +static int ColumnNull( AstFitsTable *this, const char *column, int set, + int newval, int *wasset, int *hasnull, int *status ){ +/* +*++ +* Name: +c astColumnNull +f AST_COLUMNNULL + +* Purpose: +* Get or set the null value for an integer column of a FITS table. + +* Type: +* Public virtual function. + +* Synopsis: +c #include "table.h" +c int astColumnNull( AstFitsTable *this, const char *column, int set, +c int newval, int *wasset, int *hasnull ) +f RESULT = AST_COLUMNNULL( THIS, COLUMN, SET, NEWVAL, WASSET, HASNULL, +f STATUS ) + +* Class Membership: +* FitsTable method. + +* Description: +* This function allows a null value to be stored with a named +* integer-valued column in a FitsTable. The supplied null value is +* assigned to the TNULLn keyword in the FITS header associated with +* the FitsTable. A value in the named column is then considered to be +* null if 1) it equals the null value supplied to this function, or +* 2) no value has yet been stored in the cell. +* +* As well as setting a new null value, this function also returns the +* previous null value. If no null value has been set previously, a +* default value will be returned. This default will be an integer +* value that does not currently occur anywhere within the named column. +* If no such value can be found, what happens depends on whether the +* column contains any cells in which no values have yet been stored. +* If so, an error will be reported. Otherwise (i.e. if there are no +* null values in the column), an arbitrary value of zero will be +* returned as the function value, and no TNULLn keyword will be +* stored in the FITS header. +* +* A flag is returned indicating if the returned null value was set +* explicitly by a previous call to this function, or is a default +* value. +* +* A second flag is returned indicating if the named column contains +* any null values (i.e. values equal to the supplied null value, or +* cells to which no value has yet been assigned). + +* Parameters: +c this +f THIS = INTEGER (Given) +* Pointer to the Table. +c column +f COLUMN = CHARACTER * ( * ) (Given) +* The character string holding the name of the column. Trailing +* spaces are ignored. +c set +f SET = LOGICAL (Given) +c If non-zero, the value supplied for parameter "newval" +f If .TRUE., the value supplied for argument NEWVAL +* will be stored as the current null value, replacing any value +* set by a previous call to this function. +c If zero, the value supplied for parameter "newval" +f If .FALSE., the value supplied for argument NEWVAL +* is ignored and the current null value is left unchanged. +c newval +f NEWVAL = INTEGER (Given) +* The new null value to use. Ignored if +c "set" is zero. +f SET is .FALSE. +* An error will be reported if the supplied value is outside the +* range of values that can be stored in the integer data type +* associated with the column. +c wasset +f WASSET = LOGICAL (Returned) +c Pointer to an int that will be returned non-zero +f .TRUE. will be returned +* if the returned null value was set previously via an +* earlier invocation of this function. +c Zero +f .FALSE. +* is returned otherwise. If the named column does not exist, or an +* error occurs, a value of +c zero is returned. +f .FALSE. is returned. +c hasnull +f HASNULL = LOGICAL (Returned) +c Pointer to an int that will be returned non-zero +f .TRUE. will be returned +* if and only if the named column currently contains any values +* equal to the null value on exit (i.e. +c "newval" if "set" is non-zero, +f NEWVAL if SET is .TRUE. +* or the returned function value otherwise), or contains any empty +* cells. If the named column does not exist, or an error occurs, a +* value of +c zero is returned. +f .FALSE. is returned. +c If a NULL pointer is supplied for "hasnull", no check on the +c presence of null values will be performed. +f STATUS = INTEGER (Given and Returned) +f The global status. + +* Returned Value: +c astColumnNull() +f AST_COLUMNNULL = INTEGER +* The null value that was in use on entry to this function. If a +* null value has been set by a previous invocation of this +* function, it will be returned. Otherwise, if +c "set" is non-zero, the supplied "newval" +f SET is .TRUE., the supplied NEWVAL +* value is returned. Otherwise, a default value is chosen (if +* possible) that does not currently occur in the named column. If +* all available values are in use in the column, an error is +* reported if and only if the column contains any empty cells. +* Otherwise, a value of zero is returned. A value of zero is also +* returned if the named column does not exist, or an error occurs. + +* Notes: +* - The FITS binary table definition allows only integer-valued +* columns to have an associated null value. This routine will return +* without action if the column is not integer-valued. + +*-- +*/ + +/* Local Variables: */ + AstKeyMap *col_km; /* KeyMap holding named column definition */ + AstKeyMap *cols; /* KeyMap holding all column definitions */ + char key[ AST__MXCOLKEYLEN + 1 ]; /* Current cell key string */ + int *cell; /* Pointer to array of cell values */ + int foundhi; /* Has an occurrence of "nullhi" been found yet? */ + int foundlo; /* Has an occurrence of "nulllo" been found yet? */ + int gotresult; /* Has a usable value been put into "result"? */ + int idim; /* Index of current axis in each column's value */ + int iel; /* Index of current element within cell value */ + int imax; /* Maximum storable value */ + int imin; /* Minimum storable value */ + int irow; /* Index of current row in table */ + int ndim; /* Number of axes in each column's value */ + int nel; /* Total number of values in each cell */ + int nrow; /* Number of rows in table */ + int null; /* The null value on exit */ + int nullfound; /* Has a null value been found in the column yet? */ + int nullhi; /* Higher candidate default null value */ + int nulllo; /* Lower candidate default null value */ + int result; /* Returned value */ + int type; /* Column data type */ + +/* Initialise */ + result = 0; + *wasset = 0; + if( hasnull ) *hasnull = 0; + +/* Check the global error status. */ + if ( !astOK ) return result; + +/* Store the max and min integer values that can be store din the column + data type. */ + type = astGetColumnType( this, column ); + if( type == AST__BYTETYPE ) { + imin = 0; + imax = UCHAR_MAX; + + } else if( type == AST__SINTTYPE ) { + imin = SHRT_MIN; + imax = SHRT_MAX; + + } else if( type == AST__INTTYPE ) { + imin = INT_MIN; + imax = INT_MAX; + + } else { + imax = 0; + imin = 0; + } + +/* Check the named column contains integer values of any length. */ + if( imax > imin ) { + +/* Get the KeyMap holding information about all columns. */ + cols = astColumnProps( this ); + +/* Get the KeyMap holding information about the named column. */ + if( astMapGet0A( cols, column, &col_km ) ) { + +/* If the column definition already includes a null value, put it into + "result". Also store the "*wasset" flag that indicates if the returned + null value is a default value or not. */ + *wasset = astMapGet0I( col_km, NULLKEY, &result ); + +/* If a new null value is to be established... */ + if( set ) { + +/* If there was no previously set null value, return the new null value + as the function value. */ + if( ! *wasset ) result = newval; + +/* Indicate we now know what the returned function value is. */ + gotresult = 1; + +/* Save the null value that will be in use when this function exits. */ + null = newval; + +/* Check the supplied value is in range. If so store it in the column + keymap. Otherwise report an error. */ + if( null >= imin && null <= imax ) { + astMapPut0I( col_km, NULLKEY, null, NULL ); + + } else if( astOK ) { + astError( AST__BADNULL, "astColumnNull(%s): Supplied null " + "value (%d) is outside the range of integers " + "that can be stored in column '%s'.", status, + astGetClass( this ), newval, column ); + } + +/* If no new null value was supplied, the null value on exit will be the + previously set value, if any. */ + } else { + null = result; + gotresult = *wasset; + } + +/* The rest is only needed if we need to find a default result value, or if + we need to check if there are any null values in the table. */ + if( !gotresult || hasnull ) { + +/* Get the total number of values in each cell of the column. */ + nel = astGetColumnLength( this, column ); + +/* Allocate memory to hold the values in a single cell of the column, + stored as ints. */ + cell = astMalloc( nel*sizeof( int ) ); + +/* No null values found yet. */ + nullfound = 0; + +/* On the first pass round the following loop, we search for occurrences + of the highest and lowest integer values allowed in the column. If no + such occurrences are found we use one or the other as the default null + value. If occurrences of both of these values are found, we change the + values and start the search again. */ + nullhi = imax; + nulllo = imin; + foundlo = 0; + foundhi = 0; + +/* Loop round all rows in the Table. */ + nrow = astGetNrow( this ); + for( irow = 1; irow <= nrow && astOK; irow++ ) { + +/* Format the cell name. */ + (void) MakeKey( column, irow, key, AST__MXCOLKEYLEN + 1, + status ); + +/* Attempt to get the values in the cell */ + if( astMapGet1I( this, key, nel, &nel, cell ) ) { + +/* Get the number of dimensions. */ + ndim = astGetColumnNdim( this, column ); + +/* If we know what the null value is on exit, check the cell for such null + values (but only if the caller want s to know). Skip this check after the + first null is found. */ + if( gotresult ) { + if( ! nullfound ) { + for( idim = 0; idim < ndim; idim++ ) { + if( cell[ idim ] == null ) { + nullfound = 1; + break; + } + } + } + +/* If we do not yet know what the returned value is, we try to find an + integer value within the allowed data range that is not currently used in + the column. For the moment, this is a no-brain algorithm that will + become untenable for large tables. Need to fix it when it is apparent + that it is causing a problem. */ + } else if( nulllo <= nullhi ) { + +/* See if the current cell contains any occurrences of either of the + two currently nominated null values. Is so, increment the matched + nominated null value, and start again at row 1. */ + for( iel = 0; iel < nel; iel++ ) { + + if( cell[ iel ] == nulllo ) { + foundlo = 1; + } else if( cell[ iel ] == nullhi ) { + foundhi = 1; + } + + if( foundlo && foundhi ) { + nullhi--; + nulllo++; + irow = 0; + foundlo = 0; + foundhi = 0; + continue; + } + + } + } + +/* If the column does not contain anything in the current cell, we know + there is at least one null value in the column, so store a non-zero value + in the returned flag. */ + } else { + nullfound = 1; + } + +/* If we now have a value for the result and know that there are nulls in + the column, we can leave the loop. */ + if( gotresult && nullfound ) break; + } + +/* Return the "null found" flag if required. */ + if( hasnull ) *hasnull = nullfound; + +/* If we have not yet stored the default null value to be returned as the + function value, do so now. If no unused value could be found, and + there are missing cells in the table, report an error. */ + if( !gotresult ) { + if( !foundhi ) { + result = nullhi; + + } else if( !foundlo ) { + result = nulllo; + + } else if( nullfound && astOK ) { + astError( AST__BADNULL, "astColumnNull(%s): Cannot find " + "an unused value to use as the null value in " + "column '%s'.", status, astGetClass( this ), + column ); + } + } + +/* Free resources */ + cell = astFree( cell ); + } + col_km = astAnnul( col_km ); + } + cols = astAnnul( cols ); + } + +/* Return null values if an error occurred. */ + if( !astOK ) { + result = 0; + *wasset = 0; + if( hasnull ) *hasnull = 0; + } + +/* Return the result. */ + return result; +} + +static size_t ColumnSize( AstFitsTable *this, const char *column, int *status ){ +/* +*++ +* Name: +c astColumnSize +f AST_COLUMNSIZE + +* Purpose: +* Get the number of bytes needed to hold a full column of data. + +* Type: +* Public virtual function. + +* Synopsis: +c #include "table.h" +c size_t astColumnSize( AstFitsTable *this, const char *column, +c int *hasnull ) +f RESULT = AST_COLUMNSIZE( THIS, COLUMN, STATUS ) + +* Class Membership: +* FitsTable method. + +* Description: +* This function returns the number of bytes of memory that must be +* allocated prior to retrieving the data from a column using +c astGetColumnData. +f AST_GETCOLUMNDATA. + +* Parameters: +c this +f THIS = INTEGER (Given) +* Pointer to the Table. +c column +f COLUMN = CHARACTER * ( * ) (Given) +* The character string holding the name of the column. Trailing +* spaces are ignored. +f STATUS = INTEGER (Given and Returned) +f The global status. + +* Returned Value: +c astColumnNull() +f AST_COLUMNNULL = INTEGER +* The number of bytes required to store the column data. + +* Notes: +* - An error will be reported if the named column does not exist in +* the FitsTable. +* - Zero will be returned as the function value in an error occurs. + +*-- +*/ + +/* Local Variables: */ + size_t result; /* Returned value */ + int type; /* Column data type */ + +/* Initialise */ + result = 0; + +/* Check the global error status. */ + if ( !astOK ) return result; + +/* Find the number of bytes needed to hold a single element of the value + in a column cell. */ + type = astGetColumnType( this, column ); + if( type == AST__INTTYPE ) { + result = sizeof( int ); + + } else if( type == AST__DOUBLETYPE ){ + result = sizeof( double ); + + } else if( type == AST__STRINGTYPE ){ + result = astGetColumnLenC( this, column )*sizeof( char ); + + } else if( type == AST__FLOATTYPE ){ + result = sizeof( float ); + + } else if( type == AST__SINTTYPE ){ + result = sizeof( short int ); + + } else if( type == AST__BYTETYPE ){ + result = sizeof( char ); + + } else if( astOK ) { + astError( AST__INTER, "astColumnSize(%s): Unsupported column type " + "%d (internal AST programming error).", status, + astGetClass( this ), type ); + } + +/* Multiply it by the number of elements per value. */ + result *= astGetColumnLength( this, column ); + +/* Multiply it by the number of values per column (i.e. the number of rows). */ + result *= astGetNrow( this ); + +/* Return zero if an error occurred. */ + if( !astOK ) result = 0; + +/* Return the result. */ + return result; +} + +static void CopyStrings( int nval, size_t nb, const char *cbuf, char *pout, + int *status ){ +/* +* Name: +* CopyStrings + +* Purpose: +* Remove terminating nulls from an array of fixed-length strings. + +* Type: +* Private function. + +* Synopsis: +* void CopyStrings( int nval, size_t nb, const char *cbuf, char *pout, +* int *status ) + +* Description: +* This function copies null terminated strings from "cbuf" to "pout", +* removing the terminating nulls in the process. Thus each output string +* is one character shorter than the corresponding input string. + +* Parameters: +* nval +* The number of strings to copy. +* nb +* The maximum length of each string, excluding trailing null. +* cbuf +* The input array holding "nval" adjacent strings, each occupying +* ( nb + 1 ) characters (the last one is the trailing null). +* pout +* The output array to which "nval" adjacent strings are written, +* each occupying ( nb ) characters (i.e. no trailing null). +* status +* Pointer to inherited status. + +*/ + +/* Local Variables: */ + int i; + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Copy the first "nb" characters of each string. */ + for( i = 0; i < nval; i++ ) { + memcpy( pout, cbuf, nb ); + +/* Increment the pointer to the start of the next output string. */ + pout += nb; + +/* Increment the pointer to the start of the next input string. */ + cbuf += nb + 1; + } + +} + +static int Equal( AstObject *this_object, AstObject *that_object, int *status ) { +/* +* Name: +* Equal + +* Purpose: +* Test if two FitsTables are equivalent. + +* Type: +* Private function. + +* Synopsis: +* #include "fitstable.h" +* int Equal( AstObject *this, AstObject *that, int *status ) + +* Class Membership: +* FitsTable member function (over-rides the astEqual protected +* method inherited from the astTable class). + +* Description: +* This function returns a boolean result (0 or 1) to indicate whether +* two FitsTables are equivalent. + +* Parameters: +* this +* Pointer to the first Object (a FitsTable). +* that +* Pointer to the second Object. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* One if the FitsTables are equivalent, zero otherwise. + +* Notes: +* - A value of zero will be returned if this function is invoked +* with the global status set, or if it should fail for any reason. +*/ + +/* Local Variables: */ + AstFitsTable *that; + AstFitsTable *this; + int result; + +/* Initialise. */ + result = 0; + +/* Check the global error status. */ + if ( !astOK ) return result; + +/* Obtain pointers to the two FitsTable structures. */ + this = (AstFitsTable *) this_object; + that = (AstFitsTable *) that_object; + +/* Check the second object is a FitsTable. We know the first is a + FitsTable since we have arrived at this implementation of the virtual + function. */ + if( astIsAFitsTable( that ) ) { + +/* Check the FitsTables are equal when compared as Tables. */ + if( (*parent_equal)( this_object, that_object, status ) ) { + +/* Check the headers are equal. */ + result = astEqual( this->header, that->header ); + } + } + +/* If an error occurred, clear the result value. */ + if ( !astOK ) result = 0; + +/* Return the result, */ + return result; +} + +static void GenerateColumns( AstFitsTable *this, AstFitsChan *header, + int *status ) { +/* +* Name: +* GenerateColumns + +* Purpose: +* Add new column definitions to a FitsTable as defined by a FITS +* header. + +* Type: +* Private function. + +* Synopsis: +* #include "table.h" +* void GenerateColumns( AstFitsTable *this, AstFitsChan *header, +* int *status ) + +* Class Membership: +* FitsTable member function + +* Description: +* For each binary table column defined in the supplied FITS header, +* this function adds an equivalent column to the FitsTable. + +* Parameters: +* this +* Pointer to the FitsTable. +* header +* Pointer to a FitsChan holding the column definitions. +* status +* Pointer to the inherited status. + +*/ + +/* Local Variables: */ + char *cval; + char *name; + char *p; + char *unit; + char buff[ 50 ]; + char code; + char keyword[ 20 ]; + double dval; + int *dims; + int icol; + int idim; + int ival; + int nc; + int ncol; + int ndim; + int nel; + int repeat; + int type; + int wasset; + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Initialise */ + type = AST__BADTYPE; + +/* Get the number of columns defined in the header. */ + if( !astGetFitsI( header, "TFIELDS", &ncol ) ) ncol = 0; + +/* Add a column definition to the FitsTable for each column in the header. */ + for( icol = 0; icol < ncol; icol++ ) { + +/* Get the TFORMi keyword that defines the column data type and shape from + the header. Report an error if it is missing. */ + sprintf( keyword, "TFORM%d", icol + 1 ); + if( !astGetFitsS( header, keyword, &cval ) && astOK ) { + astError( AST__NOFTS, "astFitsTable: Supplied FITS binary table " + "header does not contain the required keyword '%s'.", + status, keyword ); + } + +/* Extract the repeat count and data type code from the TFORM string. */ + if( sscanf( cval, "%d%n", &repeat, &nc ) == 0 ) { + repeat = 1; + nc = 0; + } else if( repeat < 0 && astOK ) { + astError( AST__BDFTS, "astFitsTable: Keyword '%s' in supplied FITS " + "binary table header has unsupported value '%s'.", status, + keyword, cval ); + } + code = cval[ nc ]; + +/* Get the corresponding KeyMap data type. Report an error if the FITS + data type is not supported by the KeyMap class. */ + if( code == 'B' ) { + type = AST__BYTETYPE; + + } else if( code == 'I' ) { + type = AST__SINTTYPE; + + } else if( code == 'J' ) { + type = AST__INTTYPE; + + } else if( code == 'D' ) { + type = AST__DOUBLETYPE; + + } else if( code == 'E' ) { + type = AST__FLOATTYPE; + + } else if( code == 'A' ) { + type = AST__STRINGTYPE; + + } else if( astOK ){ + astError( AST__BDFTS, "astFitsTable: Keyword '%s' in supplied FITS " + "binary table header has unsupported value '%s'.", status, + keyword, cval ); + } + +/* The TTYPEi keyword gives the column name. Create a column name based + on the index of the column. */ + sprintf( keyword, "TTYPE%d", icol + 1 ); + if( !astGetFitsS( header, keyword, &cval ) ) { + sprintf( buff, "FCOLUMN%d", icol + 1 ); + cval = buff; + } + name = astStore( NULL, cval, strlen( cval ) + 1 ); + +/* Column units. */ + sprintf( keyword, "TUNIT%d", icol + 1 ); + if( !astGetFitsS( header, keyword, &cval ) ) { + buff[ 0 ] = 0; + cval = buff; + } + unit = astStore( NULL, cval, strlen( cval ) + 1 ); + +/* Column shape is defined by the TDIMi keyword - in the form + "(i,j,k,...)". where i, j, k ... are the dimensions. If it is missing + then the field is assumed to be a 1D vector with the length specified by + the repeat count in the TFORMn keyword, or a scalar (if repeat cound + is one). */ + sprintf( keyword, "TDIM%d", icol + 1 ); + if( astGetFitsS( header, keyword, &cval ) ) { + +/* Count the commas in the keyword value. This equals one less than the + number of dimensions. */ + ndim = 1; + p = cval; + while( *p ) { + if( *(p++) == ',' ) ndim++; + } + +/* Allocate memory for the dimensions. */ + dims = astMalloc( ndim*sizeof( int ) ); + +/* Find each dimension and copy it into the above memory. Also find the + total number of elements (nel). */ + nel = 1; + idim = 0; + p = cval; + if( *p == '(' ) p++; + while( sscanf( p, "%d%n", dims + idim, &nc ) ) { + nel *= dims[ idim ]; + idim++; + p += nc; + if( *p == ',' ) p++; + } + +/* For strings, the first TDIM value gives the length of the string, so + reduce the number of dimensions by one. */ + if( type == AST__STRINGTYPE ) { + ndim--; + dims++; + } + + } else { + nel = repeat; + if( nel == 1 ) { + ndim = 0; + dims = NULL; + } else { + ndim = 1; + dims = astMalloc( sizeof( int ) ); + if( dims ) *dims = nel; + } + } + +/* Check the total number of elements equal the repeat count from the + TFORM keyword. */ + if( repeat != nel && astOK ) { + + sprintf( keyword, "TFORM%d", icol + 1 ); + astGetFitsS( header, keyword, &cval ); + strcpy( buff, cval ); + + sprintf( keyword, "TDIM%d", icol + 1 ); + if( !astGetFitsS( header, keyword, &cval ) ) cval = " "; + + astError( AST__BDFTS, "astFitsTable: Supplied FITS binary table " + "header contains inconsistent TFORM (%s) and TDIM (%s) " + "keywords for field %d.", status, buff, cval, icol + 1 ); + } + +/* Check any TSCALi value is 1.0 */ + sprintf( keyword, "TSCAL%d", icol + 1 ); + if( astGetFitsF( header, keyword, &dval ) && dval != 1.0 && astOK ) { + astError( AST__BDFTS, "astFitsTable: Supplied FITS binary table " + "header contains scaled columns which are not " + "supported by AST.", status ); + } + +/* Check any TZEROi value is 0.0 */ + sprintf( keyword, "TSCAL%d", icol + 1 ); + if( astGetFitsF( header, keyword, &dval ) && dval != 0.0 && astOK ) { + astError( AST__BDFTS, "astFitsTable: Supplied FITS binary table " + "header contains scaled columns which are not " + "supported by AST.", status ); + } + +/* Add the column to the table. */ + astAddColumn( this, name, type, ndim, dims, unit ); + +/* Set the null value, if present. */ + sprintf( keyword, "TNULL%d", icol + 1 ); + if( astGetFitsI( header, keyword, &ival ) ) { + (void) astColumnNull( this, name, 1, ival, &wasset, NULL ); + } + +/* Free resources. */ + dims = astFree( dims - ( ( type == AST__STRINGTYPE ) ? 1 : 0 ) ); + name = astFree( name ); + unit = astFree( unit ); + + } +} + +static void GetColumnData( AstFitsTable *this, const char *column, + float fnull, double dnull, size_t mxsize, + void *coldata, int *nelem, int *status ){ +/* +*++ +* Name: +c astGetColumnData +f AST_GETCOLUMNDATA + +* Purpose: +* Retrieve all the data values stored in a column. + +* Type: +* Public virtual function. + +* Synopsis: +c #include "frameset.h" +c void astGetColumnData( AstFitsTable *this, const char *column, +c float fnull, double dnull, size_t mxsize, +c void *coldata, int *nelem ) +f CALL AST_GETCOLUMNDATA( THIS, COLUMN, RNULL, DNULL, MXSIZE, +f COLDATA, NELEM, STATUS ) + +* Class Membership: +* FitsTable method. + +* Description: +c This function +f This routine +* copies all data values from a named column into a supplied buffer + +* Parameters: +c this +f THIS = INTEGER (Given) +* Pointer to the FitsTable. +c column +f COLUMN = CHARACTER * ( * ) (Given) +* The character string holding the name of the column. Trailing +* spaces are ignored. +c fnull +f RNULL = REAL (Given) +* The value to return in +c "coldata" +f COLDATA +* for any cells for which no value has been stored in the +* FitsTable. Ignored if the column's data type is not +* AST__FLOATTYPE. Supplying +c AST__NANF +f AST__NANR +* will cause a single precision IEEE NaN value to be used. +c dnull +f DNULL = REAL (Given) +* The value to return in +c "coldata" +f COLDATA +* for any cells for which no value has been stored in the +* FitsTable. Ignored if the column's data type is not +* AST__DOUBLETYPE. Supplying AST__NAN will cause a double precision +* IEEE NaN value to be used. +c mxsize +f MXSIZE = INTEGER (Given) +* The size of the +c "coldata" +f COLDATA +* array, in bytes. The amount of memory needed to hold the data +* from a column may be determined using +c astColumnSize. +f AST_COLUMNSIZE. +* If the supplied array is too small to hold all the column data, +* trailing column values will be omitted from the returned array, +* but no error will be reported. +c coldata +f COLDATA( * ) = BYTE (Given) +c A pointer to an +f An +* area of memory in which to return the data +* values currently stored in the column. The values are stored in +* row order. If the column holds non-scalar values, the elements +* of each value are stored in "Fortran" order. No data type +* conversion is performed - the data type of each returned value +* is the data type associated with the column when the column was +* added to the table. If the column holds strings, the returned +* strings will be null terminated. Any excess room at the end of +* the array will be left unchanged. +c nelem +f NELEM = INTEGER (Return) +* The number of elements returned in the +c "coldata" +f COLDATA +* array. This is the product of the number of rows returned and +* the number of elements in each column value. +f STATUS = INTEGER (Given and Returned) +f The global status. + +* Notes: +f - The RNULL and DNULL arguments +c - The "fnull" and "dnull" parameters +* specify the value to be returned for any empty cells within columns +* holding floating point values. For columns holding integer values, +* the value returned for empty cells is the value returned by the +c astColumNull function. +f AST_COLUMNNULL functiom. +* For columns holding string values, the ASCII NULL character is returned +* for empty cells. +*-- +*/ + +/* Local Variables: */ + char *cbuf; /* Array of strings returned by astMapGet1C */ + char key[ AST__MXCOLKEYLEN + 1 ]; /* Current cell key string */ + int iel; /* Index of current element */ + int irow; /* Index of value being copied */ + int nel; /* No. of elements per value */ + int nrow; /* No. of values to copy */ + int nval; /* Number of values read from KeyMap entry */ + int ok; /* Was the value found in the KeyMap? */ + int type; /* Data type */ + int wasset; /* Was the integer null value set explicitly? */ + size_t nb; /* No. of bytes for a single element of a value */ + size_t nbv; /* No. of bytes per value */ + void *pnull; /* Pointer to a buffer holding a null value */ + void *pout; /* Pointer to next output element */ + +/* Initialise */ + *nelem = 0; + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Initialise */ + nb = 0; + +/* Find the number of bytes needed to hold a single element of the value + in a column cell. */ + type = astGetColumnType( this, column ); + if( type == AST__INTTYPE ) { + nb = sizeof( int ); + + } else if( type == AST__DOUBLETYPE ){ + nb = sizeof( double ); + + } else if( type == AST__STRINGTYPE ){ + nb = astGetColumnLenC( this, column )*sizeof( char ); + + } else if( type == AST__FLOATTYPE ){ + nb = sizeof( float ); + + } else if( type == AST__SINTTYPE ){ + nb = sizeof( short int ); + + } else if( type == AST__BYTETYPE ){ + nb = sizeof( char ); + + } else if( astOK ) { + astError( AST__INTER, "astGetColumnData(%s): Unsupported column type " + "%d (internal AST programming error).", status, + astGetClass( this ), type ); + } + +/* Get the number of elements per value, and the number of bytes per value. */ + nel = astGetColumnLength( this, column ); + nbv = nb*nel; + +/* Initialise a pointer to the next element of the output array to write to. */ + pout = coldata; + +/* Get the number of rows in the table. */ + nrow = astGetNrow( this ); + +/* For string columns, the buffer returned by astMapGet1C will include a + null character at the end of each string. This is not required for the + fixed-length string format used by FITS binary tables, so for each row we + produce a copy of the string returned by astMapGet1C excluding the + trailing nulls. Allocate a buffer to receive the string returned by + astMapGet1C. */ + if( type == AST__STRINGTYPE ) { + cbuf = astMalloc( ( nb + 1 )*nel ); + } else { + cbuf = NULL; + } + +/* If required, substitute NaN values for the supplied null values. */ + fnull = astCheckNaNF( fnull ); + dnull = astCheckNaN( dnull ); + +/* Indicate we have not yet determined a null value for the column */ + pnull = NULL; + +/* Reduce the number of rows to be returned if the returned array is too + small to hold all rows. */ + if( mxsize < nbv*nrow ) nrow = mxsize/nbv; + +/* Loop round the returned rows rows. */ + for( irow = 1; irow <= nrow; irow++ ) { + +/* Format the cell name. */ + (void) MakeKey( column, irow, key, AST__MXCOLKEYLEN + 1, + status ); + +/* Get the values in the current cell of the column, using its native + data type. For floating point, convert any NaNs into the appropriate + null value (do not need to do this if the null value is itself NaN). */ + if( type == AST__INTTYPE ) { + ok = astMapGet1I( this, key, nel, &nval, pout ); + + } else if( type == AST__DOUBLETYPE ){ + ok = astMapGet1D( this, key, nel, &nval, pout ); + + if( ok && astISFINITE(dnull) ) { + for( iel = 0; iel < nel; iel++ ) { + if( !astISFINITE( ((double *)pout)[ iel ] ) ) { + ((double *)pout)[ iel ] = dnull; + } + } + } + + } else if( type == AST__FLOATTYPE ){ + ok = astMapGet1F( this, key, nel, &nval, pout ); + + if( ok && astISFINITE(fnull) ) { + for( iel = 0; iel < nel; iel++ ) { + if( !astISFINITE( ((float *)pout)[ iel ] ) ) { + ((float *)pout)[ iel ] = fnull; + } + } + } + + } else if( type == AST__SINTTYPE ){ + ok = astMapGet1S( this, key, nel, &nval, pout ); + + } else if( type == AST__BYTETYPE ){ + ok = astMapGet1B( this, key, nel, &nval, pout ); + + } else if( type == AST__STRINGTYPE ){ + ok = astMapGet1C( this, key, nb + 1, nel, &nval, cbuf ); + +/* Copy the strings returned by astMapGet1C into the returned array, + omitting the trailing null at the end of each string. */ + CopyStrings( nval, nb, cbuf, pout, status ); + + } else { + ok = 0; + } + +/* If the cell could not be found, return a suitable number of column null + values. */ + if( !ok ) { + +/* Determine the null value to use, if this has not already been done. */ + if( !pnull ) { + +/* Allocate a buffer to hold a single null value */ + pnull = astMalloc( nb ); + if( astOK ) { + +/* Copy the appropriate null value into the buffer allocated above. */ + if( type == AST__INTTYPE ) { + *( (int *) pnull ) = astColumnNull( this, column, 0, 0, + &wasset, NULL ); + } else if( type == AST__DOUBLETYPE ){ + *( (double *) pnull ) = dnull; + + } else if( type == AST__FLOATTYPE ){ + *( (float *) pnull ) = fnull; + + } else if( type == AST__STRINGTYPE ){ + memset( pnull, 0, nb ); + + } else if( type == AST__SINTTYPE ){ + *( (short int *) pnull ) = astColumnNull( this, column, 0, 0, + &wasset, NULL ); + } else if( type == AST__BYTETYPE ){ + *( (unsigned char *) pnull ) = astColumnNull( this, column, 0, 0, + &wasset, NULL ); + } + } + } + +/* Append the right number of nulls to the returned array. */ + for( iel = 0; iel < nel; iel++ ) { + memcpy( pout, pnull, nb ); + pout += nb; + } + +/* If the cell was found in the table, just increment the pointer to the next + returned value. */ + } else { + pout += nbv; + } + } + +/* Free resources. */ + cbuf = astFree( cbuf ); + pnull = astFree( pnull ); + +/* Return the number of returned elements. */ + *nelem = nel*nrow; +} + +static int GetObjSize( AstObject *this_object, int *status ) { +/* +* Name: +* GetObjSize + +* Purpose: +* Return the in-memory size of an Object. + +* Type: +* Private function. + +* Synopsis: +* #include "fitstable.h" +* int GetObjSize( AstObject *this, int *status ) + +* Class Membership: +* FitsTable member function (over-rides the astGetObjSize protected +* method inherited from the parent class). + +* Description: +* This function returns the in-memory size of the supplied FitsTables, +* in bytes. + +* Parameters: +* this +* Pointer to the FitsTable. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* The FitsTable size, in bytes. + +* Notes: +* - A value of zero will be returned if this function is invoked +* with the global status set, or if it should fail for any reason. +*/ + +/* Local Variables: */ + AstFitsTable *this; /* Pointer to FitsTable structure */ + int result; /* Result value to return */ + +/* Initialise. */ + result = 0; + +/* Check the global error status. */ + if ( !astOK ) return result; + +/* Obtain a pointers to the FitsTable structure. */ + this = (AstFitsTable *) this_object; + +/* Invoke the GetObjSize method inherited from the parent Table class, and + then add on any components of the class structure defined by this class + which are stored in dynamically allocated memory. */ + result = (*parent_getobjsize)( this_object, status ); + result += astGetObjSize( this->header ); + +/* If an error occurred, clear the result value. */ + if ( !astOK ) result = 0; + +/* Return the result, */ + return result; +} + +static AstFitsChan *GetTableHeader( AstFitsTable *this, int *status ) { +/* +*++ +* Name: +c astGetTableHeader +f AST_GetTableHeader + +* Purpose: +* Get the FITS headers from a FitsTable. + +* Type: +* Public virtual function. + +* Synopsis: +c #include "frameset.h" +c AstFitsChan *astGetTableHeader( AstFitsTable *this ) +f RESULT = AST_GETTABLEHEADER( THIS, STATUS ) + +* Class Membership: +* FitsTable method. + +* Description: +* This function returns a pointer to a FitsChan holding copies of +* the FITS headers associated with a FitsTable. + +* Parameters: +c this +f THIS = INTEGER (Given) +* Pointer to the FitsTable. +f STATUS = INTEGER (Given and Returned) +f The global status. + +* Returned Value: +c astGetTableHeader() +f AST_GetTableHeader = INTEGER +* A pointer to a deep copy of the FitsChan stored within the +* FitsTable. + +* Notes: +* - The returned pointer should be annulled using +c astAnnul +f AST_ANNUL +* when it is no longer needed. +* - Changing the contents of the returned FitsChan will have no effect +* on the FitsTable. To modify the FitsTable, the modified FitsChan must +* be stored in the FitsTable using +c astPutTableHeader. +f AST_PUTTABLEHEADER. + +*-- +*/ + +/* Check the global error status. */ + if ( !astOK ) return NULL; + +/* Ensure the fixed value headers are up-to-date in the FitsChan stored + in the FitsTable. */ + UpdateHeader( this, "astGetTableHeader", status ); + +/* Reset the current card to the first card. */ + astClearCard( this->header ); + +/* Return a deep copy of the FitsChan. */ + return astCopy( this->header ); +} + +void astInitFitsTableVtab_( AstFitsTableVtab *vtab, const char *name, int *status ) { +/* +*+ +* Name: +* astInitFitsTableVtab + +* Purpose: +* Initialise a virtual function table for a FitsTable. + +* Type: +* Protected function. + +* Synopsis: +* #include "fitstable.h" +* void astInitFitsTableVtab( AstFitsTableVtab *vtab, const char *name ) + +* Class Membership: +* FitsTable vtab initialiser. + +* Description: +* This function initialises the component of a virtual function +* table which is used by the FitsTable class. + +* Parameters: +* vtab +* Pointer to the virtual function table. The components used by +* all ancestral classes will be initialised if they have not already +* been initialised. +* name +* Pointer to a constant null-terminated character string which contains +* the name of the class to which the virtual function table belongs (it +* is this pointer value that will subsequently be returned by the Object +* astClass function). +*- +*/ + +/* Local Variables: */ + astDECLARE_GLOBALS /* Pointer to thread-specific global data */ + AstObjectVtab *object; /* Pointer to Object component of Vtab */ + AstTableVtab *table; /* Pointer to Table component of Vtab */ + +/* Check the local error status. */ + if ( !astOK ) return; + +/* Get a pointer to the thread specific global data structure. */ + astGET_GLOBALS(NULL); + +/* Initialize the component of the virtual function table used by the + parent class. */ + astInitTableVtab( (AstTableVtab *) vtab, name ); + +/* Store a unique "magic" value in the virtual function table. This + will be used (by astIsAFitsTable) to determine if an object belongs + to this class. We can conveniently use the address of the (static) + class_check variable to generate this unique value. */ + vtab->id.check = &class_check; + vtab->id.parent = &(((AstTableVtab *) vtab)->id); + +/* Initialise member function pointers. */ +/* ------------------------------------ */ +/* Store pointers to the member functions (implemented here) that provide + virtual methods for this class. */ + vtab->GetTableHeader = GetTableHeader; + vtab->PutTableHeader = PutTableHeader; + vtab->ColumnNull = ColumnNull; + vtab->ColumnSize = ColumnSize; + vtab->GetColumnData = GetColumnData; + vtab->PutColumnData = PutColumnData; + +/* Save the inherited pointers to methods that will be extended, and + replace them with pointers to the new member functions. */ + object = (AstObjectVtab *) vtab; + table = (AstTableVtab *) vtab; + + parent_equal = object->Equal; + object->Equal = Equal; + + parent_getobjsize = object->GetObjSize; + object->GetObjSize = GetObjSize; + +#if defined(THREAD_SAFE) + parent_managelock = object->ManageLock; + object->ManageLock = ManageLock; +#endif + + parent_addcolumn = table->AddColumn; + table->AddColumn = AddColumn; + +/* Declare the copy constructor, destructor and class dump function. */ + astSetCopy( vtab, Copy ); + astSetDelete( vtab, Delete ); + astSetDump( vtab, Dump, "FitsTable", "FITS binary table" ); + +/* If we have just initialised the vtab for the current class, indicate + that the vtab is now initialised, and store a pointer to the class + identifier in the base "object" level of the vtab. */ + if( vtab == &class_vtab ) { + class_init = 1; + astSetVtabClassIdentifier( vtab, &(vtab->id) ); + } +} + +static char *MakeKey( const char *column, int irow, char *buf, int len, + int *status ){ +/* +* Name: +* MakeKey + +* Purpose: +* Construct a key for a column cell from a column name and row number. + +* Type: +* Private function. + +* Synopsis: +* #include "fitstable.h" +* char *MakeKey( const char *column, int irow, char *buf, int len, +* int *status ) + +* Class Membership: +* FitsTable member function + +* Description: +* This function constructs a key for a column cell from a column name +* and row number. An error is reported if the buffer is too short. + +* Parameters: +* column +* Pointer to the column name. Trailing white space is ignored. +* irow +* One-based index of the row. +* buf +* Pointer to a buffer in which to store the returned key. +* len +* The length of the buffer. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* A copy of "buf". + +*/ + +/* Local Variables: */ + char *result; + char rbuf[ 40 ]; + int collen; + int nc; + +/* Initialise. */ + result = buf; + +/* Check the global error status. */ + if ( !astOK ) return result; + +/* Format the column number. */ + nc = sprintf( rbuf, "%d", irow ); + +/* Get the used length of the column name (i.e. excluding trailing white + space). */ + collen = astChrLen( column ); + +/* For the total length of the returned string. */ + nc += collen + 3; + +/* If the buffer is large enough, store the returned string. */ + if( len >= nc ) { + sprintf( buf, "%.*s(%s)", collen, column, rbuf ); + } else { + astError( AST__INTER, "MakeKey(FitsTable): Internal buffer is too " + "short to hold Table cell name '%.*s(%s)' (internal AST " + "programming error).", status, collen, column, rbuf ); + } + +/* Return the result, */ + return result; +} + +#if defined(THREAD_SAFE) +static int ManageLock( AstObject *this_object, int mode, int extra, + AstObject **fail, int *status ) { +/* +* Name: +* ManageLock + +* Purpose: +* Manage the thread lock on an Object. + +* Type: +* Private function. + +* Synopsis: +* #include "object.h" +* AstObject *ManageLock( AstObject *this, int mode, int extra, +* AstObject **fail, int *status ) + +* Class Membership: +* FitsTable member function (over-rides the astManageLock protected +* method inherited from the parent class). + +* Description: +* This function manages the thread lock on the supplied Object. The +* lock can be locked, unlocked or checked by this function as +* deteremined by parameter "mode". See astLock for details of the way +* these locks are used. + +* Parameters: +* this +* Pointer to the Object. +* mode +* An integer flag indicating what the function should do: +* +* AST__LOCK: Lock the Object for exclusive use by the calling +* thread. The "extra" value indicates what should be done if the +* Object is already locked (wait or report an error - see astLock). +* +* AST__UNLOCK: Unlock the Object for use by other threads. +* +* AST__CHECKLOCK: Check that the object is locked for use by the +* calling thread (report an error if not). +* extra +* Extra mode-specific information. +* fail +* If a non-zero function value is returned, a pointer to the +* Object that caused the failure is returned at "*fail". This may +* be "this" or it may be an Object contained within "this". Note, +* the Object's reference count is not incremented, and so the +* returned pointer should not be annulled. A NULL pointer is +* returned if this function returns a value of zero. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* A local status value: +* 0 - Success +* 1 - Could not lock or unlock the object because it was already +* locked by another thread. +* 2 - Failed to lock a POSIX mutex +* 3 - Failed to unlock a POSIX mutex +* 4 - Bad "mode" value supplied. + +* Notes: +* - This function attempts to execute even if an error has already +* occurred. +*/ + +/* Local Variables: */ + AstFitsTable *this; /* Pointer to FitsTable structure */ + int result; /* Returned status value */ + +/* Initialise */ + result = 0; + +/* Check the supplied pointer is not NULL. */ + if( !this_object ) return result; + +/* Obtain a pointers to the FitsTable structure. */ + this = (AstFitsTable *) this_object; + +/* Invoke the ManageLock method inherited from the parent class. */ + if( !result ) result = (*parent_managelock)( this_object, mode, extra, + fail, status ); + +/* Invoke the astManageLock method on any Objects contained within + the supplied Object. */ + if( !result ) result = astManageLock( this->header, mode, extra, fail ); + + return result; + +} +#endif + +static void PurgeHeader( AstFitsTable *this, int *status ) { +/* +* Name: +* PurgeHeader + +* Purpose: +* Remove fixed-value keywords from the table header. + +* Type: +* Private function. + +* Synopsis: +* void PurgeHeader( AstFitsTable *this, int *status ) + +* Description: +* This function ensures that the headers that are determined by the +* table contents or by the FITS standard do not exist in the header +* of the supplied FitsTable. + +* Parameters: +* this +* Pointer to the FitsTable. +* status +* Pointer to inherited status. + +*/ + +/* Local Constants: */ +#define nfixed 14 /* Number of fixed-value keywords to check for */ + +/* Local Variables: */ + int ifixed; + +/* A list of FITS keywords that have values that are fixed by the FITS + standard or by the contents of the Table. */ + const char *fixed[] = { "XTENSION", "BITPIX", "NAXIS", "NAXIS1", + "NAXIS2", "PCOUNT", "GCOUNT", "TFIELDS", + "TFORM%d", "TTYPE%d", "TNULL%d", "THEAP", + "TDIM%d", "TUNIT%d" }; + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Remove headers that have fixed values. */ + for( ifixed = 0; ifixed < nfixed; ifixed++ ) { + astClearCard( this->header ); + while( astFindFits( this->header, fixed[ ifixed ], NULL, 0 ) ) { + astDelFits( this->header ); + } + } + +/* Undefine local constants */ +#undef nfixed +} + +static void PutColumnData( AstFitsTable *this, const char *column, + int clen, size_t size, void *coldata, int *status ){ +/* +*++ +* Name: +c astPutColumnData +f AST_PUTCOLUMNDATA + +* Purpose: +* Store new data values for all rows of a column. + +* Type: +* Public virtual function. + +* Synopsis: +c #include "frameset.h" +c void astPutColumnData( AstFitsTable *this, const char *column, +c int clen, size_t size, void *coldata ) +f CALL AST_PUTCOLUMNDATA( THIS, COLUMN, CLEN, SIZE, COLDATA, STATUS ) + +* Class Membership: +* FitsTable method. + +* Description: +c This function +f This routine +* copies data values from a supplied buffer into a named column. The +* first element in the buffer becomes the first element in the first +* row of the column. If the buffer does not completely fill the +* column, then any trailing rows are filled with null values. + +* Parameters: +c this +f THIS = INTEGER (Given) +* Pointer to the FitsTable. +c column +f COLUMN = CHARACTER * ( * ) (Given) +* The character string holding the name of the column. Trailing +* spaces are ignored. +c clen +f CLEN = INTEGER (Given) +* If the column holds character strings, then this must be set to +* the length of each fixed length string in the supplied array. +* This is often determined by the appropriate TFORMn keyword in +* the binary table header. The supplied value is ignored if the +* column does not hold character data. +c size +f SIZE = INTEGER (Given) +* The size of the +c "coldata" +f COLDATA +* array, in bytes. This should be an integer multiple of the +* number of bytes needed to hold the full vector value stored in a +* single cell of the column. An error is reported if this is not +* the case. +c coldata +f COLDATA( * ) = BYTE (Given) +c A pointer to an +f An +* area of memory holding the data to copy into the column. The values +* should be stored in row order. If the column holds non-scalar values, +* the elements of each value should be stored in "Fortran" order. No +* data type conversion is performed. +f STATUS = INTEGER (Given and Returned) +f The global status. + +*-- +*/ + +/* Local Variables: */ + char key[ AST__MXCOLKEYLEN + 1 ]; /* Current cell key string */ + char **carray; /* Pointer to array of null terminated string pointers */ + int irow; /* Index of value being copied */ + int iel; /* Index of current element */ + int nel; /* No. of elements per value */ + int nrow; /* No. of values to copy */ + int type; /* Data type */ + size_t nb; /* No. of bytes for a single element of a value */ + size_t nbv; /* No. of bytes per value */ + void *pin; /* Pointer to next input array element */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Initialise */ + nb = 0; + +/* Find the number of bytes in the supplied array holding a single element + of the value in a column cell. */ + type = astGetColumnType( this, column ); + if( type == AST__INTTYPE ) { + nb = sizeof( int ); + + } else if( type == AST__DOUBLETYPE ){ + nb = sizeof( double ); + + } else if( type == AST__STRINGTYPE ){ + nb = clen*sizeof( char ); + + } else if( type == AST__FLOATTYPE ){ + nb = sizeof( float ); + + } else if( type == AST__SINTTYPE ){ + nb = sizeof( short int ); + + } else if( type == AST__BYTETYPE ){ + nb = sizeof( char ); + + } else if( astOK ) { + astError( AST__INTER, "astPutColumnData(%s): Unsupported column type " + "%d (internal AST programming error).", status, + astGetClass( this ), type ); + } + +/* Get the number of elements per value, and the number of bytes (in the + supplied array) per value. */ + nel = astGetColumnLength( this, column ); + nbv = nb*nel; + +/* Initialise a pointer to the next element of the supplied array to read. */ + pin = coldata; + +/* Get the number of rows to copy from the supplied array. */ + nrow = nbv ? size / nbv : 0; + +/* As yet we have no array of null terminated character pointers. */ + carray = NULL; + +/* Report an error if the supplied array does not hold an exact number of + column cells. */ + if( nrow*nbv != size && astOK ) { + astError( AST__BADSIZ, "astPutColumnData(%s): The supplied array size " + "(%d bytes) is not an exact multiple of the size of one " + "column value (%d bytes).", status, astGetClass( this ), + (int) size, (int) nbv ); + } + +/* Loop round the rows to be copied. */ + for( irow = 1; irow <= nrow; irow++ ) { + +/* Format the cell name. */ + (void) MakeKey( column, irow, key, AST__MXCOLKEYLEN + 1, + status ); + +/* Put the next value into the current cell of the column, using its native + data type. Skip floating point values that are entirely NaN. */ + if( type == AST__INTTYPE ) { + astMapPut1I( this, key, nel, pin, NULL ); + + } else if( type == AST__DOUBLETYPE ){ + for( iel = 0; iel < nel; iel++ ) { + if( astISFINITE( ((double *)pin)[ iel ] ) ) { + astMapPut1D( this, key, nel, pin, NULL ); + break; + } + } + + } else if( type == AST__FLOATTYPE ){ + for( iel = 0; iel < nel; iel++ ) { + if( astISFINITE( ((double *)pin)[ iel ] ) ) { + astMapPut1F( this, key, nel, pin, NULL ); + break; + } + } + + } else if( type == AST__SINTTYPE ){ + astMapPut1S( this, key, nel, pin, NULL ); + + } else if( type == AST__BYTETYPE ){ + astMapPut1B( this, key, nel, pin, NULL ); + +/* If each cell in the column holds an array of strings, we need to + convert the fixed length strings in the supplied array into an array + of pointers to null terminated strings. */ + } else if( type == AST__STRINGTYPE ){ + carray = astStringArray( pin, nel, clen ); + astMapPut1C( this, key, nel, (const char ** ) carray, NULL ); + carray = astFree( carray ); + } + +/* Increment the pointer to the next input value. */ + pin += nbv; + } + +/* Remove any remaining cells already present in this column. */ + nrow = astGetNrow( this ); + for( ; irow <= nrow; irow++ ) { + (void) MakeKey( column, irow, key, AST__MXCOLKEYLEN + 1, + status ); + astMapRemove( this, key ); + } +} + +static void PutTableHeader( AstFitsTable *this, AstFitsChan *header, + int *status ) { +/* +*++ +* Name: +c astPutTableHeader +f AST_PUTTABLEHEADER + +* Purpose: +* Store new FITS headers in a FitsTable. + +* Type: +* Public virtual function. + +* Synopsis: +c #include "frameset.h" +c void astPutTableHeader( AstFitsTable *this, AstFitsChan *header ) +f CALL AST_PUTTABLEHEADER( THIS, HEADER, STATUS ) + +* Class Membership: +* FitsTable method. + +* Description: +c This function +f This routine +* stores new FITS headers in the supplied FitsTable. Any existing +* headers are first deleted. + +* Parameters: +c this +f THIS = INTEGER (Given) +* Pointer to the FitsTable. +c header +f HEADER = INTEGER (Given) +* Pointer to a FitsChan holding the headers for the FitsTable. +* A deep copy of the supplied FitsChan is stored in the FitsTable, +* replacing the current FitsChan in the Fitstable. Keywords that +* are fixed either by the properties of the Table, or by the FITS +* standard, are removed from the copy (see "Notes:" below). +f STATUS = INTEGER (Given and Returned) +f The global status. + +* Notes: +* - The attributes of the supplied FitsChan, together with any source +* and sink functions associated with the FitsChan, are copied to the +* FitsTable. +* - Values for the following keywords are generated automatically by +* the FitsTable (any values for these keywords in the supplied +* FitsChan will be ignored): "XTENSION", "BITPIX", "NAXIS", "NAXIS1", +* "NAXIS2", "PCOUNT", "GCOUNT", "TFIELDS", "TFORM%d", "TTYPE%d", +* "TNULL%d", "THEAP", "TDIM%d". + +*-- +*/ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Annul the existing FitsChan. */ + (void) astAnnul( this->header ); + +/* Store a deep copy of the supplied FitsChan in the FitsTable. */ + this->header = astCopy( header ); + +/* Remove headers that have fixed values. */ + PurgeHeader( this, status ); +} + +static void UpdateHeader( AstFitsTable *this, const char *method, + int *status ) { +/* +* Name: +* UpdateHeader + +* Purpose: +* Ensure FITS headers accurately describe the current table contents. + +* Type: +* Private function. + +* Synopsis: +* void UpdateHeader( AstFitsTable *this, const char *method, +* int *status ) + +* Description: +* This function ensures that the FITS headers that are determined by +* the table contents or by the FITS standard are up to date. + +* Parameters: +* this +* Pointer to the FitsTable. +* method +* Pointer to a string holding the name of the method to include in +* error messages. +* status +* Pointer to inherited status. + +*/ + +/* Local Variables: */ + char *dimbuf; + char buf[ 20 ]; + char code; + char keyword[ 14 ]; + const char *unit; + const char *name; + int *dims; + int hasNull; + int icol; + int idim; + int nc; + int ncol; + int ndim; + int nel; + int null; + int rowsize; + int set; + int slen; + int type; + +/* Check inherited status */ + if( !astOK ) return; + +/* Remove any existing headers that will have values stored for them by + this function. */ + PurgeHeader( this, status ); + +/* Store headers that have fixed values regardless of the contents of the + table. Rewind the FitsChan first so they go at the start of the header. */ + astClearCard( this->header ); + astSetFitsS( this->header, "XTENSION", "BINTABLE", NULL, 0 ); + astSetFitsI( this->header, "BITPIX", 8, NULL, 0 ); + astSetFitsI( this->header, "NAXIS", 2, NULL, 0 ); + astSetFitsI( this->header, "PCOUNT", 0, NULL, 0 ); + astSetFitsI( this->header, "GCOUNT", 1, NULL, 0 ); + +/* The number of columns. */ + ncol = astGetNcolumn( this ); + astSetFitsI( this->header, "TFIELDS", ncol, NULL, 0 ); + +/* Add column-specific keywords, one for each column in the Table. */ + dims = NULL; + dimbuf = NULL; + rowsize = 0; + for( icol = 1; icol <= ncol && astOK; icol++ ){ + +/* Get the name, type and shape of the current column. */ + name = astColumnName( this, icol ); + nel = astGetColumnLength( this, name ); + type = astGetColumnType( this, name ); + unit = astGetColumnUnit( this, name ); + ndim = astGetColumnNdim( this, name ); + dims = astGrow( dims, ndim, sizeof( int ) ); + if( astOK ) { + astColumnShape( this, name, ndim, &ndim, dims ); + +/* Get the FITS code that describes the column data type. Also increment + the number of bytes (rowsize) used to describe a whole row. */ + slen = 0; + code = ' '; + if( type == AST__BYTETYPE ) { + code = 'B'; + rowsize += nel; + + } else if( type == AST__SINTTYPE ) { + code = 'I'; + rowsize += 2*nel; + + } else if( type == AST__INTTYPE ) { + code = 'J'; + rowsize += 4*nel; + + } else if( type == AST__DOUBLETYPE ) { + code = 'D'; + rowsize += 8*nel; + + } else if( type == AST__FLOATTYPE ) { + code = 'E'; + rowsize += 4*nel; + + } else if( type == AST__STRINGTYPE ) { + code = 'A'; + +/* Use the maximum length of the strings in the current column (excluding + null) to scale the FITS repeat count. */ + slen = astGetColumnLenC( this, name ); + nel *= slen; + rowsize += nel; + +/* Report an error if the data type is not supported by FITS. */ + } else if( astOK ) { + astError( AST__INTER, "%s(%s): Illegal type %d for column '%s' " + "in a %s (internal AST programming error).", status, + method, astGetClass( this ), type, name, + astGetClass( this ) ); + } + +/* Start the TFORMn keyword value. This is the number of values in each + cell, and is not needed if the cell contains only one value. */ + nc = sprintf( buf, "%d", nel ); + +/* Add the data type code to complete the TFORMn value, and store it in + the FitsChan. */ + sprintf( buf + nc, "%c", code ); + sprintf( keyword, "TFORM%d", icol ); + astSetFitsS( this->header, keyword, buf, NULL, 0 ); + +/* Column name. */ + sprintf( keyword, "TTYPE%d", icol ); + astSetFitsS( this->header, keyword, name, NULL, 0 ); + +/* Column units. */ + if( astChrLen( unit ) ) { + sprintf( keyword, "TUNIT%d", icol ); + astSetFitsS( this->header, keyword, unit, NULL, 0 ); + } + +/* Column null value (integer columns only). Only store a TNULLn keyword + if the NULL attribute has been set for the column, or if the column + contains missing (i.e. null) values. */ + if( type == AST__BYTETYPE || type == AST__SINTTYPE || + type == AST__INTTYPE ) { + null = astColumnNull( this, name, 0, 0, &set, &hasNull ); + if( set || hasNull ) { + sprintf( keyword, "TNULL%d", icol ); + astSetFitsI( this->header, keyword, null, NULL, 0 ); + } + } + +/* Array dimensions (only needed for non-scalars). */ + if( ndim > 0 ) { + dimbuf = astGrow( dimbuf, ndim, 15 ); + if( astOK ) { + +/* For strings, the first dimension is the length of the fixed-length + strings that make up the array. */ + if( type != AST__STRINGTYPE ) { + nc = sprintf( dimbuf, "(%d", dims[ 0 ] ); + } else { + nc = sprintf( dimbuf, "(%d,%d", slen, dims[ 0 ] ); + } + +/* Append the second and subsequent dimensions to the buffer. */ + for( idim = 1; idim < ndim; idim++ ) { + nc += sprintf( dimbuf + nc, ",%d", dims[ idim ] ); + } + sprintf( dimbuf + nc, ")" ); + +/* Store the buffered string as the value for keyword TDIMn in the + FitsChan. */ + sprintf( keyword, "TDIM%d", icol ); + astSetFitsS( this->header, keyword, dimbuf, NULL, 0 ); + } + } + } + } + +/* Insert the NAXISi keywords into the header, following the NAXIS value + (i.e. starting at card 4). */ + astSetCard( this->header, 4 ); + astSetFitsI( this->header, "NAXIS1", rowsize, NULL, 0 ); + astSetFitsI( this->header, "NAXIS2", astGetNrow( this ), NULL, 0 ); + +/* Free resources. */ + dims = astFree( dims ); + dimbuf = astFree( dimbuf ); +} + +/* Functions which access class attributes. */ +/* ---------------------------------------- */ +/* Implement member functions to access the attributes associated with + this class using the macros defined for this purpose in the + "object.h" file. For a description of each attribute, see the class + interface (in the associated .h file). */ + + +/* Copy constructor. */ +/* ----------------- */ +static void Copy( const AstObject *objin, AstObject *objout, int *status ) { +/* +* Name: +* Copy + +* Purpose: +* Copy constructor for FitsTable objects. + +* Type: +* Private function. + +* Synopsis: +* void Copy( const AstObject *objin, AstObject *objout, int *status ) + +* Description: +* This function implements the copy constructor for FitsTable objects. + +* Parameters: +* objin +* Pointer to the object to be copied. +* objout +* Pointer to the object being constructed. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* void + +* Notes: +* - This constructor makes a deep copy, including a copy of the component +* Mappings within the FitsTable. +*/ + +/* Local Variables: */ + AstFitsTable *in; /* Pointer to input FitsTable */ + AstFitsTable *out; /* Pointer to output FitsTable */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Obtain pointers to the input and output FitsTables. */ + in = (AstFitsTable *) objin; + out = (AstFitsTable *) objout; + +/* Make copies of the component Tables and store pointers to them in the + output FitsTable structure. */ + out->header = astCopy( in->header ); +} + + +/* Destructor. */ +/* ----------- */ +static void Delete( AstObject *obj, int *status ) { +/* +* Name: +* Delete + +* Purpose: +* Destructor for FitsTable objects. + +* Type: +* Private function. + +* Synopsis: +* void Delete( AstObject *obj, int *status ) + +* Description: +* This function implements the destructor for FitsTable objects. + +* Parameters: +* obj +* Pointer to the object to be deleted. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* void + +* Notes: +* This function attempts to execute even if the global error status is +* set. +*/ + +/* Local Variables: */ + AstFitsTable *this; /* Pointer to FitsTable */ + +/* Obtain a pointer to the FitsTable structure. */ + this = (AstFitsTable *) obj; + +/* Annul the pointers to the component Tables. */ + this->header = astAnnul( this->header ); + +} + + +/* Dump function. */ +/* -------------- */ +static void Dump( AstObject *this_object, AstChannel *channel, int *status ) { +/* +* Name: +* Dump + +* Purpose: +* Dump function for FitsTable objects. + +* Type: +* Private function. + +* Synopsis: +* void Dump( AstObject *this, AstChannel *channel, int *status ) + +* Description: +* This function implements the Dump function which writes out data +* for the FitsTable class to an output Channel. + +* Parameters: +* this +* Pointer to the FitsTable whose data are being written. +* channel +* Pointer to the Channel to which the data are being written. +* status +* Pointer to the inherited status variable. +*/ + +/* Local Variables: */ + AstFitsTable *this; /* Pointer to the FitsTable structure */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Obtain a pointer to the FitsTable structure. */ + this = (AstFitsTable *) this_object; + +/* Write out values representing the instance variables for the FitsTable + class. Note, the primitive data in the FitsTable will be written out + by the parent Table Dump function. This function deals just with the + extra information held in the FitsTable structure. */ + +/* Write out the FITS header. */ + astWriteObject( channel, "Header", 1, 0, this->header, "FITS headers" ); +} + + + + + + + + + + +/* Standard class functions. */ +/* ========================= */ +/* Implement the astIsAFitsTable and astCheckFitsTable functions using the macros + defined for this purpose in the "object.h" header file. */ +astMAKE_ISA(FitsTable,Table) +astMAKE_CHECK(FitsTable) + +AstFitsTable *astFitsTable_( void *header_void, const char *options, int *status, ...) { +/* +*++ +* Name: +c astFitsTable +f AST_FITSTABLE + +* Purpose: +* Create a FitsTable. + +* Type: +* Public function. + +* Synopsis: +c #include "fitstable.h" +c AstFitsTable *astFitsTable( AstFitsChan *header, const char *options, ... ) +f RESULT = AST_FITSTABLE( HEADER, OPTIONS, STATUS ) + +* Class Membership: +* FitsTable constructor. + +* Description: +* This function creates a new FitsTable and optionally initialises +* its attributes. +* +* The FitsTable class is a representation of a FITS binary table. It +* inherits from the Table class. The parent Table is used to hold the +* binary data of the main table, and a FitsChan is used to hold the FITS +* header. Note, there is no provision for binary data following the main +* table (such data is referred to as a "heap" in the FITS standard). +* +* Note - it is not recommended to use the FitsTable class to store +* very large tables. + +* Parameters: +c header +f HEADER = INTEGER (Given) +* Pointer to an optional FitsChan containing headers to be stored +* in the FitsTable. +c NULL +f AST__NULL +* may be supplied if the new FitsTable is to be left empty. If +* supplied, and if the headers describe columns of a FITS binary +* table, then equivalent (empty) columns are added to the FitsTable. +* Each column has the same index in the FitsTable that it has in +* the supplied header. +c options +f OPTIONS = CHARACTER * ( * ) (Given) +c Pointer to a null-terminated string containing an optional +c comma-separated list of attribute assignments to be used for +c initialising the new FitsTable. The syntax used is identical to +c that for the astSet function and may include "printf" format +c specifiers identified by "%" symbols in the normal way. +f A character string containing an optional comma-separated +f list of attribute assignments to be used for initialising the +f new FitsTable. The syntax used is identical to that for the +f AST_SET routine. +c ... +c If the "options" string contains "%" format specifiers, then +c an optional list of additional arguments may follow it in +c order to supply values to be substituted for these +c specifiers. The rules for supplying these are identical to +c those for the astSet function (and for the C "printf" +c function). +f STATUS = INTEGER (Given and Returned) +f The global status. + +* Returned Value: +c astFitsTable() +f AST_FITSTABLE = INTEGER +* A pointer to the new FitsTable. + +* Notes: +* - A null Object pointer (AST__NULL) will be returned if this +c function is invoked with the AST error status set, or if it +f function is invoked with STATUS set to an error value, or if it +* should fail for any reason. + +* Status Handling: +* The protected interface to this function includes an extra +* parameter at the end of the parameter list described above. This +* parameter is a pointer to the integer inherited status +* variable: "int *status". + +*-- +*/ + +/* Local Variables: */ + astDECLARE_GLOBALS /* Pointer to thread-specific global data */ + AstFitsTable *new; /* Pointer to new FitsTable */ + AstFitsChan *header; /* Pointer to header FitsChan */ + va_list args; /* Variable argument list */ + +/* Get a pointer to the thread specific global data structure. */ + astGET_GLOBALS(NULL); + +/* Check the global status. */ + if ( !astOK ) return NULL; + +/* Obtain and validate pointers to the header FitsChan provided. */ + header = header_void ? astCheckFitsChan( header_void ) : NULL; + +/* Initialise the FitsTable, allocating memory and initialising the + virtual function table as well if necessary. */ + new = astInitFitsTable( NULL, sizeof( AstFitsTable ), !class_init, + &class_vtab, "FitsTable", header ); + +/* If successful, note that the virtual function table has been + initialised. */ + if ( astOK ) { + class_init = 1; + +/* Obtain the variable argument list and pass it along with the options string + to the astVSet method to initialise the new FitsTable's attributes. */ + va_start( args, status ); + astVSet( new, options, NULL, args ); + va_end( args ); + +/* If an error occurred, clean up by deleting the new object. */ + if ( !astOK ) new = astDelete( new ); + } + +/* Return a pointer to the new FitsTable. */ + return new; +} + +AstFitsTable *astFitsTableId_( void *header_void, const char *options, ... ) { +/* +* Name: +* astFitsTableId_ + +* Purpose: +* Create a FitsTable. + +* Type: +* Private function. + +* Synopsis: +* #include "fitstable.h" +* AstFitsTable *astFitsTableId_( AstFitsChan *header, const char *options, ... ) + +* Class Membership: +* FitsTable constructor. + +* Description: +* This function implements the external (public) interface to the +* astFitsTable constructor function. It returns an ID value (instead +* of a true C pointer) to external users, and must be provided +* because astFitsTable_ has a variable argument list which cannot be +* encapsulated in a macro (where this conversion would otherwise +* occur). +* +* The variable argument list also prevents this function from +* invoking astFitsTable_ directly, so it must be a re-implementation +* of it in all respects, except for the final conversion of the +* result to an ID value. + +* Parameters: +* As for astFitsTable_. + +* Returned Value: +* The ID value associated with the new FitsTable. +*/ + +/* Local Variables: */ + astDECLARE_GLOBALS /* Pointer to thread-specific global data */ + AstFitsChan *header; /* Genuine C poitner to header FitsChan */ + AstFitsTable *new; /* Pointer to new FitsTable */ + int *status; /* Pointer to inherited status value */ + va_list args; /* Variable argument list */ + +/* Get a pointer to the inherited status value. */ + status = astGetStatusPtr; + +/* Get a pointer to the thread specific global data structure. */ + astGET_GLOBALS(NULL); + +/* Check the global status. */ + if ( !astOK ) return NULL; + +/* Obtain a FitsChan pointer from any ID supplied and validate the + pointer to ensure it identifies a valid FitsChan. */ + header = header_void ? astCheckFitsChan( astMakePointer( header_void ) ) : NULL; + +/* Initialise the FitsTable, allocating memory and initialising the + virtual function table as well if necessary. */ + new = astInitFitsTable( NULL, sizeof( AstFitsTable ), !class_init, + &class_vtab, "FitsTable", header ); + +/* If successful, note that the virtual function table has been + initialised. */ + if ( astOK ) { + class_init = 1; + +/* Obtain the variable argument list and pass it along with the options string + to the astVSet method to initialise the new FitsTable's attributes. */ + va_start( args, options ); + astVSet( new, options, NULL, args ); + va_end( args ); + +/* If an error occurred, clean up by deleting the new object. */ + if ( !astOK ) new = astDelete( new ); + } + +/* Return an ID value for the new FitsTable. */ + return astMakeId( new ); +} + +AstFitsTable *astInitFitsTable_( void *mem, size_t size, int init, + AstFitsTableVtab *vtab, const char *name, + AstFitsChan *header, int *status ) { +/* +*+ +* Name: +* astInitFitsTable + +* Purpose: +* Initialise a FitsTable. + +* Type: +* Protected function. + +* Synopsis: +* #include "fitstable.h" +* AstFitsTable *astInitFitsTable( void *mem, size_t size, int init, +* AstFitsTableVtab *vtab, const char *name, +* AstFitsChan *header ) + +* Class Membership: +* FitsTable initialiser. + +* Description: +* This function is provided for use by class implementations to initialise +* a new FitsTable object. It allocates memory (if necessary) to accommodate +* the FitsTable plus any additional data associated with the derived class. +* It then initialises a FitsTable structure at the start of this memory. If +* the "init" flag is set, it also initialises the contents of a virtual +* function table for a FitsTable at the start of the memory passed via the +* "vtab" parameter. + +* Parameters: +* mem +* A pointer to the memory in which the FitsTable is to be initialised. +* This must be of sufficient size to accommodate the FitsTable data +* (sizeof(FitsTable)) plus any data used by the derived class. If a value +* of NULL is given, this function will allocate the memory itself using +* the "size" parameter to determine its size. +* size +* The amount of memory used by the FitsTable (plus derived class data). +* This will be used to allocate memory if a value of NULL is given for +* the "mem" parameter. This value is also stored in the FitsTable +* structure, so a valid value must be supplied even if not required for +* allocating memory. +* init +* A logical flag indicating if the FitsTable's virtual function table is +* to be initialised. If this value is non-zero, the virtual function +* table will be initialised by this function. +* vtab +* Pointer to the start of the virtual function table to be associated +* with the new FitsTable. +* name +* Pointer to a constant null-terminated character string which contains +* the name of the class to which the new object belongs (it is this +* pointer value that will subsequently be returned by the astGetClass +* method). +* header +* If not NULL, a FitsChan that is used to populate the FitsTable +* with headers and columns. + +* Returned Value: +* A pointer to the new FitsTable. + +* Notes: +* - A null pointer will be returned if this function is invoked with the +* global error status set, or if it should fail for any reason. +*- +*/ + +/* Local Variables: */ + AstFitsTable *new; /* Pointer to new FitsTable */ + +/* Check the global status. */ + if ( !astOK ) return NULL; + +/* If necessary, initialise the virtual function table. */ + if ( init ) astInitFitsTableVtab( vtab, name ); + +/* Initialise. */ + new = NULL; + +/* Initialise a Table structure (the parent class) as the first component + within the FitsTable structure, allocating memory if necessary. Specify that + the Table should be defined in both the forward and inverse directions. */ + new = (AstFitsTable *) astInitTable( mem, size, 0, (AstTableVtab *) vtab, + name ); + if ( astOK ) { + +/* Initialise the FitsTable data. */ +/* ---------------------------- */ + new->header = astFitsChan( NULL, NULL, " ", status ); + +/* If a header was supplied, add equivalent columns to the FitsTable, and + store the header. */ + if( header ) { + GenerateColumns( new, header, status ); + PutTableHeader( new, header, status ); + } + +/* If an error occurred, clean up by deleting the new FitsTable. */ + if ( !astOK ) new = astDelete( new ); + } + +/* Return a pointer to the new FitsTable. */ + return new; +} + +AstFitsTable *astLoadFitsTable_( void *mem, size_t size, AstFitsTableVtab *vtab, + const char *name, AstChannel *channel, + int *status ) { +/* +*+ +* Name: +* astLoadFitsTable + +* Purpose: +* Load a FitsTable. + +* Type: +* Protected function. + +* Synopsis: +* #include "fitstable.h" +* AstFitsTable *astLoadFitsTable( void *mem, size_t size, AstFitsTableVtab *vtab, +* const char *name, AstChannel *channel ) + +* Class Membership: +* FitsTable loader. + +* Description: +* This function is provided to load a new FitsTable using data read +* from a Channel. It first loads the data used by the parent class +* (which allocates memory if necessary) and then initialises a +* FitsTable structure in this memory, using data read from the input +* Channel. +* +* If the "init" flag is set, it also initialises the contents of a +* virtual function table for a FitsTable at the start of the memory +* passed via the "vtab" parameter. + + +* Parameters: +* mem +* A pointer to the memory into which the FitsTable is to be +* loaded. This must be of sufficient size to accommodate the +* FitsTable data (sizeof(FitsTable)) plus any data used by derived +* classes. If a value of NULL is given, this function will +* allocate the memory itself using the "size" parameter to +* determine its size. +* size +* The amount of memory used by the FitsTable (plus derived class +* data). This will be used to allocate memory if a value of +* NULL is given for the "mem" parameter. This value is also +* stored in the FitsTable structure, so a valid value must be +* supplied even if not required for allocating memory. +* +* If the "vtab" parameter is NULL, the "size" value is ignored +* and sizeof(AstFitsTable) is used instead. +* vtab +* Pointer to the start of the virtual function table to be +* associated with the new FitsTable. If this is NULL, a pointer +* to the (static) virtual function table for the FitsTable class +* is used instead. +* name +* Pointer to a constant null-terminated character string which +* contains the name of the class to which the new object +* belongs (it is this pointer value that will subsequently be +* returned by the astGetClass method). +* +* If the "vtab" parameter is NULL, the "name" value is ignored +* and a pointer to the string "FitsTable" is used instead. + +* Returned Value: +* A pointer to the new FitsTable. + +* Notes: +* - A null pointer will be returned if this function is invoked +* with the global error status set, or if it should fail for any +* reason. +*- +*/ + +/* Local Variables: */ + astDECLARE_GLOBALS /* Pointer to thread-specific global data */ + AstFitsTable *new; /* Pointer to the new FitsTable */ + +/* Initialise. */ + new = NULL; + +/* Check the global error status. */ + if ( !astOK ) return new; + +/* Get a pointer to the thread specific global data structure. */ + astGET_GLOBALS(channel); + +/* If a NULL virtual function table has been supplied, then this is + the first loader to be invoked for this FitsTable. In this case the + FitsTable belongs to this class, so supply appropriate values to be + passed to the parent class loader (and its parent, etc.). */ + if ( !vtab ) { + size = sizeof( AstFitsTable ); + vtab = &class_vtab; + name = "FitsTable"; + +/* If required, initialise the virtual function table for this class. */ + if ( !class_init ) { + astInitFitsTableVtab( vtab, name ); + class_init = 1; + } + } + +/* Invoke the parent class loader to load data for all the ancestral + classes of the current one, returning a pointer to the resulting + partly-built FitsTable. */ + new = astLoadTable( mem, size, (AstTableVtab *) vtab, name, + channel ); + + if ( astOK ) { + +/* Read input data. */ +/* ================ */ +/* Request the input Channel to read all the input data appropriate to + this class into the internal "values list". */ + astReadClassData( channel, "FitsTable" ); + +/* Now read each individual data item from this list and use it to + initialise the appropriate instance variable(s) for this class. */ + +/* FitsChan holding table headers. */ + new->header = astReadObject( channel, "header", NULL ); + +/* If an error occurred, clean up by deleting the new FitsTable. */ + if ( !astOK ) new = astDelete( new ); + } + +/* Return the new FitsTable pointer. */ + return new; +} + +/* Virtual function interfaces. */ +/* ============================ */ +/* These provide the external interface to the virtual functions defined by + this class. Each simply checks the global error status and then locates and + executes the appropriate member function, using the function pointer stored + in the object's virtual function table (this pointer is located using the + astMEMBER macro defined in "object.h"). + + Note that the member function may not be the one defined here, as it may + have been over-ridden by a derived class. However, it should still have the + same interface. */ + +AstFitsChan *astGetTableHeader_( AstFitsTable *this, int *status ) { + if ( !astOK ) return NULL; + return (**astMEMBER(this,FitsTable,GetTableHeader))(this,status); +} + +void astPutTableHeader_( AstFitsTable *this, AstFitsChan *header, int *status ) { + if ( !astOK ) return; + (**astMEMBER(this,FitsTable,PutTableHeader))(this,header,status); +} + +int astColumnNull_( AstFitsTable *this, const char *column, int set, + int newval, int *wasset, int *hasnull, int *status ){ + *wasset = 0; + if( hasnull ) *hasnull = 0; + if ( !astOK ) return 0; + return (**astMEMBER(this,FitsTable,ColumnNull))(this,column,set,newval,wasset,hasnull,status); +} + +size_t astColumnSize_( AstFitsTable *this, const char *column, int *status ){ + if ( !astOK ) return 0; + return (**astMEMBER(this,FitsTable,ColumnSize))(this,column,status); +} + +void astGetColumnData_( AstFitsTable *this, const char *column, float fnull, + double dnull, size_t mxsize, void *coldata, int *nelem, + int *status ){ + if ( !astOK ) return; + (**astMEMBER(this,FitsTable,GetColumnData))(this,column,fnull,dnull,mxsize, + coldata,nelem,status); +} + +void astPutColumnData_( AstFitsTable *this, const char *column, int clen, + size_t size, void *coldata, int *status ){ + if ( !astOK ) return; + (**astMEMBER(this,FitsTable,PutColumnData))(this,column,clen,size,coldata,status); +} + + + + + + + + |