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