1 /*
2 *class++
3 *  Name:
4 *     FitsTable
5 
6 *  Purpose:
7 *     A representation of a FITS binary table.
8 
9 *  Constructor Function:
10 c     astFitsTable
11 f     AST_FITSTABLE
12 
13 *  Description:
14 *     The FitsTable class is a representation of a FITS binary table. It
15 *     inherits from the Table class. The parent Table is used to hold the
16 *     binary data of the main table, and a FitsChan (encapsulated within
17 *     the FitsTable) is used to hold the FITS header.
18 *
19 *     Note - it is not recommended to use the FitsTable class to store
20 *     very large tables.
21 *
22 *     FitsTables are primarily geared towards the needs of the "-TAB"
23 *     algorithm defined in FITS-WCS paper 2, and so do not support all
24 *     features of FITS binary tables. In particularly, they do not
25 *     provide any equivalent to the following features of FITS binary
26 *     tables: "heap" data (i.e. binary data following the main table),
27 *     columns holding complex values, columns holding variable length
28 *     arrays, scaled columns, column formats, columns holding bit values,
29 *     8-byte integer values or logical values.
30 
31 *  Inheritance:
32 *     The FitsTable class inherits from the Table class.
33 
34 *  Attributes:
35 *     The FitsTable class does not define any new attributes beyond
36 *     those which are applicable to all Tables.
37 
38 *  Functions:
39 c     In addition to those functions applicable to all Tables, the
40 c     following functions may also be applied to all FitsTables:
41 f     In addition to those routines applicable to all Tables, the
42 f     following routines may also be applied to all FitsTables:
43 *
44 c     - astColumnNull: Get/set the null value for a column of a FitsTable
45 c     - astColumnSize: Get number of bytes needed to hold a full column of data
46 c     - astGetColumnData: Retrieve all the data values stored in a column
47 c     - astGetTableHeader: Get the FITS headers from a FitsTable
48 c     - astPutColumnData: Store data values in a column
49 c     - astPutTableHeader: Store FITS headers within a FitsTable
50 f     - AST_COLUMNNULL: Get/set the null value for a column of a FitsTable
51 f     - AST_COLUMNSIZE: Get number of bytes needed to hold a full column of data
52 f     - AST_GETCOLUMNDATA: Retrieve all the data values stored in a column
53 f     - AST_GETTABLEHEADER: Get the FITS headers from a FitsTable
54 f     - AST_PUTCOLUMNDATA: Store data values in a column
55 f     - AST_PUTTABLEHEADER: Store FITS headers within a FitsTable
56 
57 *  Copyright:
58 *     Copyright (C) 2010 Science & Technology Facilities Council.
59 *     All Rights Reserved.
60 
61 *  Licence:
62 *     This program is free software: you can redistribute it and/or
63 *     modify it under the terms of the GNU Lesser General Public
64 *     License as published by the Free Software Foundation, either
65 *     version 3 of the License, or (at your option) any later
66 *     version.
67 *
68 *     This program is distributed in the hope that it will be useful,
69 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
70 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
71 *     GNU Lesser General Public License for more details.
72 *
73 *     You should have received a copy of the GNU Lesser General
74 *     License along with this program.  If not, see
75 *     <http://www.gnu.org/licenses/>.
76 
77 *  Authors:
78 *     DSB: David S. Berry (Starlink)
79 
80 *  History:
81 *     25-NOV-2010 (DSB):
82 *        Original version.
83 *     2-OCT-2012 (DSB):
84 *        Check for Infs as well as NaNs.
85 *class--
86 */
87 
88 /* Module Macros. */
89 /* ============== */
90 /* Set the name of the class we are implementing. This indicates to
91    the header files that define class interfaces that they should make
92    "protected" symbols available. */
93 #define astCLASS FitsTable
94 
95 /* The KeyMap key use to store the null value for a column. */
96 #define NULLKEY "Null"
97 
98 /* Include files. */
99 /* ============== */
100 /* Interface definitions. */
101 /* ---------------------- */
102 
103 #include "globals.h"             /* Thread-safe global data access */
104 #include "error.h"               /* Error reporting facilities */
105 #include "memory.h"              /* Memory allocation facilities */
106 #include "object.h"              /* Base Object class */
107 #include "table.h"               /* Tables (parent class) */
108 #include "channel.h"             /* I/O channels */
109 #include "pointset.h"            /* For astCheckNaN(F) functions */
110 #include "fitstable.h"           /* Interface definition for this class */
111 
112 
113 /* Error code definitions. */
114 /* ----------------------- */
115 #include "ast_err.h"             /* AST error codes */
116 
117 /* C header files. */
118 /* --------------- */
119 #include <limits.h>
120 #include <stdio.h>
121 #include <string.h>
122 
123 
124 /* Module Variables. */
125 /* ================= */
126 
127 /* Address of this static variable is used as a unique identifier for
128    member of this class. */
129 static int class_check;
130 
131 /* Pointers to parent class methods which are extended by this class. */
132 static int (* parent_equal)( AstObject *, AstObject *, int * );
133 static int (* parent_getobjsize)( AstObject *, int * );
134 static void (* parent_addcolumn)( AstTable *, const char *, int, int, int *, const char *, int * );
135 
136 #if defined(THREAD_SAFE)
137 static int (* parent_managelock)( AstObject *, int, int, AstObject **, int * );
138 #endif
139 
140 
141 /* Define macros for accessing each item of thread specific global data. */
142 #ifdef THREAD_SAFE
143 
144 /* Define how to initialise thread-specific globals. */
145 #define GLOBAL_inits \
146    globals->Class_Init = 0;
147 
148 /* Create the function that initialises global data for this module. */
149 astMAKE_INITGLOBALS(FitsTable)
150 
151 /* Define macros for accessing each item of thread specific global data. */
152 #define class_init astGLOBAL(FitsTable,Class_Init)
153 #define class_vtab astGLOBAL(FitsTable,Class_Vtab)
154 
155 
156 /* If thread safety is not needed, declare and initialise globals at static
157    variables. */
158 #else
159 
160 /* Define the class virtual function table and its initialisation flag
161    as static variables. */
162 static AstFitsTableVtab class_vtab;   /* Virtual function table */
163 static int class_init = 0;       /* Virtual function table initialised? */
164 
165 #endif
166 
167 /* External Interface Function Prototypes. */
168 /* ======================================= */
169 /* The following functions have public prototypes only (i.e. no
170    protected prototypes), so we must provide local prototypes for use
171    within this module. */
172 AstFitsTable *astFitsTableId_( void *, const char *, ... );
173 
174 /* Prototypes for Private Member Functions. */
175 /* ======================================== */
176 static AstFitsChan *GetTableHeader( AstFitsTable *, int * );
177 static char *MakeKey( const char *, int, char *, int, int * );
178 static int ColumnNull( AstFitsTable *, const char *, int, int, int *, int *, int * );
179 static int Equal( AstObject *, AstObject *, int * );
180 static int GetObjSize( AstObject *, int * );
181 static size_t ColumnSize( AstFitsTable *, const char *, int * );
182 static void AddColumn( AstTable *, const char *, int, int, int *, const char *, int * );
183 static void Copy( const AstObject *, AstObject *, int * );
184 static void CopyStrings( int, size_t, const char *, char *, int * );
185 static void Delete( AstObject *, int * );
186 static void Dump( AstObject *, AstChannel *, int * );
187 static void GenerateColumns( AstFitsTable *, AstFitsChan *, int * );
188 static void GetColumnData( AstFitsTable *, const char *, float, double, size_t, void *, int *, int * );
189 static void PurgeHeader( AstFitsTable *, int * );
190 static void PutColumnData( AstFitsTable *, const char *, int, size_t, void *, int * );
191 static void PutTableHeader( AstFitsTable *, AstFitsChan *, int * );
192 static void UpdateHeader( AstFitsTable *, const char *, int * );
193 
194 #if defined(THREAD_SAFE)
195 static int ManageLock( AstObject *, int, int, AstObject **, int * );
196 #endif
197 
198 /* Member functions. */
199 /* ================= */
200 
AddColumn(AstTable * this,const char * name,int type,int ndim,int * dims,const char * unit,int * status)201 static void AddColumn( AstTable *this, const char *name, int type,
202                        int ndim, int *dims, const char *unit, int *status ) {
203 /*
204 *  Name:
205 *     AddColumn
206 
207 *  Purpose:
208 *     Add a new column definition to a FitsTable.
209 
210 *  Type:
211 *     Private function.
212 
213 *  Synopsis:
214 *     #include "table.h"
215 *     void AddColumn( AstTable *this, const char *name, int type, int ndim,
216 *                     int *dims, const char *unit, int *status )
217 
218 *  Class Membership:
219 *     FitsTable member function (over-rides the astAddColumn method
220 *     inherited from the Table class).
221 
222 *  Description:
223 *     Adds the definition of a new column to the supplied table. Initially,
224 *     the column contains a null value for every row. Values may be added
225 *     subsequently using the methods of the KeyMap class.
226 *
227 *     The FitsTable class extend the method inherited from the parent
228 *     Table class in order to prevent the addition of columns with properties
229 *     not supported by FITS binary tables.
230 
231 *  Parameters:
232 *     this
233 *        Pointer to the Table.
234 *     name
235 *        The column name. Trailing spaces are ignored (all other spaces
236 *        are significant). The supplied string is converted to upper case.
237 *     type
238 *        The data type associated with the column. One of AST__INTTYPE
239 *        (for integer), AST__SINTTYPE (for short int), AST__BYTETYPE (for
240 *        unsigned bytes - i.e. unsigned chars), AST__DOUBLETYPE (for double
241 *        precision floating point), AST__FLOATTYPE (for single precision
242 *        floating point), AST__STRINGTYPE (for character string). Note,
243 *        pointers and undefined values cannot be stored in a FitsTable
244 *        column.
245 *     ndim
246 *        The number of dimensions spanned by the values stored in a single
247 *        cell of the column. Zero if the column holds scalar values.
248 *     dims
249 *        An array holding the the lengths of each of the axes spanned by
250 *        the values stored in a single cell of the column. Ignored if the
251 *        column holds scalara values.
252 *     unit
253 *        A string specifying the units of the column. Supply a blank
254 *        string if the column is unitless.
255 *     status
256 *        Pointer to the inherited status.
257 
258 *  Notes:
259 *     - This function returns without action if a column already exists in
260 *     the Table with the supplied name and properties. However an error is
261 *     reported if any of the properties differ.
262 */
263 
264 /* Local Variables: */
265    const char *text;     /* Data type string */
266 
267 /* Check the global error status. */
268    if ( !astOK ) return;
269 
270 /* Report an error if the supplied data type is supported by the Table
271    class but not by the FitsTable class. */
272    if( type == AST__OBJECTTYPE ) {
273       text = "Object pointer";
274 
275    } else if( type == AST__POINTERTYPE ) {
276       text = "generic pointer";
277 
278    } else if( type == AST__UNDEFTYPE ) {
279       text = "undefined type";
280 
281    } else {
282       text = NULL;
283    }
284 
285    if( text ) {
286       astError( AST__NAXIN, "astAddColumn(%s): Bad data type (%s) supplied "
287                 "for new column %s. The %s class does not support %s "
288                 "columns.", status, astGetClass( this ), text, name,
289                 astGetClass( this ), text );
290 
291 /* Otherwise, invoke the parent method to add the column. */
292    } else {
293       (*parent_addcolumn)( this, name, type, ndim, dims, unit, status );
294    }
295 }
296 
ColumnNull(AstFitsTable * this,const char * column,int set,int newval,int * wasset,int * hasnull,int * status)297 static int ColumnNull( AstFitsTable *this, const char *column, int set,
298                        int newval, int *wasset, int *hasnull, int *status ){
299 /*
300 *++
301 *  Name:
302 c     astColumnNull
303 f     AST_COLUMNNULL
304 
305 *  Purpose:
306 *     Get or set the null value for an integer column of a FITS table.
307 
308 *  Type:
309 *     Public virtual function.
310 
311 *  Synopsis:
312 c     #include "table.h"
313 c     int astColumnNull( AstFitsTable *this, const char *column, int set,
314 c                        int newval, int *wasset, int *hasnull )
315 f     RESULT = AST_COLUMNNULL( THIS, COLUMN, SET, NEWVAL, WASSET, HASNULL,
316 f                              STATUS )
317 
318 *  Class Membership:
319 *     FitsTable method.
320 
321 *  Description:
322 *     This function allows a null value to be stored with a named
323 *     integer-valued column in a FitsTable. The supplied null value is
324 *     assigned to the TNULLn keyword in the FITS header associated with
325 *     the FitsTable. A value in the named column is then considered to be
326 *     null if 1) it equals the null value supplied to this function, or
327 *     2) no value has yet been stored in the cell.
328 *
329 *     As well as setting a new null value, this function also returns the
330 *     previous null value. If no null value has been set previously, a
331 *     default value will be returned. This default will be an integer
332 *     value that does not currently occur anywhere within the named column.
333 *     If no such value can be found, what happens depends on whether the
334 *     column contains any cells in which no values have yet been stored.
335 *     If so, an error will be reported. Otherwise (i.e. if there are no
336 *     null values in the column), an arbitrary value of zero will be
337 *     returned as the function value, and no TNULLn keyword will be
338 *     stored in the FITS header.
339 *
340 *     A flag is returned indicating if the returned null value was set
341 *     explicitly by a previous call to this function, or is a default
342 *     value.
343 *
344 *     A second flag is returned indicating if the named column contains
345 *     any null values (i.e. values equal to the supplied null value, or
346 *     cells to which no value has yet been assigned).
347 
348 *  Parameters:
349 c     this
350 f     THIS = INTEGER (Given)
351 *        Pointer to the Table.
352 c     column
353 f     COLUMN = CHARACTER * ( * ) (Given)
354 *        The character string holding the name of the column. Trailing
355 *        spaces are ignored.
356 c     set
357 f     SET = LOGICAL (Given)
358 c        If non-zero, the value supplied for parameter "newval"
359 f        If .TRUE., the value supplied for argument NEWVAL
360 *        will be stored as the current null value, replacing any value
361 *        set by a previous call to this function.
362 c        If zero, the value supplied for parameter "newval"
363 f        If .FALSE., the value supplied for argument NEWVAL
364 *        is ignored and the current null value is left unchanged.
365 c     newval
366 f     NEWVAL = INTEGER (Given)
367 *        The new null value to use. Ignored if
368 c        "set" is zero.
369 f        SET is .FALSE.
370 *        An error will be reported if the supplied value is outside the
371 *        range of values that can be stored in the integer data type
372 *        associated with the column.
373 c     wasset
374 f     WASSET = LOGICAL (Returned)
375 c        Pointer to an int that will be returned non-zero
376 f        .TRUE. will be returned
377 *        if the returned null value was set previously via an
378 *        earlier invocation of this function.
379 c        Zero
380 f        .FALSE.
381 *        is returned otherwise. If the named column does not exist, or an
382 *        error occurs, a value of
383 c        zero is returned.
384 f        .FALSE. is returned.
385 c     hasnull
386 f     HASNULL = LOGICAL (Returned)
387 c        Pointer to an int that will be returned non-zero
388 f        .TRUE. will be returned
389 *        if and only if the named column currently contains any values
390 *        equal to the null value on exit (i.e.
391 c        "newval" if "set" is non-zero,
392 f        NEWVAL if SET is .TRUE.
393 *        or the returned function value otherwise), or contains any empty
394 *        cells. If the named column does not exist, or an error occurs, a
395 *        value of
396 c        zero is returned.
397 f        .FALSE. is returned.
398 c        If a NULL pointer is supplied for "hasnull", no check on the
399 c        presence of null values will be performed.
400 f     STATUS = INTEGER (Given and Returned)
401 f        The global status.
402 
403 *  Returned Value:
404 c     astColumnNull()
405 f     AST_COLUMNNULL = INTEGER
406 *        The null value that was in use on entry to this function. If a
407 *        null value has been set by a previous invocation of this
408 *        function, it will be returned. Otherwise, if
409 c        "set" is non-zero, the supplied "newval"
410 f        SET is .TRUE., the supplied NEWVAL
411 *        value is returned. Otherwise, a default value is chosen (if
412 *        possible) that does not currently occur in the named column. If
413 *        all available values are in use in the column, an error is
414 *        reported if and only if the column contains any empty cells.
415 *        Otherwise, a value of zero is returned. A value of zero is also
416 *        returned if the named column does not exist, or an error occurs.
417 
418 *  Notes:
419 *     - The FITS binary table definition allows only integer-valued
420 *     columns to have an associated null value. This routine will return
421 *     without action if the column is not integer-valued.
422 
423 *--
424 */
425 
426 /* Local Variables: */
427    AstKeyMap *col_km;      /* KeyMap holding named column definition */
428    AstKeyMap *cols;        /* KeyMap holding all column definitions */
429    char key[ AST__MXCOLKEYLEN + 1 ]; /* Current cell key string */
430    int *cell;              /* Pointer to array of cell values */
431    int foundhi;            /* Has an occurrence of "nullhi" been found yet? */
432    int foundlo;            /* Has an occurrence of "nulllo" been found yet? */
433    int gotresult;          /* Has a usable value been put into "result"? */
434    int idim;               /* Index of current axis in each column's value */
435    int iel;                /* Index of current element within cell value */
436    int imax;               /* Maximum storable value */
437    int imin;               /* Minimum storable value */
438    int irow;               /* Index of current row in table */
439    int ndim;               /* Number of axes in each column's value */
440    int nel;                /* Total number of values in each cell */
441    int nrow;               /* Number of rows in table */
442    int null;               /* The null value on exit */
443    int nullfound;          /* Has a null value been found in the column yet? */
444    int nullhi;             /* Higher candidate default null value */
445    int nulllo;             /* Lower candidate default null value */
446    int result;             /* Returned value */
447    int type;               /* Column data type */
448 
449 /* Initialise */
450    result = 0;
451    *wasset = 0;
452    if( hasnull ) *hasnull = 0;
453 
454 /* Check the global error status. */
455    if ( !astOK ) return result;
456 
457 /* Store the max and min integer values that can be store din the column
458    data type. */
459    type = astGetColumnType( this, column );
460    if( type == AST__BYTETYPE ) {
461       imin = 0;
462       imax = UCHAR_MAX;
463 
464    } else if( type == AST__SINTTYPE ) {
465       imin = SHRT_MIN;
466       imax = SHRT_MAX;
467 
468    } else if( type == AST__INTTYPE ) {
469       imin = INT_MIN;
470       imax = INT_MAX;
471 
472    } else {
473       imax = 0;
474       imin = 0;
475    }
476 
477 /* Check the named column contains integer values of any length. */
478    if( imax > imin ) {
479 
480 /* Get the KeyMap holding information about all columns. */
481       cols = astColumnProps( this );
482 
483 /* Get the KeyMap holding information about the named column. */
484       if( astMapGet0A( cols, column, &col_km ) ) {
485 
486 /* If the column definition already includes a null value, put it into
487    "result". Also store the "*wasset" flag that indicates if the returned
488    null value is a default value or not. */
489          *wasset = astMapGet0I( col_km, NULLKEY, &result );
490 
491 /* If a new null value is to be established... */
492          if( set ) {
493 
494 /* If there was no previously set null value, return the new null value
495    as the function value. */
496             if( ! *wasset ) result = newval;
497 
498 /* Indicate we now know what the returned function value is. */
499             gotresult = 1;
500 
501 /* Save the null value that will be in use when this function exits. */
502             null = newval;
503 
504 /* Check the supplied value is in range. If so store it in the column
505    keymap. Otherwise report an error. */
506             if( null >= imin && null <= imax ) {
507                astMapPut0I( col_km, NULLKEY, null, NULL );
508 
509             } else if( astOK ) {
510                astError( AST__BADNULL, "astColumnNull(%s): Supplied null "
511                          "value (%d) is outside the range of integers "
512                          "that can be stored in column '%s'.", status,
513                          astGetClass( this ), newval, column );
514             }
515 
516 /* If no new null value was supplied, the null value on exit will be the
517    previously set value, if any. */
518          } else {
519             null = result;
520             gotresult = *wasset;
521          }
522 
523 /* The rest is only needed if we need to find a default result value, or if
524    we need to check if there are any null values in the table. */
525          if( !gotresult || hasnull ) {
526 
527 /* Get the total number of values in each cell of the column. */
528             nel = astGetColumnLength( this, column );
529 
530 /* Allocate memory to hold the values in a single cell of the column,
531    stored as ints. */
532             cell = astMalloc( nel*sizeof( int ) );
533 
534 /* No null values found yet. */
535             nullfound = 0;
536 
537 /* On the first pass round the following loop, we search for occurrences
538    of the highest and lowest integer values allowed in the column. If no
539    such occurrences are found we use one or the other as the default null
540    value. If occurrences of both of these values are found, we change the
541    values and start the search again. */
542             nullhi = imax;
543             nulllo = imin;
544             foundlo = 0;
545             foundhi = 0;
546 
547 /* Loop round all rows in the Table. */
548             nrow = astGetNrow( this );
549             for( irow = 1; irow <= nrow && astOK; irow++ ) {
550 
551 /* Format the cell name. */
552                (void) MakeKey( column, irow, key, AST__MXCOLKEYLEN + 1,
553                                status );
554 
555 /* Attempt to get the values in the cell */
556                if( astMapGet1I( this, key, nel, &nel, cell ) ) {
557 
558 /* Get the number of dimensions. */
559                   ndim = astGetColumnNdim( this, column );
560 
561 /* If we know what the null value is on exit, check the cell for such null
562    values (but only if the caller want s to know). Skip this check after the
563    first null is found. */
564                   if( gotresult ) {
565                      if( ! nullfound ) {
566                         for( idim = 0; idim < ndim; idim++ ) {
567                            if( cell[ idim ] == null ) {
568                               nullfound = 1;
569                               break;
570                            }
571                         }
572                      }
573 
574 /* If we do not yet know what the returned value is, we try to find an
575    integer value within the allowed data range that is not currently used in
576    the column. For the moment, this is a no-brain algorithm that will
577    become untenable for large tables. Need to fix it when it is apparent
578    that it is causing a problem. */
579                   } else if( nulllo <= nullhi ) {
580 
581 /* See if the current cell contains any occurrences of either of the
582    two currently nominated null values. Is so, increment the matched
583    nominated null value, and start again at row 1. */
584                      for( iel = 0; iel < nel; iel++ ) {
585 
586                         if( cell[ iel ] == nulllo ) {
587                            foundlo = 1;
588                         } else if( cell[ iel ] == nullhi ) {
589                            foundhi = 1;
590                         }
591 
592                         if( foundlo && foundhi ) {
593                            nullhi--;
594                            nulllo++;
595                            irow = 0;
596                            foundlo = 0;
597                            foundhi = 0;
598                            continue;
599                         }
600 
601                      }
602                   }
603 
604 /* If the column does not contain anything in the current cell, we know
605    there is at least one null value in the column, so store a non-zero value
606    in the returned flag. */
607                } else {
608                   nullfound = 1;
609                }
610 
611 /* If we now have a value for the result and know that there are nulls in
612    the column, we can leave the loop. */
613                if( gotresult && nullfound ) break;
614             }
615 
616 /* Return the "null found" flag if required. */
617             if( hasnull ) *hasnull = nullfound;
618 
619 /* If we have not yet stored the default null value to be returned as the
620    function value, do so now. If no unused value could be found, and
621    there are missing cells in the table, report an error. */
622             if( !gotresult ) {
623                if( !foundhi ) {
624                   result = nullhi;
625 
626                } else if( !foundlo ) {
627                   result = nulllo;
628 
629                } else if( nullfound && astOK ) {
630                   astError( AST__BADNULL, "astColumnNull(%s): Cannot find "
631                             "an unused value to use as the null value in "
632                             "column '%s'.", status, astGetClass( this ),
633                             column );
634                }
635             }
636 
637 /* Free resources */
638             cell = astFree( cell );
639          }
640          col_km = astAnnul( col_km );
641       }
642       cols = astAnnul( cols );
643    }
644 
645 /* Return null values if an error occurred. */
646    if( !astOK ) {
647       result = 0;
648       *wasset = 0;
649       if( hasnull ) *hasnull = 0;
650    }
651 
652 /* Return the result. */
653    return result;
654 }
655 
ColumnSize(AstFitsTable * this,const char * column,int * status)656 static size_t ColumnSize( AstFitsTable *this, const char *column, int *status ){
657 /*
658 *++
659 *  Name:
660 c     astColumnSize
661 f     AST_COLUMNSIZE
662 
663 *  Purpose:
664 *     Get the number of bytes needed to hold a full column of data.
665 
666 *  Type:
667 *     Public virtual function.
668 
669 *  Synopsis:
670 c     #include "table.h"
671 c     size_t astColumnSize( AstFitsTable *this, const char *column,
672 c                           int *hasnull )
673 f     RESULT = AST_COLUMNSIZE( THIS, COLUMN, STATUS )
674 
675 *  Class Membership:
676 *     FitsTable method.
677 
678 *  Description:
679 *     This function returns the number of bytes of memory that must be
680 *     allocated prior to retrieving the data from a column using
681 c     astGetColumnData.
682 f     AST_GETCOLUMNDATA.
683 
684 *  Parameters:
685 c     this
686 f     THIS = INTEGER (Given)
687 *        Pointer to the Table.
688 c     column
689 f     COLUMN = CHARACTER * ( * ) (Given)
690 *        The character string holding the name of the column. Trailing
691 *        spaces are ignored.
692 f     STATUS = INTEGER (Given and Returned)
693 f        The global status.
694 
695 *  Returned Value:
696 c     astColumnNull()
697 f     AST_COLUMNNULL = INTEGER
698 *        The number of bytes required to store the column data.
699 
700 *  Notes:
701 *     - An error will be reported if the named column does not exist in
702 *     the FitsTable.
703 *     - Zero will be returned as the function value in an error occurs.
704 
705 *--
706 */
707 
708 /* Local Variables: */
709    size_t result;          /* Returned value */
710    int type;               /* Column data type */
711 
712 /* Initialise */
713    result = 0;
714 
715 /* Check the global error status. */
716    if ( !astOK ) return result;
717 
718 /* Find the number of bytes needed to hold a single element of the value
719    in a column cell. */
720    type = astGetColumnType( this, column );
721    if( type == AST__INTTYPE ) {
722       result = sizeof( int );
723 
724    } else if(  type == AST__DOUBLETYPE ){
725       result = sizeof( double );
726 
727    } else if(  type == AST__STRINGTYPE ){
728       result = astGetColumnLenC( this, column )*sizeof( char );
729 
730    } else if(  type == AST__FLOATTYPE ){
731       result = sizeof( float );
732 
733    } else if(  type == AST__SINTTYPE ){
734       result = sizeof( short int );
735 
736    } else if(  type == AST__BYTETYPE ){
737       result = sizeof( char );
738 
739    } else if( astOK ) {
740       astError( AST__INTER, "astColumnSize(%s): Unsupported column type "
741                 "%d (internal AST programming error).", status,
742                 astGetClass( this ), type );
743    }
744 
745 /* Multiply it by the number of elements per value. */
746    result *= astGetColumnLength( this, column );
747 
748 /* Multiply it by the number of values per column (i.e. the number of rows). */
749    result *= astGetNrow( this );
750 
751 /* Return zero if an error occurred. */
752    if( !astOK ) result = 0;
753 
754 /* Return the result. */
755    return result;
756 }
757 
CopyStrings(int nval,size_t nb,const char * cbuf,char * pout,int * status)758 static void CopyStrings( int nval, size_t nb, const char *cbuf, char *pout,
759                          int *status ){
760 /*
761 *  Name:
762 *     CopyStrings
763 
764 *  Purpose:
765 *     Remove terminating nulls from an array of fixed-length strings.
766 
767 *  Type:
768 *     Private function.
769 
770 *  Synopsis:
771 *     void CopyStrings( int nval, size_t nb, const char *cbuf, char *pout,
772 *                       int *status )
773 
774 *  Description:
775 *     This function copies null terminated strings from "cbuf" to "pout",
776 *     removing the terminating nulls in the process. Thus each output string
777 *     is one character shorter than the corresponding input string.
778 
779 *  Parameters:
780 *     nval
781 *        The number of strings to copy.
782 *     nb
783 *        The maximum length of each string, excluding trailing null.
784 *     cbuf
785 *        The input array holding "nval" adjacent strings, each occupying
786 *        ( nb + 1 ) characters (the last one is the trailing null).
787 *     pout
788 *        The output array to which "nval" adjacent strings are written,
789 *        each occupying ( nb ) characters (i.e. no trailing null).
790 *     status
791 *        Pointer to inherited status.
792 
793 */
794 
795 /* Local Variables: */
796    int i;
797 
798 /* Check the global error status. */
799    if ( !astOK ) return;
800 
801 /* Copy the first "nb" characters of each string. */
802    for( i = 0; i < nval; i++ ) {
803       memcpy( pout, cbuf, nb );
804 
805 /* Increment the pointer to the start of the next output string. */
806       pout += nb;
807 
808 /* Increment the pointer to the start of the next input string. */
809       cbuf += nb + 1;
810    }
811 
812 }
813 
Equal(AstObject * this_object,AstObject * that_object,int * status)814 static int Equal( AstObject *this_object, AstObject *that_object, int *status ) {
815 /*
816 *  Name:
817 *     Equal
818 
819 *  Purpose:
820 *     Test if two FitsTables are equivalent.
821 
822 *  Type:
823 *     Private function.
824 
825 *  Synopsis:
826 *     #include "fitstable.h"
827 *     int Equal( AstObject *this, AstObject *that, int *status )
828 
829 *  Class Membership:
830 *     FitsTable member function (over-rides the astEqual protected
831 *     method inherited from the astTable class).
832 
833 *  Description:
834 *     This function returns a boolean result (0 or 1) to indicate whether
835 *     two FitsTables are equivalent.
836 
837 *  Parameters:
838 *     this
839 *        Pointer to the first Object (a FitsTable).
840 *     that
841 *        Pointer to the second Object.
842 *     status
843 *        Pointer to the inherited status variable.
844 
845 *  Returned Value:
846 *     One if the FitsTables are equivalent, zero otherwise.
847 
848 *  Notes:
849 *     - A value of zero will be returned if this function is invoked
850 *     with the global status set, or if it should fail for any reason.
851 */
852 
853 /* Local Variables: */
854    AstFitsTable *that;
855    AstFitsTable *this;
856    int result;
857 
858 /* Initialise. */
859    result = 0;
860 
861 /* Check the global error status. */
862    if ( !astOK ) return result;
863 
864 /* Obtain pointers to the two FitsTable structures. */
865    this = (AstFitsTable *) this_object;
866    that = (AstFitsTable *) that_object;
867 
868 /* Check the second object is a FitsTable. We know the first is a
869    FitsTable since we have arrived at this implementation of the virtual
870    function. */
871    if( astIsAFitsTable( that ) ) {
872 
873 /* Check the FitsTables are equal when compared as Tables. */
874       if( (*parent_equal)( this_object, that_object, status ) ) {
875 
876 /* Check the headers are equal.  */
877          result = astEqual( this->header, that->header );
878       }
879    }
880 
881 /* If an error occurred, clear the result value. */
882    if ( !astOK ) result = 0;
883 
884 /* Return the result, */
885    return result;
886 }
887 
GenerateColumns(AstFitsTable * this,AstFitsChan * header,int * status)888 static void GenerateColumns( AstFitsTable *this, AstFitsChan *header,
889                              int *status ) {
890 /*
891 *  Name:
892 *     GenerateColumns
893 
894 *  Purpose:
895 *     Add new column definitions to a FitsTable as defined by a FITS
896 *     header.
897 
898 *  Type:
899 *     Private function.
900 
901 *  Synopsis:
902 *     #include "table.h"
903 *     void GenerateColumns( AstFitsTable *this, AstFitsChan *header,
904 *                           int *status )
905 
906 *  Class Membership:
907 *     FitsTable member function
908 
909 *  Description:
910 *     For each binary table column defined in the supplied FITS header,
911 *     this function adds an equivalent column to the FitsTable.
912 
913 *  Parameters:
914 *     this
915 *        Pointer to the FitsTable.
916 *     header
917 *        Pointer to a FitsChan holding the column definitions.
918 *     status
919 *        Pointer to the inherited status.
920 
921 */
922 
923 /* Local Variables: */
924    char *cval;
925    char *name;
926    char *p;
927    char *unit;
928    char buff[ 50 ];
929    char code;
930    char keyword[ 20 ];
931    double dval;
932    int *dims;
933    int icol;
934    int idim;
935    int ival;
936    int nc;
937    int ncol;
938    int ndim;
939    int nel;
940    int repeat;
941    int type;
942    int wasset;
943 
944 /* Check the global error status. */
945    if ( !astOK ) return;
946 
947 /* Initialise */
948    type = AST__BADTYPE;
949 
950 /* Get the number of columns defined in the header. */
951    if( !astGetFitsI( header, "TFIELDS", &ncol ) ) ncol = 0;
952 
953 /* Add a column definition to the FitsTable for each column in the header. */
954    for( icol = 0; icol < ncol; icol++ ) {
955 
956 /* Get the TFORMi keyword that defines the column data type and shape from
957    the header. Report an error if it is missing. */
958       sprintf( keyword, "TFORM%d", icol + 1 );
959       if( !astGetFitsS( header, keyword, &cval ) && astOK ) {
960          astError( AST__NOFTS, "astFitsTable: Supplied FITS binary table "
961                    "header does not contain the required keyword '%s'.",
962                    status, keyword );
963       }
964 
965 /* Extract the repeat count and data type code from the TFORM string. */
966       if( sscanf( cval, "%d%n", &repeat, &nc ) == 0 ) {
967          repeat = 1;
968          nc = 0;
969       } else if( repeat < 0 && astOK ) {
970          astError( AST__BDFTS, "astFitsTable: Keyword '%s' in supplied FITS "
971                    "binary table header has unsupported value '%s'.", status,
972                    keyword, cval );
973       }
974       code = cval[ nc ];
975 
976 /* Get the corresponding KeyMap data type. Report an error if the FITS
977    data type is not supported by the KeyMap class. */
978       if( code == 'B' ) {
979          type = AST__BYTETYPE;
980 
981       } else if( code == 'I' ) {
982          type = AST__SINTTYPE;
983 
984       } else if( code == 'J' ) {
985          type = AST__INTTYPE;
986 
987       } else if( code == 'D' ) {
988          type = AST__DOUBLETYPE;
989 
990       } else if( code == 'E' ) {
991          type = AST__FLOATTYPE;
992 
993       } else if( code == 'A' ) {
994          type = AST__STRINGTYPE;
995 
996       } else if( astOK ){
997          astError( AST__BDFTS, "astFitsTable: Keyword '%s' in supplied FITS "
998                    "binary table header has unsupported value '%s'.", status,
999                    keyword, cval );
1000       }
1001 
1002 /* The TTYPEi keyword gives the column name. Create a column name based
1003    on the index of the column. */
1004       sprintf( keyword, "TTYPE%d", icol + 1 );
1005       if( !astGetFitsS( header, keyword, &cval ) ) {
1006          sprintf( buff, "FCOLUMN%d", icol + 1 );
1007          cval = buff;
1008       }
1009       name = astStore( NULL, cval, strlen( cval ) + 1 );
1010 
1011 /* Column units. */
1012       sprintf( keyword, "TUNIT%d", icol + 1 );
1013       if( !astGetFitsS( header, keyword, &cval ) ) {
1014          buff[ 0 ] = 0;
1015          cval = buff;
1016       }
1017       unit = astStore( NULL, cval, strlen( cval ) + 1 );
1018 
1019 /* Column shape is defined by the TDIMi keyword - in the form
1020    "(i,j,k,...)". where i, j, k ... are the dimensions. If it is missing
1021    then the field is assumed to be a 1D vector with the length specified by
1022    the repeat count in the TFORMn keyword, or a scalar (if repeat cound
1023    is one). */
1024       sprintf( keyword, "TDIM%d", icol + 1 );
1025       if( astGetFitsS( header, keyword, &cval ) ) {
1026 
1027 /* Count the commas in the keyword value. This equals one less than the
1028    number of dimensions. */
1029          ndim = 1;
1030          p = cval;
1031          while( *p ) {
1032             if( *(p++) == ',' ) ndim++;
1033          }
1034 
1035 /* Allocate memory for the dimensions. */
1036          dims = astMalloc( ndim*sizeof( int ) );
1037 
1038 /* Find each dimension and copy it into the above memory. Also find the
1039    total number of elements (nel). */
1040          nel = 1;
1041          idim = 0;
1042          p = cval;
1043          if( *p == '(' ) p++;
1044          while( sscanf( p, "%d%n", dims + idim, &nc ) ) {
1045             nel *= dims[ idim ];
1046             idim++;
1047             p += nc;
1048             if( *p == ',' ) p++;
1049          }
1050 
1051 /* For strings, the first TDIM value gives the length of the string, so
1052    reduce the number of dimensions by one. */
1053          if( type == AST__STRINGTYPE ) {
1054             ndim--;
1055             dims++;
1056          }
1057 
1058       } else {
1059          nel = repeat;
1060          if( nel == 1 ) {
1061             ndim = 0;
1062             dims = NULL;
1063          } else {
1064             ndim = 1;
1065             dims = astMalloc( sizeof( int ) );
1066             if( dims ) *dims = nel;
1067          }
1068       }
1069 
1070 /* Check the total number of elements equal the repeat count from the
1071    TFORM keyword. */
1072       if( repeat != nel && astOK ) {
1073 
1074          sprintf( keyword, "TFORM%d", icol + 1 );
1075          astGetFitsS( header, keyword, &cval );
1076          strcpy( buff, cval );
1077 
1078          sprintf( keyword, "TDIM%d", icol + 1 );
1079          if( !astGetFitsS( header, keyword, &cval ) ) cval = " ";
1080 
1081          astError( AST__BDFTS, "astFitsTable: Supplied FITS binary table "
1082                    "header contains inconsistent TFORM (%s) and TDIM (%s) "
1083                    "keywords for field %d.", status, buff, cval, icol + 1 );
1084       }
1085 
1086 /* Check any TSCALi value is 1.0 */
1087       sprintf( keyword, "TSCAL%d", icol + 1 );
1088       if( astGetFitsF( header, keyword, &dval ) && dval != 1.0 && astOK ) {
1089          astError( AST__BDFTS, "astFitsTable: Supplied FITS binary table "
1090                    "header contains scaled columns which are not "
1091                    "supported by AST.", status );
1092       }
1093 
1094 /* Check any TZEROi value is 0.0 */
1095       sprintf( keyword, "TSCAL%d", icol + 1 );
1096       if( astGetFitsF( header, keyword, &dval ) && dval != 0.0 && astOK ) {
1097          astError( AST__BDFTS, "astFitsTable: Supplied FITS binary table "
1098                    "header contains scaled columns which are not "
1099                    "supported by AST.", status );
1100       }
1101 
1102 /* Add the column to the table. */
1103       astAddColumn( this, name, type, ndim, dims, unit );
1104 
1105 /* Set the null value, if present. */
1106       sprintf( keyword, "TNULL%d", icol + 1 );
1107       if( astGetFitsI( header, keyword, &ival ) ) {
1108          (void) astColumnNull( this, name, 1, ival, &wasset, NULL );
1109       }
1110 
1111 /* Free resources. */
1112       dims = astFree( dims - ( ( type == AST__STRINGTYPE ) ? 1 : 0 ) );
1113       name = astFree( name );
1114       unit = astFree( unit );
1115 
1116    }
1117 }
1118 
GetColumnData(AstFitsTable * this,const char * column,float fnull,double dnull,size_t mxsize,void * coldata,int * nelem,int * status)1119 static void GetColumnData( AstFitsTable *this, const char *column,
1120                            float fnull, double dnull, size_t mxsize,
1121                            void *coldata, int *nelem, int *status ){
1122 /*
1123 *++
1124 *  Name:
1125 c     astGetColumnData
1126 f     AST_GETCOLUMNDATA
1127 
1128 *  Purpose:
1129 *     Retrieve all the data values stored in a column.
1130 
1131 *  Type:
1132 *     Public virtual function.
1133 
1134 *  Synopsis:
1135 c     #include "frameset.h"
1136 c     void astGetColumnData( AstFitsTable *this, const char *column,
1137 c                            float fnull, double dnull, size_t mxsize,
1138 c                            void *coldata, int *nelem )
1139 f     CALL AST_GETCOLUMNDATA( THIS, COLUMN, RNULL, DNULL, MXSIZE,
1140 f                             COLDATA, NELEM, STATUS )
1141 
1142 *  Class Membership:
1143 *     FitsTable method.
1144 
1145 *  Description:
1146 c     This function
1147 f     This routine
1148 *     copies all data values from a named column into a supplied buffer
1149 
1150 *  Parameters:
1151 c     this
1152 f     THIS = INTEGER (Given)
1153 *        Pointer to the FitsTable.
1154 c     column
1155 f     COLUMN = CHARACTER * ( * ) (Given)
1156 *        The character string holding the name of the column. Trailing
1157 *        spaces are ignored.
1158 c     fnull
1159 f     RNULL = REAL (Given)
1160 *        The value to return in
1161 c        "coldata"
1162 f        COLDATA
1163 *        for any cells for which no value has been stored in the
1164 *        FitsTable. Ignored if the column's data type is not
1165 *        AST__FLOATTYPE. Supplying
1166 c        AST__NANF
1167 f        AST__NANR
1168 *        will cause a single precision IEEE NaN value to be used.
1169 c     dnull
1170 f     DNULL = REAL (Given)
1171 *        The value to return in
1172 c        "coldata"
1173 f        COLDATA
1174 *        for any cells for which no value has been stored in the
1175 *        FitsTable. Ignored if the column's data type is not
1176 *        AST__DOUBLETYPE. Supplying AST__NAN will cause a double precision
1177 *        IEEE NaN value to be used.
1178 c     mxsize
1179 f     MXSIZE = INTEGER (Given)
1180 *        The size of the
1181 c        "coldata"
1182 f        COLDATA
1183 *        array, in bytes. The amount of memory needed to hold the data
1184 *        from a column may be determined using
1185 c        astColumnSize.
1186 f        AST_COLUMNSIZE.
1187 *        If the supplied array is too small to hold all the column data,
1188 *        trailing column values will be omitted from the returned array,
1189 *        but no error will be reported.
1190 c     coldata
1191 f     COLDATA( * ) = BYTE (Given)
1192 c        A pointer to an
1193 f        An
1194 *        area of memory in which to return the data
1195 *        values currently stored in the column. The values are stored in
1196 *        row order. If the column holds non-scalar values, the elements
1197 *        of each value are stored in "Fortran" order. No data type
1198 *        conversion is performed - the data type of each returned value
1199 *        is the data type associated with the column when the column was
1200 *        added to the table. If the column holds strings, the returned
1201 *        strings will be null terminated. Any excess room at the end of
1202 *        the array will be left unchanged.
1203 c     nelem
1204 f     NELEM = INTEGER (Return)
1205 *        The number of elements returned in the
1206 c        "coldata"
1207 f        COLDATA
1208 *        array. This is the product of the number of rows returned and
1209 *        the number of elements in each column value.
1210 f     STATUS = INTEGER (Given and Returned)
1211 f        The global status.
1212 
1213 *  Notes:
1214 f     - The RNULL and DNULL arguments
1215 c     - The "fnull" and "dnull" parameters
1216 *     specify the value to be returned for any empty cells within columns
1217 *     holding floating point values. For columns holding integer values,
1218 *     the value returned for empty cells is the value returned by the
1219 c     astColumNull function.
1220 f     AST_COLUMNNULL functiom.
1221 *     For columns holding string values, the ASCII NULL character is returned
1222 *     for empty cells.
1223 *--
1224 */
1225 
1226 /* Local Variables: */
1227    char *cbuf;       /* Array of strings returned by astMapGet1C */
1228    char key[ AST__MXCOLKEYLEN + 1 ]; /* Current cell key string */
1229    int iel;          /* Index of current element */
1230    int irow;         /* Index of value being copied */
1231    int nel;          /* No. of elements per value */
1232    int nrow;         /* No. of values to copy */
1233    int nval;         /* Number of values read from KeyMap entry */
1234    int ok;           /* Was the value found in the KeyMap? */
1235    int type;         /* Data type */
1236    int wasset;       /* Was the integer null value set explicitly? */
1237    size_t nb;        /* No. of bytes for a single element of a value */
1238    size_t nbv;       /* No. of bytes per value */
1239    void *pnull;      /* Pointer to a buffer holding a null value */
1240    void *pout;       /* Pointer to next output element */
1241 
1242 /* Initialise */
1243    *nelem = 0;
1244 
1245 /* Check the global error status. */
1246    if ( !astOK ) return;
1247 
1248 /* Initialise */
1249    nb = 0;
1250 
1251 /* Find the number of bytes needed to hold a single element of the value
1252    in a column cell. */
1253    type = astGetColumnType( this, column );
1254    if( type == AST__INTTYPE ) {
1255       nb = sizeof( int );
1256 
1257    } else if( type == AST__DOUBLETYPE ){
1258       nb = sizeof( double );
1259 
1260    } else if( type == AST__STRINGTYPE ){
1261       nb = astGetColumnLenC( this, column )*sizeof( char );
1262 
1263    } else if( type == AST__FLOATTYPE ){
1264       nb = sizeof( float );
1265 
1266    } else if( type == AST__SINTTYPE ){
1267       nb = sizeof( short int );
1268 
1269    } else if( type == AST__BYTETYPE ){
1270       nb = sizeof( char );
1271 
1272    } else if( astOK ) {
1273       astError( AST__INTER, "astGetColumnData(%s): Unsupported column type "
1274                 "%d (internal AST programming error).", status,
1275                 astGetClass( this ), type );
1276    }
1277 
1278 /* Get the number of elements per value, and the number of bytes per value. */
1279    nel = astGetColumnLength( this, column );
1280    nbv = nb*nel;
1281 
1282 /* Initialise a pointer to the next element of the output array to write to. */
1283    pout = coldata;
1284 
1285 /* Get the number of rows in the table. */
1286    nrow = astGetNrow( this );
1287 
1288 /* For string columns, the buffer returned by astMapGet1C will include a
1289    null character at the end of each string. This is not required for the
1290    fixed-length string format used by FITS binary tables, so for each row we
1291    produce a copy of the string returned by astMapGet1C excluding the
1292    trailing nulls. Allocate a buffer to receive the string returned by
1293    astMapGet1C. */
1294    if(  type == AST__STRINGTYPE ) {
1295       cbuf = astMalloc( ( nb + 1 )*nel );
1296    } else {
1297       cbuf = NULL;
1298    }
1299 
1300 /* If required, substitute NaN values for the supplied null values. */
1301    fnull = astCheckNaNF( fnull );
1302    dnull = astCheckNaN( dnull );
1303 
1304 /* Indicate we have not yet determined a null value for the column */
1305    pnull = NULL;
1306 
1307 /* Reduce the number of rows to be returned if the returned array is too
1308    small to hold all rows. */
1309    if( mxsize < nbv*nrow ) nrow = mxsize/nbv;
1310 
1311 /* Loop round the returned rows rows. */
1312    for( irow = 1; irow <= nrow; irow++ ) {
1313 
1314 /* Format the cell name. */
1315       (void) MakeKey( column, irow, key, AST__MXCOLKEYLEN + 1,
1316                       status );
1317 
1318 /* Get the values in the current cell of the column, using its native
1319    data type. For floating point, convert any NaNs into the appropriate
1320    null value (do not need to do this if the null value is itself NaN). */
1321       if( type == AST__INTTYPE ) {
1322          ok = astMapGet1I( this, key, nel, &nval, pout );
1323 
1324       } else if(  type == AST__DOUBLETYPE ){
1325          ok = astMapGet1D( this, key, nel, &nval, pout );
1326 
1327          if( ok && astISFINITE(dnull) ) {
1328             for( iel = 0; iel < nel; iel++ ) {
1329                if( !astISFINITE( ((double *)pout)[ iel ] ) ) {
1330                   ((double *)pout)[ iel ] = dnull;
1331                }
1332             }
1333          }
1334 
1335       } else if(  type == AST__FLOATTYPE ){
1336          ok = astMapGet1F( this, key, nel, &nval, pout );
1337 
1338          if( ok && astISFINITE(fnull) ) {
1339             for( iel = 0; iel < nel; iel++ ) {
1340                if( !astISFINITE( ((float *)pout)[ iel ] ) ) {
1341                   ((float *)pout)[ iel ] = fnull;
1342                }
1343             }
1344          }
1345 
1346       } else if(  type == AST__SINTTYPE ){
1347          ok = astMapGet1S( this, key, nel, &nval, pout );
1348 
1349       } else if(  type == AST__BYTETYPE ){
1350          ok = astMapGet1B( this, key, nel, &nval, pout );
1351 
1352       } else if(  type == AST__STRINGTYPE ){
1353          ok = astMapGet1C( this, key, nb + 1, nel, &nval, cbuf );
1354 
1355 /* Copy the strings returned by astMapGet1C into the returned array,
1356    omitting the trailing null at the end of each string. */
1357          CopyStrings( nval, nb, cbuf, pout, status );
1358 
1359       } else {
1360          ok = 0;
1361       }
1362 
1363 /* If the cell could not be found, return a suitable number of column null
1364    values. */
1365       if( !ok ) {
1366 
1367 /* Determine the null value to use, if this has not already been done. */
1368          if( !pnull ) {
1369 
1370 /* Allocate a buffer to hold a single null value */
1371             pnull = astMalloc( nb );
1372             if( astOK ) {
1373 
1374 /* Copy the appropriate null value into the buffer allocated above. */
1375                if( type == AST__INTTYPE ) {
1376                   *( (int *) pnull ) = astColumnNull( this, column, 0, 0,
1377                                                       &wasset, NULL );
1378                } else if(  type == AST__DOUBLETYPE ){
1379                   *( (double *) pnull ) = dnull;
1380 
1381                } else if(  type == AST__FLOATTYPE ){
1382                   *( (float *) pnull ) = fnull;
1383 
1384                } else if(  type == AST__STRINGTYPE ){
1385                   memset( pnull, 0, nb );
1386 
1387                } else if(  type == AST__SINTTYPE ){
1388                   *( (short int *) pnull ) = astColumnNull( this, column, 0, 0,
1389                                                             &wasset, NULL );
1390                } else if(  type == AST__BYTETYPE ){
1391                   *( (unsigned char *) pnull ) = astColumnNull( this, column, 0, 0,
1392                                                                 &wasset, NULL );
1393                }
1394             }
1395          }
1396 
1397 /* Append the right number of nulls to the returned array. */
1398          for( iel = 0; iel < nel; iel++ ) {
1399             memcpy( pout, pnull, nb );
1400             pout += nb;
1401          }
1402 
1403 /* If the cell was found in the table, just increment the pointer to the next
1404    returned value. */
1405       } else {
1406          pout += nbv;
1407       }
1408    }
1409 
1410 /* Free resources. */
1411    cbuf = astFree( cbuf );
1412    pnull = astFree( pnull );
1413 
1414 /* Return the number of returned elements. */
1415    *nelem = nel*nrow;
1416 }
1417 
GetObjSize(AstObject * this_object,int * status)1418 static int GetObjSize( AstObject *this_object, int *status ) {
1419 /*
1420 *  Name:
1421 *     GetObjSize
1422 
1423 *  Purpose:
1424 *     Return the in-memory size of an Object.
1425 
1426 *  Type:
1427 *     Private function.
1428 
1429 *  Synopsis:
1430 *     #include "fitstable.h"
1431 *     int GetObjSize( AstObject *this, int *status )
1432 
1433 *  Class Membership:
1434 *     FitsTable member function (over-rides the astGetObjSize protected
1435 *     method inherited from the parent class).
1436 
1437 *  Description:
1438 *     This function returns the in-memory size of the supplied FitsTables,
1439 *     in bytes.
1440 
1441 *  Parameters:
1442 *     this
1443 *        Pointer to the FitsTable.
1444 *     status
1445 *        Pointer to the inherited status variable.
1446 
1447 *  Returned Value:
1448 *     The FitsTable size, in bytes.
1449 
1450 *  Notes:
1451 *     - A value of zero will be returned if this function is invoked
1452 *     with the global status set, or if it should fail for any reason.
1453 */
1454 
1455 /* Local Variables: */
1456    AstFitsTable *this;            /* Pointer to FitsTable structure */
1457    int result;                /* Result value to return */
1458 
1459 /* Initialise. */
1460    result = 0;
1461 
1462 /* Check the global error status. */
1463    if ( !astOK ) return result;
1464 
1465 /* Obtain a pointers to the FitsTable structure. */
1466    this = (AstFitsTable *) this_object;
1467 
1468 /* Invoke the GetObjSize method inherited from the parent Table class, and
1469    then add on any components of the class structure defined by this class
1470    which are stored in dynamically allocated memory. */
1471    result = (*parent_getobjsize)( this_object, status );
1472    result += astGetObjSize( this->header );
1473 
1474 /* If an error occurred, clear the result value. */
1475    if ( !astOK ) result = 0;
1476 
1477 /* Return the result, */
1478    return result;
1479 }
1480 
GetTableHeader(AstFitsTable * this,int * status)1481 static AstFitsChan *GetTableHeader( AstFitsTable *this, int *status ) {
1482 /*
1483 *++
1484 *  Name:
1485 c     astGetTableHeader
1486 f     AST_GetTableHeader
1487 
1488 *  Purpose:
1489 *     Get the FITS headers from a FitsTable.
1490 
1491 *  Type:
1492 *     Public virtual function.
1493 
1494 *  Synopsis:
1495 c     #include "frameset.h"
1496 c     AstFitsChan *astGetTableHeader( AstFitsTable *this )
1497 f     RESULT = AST_GETTABLEHEADER( THIS, STATUS )
1498 
1499 *  Class Membership:
1500 *     FitsTable method.
1501 
1502 *  Description:
1503 *     This function returns a pointer to a FitsChan holding copies of
1504 *     the FITS headers associated with a FitsTable.
1505 
1506 *  Parameters:
1507 c     this
1508 f     THIS = INTEGER (Given)
1509 *        Pointer to the FitsTable.
1510 f     STATUS = INTEGER (Given and Returned)
1511 f        The global status.
1512 
1513 *  Returned Value:
1514 c     astGetTableHeader()
1515 f     AST_GetTableHeader = INTEGER
1516 *        A pointer to a deep copy of the FitsChan stored within the
1517 *        FitsTable.
1518 
1519 *  Notes:
1520 *     - The returned pointer should be annulled using
1521 c     astAnnul
1522 f     AST_ANNUL
1523 *     when it is no longer needed.
1524 *     - Changing the contents of the returned FitsChan will have no effect
1525 *     on the FitsTable. To modify the FitsTable, the modified FitsChan must
1526 *     be stored in the FitsTable using
1527 c     astPutTableHeader.
1528 f     AST_PUTTABLEHEADER.
1529 
1530 *--
1531 */
1532 
1533 /* Check the global error status. */
1534    if ( !astOK ) return NULL;
1535 
1536 /* Ensure the fixed value headers are up-to-date in the FitsChan stored
1537    in the FitsTable. */
1538    UpdateHeader( this, "astGetTableHeader", status );
1539 
1540 /* Reset the current card to the first card. */
1541    astClearCard( this->header );
1542 
1543 /* Return a deep copy of the FitsChan. */
1544    return astCopy( this->header );
1545 }
1546 
astInitFitsTableVtab_(AstFitsTableVtab * vtab,const char * name,int * status)1547 void astInitFitsTableVtab_(  AstFitsTableVtab *vtab, const char *name, int *status ) {
1548 /*
1549 *+
1550 *  Name:
1551 *     astInitFitsTableVtab
1552 
1553 *  Purpose:
1554 *     Initialise a virtual function table for a FitsTable.
1555 
1556 *  Type:
1557 *     Protected function.
1558 
1559 *  Synopsis:
1560 *     #include "fitstable.h"
1561 *     void astInitFitsTableVtab( AstFitsTableVtab *vtab, const char *name )
1562 
1563 *  Class Membership:
1564 *     FitsTable vtab initialiser.
1565 
1566 *  Description:
1567 *     This function initialises the component of a virtual function
1568 *     table which is used by the FitsTable class.
1569 
1570 *  Parameters:
1571 *     vtab
1572 *        Pointer to the virtual function table. The components used by
1573 *        all ancestral classes will be initialised if they have not already
1574 *        been initialised.
1575 *     name
1576 *        Pointer to a constant null-terminated character string which contains
1577 *        the name of the class to which the virtual function table belongs (it
1578 *        is this pointer value that will subsequently be returned by the Object
1579 *        astClass function).
1580 *-
1581 */
1582 
1583 /* Local Variables: */
1584    astDECLARE_GLOBALS            /* Pointer to thread-specific global data */
1585    AstObjectVtab *object;        /* Pointer to Object component of Vtab */
1586    AstTableVtab *table;          /* Pointer to Table component of Vtab */
1587 
1588 /* Check the local error status. */
1589    if ( !astOK ) return;
1590 
1591 /* Get a pointer to the thread specific global data structure. */
1592    astGET_GLOBALS(NULL);
1593 
1594 /* Initialize the component of the virtual function table used by the
1595    parent class. */
1596    astInitTableVtab( (AstTableVtab *) vtab, name );
1597 
1598 /* Store a unique "magic" value in the virtual function table. This
1599    will be used (by astIsAFitsTable) to determine if an object belongs
1600    to this class.  We can conveniently use the address of the (static)
1601    class_check variable to generate this unique value. */
1602    vtab->id.check = &class_check;
1603    vtab->id.parent = &(((AstTableVtab *) vtab)->id);
1604 
1605 /* Initialise member function pointers. */
1606 /* ------------------------------------ */
1607 /* Store pointers to the member functions (implemented here) that provide
1608    virtual methods for this class. */
1609    vtab->GetTableHeader = GetTableHeader;
1610    vtab->PutTableHeader = PutTableHeader;
1611    vtab->ColumnNull = ColumnNull;
1612    vtab->ColumnSize = ColumnSize;
1613    vtab->GetColumnData = GetColumnData;
1614    vtab->PutColumnData = PutColumnData;
1615 
1616 /* Save the inherited pointers to methods that will be extended, and
1617    replace them with pointers to the new member functions. */
1618    object = (AstObjectVtab *) vtab;
1619    table = (AstTableVtab *) vtab;
1620 
1621    parent_equal = object->Equal;
1622    object->Equal = Equal;
1623 
1624    parent_getobjsize = object->GetObjSize;
1625    object->GetObjSize = GetObjSize;
1626 
1627 #if defined(THREAD_SAFE)
1628    parent_managelock = object->ManageLock;
1629    object->ManageLock = ManageLock;
1630 #endif
1631 
1632    parent_addcolumn = table->AddColumn;
1633    table->AddColumn = AddColumn;
1634 
1635 /* Declare the copy constructor, destructor and class dump function. */
1636    astSetCopy( vtab, Copy );
1637    astSetDelete( vtab, Delete );
1638    astSetDump( vtab, Dump, "FitsTable", "FITS binary table" );
1639 
1640 /* If we have just initialised the vtab for the current class, indicate
1641    that the vtab is now initialised, and store a pointer to the class
1642    identifier in the base "object" level of the vtab. */
1643    if( vtab == &class_vtab ) {
1644       class_init = 1;
1645       astSetVtabClassIdentifier( vtab, &(vtab->id) );
1646    }
1647 }
1648 
MakeKey(const char * column,int irow,char * buf,int len,int * status)1649 static char *MakeKey( const char *column, int irow, char *buf, int len,
1650                       int *status ){
1651 /*
1652 *  Name:
1653 *     MakeKey
1654 
1655 *  Purpose:
1656 *     Construct a key for a column cell from a column name and row number.
1657 
1658 *  Type:
1659 *     Private function.
1660 
1661 *  Synopsis:
1662 *     #include "fitstable.h"
1663 *     char *MakeKey( const char *column, int irow, char *buf, int len,
1664 *                    int *status )
1665 
1666 *  Class Membership:
1667 *     FitsTable member function
1668 
1669 *  Description:
1670 *     This function constructs a key for a column cell from a column name
1671 *     and row number. An error is reported if the buffer is too short.
1672 
1673 *  Parameters:
1674 *     column
1675 *        Pointer to the column name. Trailing white space is ignored.
1676 *     irow
1677 *        One-based index of the row.
1678 *     buf
1679 *        Pointer to a buffer in which to store the returned key.
1680 *     len
1681 *        The length of the buffer.
1682 *     status
1683 *        Pointer to the inherited status variable.
1684 
1685 *  Returned Value:
1686 *     A copy of "buf".
1687 
1688 */
1689 
1690 /* Local Variables: */
1691    char *result;
1692    char rbuf[ 40 ];
1693    int collen;
1694    int nc;
1695 
1696 /* Initialise. */
1697    result = buf;
1698 
1699 /* Check the global error status. */
1700    if ( !astOK ) return result;
1701 
1702 /* Format the column number. */
1703    nc = sprintf( rbuf, "%d", irow );
1704 
1705 /* Get the used length of the column name (i.e. excluding trailing white
1706    space). */
1707    collen = astChrLen( column );
1708 
1709 /* For the total length of the returned string. */
1710    nc += collen + 3;
1711 
1712 /* If the buffer is large enough, store the returned string. */
1713    if( len >= nc ) {
1714       sprintf( buf, "%.*s(%s)", collen, column, rbuf );
1715    } else {
1716       astError( AST__INTER, "MakeKey(FitsTable): Internal buffer is too "
1717                 "short to hold Table cell name '%.*s(%s)' (internal AST "
1718                 "programming error).", status, collen, column, rbuf );
1719    }
1720 
1721 /* Return the result, */
1722    return result;
1723 }
1724 
1725 #if defined(THREAD_SAFE)
ManageLock(AstObject * this_object,int mode,int extra,AstObject ** fail,int * status)1726 static int ManageLock( AstObject *this_object, int mode, int extra,
1727                        AstObject **fail, int *status ) {
1728 /*
1729 *  Name:
1730 *     ManageLock
1731 
1732 *  Purpose:
1733 *     Manage the thread lock on an Object.
1734 
1735 *  Type:
1736 *     Private function.
1737 
1738 *  Synopsis:
1739 *     #include "object.h"
1740 *     AstObject *ManageLock( AstObject *this, int mode, int extra,
1741 *                            AstObject **fail, int *status )
1742 
1743 *  Class Membership:
1744 *     FitsTable member function (over-rides the astManageLock protected
1745 *     method inherited from the parent class).
1746 
1747 *  Description:
1748 *     This function manages the thread lock on the supplied Object. The
1749 *     lock can be locked, unlocked or checked by this function as
1750 *     deteremined by parameter "mode". See astLock for details of the way
1751 *     these locks are used.
1752 
1753 *  Parameters:
1754 *     this
1755 *        Pointer to the Object.
1756 *     mode
1757 *        An integer flag indicating what the function should do:
1758 *
1759 *        AST__LOCK: Lock the Object for exclusive use by the calling
1760 *        thread. The "extra" value indicates what should be done if the
1761 *        Object is already locked (wait or report an error - see astLock).
1762 *
1763 *        AST__UNLOCK: Unlock the Object for use by other threads.
1764 *
1765 *        AST__CHECKLOCK: Check that the object is locked for use by the
1766 *        calling thread (report an error if not).
1767 *     extra
1768 *        Extra mode-specific information.
1769 *     fail
1770 *        If a non-zero function value is returned, a pointer to the
1771 *        Object that caused the failure is returned at "*fail". This may
1772 *        be "this" or it may be an Object contained within "this". Note,
1773 *        the Object's reference count is not incremented, and so the
1774 *        returned pointer should not be annulled. A NULL pointer is
1775 *        returned if this function returns a value of zero.
1776 *     status
1777 *        Pointer to the inherited status variable.
1778 
1779 *  Returned Value:
1780 *    A local status value:
1781 *        0 - Success
1782 *        1 - Could not lock or unlock the object because it was already
1783 *            locked by another thread.
1784 *        2 - Failed to lock a POSIX mutex
1785 *        3 - Failed to unlock a POSIX mutex
1786 *        4 - Bad "mode" value supplied.
1787 
1788 *  Notes:
1789 *     - This function attempts to execute even if an error has already
1790 *     occurred.
1791 */
1792 
1793 /* Local Variables: */
1794    AstFitsTable *this;         /* Pointer to FitsTable structure */
1795    int result;             /* Returned status value */
1796 
1797 /* Initialise */
1798    result = 0;
1799 
1800 /* Check the supplied pointer is not NULL. */
1801    if( !this_object ) return result;
1802 
1803 /* Obtain a pointers to the FitsTable structure. */
1804    this = (AstFitsTable *) this_object;
1805 
1806 /* Invoke the ManageLock method inherited from the parent class. */
1807    if( !result ) result = (*parent_managelock)( this_object, mode, extra,
1808                                                 fail, status );
1809 
1810 /* Invoke the astManageLock method on any Objects contained within
1811    the supplied Object. */
1812    if( !result ) result = astManageLock( this->header, mode, extra, fail );
1813 
1814    return result;
1815 
1816 }
1817 #endif
1818 
PurgeHeader(AstFitsTable * this,int * status)1819 static void PurgeHeader( AstFitsTable *this, int *status ) {
1820 /*
1821 *  Name:
1822 *     PurgeHeader
1823 
1824 *  Purpose:
1825 *     Remove fixed-value keywords from the table header.
1826 
1827 *  Type:
1828 *     Private function.
1829 
1830 *  Synopsis:
1831 *     void PurgeHeader( AstFitsTable *this, int *status )
1832 
1833 *  Description:
1834 *     This function ensures that the headers that are determined by the
1835 *     table contents or by the FITS standard do not exist in the header
1836 *     of the supplied FitsTable.
1837 
1838 *  Parameters:
1839 *     this
1840 *        Pointer to the FitsTable.
1841 *     status
1842 *        Pointer to inherited status.
1843 
1844 */
1845 
1846 /* Local Constants: */
1847 #define nfixed 14  /* Number of fixed-value keywords to check for */
1848 
1849 /* Local Variables: */
1850    int ifixed;
1851 
1852 /* A list of FITS keywords that have values that are fixed by the FITS
1853    standard or by the contents of the Table. */
1854    const char *fixed[] = { "XTENSION", "BITPIX", "NAXIS", "NAXIS1",
1855                            "NAXIS2", "PCOUNT", "GCOUNT", "TFIELDS",
1856                            "TFORM%d", "TTYPE%d", "TNULL%d", "THEAP",
1857                            "TDIM%d", "TUNIT%d" };
1858 
1859 /* Check the global error status. */
1860    if ( !astOK ) return;
1861 
1862 /* Remove headers that have fixed values. */
1863    for( ifixed = 0; ifixed < nfixed; ifixed++ ) {
1864       astClearCard( this->header );
1865       while( astFindFits( this->header, fixed[ ifixed ], NULL, 0 ) ) {
1866          astDelFits( this->header );
1867       }
1868    }
1869 
1870 /* Undefine local constants */
1871 #undef nfixed
1872 }
1873 
PutColumnData(AstFitsTable * this,const char * column,int clen,size_t size,void * coldata,int * status)1874 static void PutColumnData( AstFitsTable *this, const char *column,
1875                            int clen, size_t size, void *coldata, int *status ){
1876 /*
1877 *++
1878 *  Name:
1879 c     astPutColumnData
1880 f     AST_PUTCOLUMNDATA
1881 
1882 *  Purpose:
1883 *     Store new data values for all rows of a column.
1884 
1885 *  Type:
1886 *     Public virtual function.
1887 
1888 *  Synopsis:
1889 c     #include "frameset.h"
1890 c     void astPutColumnData( AstFitsTable *this, const char *column,
1891 c                            int clen, size_t size, void *coldata )
1892 f     CALL AST_PUTCOLUMNDATA( THIS, COLUMN, CLEN, SIZE, COLDATA, STATUS )
1893 
1894 *  Class Membership:
1895 *     FitsTable method.
1896 
1897 *  Description:
1898 c     This function
1899 f     This routine
1900 *     copies data values from a supplied buffer into a named column. The
1901 *     first element in the buffer becomes the first element in the first
1902 *     row of the column. If the buffer does not completely fill the
1903 *     column, then any trailing rows are filled with null values.
1904 
1905 *  Parameters:
1906 c     this
1907 f     THIS = INTEGER (Given)
1908 *        Pointer to the FitsTable.
1909 c     column
1910 f     COLUMN = CHARACTER * ( * ) (Given)
1911 *        The character string holding the name of the column. Trailing
1912 *        spaces are ignored.
1913 c     clen
1914 f     CLEN = INTEGER (Given)
1915 *        If the column holds character strings, then this must be set to
1916 *        the length of each fixed length string in the supplied array.
1917 *        This is often determined by the appropriate TFORMn keyword in
1918 *        the binary table header. The supplied value is ignored if the
1919 *        column does not hold character data.
1920 c     size
1921 f     SIZE = INTEGER (Given)
1922 *        The size of the
1923 c        "coldata"
1924 f        COLDATA
1925 *        array, in bytes. This should be an integer multiple of the
1926 *        number of bytes needed to hold the full vector value stored in a
1927 *        single cell of the column. An error is reported if this is not
1928 *        the case.
1929 c     coldata
1930 f     COLDATA( * ) = BYTE (Given)
1931 c        A pointer to an
1932 f        An
1933 *        area of memory holding the data to copy into the column. The values
1934 *        should be stored in row order. If the column holds non-scalar values,
1935 *        the elements of each value should be stored in "Fortran" order. No
1936 *        data type conversion is performed.
1937 f     STATUS = INTEGER (Given and Returned)
1938 f        The global status.
1939 
1940 *--
1941 */
1942 
1943 /* Local Variables: */
1944    char key[ AST__MXCOLKEYLEN + 1 ]; /* Current cell key string */
1945    char **carray;    /* Pointer to array of null terminated string pointers */
1946    int irow;         /* Index of value being copied */
1947    int iel;          /* Index of current element */
1948    int nel;          /* No. of elements per value */
1949    int nrow;         /* No. of values to copy */
1950    int type;         /* Data type */
1951    size_t nb;        /* No. of bytes for a single element of a value */
1952    size_t nbv;       /* No. of bytes per value */
1953    void *pin;        /* Pointer to next input array element */
1954 
1955 /* Check the global error status. */
1956    if ( !astOK ) return;
1957 
1958 /* Initialise */
1959    nb = 0;
1960 
1961 /* Find the number of bytes in the supplied array holding a single element
1962    of the value in a column cell. */
1963    type = astGetColumnType( this, column );
1964    if( type == AST__INTTYPE ) {
1965       nb = sizeof( int );
1966 
1967    } else if(  type == AST__DOUBLETYPE ){
1968       nb = sizeof( double );
1969 
1970    } else if(  type == AST__STRINGTYPE ){
1971       nb = clen*sizeof( char );
1972 
1973    } else if(  type == AST__FLOATTYPE ){
1974       nb = sizeof( float );
1975 
1976    } else if(  type == AST__SINTTYPE ){
1977       nb = sizeof( short int );
1978 
1979    } else if(  type == AST__BYTETYPE ){
1980       nb = sizeof( char );
1981 
1982    } else if( astOK ) {
1983       astError( AST__INTER, "astPutColumnData(%s): Unsupported column type "
1984                 "%d (internal AST programming error).", status,
1985                 astGetClass( this ), type );
1986    }
1987 
1988 /* Get the number of elements per value, and the number of bytes (in the
1989    supplied array) per value. */
1990    nel = astGetColumnLength( this, column );
1991    nbv = nb*nel;
1992 
1993 /* Initialise a pointer to the next element of the supplied array to read. */
1994    pin = coldata;
1995 
1996 /* Get the number of rows to copy from the supplied array. */
1997    nrow = nbv ? size / nbv : 0;
1998 
1999 /* As yet we have no array of null terminated character pointers. */
2000    carray = NULL;
2001 
2002 /* Report an error if the supplied array does not hold an exact number of
2003    column cells. */
2004    if( nrow*nbv != size && astOK ) {
2005       astError( AST__BADSIZ, "astPutColumnData(%s): The supplied array size "
2006                 "(%d bytes) is not an exact multiple of the size of one "
2007                 "column value (%d bytes).", status, astGetClass( this ),
2008                 (int) size, (int) nbv );
2009    }
2010 
2011 /* Loop round the rows to be copied. */
2012    for( irow = 1; irow <= nrow; irow++ ) {
2013 
2014 /* Format the cell name. */
2015       (void) MakeKey( column, irow, key, AST__MXCOLKEYLEN + 1,
2016                       status );
2017 
2018 /* Put the next value into the current cell of the column, using its native
2019    data type. Skip floating point values that are entirely NaN. */
2020       if( type == AST__INTTYPE ) {
2021          astMapPut1I( this, key, nel, pin, NULL );
2022 
2023       } else if(  type == AST__DOUBLETYPE ){
2024          for( iel = 0; iel < nel; iel++ ) {
2025             if( astISFINITE( ((double *)pin)[ iel ] ) ) {
2026                astMapPut1D( this, key, nel, pin, NULL );
2027                break;
2028             }
2029          }
2030 
2031       } else if(  type == AST__FLOATTYPE ){
2032          for( iel = 0; iel < nel; iel++ ) {
2033             if( astISFINITE( ((double *)pin)[ iel ] ) ) {
2034                astMapPut1F( this, key, nel, pin, NULL );
2035                break;
2036             }
2037          }
2038 
2039       } else if(  type == AST__SINTTYPE ){
2040          astMapPut1S( this, key, nel, pin, NULL );
2041 
2042       } else if(  type == AST__BYTETYPE ){
2043          astMapPut1B( this, key, nel, pin, NULL );
2044 
2045 /* If each cell in the column holds an array of strings, we need to
2046    convert the fixed length strings in the supplied array into an array
2047    of pointers to null terminated strings. */
2048       } else if(  type == AST__STRINGTYPE ){
2049          carray = astStringArray( pin, nel, clen );
2050          astMapPut1C( this, key, nel, (const char ** ) carray, NULL );
2051          carray = astFree( carray );
2052       }
2053 
2054 /* Increment the pointer to the next input value. */
2055       pin += nbv;
2056    }
2057 
2058 /* Remove any remaining cells already present in this column. */
2059    nrow = astGetNrow( this );
2060    for( ; irow <= nrow; irow++ ) {
2061       (void) MakeKey( column, irow, key, AST__MXCOLKEYLEN + 1,
2062                       status );
2063       astMapRemove( this, key );
2064    }
2065 }
2066 
PutTableHeader(AstFitsTable * this,AstFitsChan * header,int * status)2067 static void PutTableHeader( AstFitsTable *this, AstFitsChan *header,
2068                             int *status ) {
2069 /*
2070 *++
2071 *  Name:
2072 c     astPutTableHeader
2073 f     AST_PUTTABLEHEADER
2074 
2075 *  Purpose:
2076 *     Store new FITS headers in a FitsTable.
2077 
2078 *  Type:
2079 *     Public virtual function.
2080 
2081 *  Synopsis:
2082 c     #include "frameset.h"
2083 c     void astPutTableHeader( AstFitsTable *this, AstFitsChan *header )
2084 f     CALL AST_PUTTABLEHEADER( THIS, HEADER, STATUS )
2085 
2086 *  Class Membership:
2087 *     FitsTable method.
2088 
2089 *  Description:
2090 c     This function
2091 f     This routine
2092 *     stores new FITS headers in the supplied FitsTable. Any existing
2093 *     headers are first deleted.
2094 
2095 *  Parameters:
2096 c     this
2097 f     THIS = INTEGER (Given)
2098 *        Pointer to the FitsTable.
2099 c     header
2100 f     HEADER = INTEGER (Given)
2101 *        Pointer to a FitsChan holding the headers for the FitsTable.
2102 *        A deep copy of the supplied FitsChan is stored in the FitsTable,
2103 *        replacing the current FitsChan in the Fitstable. Keywords that
2104 *        are fixed either by the properties of the Table, or by the FITS
2105 *        standard, are removed from the copy (see "Notes:" below).
2106 f     STATUS = INTEGER (Given and Returned)
2107 f        The global status.
2108 
2109 *  Notes:
2110 *     - The attributes of the supplied FitsChan, together with any source
2111 *     and sink functions associated with the FitsChan, are copied to the
2112 *     FitsTable.
2113 *     - Values for the following keywords are generated automatically by
2114 *     the FitsTable (any values for these keywords in the supplied
2115 *     FitsChan will be ignored): "XTENSION", "BITPIX", "NAXIS", "NAXIS1",
2116 *     "NAXIS2", "PCOUNT", "GCOUNT", "TFIELDS", "TFORM%d", "TTYPE%d",
2117 *     "TNULL%d", "THEAP", "TDIM%d".
2118 
2119 *--
2120 */
2121 
2122 /* Check the global error status. */
2123    if ( !astOK ) return;
2124 
2125 /* Annul the existing FitsChan. */
2126    (void) astAnnul( this->header );
2127 
2128 /* Store a deep copy of the supplied FitsChan in the FitsTable. */
2129    this->header = astCopy( header );
2130 
2131 /* Remove headers that have fixed values. */
2132    PurgeHeader( this, status );
2133 }
2134 
UpdateHeader(AstFitsTable * this,const char * method,int * status)2135 static void UpdateHeader( AstFitsTable *this, const char *method,
2136                           int *status ) {
2137 /*
2138 *  Name:
2139 *     UpdateHeader
2140 
2141 *  Purpose:
2142 *     Ensure FITS headers accurately describe the current table contents.
2143 
2144 *  Type:
2145 *     Private function.
2146 
2147 *  Synopsis:
2148 *     void UpdateHeader( AstFitsTable *this, const char *method,
2149 *                        int *status )
2150 
2151 *  Description:
2152 *     This function ensures that the FITS headers that are determined by
2153 *     the table contents or by the FITS standard are up to date.
2154 
2155 *  Parameters:
2156 *     this
2157 *        Pointer to the FitsTable.
2158 *     method
2159 *        Pointer to a string holding the name of the method to include in
2160 *        error messages.
2161 *     status
2162 *        Pointer to inherited status.
2163 
2164 */
2165 
2166 /* Local Variables: */
2167    char *dimbuf;
2168    char buf[ 20 ];
2169    char code;
2170    char keyword[ 14 ];
2171    const char *unit;
2172    const char *name;
2173    int *dims;
2174    int hasNull;
2175    int icol;
2176    int idim;
2177    int nc;
2178    int ncol;
2179    int ndim;
2180    int nel;
2181    int null;
2182    int rowsize;
2183    int set;
2184    int slen;
2185    int type;
2186 
2187 /* Check inherited status */
2188    if( !astOK ) return;
2189 
2190 /* Remove any existing headers that will have values stored for them by
2191    this function. */
2192    PurgeHeader( this, status );
2193 
2194 /* Store headers that have fixed values regardless of the contents of the
2195    table. Rewind the FitsChan first so they go at the start of the header. */
2196    astClearCard( this->header );
2197    astSetFitsS( this->header, "XTENSION", "BINTABLE", NULL, 0 );
2198    astSetFitsI( this->header, "BITPIX", 8, NULL, 0 );
2199    astSetFitsI( this->header, "NAXIS", 2, NULL, 0 );
2200    astSetFitsI( this->header, "PCOUNT", 0, NULL, 0 );
2201    astSetFitsI( this->header, "GCOUNT", 1, NULL, 0 );
2202 
2203 /* The number of columns. */
2204    ncol = astGetNcolumn( this );
2205    astSetFitsI( this->header, "TFIELDS", ncol, NULL, 0 );
2206 
2207 /* Add column-specific keywords, one for each column in the Table. */
2208    dims = NULL;
2209    dimbuf = NULL;
2210    rowsize = 0;
2211    for( icol = 1; icol <= ncol && astOK; icol++ ){
2212 
2213 /* Get the name, type and shape of the current column. */
2214       name = astColumnName( this, icol );
2215       nel = astGetColumnLength( this, name );
2216       type = astGetColumnType( this, name );
2217       unit = astGetColumnUnit( this, name );
2218       ndim = astGetColumnNdim( this, name );
2219       dims = astGrow( dims, ndim, sizeof( int ) );
2220       if( astOK ) {
2221          astColumnShape( this, name, ndim, &ndim, dims );
2222 
2223 /* Get the FITS code that describes the column data type. Also increment
2224    the number of bytes (rowsize) used to describe a whole row. */
2225          slen = 0;
2226          code = ' ';
2227          if( type == AST__BYTETYPE ) {
2228             code = 'B';
2229             rowsize += nel;
2230 
2231          } else if( type == AST__SINTTYPE ) {
2232             code = 'I';
2233             rowsize += 2*nel;
2234 
2235          } else if( type == AST__INTTYPE ) {
2236             code = 'J';
2237             rowsize += 4*nel;
2238 
2239          } else if( type == AST__DOUBLETYPE ) {
2240             code = 'D';
2241             rowsize += 8*nel;
2242 
2243          } else if( type == AST__FLOATTYPE ) {
2244             code = 'E';
2245             rowsize += 4*nel;
2246 
2247          } else if( type == AST__STRINGTYPE ) {
2248             code = 'A';
2249 
2250 /* Use the maximum length of the strings in the current column (excluding
2251    null) to scale the FITS repeat count. */
2252             slen = astGetColumnLenC( this, name );
2253             nel *= slen;
2254             rowsize += nel;
2255 
2256 /* Report an error if the data type is not supported by FITS. */
2257          } else if( astOK ) {
2258             astError( AST__INTER, "%s(%s): Illegal type %d for column '%s' "
2259                       "in a %s (internal AST programming error).", status,
2260                       method, astGetClass( this ), type, name,
2261                       astGetClass( this ) );
2262          }
2263 
2264 /* Start the TFORMn keyword value. This is the number of values in each
2265    cell, and is not needed if the cell contains only one value. */
2266          nc = sprintf( buf, "%d", nel );
2267 
2268 /* Add the data type code to complete the TFORMn value, and store it in
2269    the FitsChan. */
2270          sprintf( buf + nc, "%c", code );
2271          sprintf( keyword, "TFORM%d", icol );
2272          astSetFitsS( this->header, keyword, buf, NULL, 0 );
2273 
2274 /* Column name. */
2275          sprintf( keyword, "TTYPE%d", icol );
2276          astSetFitsS( this->header, keyword, name, NULL, 0 );
2277 
2278 /* Column units. */
2279          if( astChrLen( unit ) ) {
2280             sprintf( keyword, "TUNIT%d", icol );
2281             astSetFitsS( this->header, keyword, unit, NULL, 0 );
2282          }
2283 
2284 /* Column null value (integer columns only). Only store a TNULLn keyword
2285    if the NULL attribute has been set for the column, or if the column
2286    contains missing (i.e. null) values. */
2287          if( type == AST__BYTETYPE || type == AST__SINTTYPE ||
2288              type == AST__INTTYPE ) {
2289             null = astColumnNull( this, name, 0, 0, &set, &hasNull );
2290             if( set || hasNull ) {
2291                sprintf( keyword, "TNULL%d", icol );
2292                astSetFitsI( this->header, keyword, null, NULL, 0 );
2293             }
2294          }
2295 
2296 /* Array dimensions (only needed for non-scalars). */
2297          if( ndim > 0 ) {
2298             dimbuf = astGrow( dimbuf, ndim, 15 );
2299             if( astOK ) {
2300 
2301 /* For strings, the first dimension is the length of the fixed-length
2302    strings that make up the array. */
2303                if( type != AST__STRINGTYPE ) {
2304                   nc = sprintf( dimbuf, "(%d", dims[ 0 ] );
2305                } else {
2306                   nc = sprintf( dimbuf, "(%d,%d", slen, dims[ 0 ] );
2307                }
2308 
2309 /* Append the second and subsequent dimensions to the buffer. */
2310                for( idim = 1; idim < ndim; idim++ ) {
2311                   nc += sprintf( dimbuf + nc, ",%d", dims[ idim ] );
2312                }
2313                sprintf( dimbuf + nc, ")" );
2314 
2315 /* Store the buffered string as the value for keyword TDIMn in the
2316    FitsChan. */
2317                sprintf( keyword, "TDIM%d", icol );
2318                astSetFitsS( this->header, keyword, dimbuf, NULL, 0 );
2319             }
2320          }
2321       }
2322    }
2323 
2324 /* Insert the NAXISi keywords into the header, following the NAXIS value
2325    (i.e. starting at card 4). */
2326    astSetCard( this->header, 4 );
2327    astSetFitsI( this->header, "NAXIS1", rowsize, NULL, 0 );
2328    astSetFitsI( this->header, "NAXIS2", astGetNrow( this ), NULL, 0 );
2329 
2330 /* Free resources. */
2331    dims = astFree( dims );
2332    dimbuf = astFree( dimbuf );
2333 }
2334 
2335 /* Functions which access class attributes. */
2336 /* ---------------------------------------- */
2337 /* Implement member functions to access the attributes associated with
2338    this class using the macros defined for this purpose in the
2339    "object.h" file. For a description of each attribute, see the class
2340    interface (in the associated .h file). */
2341 
2342 
2343 /* Copy constructor. */
2344 /* ----------------- */
Copy(const AstObject * objin,AstObject * objout,int * status)2345 static void Copy( const AstObject *objin, AstObject *objout, int *status ) {
2346 /*
2347 *  Name:
2348 *     Copy
2349 
2350 *  Purpose:
2351 *     Copy constructor for FitsTable objects.
2352 
2353 *  Type:
2354 *     Private function.
2355 
2356 *  Synopsis:
2357 *     void Copy( const AstObject *objin, AstObject *objout, int *status )
2358 
2359 *  Description:
2360 *     This function implements the copy constructor for FitsTable objects.
2361 
2362 *  Parameters:
2363 *     objin
2364 *        Pointer to the object to be copied.
2365 *     objout
2366 *        Pointer to the object being constructed.
2367 *     status
2368 *        Pointer to the inherited status variable.
2369 
2370 *  Returned Value:
2371 *     void
2372 
2373 *  Notes:
2374 *     -  This constructor makes a deep copy, including a copy of the component
2375 *     Mappings within the FitsTable.
2376 */
2377 
2378 /* Local Variables: */
2379    AstFitsTable *in;                /* Pointer to input FitsTable */
2380    AstFitsTable *out;               /* Pointer to output FitsTable */
2381 
2382 /* Check the global error status. */
2383    if ( !astOK ) return;
2384 
2385 /* Obtain pointers to the input and output FitsTables. */
2386    in = (AstFitsTable *) objin;
2387    out = (AstFitsTable *) objout;
2388 
2389 /* Make copies of the component Tables and store pointers to them in the
2390    output FitsTable structure. */
2391    out->header = astCopy( in->header );
2392 }
2393 
2394 
2395 /* Destructor. */
2396 /* ----------- */
Delete(AstObject * obj,int * status)2397 static void Delete( AstObject *obj, int *status ) {
2398 /*
2399 *  Name:
2400 *     Delete
2401 
2402 *  Purpose:
2403 *     Destructor for FitsTable objects.
2404 
2405 *  Type:
2406 *     Private function.
2407 
2408 *  Synopsis:
2409 *     void Delete( AstObject *obj, int *status )
2410 
2411 *  Description:
2412 *     This function implements the destructor for FitsTable objects.
2413 
2414 *  Parameters:
2415 *     obj
2416 *        Pointer to the object to be deleted.
2417 *     status
2418 *        Pointer to the inherited status variable.
2419 
2420 *  Returned Value:
2421 *     void
2422 
2423 *  Notes:
2424 *     This function attempts to execute even if the global error status is
2425 *     set.
2426 */
2427 
2428 /* Local Variables: */
2429    AstFitsTable *this;              /* Pointer to FitsTable */
2430 
2431 /* Obtain a pointer to the FitsTable structure. */
2432    this = (AstFitsTable *) obj;
2433 
2434 /* Annul the pointers to the component Tables. */
2435    this->header = astAnnul( this->header );
2436 
2437 }
2438 
2439 
2440 /* Dump function. */
2441 /* -------------- */
Dump(AstObject * this_object,AstChannel * channel,int * status)2442 static void Dump( AstObject *this_object, AstChannel *channel, int *status ) {
2443 /*
2444 *  Name:
2445 *     Dump
2446 
2447 *  Purpose:
2448 *     Dump function for FitsTable objects.
2449 
2450 *  Type:
2451 *     Private function.
2452 
2453 *  Synopsis:
2454 *     void Dump( AstObject *this, AstChannel *channel, int *status )
2455 
2456 *  Description:
2457 *     This function implements the Dump function which writes out data
2458 *     for the FitsTable class to an output Channel.
2459 
2460 *  Parameters:
2461 *     this
2462 *        Pointer to the FitsTable whose data are being written.
2463 *     channel
2464 *        Pointer to the Channel to which the data are being written.
2465 *     status
2466 *        Pointer to the inherited status variable.
2467 */
2468 
2469 /* Local Variables: */
2470    AstFitsTable *this;             /* Pointer to the FitsTable structure */
2471 
2472 /* Check the global error status. */
2473    if ( !astOK ) return;
2474 
2475 /* Obtain a pointer to the FitsTable structure. */
2476    this = (AstFitsTable *) this_object;
2477 
2478 /* Write out values representing the instance variables for the FitsTable
2479    class.  Note, the primitive data in the FitsTable will be written out
2480    by the parent Table Dump function. This function deals just with the
2481    extra information held in the FitsTable structure. */
2482 
2483 /* Write out the FITS header. */
2484    astWriteObject( channel, "Header", 1, 0, this->header, "FITS headers" );
2485 }
2486 
2487 
2488 
2489 
2490 
2491 
2492 
2493 
2494 
2495 
2496 /* Standard class functions. */
2497 /* ========================= */
2498 /* Implement the astIsAFitsTable and astCheckFitsTable functions using the macros
2499    defined for this purpose in the "object.h" header file. */
astMAKE_ISA(FitsTable,Table)2500 astMAKE_ISA(FitsTable,Table)
2501 astMAKE_CHECK(FitsTable)
2502 
2503 AstFitsTable *astFitsTable_( void *header_void, const char *options, int *status, ...) {
2504 /*
2505 *++
2506 *  Name:
2507 c     astFitsTable
2508 f     AST_FITSTABLE
2509 
2510 *  Purpose:
2511 *     Create a FitsTable.
2512 
2513 *  Type:
2514 *     Public function.
2515 
2516 *  Synopsis:
2517 c     #include "fitstable.h"
2518 c     AstFitsTable *astFitsTable( AstFitsChan *header, const char *options, ... )
2519 f     RESULT = AST_FITSTABLE( HEADER, OPTIONS, STATUS )
2520 
2521 *  Class Membership:
2522 *     FitsTable constructor.
2523 
2524 *  Description:
2525 *     This function creates a new FitsTable and optionally initialises
2526 *     its attributes.
2527 *
2528 *     The FitsTable class is a representation of a FITS binary table. It
2529 *     inherits from the Table class. The parent Table is used to hold the
2530 *     binary data of the main table, and a FitsChan is used to hold the FITS
2531 *     header. Note, there is no provision for binary data following the main
2532 *     table (such data is referred to as a "heap" in the FITS standard).
2533 *
2534 *     Note - it is not recommended to use the FitsTable class to store
2535 *     very large tables.
2536 
2537 *  Parameters:
2538 c     header
2539 f     HEADER = INTEGER (Given)
2540 *        Pointer to an optional FitsChan containing headers to be stored
2541 *        in the FitsTable.
2542 c        NULL
2543 f        AST__NULL
2544 *        may be supplied if the new FitsTable is to be left empty. If
2545 *        supplied, and if the headers describe columns of a FITS binary
2546 *        table, then equivalent (empty) columns are added to the FitsTable.
2547 *        Each column has the same index in the FitsTable that it has in
2548 *        the supplied header.
2549 c     options
2550 f     OPTIONS = CHARACTER * ( * ) (Given)
2551 c        Pointer to a null-terminated string containing an optional
2552 c        comma-separated list of attribute assignments to be used for
2553 c        initialising the new FitsTable. The syntax used is identical to
2554 c        that for the astSet function and may include "printf" format
2555 c        specifiers identified by "%" symbols in the normal way.
2556 f        A character string containing an optional comma-separated
2557 f        list of attribute assignments to be used for initialising the
2558 f        new FitsTable. The syntax used is identical to that for the
2559 f        AST_SET routine.
2560 c     ...
2561 c        If the "options" string contains "%" format specifiers, then
2562 c        an optional list of additional arguments may follow it in
2563 c        order to supply values to be substituted for these
2564 c        specifiers. The rules for supplying these are identical to
2565 c        those for the astSet function (and for the C "printf"
2566 c        function).
2567 f     STATUS = INTEGER (Given and Returned)
2568 f        The global status.
2569 
2570 *  Returned Value:
2571 c     astFitsTable()
2572 f     AST_FITSTABLE = INTEGER
2573 *        A pointer to the new FitsTable.
2574 
2575 *  Notes:
2576 *     - A null Object pointer (AST__NULL) will be returned if this
2577 c     function is invoked with the AST error status set, or if it
2578 f     function is invoked with STATUS set to an error value, or if it
2579 *     should fail for any reason.
2580 
2581 *  Status Handling:
2582 *     The protected interface to this function includes an extra
2583 *     parameter at the end of the parameter list described above. This
2584 *     parameter is a pointer to the integer inherited status
2585 *     variable: "int *status".
2586 
2587 *--
2588 */
2589 
2590 /* Local Variables: */
2591    astDECLARE_GLOBALS            /* Pointer to thread-specific global data */
2592    AstFitsTable *new;            /* Pointer to new FitsTable */
2593    AstFitsChan *header;          /* Pointer to header FitsChan */
2594    va_list args;                 /* Variable argument list */
2595 
2596 /* Get a pointer to the thread specific global data structure. */
2597    astGET_GLOBALS(NULL);
2598 
2599 /* Check the global status. */
2600    if ( !astOK ) return NULL;
2601 
2602 /* Obtain and validate pointers to the header FitsChan provided. */
2603    header = header_void ? astCheckFitsChan( header_void ) : NULL;
2604 
2605 /* Initialise the FitsTable, allocating memory and initialising the
2606    virtual function table as well if necessary. */
2607    new = astInitFitsTable( NULL, sizeof( AstFitsTable ), !class_init,
2608                            &class_vtab, "FitsTable", header );
2609 
2610 /* If successful, note that the virtual function table has been
2611    initialised. */
2612    if ( astOK ) {
2613       class_init = 1;
2614 
2615 /* Obtain the variable argument list and pass it along with the options string
2616    to the astVSet method to initialise the new FitsTable's attributes. */
2617       va_start( args, status );
2618       astVSet( new, options, NULL, args );
2619       va_end( args );
2620 
2621 /* If an error occurred, clean up by deleting the new object. */
2622       if ( !astOK ) new = astDelete( new );
2623    }
2624 
2625 /* Return a pointer to the new FitsTable. */
2626    return new;
2627 }
2628 
astFitsTableId_(void * header_void,const char * options,...)2629 AstFitsTable *astFitsTableId_( void *header_void, const char *options, ... ) {
2630 /*
2631 *  Name:
2632 *     astFitsTableId_
2633 
2634 *  Purpose:
2635 *     Create a FitsTable.
2636 
2637 *  Type:
2638 *     Private function.
2639 
2640 *  Synopsis:
2641 *     #include "fitstable.h"
2642 *     AstFitsTable *astFitsTableId_( AstFitsChan *header, const char *options, ... )
2643 
2644 *  Class Membership:
2645 *     FitsTable constructor.
2646 
2647 *  Description:
2648 *     This function implements the external (public) interface to the
2649 *     astFitsTable constructor function. It returns an ID value (instead
2650 *     of a true C pointer) to external users, and must be provided
2651 *     because astFitsTable_ has a variable argument list which cannot be
2652 *     encapsulated in a macro (where this conversion would otherwise
2653 *     occur).
2654 *
2655 *     The variable argument list also prevents this function from
2656 *     invoking astFitsTable_ directly, so it must be a re-implementation
2657 *     of it in all respects, except for the final conversion of the
2658 *     result to an ID value.
2659 
2660 *  Parameters:
2661 *     As for astFitsTable_.
2662 
2663 *  Returned Value:
2664 *     The ID value associated with the new FitsTable.
2665 */
2666 
2667 /* Local Variables: */
2668    astDECLARE_GLOBALS            /* Pointer to thread-specific global data */
2669    AstFitsChan *header;          /* Genuine C poitner to header FitsChan */
2670    AstFitsTable *new;            /* Pointer to new FitsTable */
2671    int *status;                  /* Pointer to inherited status value */
2672    va_list args;                 /* Variable argument list */
2673 
2674 /* Get a pointer to the inherited status value. */
2675    status = astGetStatusPtr;
2676 
2677 /* Get a pointer to the thread specific global data structure. */
2678    astGET_GLOBALS(NULL);
2679 
2680 /* Check the global status. */
2681    if ( !astOK ) return NULL;
2682 
2683 /* Obtain a FitsChan pointer from any ID supplied and validate the
2684    pointer to ensure it identifies a valid FitsChan. */
2685    header = header_void ? astCheckFitsChan( astMakePointer( header_void ) ) : NULL;
2686 
2687 /* Initialise the FitsTable, allocating memory and initialising the
2688    virtual function table as well if necessary. */
2689    new = astInitFitsTable( NULL, sizeof( AstFitsTable ), !class_init,
2690                            &class_vtab, "FitsTable", header );
2691 
2692 /* If successful, note that the virtual function table has been
2693    initialised. */
2694    if ( astOK ) {
2695       class_init = 1;
2696 
2697 /* Obtain the variable argument list and pass it along with the options string
2698    to the astVSet method to initialise the new FitsTable's attributes. */
2699       va_start( args, options );
2700       astVSet( new, options, NULL, args );
2701       va_end( args );
2702 
2703 /* If an error occurred, clean up by deleting the new object. */
2704       if ( !astOK ) new = astDelete( new );
2705    }
2706 
2707 /* Return an ID value for the new FitsTable. */
2708    return astMakeId( new );
2709 }
2710 
astInitFitsTable_(void * mem,size_t size,int init,AstFitsTableVtab * vtab,const char * name,AstFitsChan * header,int * status)2711 AstFitsTable *astInitFitsTable_( void *mem, size_t size, int init,
2712                                  AstFitsTableVtab *vtab, const char *name,
2713                                  AstFitsChan *header, int *status ) {
2714 /*
2715 *+
2716 *  Name:
2717 *     astInitFitsTable
2718 
2719 *  Purpose:
2720 *     Initialise a FitsTable.
2721 
2722 *  Type:
2723 *     Protected function.
2724 
2725 *  Synopsis:
2726 *     #include "fitstable.h"
2727 *     AstFitsTable *astInitFitsTable( void *mem, size_t size, int init,
2728 *                                     AstFitsTableVtab *vtab, const char *name,
2729 *                                     AstFitsChan *header )
2730 
2731 *  Class Membership:
2732 *     FitsTable initialiser.
2733 
2734 *  Description:
2735 *     This function is provided for use by class implementations to initialise
2736 *     a new FitsTable object. It allocates memory (if necessary) to accommodate
2737 *     the FitsTable plus any additional data associated with the derived class.
2738 *     It then initialises a FitsTable structure at the start of this memory. If
2739 *     the "init" flag is set, it also initialises the contents of a virtual
2740 *     function table for a FitsTable at the start of the memory passed via the
2741 *     "vtab" parameter.
2742 
2743 *  Parameters:
2744 *     mem
2745 *        A pointer to the memory in which the FitsTable is to be initialised.
2746 *        This must be of sufficient size to accommodate the FitsTable data
2747 *        (sizeof(FitsTable)) plus any data used by the derived class. If a value
2748 *        of NULL is given, this function will allocate the memory itself using
2749 *        the "size" parameter to determine its size.
2750 *     size
2751 *        The amount of memory used by the FitsTable (plus derived class data).
2752 *        This will be used to allocate memory if a value of NULL is given for
2753 *        the "mem" parameter. This value is also stored in the FitsTable
2754 *        structure, so a valid value must be supplied even if not required for
2755 *        allocating memory.
2756 *     init
2757 *        A logical flag indicating if the FitsTable's virtual function table is
2758 *        to be initialised. If this value is non-zero, the virtual function
2759 *        table will be initialised by this function.
2760 *     vtab
2761 *        Pointer to the start of the virtual function table to be associated
2762 *        with the new FitsTable.
2763 *     name
2764 *        Pointer to a constant null-terminated character string which contains
2765 *        the name of the class to which the new object belongs (it is this
2766 *        pointer value that will subsequently be returned by the astGetClass
2767 *        method).
2768 *     header
2769 *        If not NULL, a FitsChan that is used to populate the FitsTable
2770 *        with headers and columns.
2771 
2772 *  Returned Value:
2773 *     A pointer to the new FitsTable.
2774 
2775 *  Notes:
2776 *     -  A null pointer will be returned if this function is invoked with the
2777 *     global error status set, or if it should fail for any reason.
2778 *-
2779 */
2780 
2781 /* Local Variables: */
2782    AstFitsTable *new;              /* Pointer to new FitsTable */
2783 
2784 /* Check the global status. */
2785    if ( !astOK ) return NULL;
2786 
2787 /* If necessary, initialise the virtual function table. */
2788    if ( init ) astInitFitsTableVtab( vtab, name );
2789 
2790 /* Initialise. */
2791    new = NULL;
2792 
2793 /* Initialise a Table structure (the parent class) as the first component
2794    within the FitsTable structure, allocating memory if necessary. Specify that
2795    the Table should be defined in both the forward and inverse directions. */
2796    new = (AstFitsTable *) astInitTable( mem, size, 0, (AstTableVtab *) vtab,
2797                                      name );
2798    if ( astOK ) {
2799 
2800 /* Initialise the FitsTable data. */
2801 /* ---------------------------- */
2802       new->header = astFitsChan( NULL, NULL, " ", status );
2803 
2804 /* If a header was supplied, add equivalent columns to the FitsTable, and
2805    store the header. */
2806       if( header ) {
2807          GenerateColumns( new, header, status );
2808          PutTableHeader( new, header, status );
2809       }
2810 
2811 /* If an error occurred, clean up by deleting the new FitsTable. */
2812       if ( !astOK ) new = astDelete( new );
2813    }
2814 
2815 /* Return a pointer to the new FitsTable. */
2816    return new;
2817 }
2818 
astLoadFitsTable_(void * mem,size_t size,AstFitsTableVtab * vtab,const char * name,AstChannel * channel,int * status)2819 AstFitsTable *astLoadFitsTable_( void *mem, size_t size, AstFitsTableVtab *vtab,
2820                                  const char *name, AstChannel *channel,
2821                                  int *status ) {
2822 /*
2823 *+
2824 *  Name:
2825 *     astLoadFitsTable
2826 
2827 *  Purpose:
2828 *     Load a FitsTable.
2829 
2830 *  Type:
2831 *     Protected function.
2832 
2833 *  Synopsis:
2834 *     #include "fitstable.h"
2835 *     AstFitsTable *astLoadFitsTable( void *mem, size_t size, AstFitsTableVtab *vtab,
2836 *                                     const char *name, AstChannel *channel )
2837 
2838 *  Class Membership:
2839 *     FitsTable loader.
2840 
2841 *  Description:
2842 *     This function is provided to load a new FitsTable using data read
2843 *     from a Channel. It first loads the data used by the parent class
2844 *     (which allocates memory if necessary) and then initialises a
2845 *     FitsTable structure in this memory, using data read from the input
2846 *     Channel.
2847 *
2848 *     If the "init" flag is set, it also initialises the contents of a
2849 *     virtual function table for a FitsTable at the start of the memory
2850 *     passed via the "vtab" parameter.
2851 
2852 
2853 *  Parameters:
2854 *     mem
2855 *        A pointer to the memory into which the FitsTable is to be
2856 *        loaded.  This must be of sufficient size to accommodate the
2857 *        FitsTable data (sizeof(FitsTable)) plus any data used by derived
2858 *        classes. If a value of NULL is given, this function will
2859 *        allocate the memory itself using the "size" parameter to
2860 *        determine its size.
2861 *     size
2862 *        The amount of memory used by the FitsTable (plus derived class
2863 *        data).  This will be used to allocate memory if a value of
2864 *        NULL is given for the "mem" parameter. This value is also
2865 *        stored in the FitsTable structure, so a valid value must be
2866 *        supplied even if not required for allocating memory.
2867 *
2868 *        If the "vtab" parameter is NULL, the "size" value is ignored
2869 *        and sizeof(AstFitsTable) is used instead.
2870 *     vtab
2871 *        Pointer to the start of the virtual function table to be
2872 *        associated with the new FitsTable. If this is NULL, a pointer
2873 *        to the (static) virtual function table for the FitsTable class
2874 *        is used instead.
2875 *     name
2876 *        Pointer to a constant null-terminated character string which
2877 *        contains the name of the class to which the new object
2878 *        belongs (it is this pointer value that will subsequently be
2879 *        returned by the astGetClass method).
2880 *
2881 *        If the "vtab" parameter is NULL, the "name" value is ignored
2882 *        and a pointer to the string "FitsTable" is used instead.
2883 
2884 *  Returned Value:
2885 *     A pointer to the new FitsTable.
2886 
2887 *  Notes:
2888 *     - A null pointer will be returned if this function is invoked
2889 *     with the global error status set, or if it should fail for any
2890 *     reason.
2891 *-
2892 */
2893 
2894 /* Local Variables: */
2895    astDECLARE_GLOBALS            /* Pointer to thread-specific global data */
2896    AstFitsTable *new;                /* Pointer to the new FitsTable */
2897 
2898 /* Initialise. */
2899    new = NULL;
2900 
2901 /* Check the global error status. */
2902    if ( !astOK ) return new;
2903 
2904 /* Get a pointer to the thread specific global data structure. */
2905    astGET_GLOBALS(channel);
2906 
2907 /* If a NULL virtual function table has been supplied, then this is
2908    the first loader to be invoked for this FitsTable. In this case the
2909    FitsTable belongs to this class, so supply appropriate values to be
2910    passed to the parent class loader (and its parent, etc.). */
2911    if ( !vtab ) {
2912       size = sizeof( AstFitsTable );
2913       vtab = &class_vtab;
2914       name = "FitsTable";
2915 
2916 /* If required, initialise the virtual function table for this class. */
2917       if ( !class_init ) {
2918          astInitFitsTableVtab( vtab, name );
2919          class_init = 1;
2920       }
2921    }
2922 
2923 /* Invoke the parent class loader to load data for all the ancestral
2924    classes of the current one, returning a pointer to the resulting
2925    partly-built FitsTable. */
2926    new = astLoadTable( mem, size, (AstTableVtab *) vtab, name,
2927                          channel );
2928 
2929    if ( astOK ) {
2930 
2931 /* Read input data. */
2932 /* ================ */
2933 /* Request the input Channel to read all the input data appropriate to
2934    this class into the internal "values list". */
2935       astReadClassData( channel, "FitsTable" );
2936 
2937 /* Now read each individual data item from this list and use it to
2938    initialise the appropriate instance variable(s) for this class. */
2939 
2940 /* FitsChan holding table headers. */
2941       new->header = astReadObject( channel, "header", NULL );
2942 
2943 /* If an error occurred, clean up by deleting the new FitsTable. */
2944       if ( !astOK ) new = astDelete( new );
2945    }
2946 
2947 /* Return the new FitsTable pointer. */
2948    return new;
2949 }
2950 
2951 /* Virtual function interfaces. */
2952 /* ============================ */
2953 /* These provide the external interface to the virtual functions defined by
2954    this class. Each simply checks the global error status and then locates and
2955    executes the appropriate member function, using the function pointer stored
2956    in the object's virtual function table (this pointer is located using the
2957    astMEMBER macro defined in "object.h").
2958 
2959    Note that the member function may not be the one defined here, as it may
2960    have been over-ridden by a derived class. However, it should still have the
2961    same interface. */
2962 
astGetTableHeader_(AstFitsTable * this,int * status)2963 AstFitsChan *astGetTableHeader_( AstFitsTable *this, int *status ) {
2964    if ( !astOK ) return NULL;
2965    return (**astMEMBER(this,FitsTable,GetTableHeader))(this,status);
2966 }
2967 
astPutTableHeader_(AstFitsTable * this,AstFitsChan * header,int * status)2968 void astPutTableHeader_( AstFitsTable *this, AstFitsChan *header, int *status ) {
2969    if ( !astOK ) return;
2970    (**astMEMBER(this,FitsTable,PutTableHeader))(this,header,status);
2971 }
2972 
astColumnNull_(AstFitsTable * this,const char * column,int set,int newval,int * wasset,int * hasnull,int * status)2973 int astColumnNull_( AstFitsTable *this, const char *column, int set,
2974                     int newval, int *wasset, int *hasnull, int *status ){
2975    *wasset = 0;
2976    if( hasnull ) *hasnull = 0;
2977    if ( !astOK ) return 0;
2978    return (**astMEMBER(this,FitsTable,ColumnNull))(this,column,set,newval,wasset,hasnull,status);
2979 }
2980 
astColumnSize_(AstFitsTable * this,const char * column,int * status)2981 size_t astColumnSize_( AstFitsTable *this, const char *column, int *status ){
2982    if ( !astOK ) return 0;
2983    return (**astMEMBER(this,FitsTable,ColumnSize))(this,column,status);
2984 }
2985 
astGetColumnData_(AstFitsTable * this,const char * column,float fnull,double dnull,size_t mxsize,void * coldata,int * nelem,int * status)2986 void astGetColumnData_( AstFitsTable *this, const char *column, float fnull,
2987                         double dnull, size_t mxsize, void *coldata, int *nelem,
2988                         int *status ){
2989    if ( !astOK ) return;
2990    (**astMEMBER(this,FitsTable,GetColumnData))(this,column,fnull,dnull,mxsize,
2991                                                coldata,nelem,status);
2992 }
2993 
astPutColumnData_(AstFitsTable * this,const char * column,int clen,size_t size,void * coldata,int * status)2994 void astPutColumnData_( AstFitsTable *this, const char *column, int clen,
2995                         size_t size, void *coldata, int *status ){
2996    if ( !astOK ) return;
2997    (**astMEMBER(this,FitsTable,PutColumnData))(this,column,clen,size,coldata,status);
2998 }
2999 
3000 
3001 
3002 
3003 
3004 
3005 
3006 
3007