1
0
Fork 0
sattools/qfits/src/tfits.c

2747 lines
74 KiB
C

/*----------------------------------------------------------------------------*/
/**
@file tfits.c
@author Y. Jung
@date July 1999
@version $Revision: 1.60 $
@brief
FITS table handling
*/
/*----------------------------------------------------------------------------*/
/*
$Id: tfits.c,v 1.60 2005/07/20 11:54:42 yjung Exp $
$Author: yjung $
$Date: 2005/07/20 11:54:42 $
$Revision: 1.60 $
*/
/*-----------------------------------------------------------------------------
Includes
-----------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
#include "tfits.h"
#include "ieeefp-compat.h"
#include "fits_std.h"
#include "byteswap.h"
#include "simple.h"
#include "t_iso8601.h"
#include "config.h"
#include "fits_rw.h"
#include "fits_md5.h"
#include "xmemory.h"
#include "qerror.h"
/*-----------------------------------------------------------------------------
Define
-----------------------------------------------------------------------------*/
#define ELEMENT_MAX_DISPLAY_SIZE 50
/*-----------------------------------------------------------------------------
Function prototypes
-----------------------------------------------------------------------------*/
static char *qfits_bintable_field_to_string (qfits_table *, int, int, int);
static char *qfits_asciitable_field_to_string (qfits_table *, int, int, int);
static char *qfits_build_format (qfits_col *);
static int qfits_table_append_bin_xtension (FILE *, qfits_table *, void **);
static int qfits_table_append_ascii_xtension (FILE *, qfits_table *, void **);
static int qfits_table_append_data (FILE *, qfits_table *, void **);
static int qfits_table_get_field_size (int, qfits_col *);
static int qfits_table_interpret_type (char *, int *, int *, tfits_type *,
int);
static char *qfits_strstrip (char *);
static double qfits_str2dec (char *, int);
/*-----------------------------------------------------------------------------
Function codes
-----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
/**
@brief Identify a file as containing a FITS table in extension.
@param filename Name of the FITS file to examine.
@param xtnum Extension number to check (starting from 1).
@return int 1 if the extension contains a table, 0 else.
Examines the requested extension and identifies the presence of a FITS table.
*/
/*----------------------------------------------------------------------------*/
int
qfits_is_table (char *filename, int xtnum)
{
char *value;
int ttype;
ttype = QFITS_INVALIDTABLE;
value = qfits_query_ext (filename, "XTENSION", xtnum);
if (value == NULL)
return ttype;
value = qfits_pretty_string (value);
if (!strcmp (value, "TABLE"))
{
ttype = QFITS_ASCIITABLE;
}
else if (!strcmp (value, "BINTABLE"))
{
ttype = QFITS_BINTABLE;
}
return ttype;
}
/*----------------------------------------------------------------------------*/
/**
@brief Generate a default primary header to store tables
@return the header object
*/
/*----------------------------------------------------------------------------*/
qfits_header *
qfits_table_prim_header_default (void)
{
qfits_header *fh;
fh = qfits_header_new ();
qfits_header_append (fh, "SIMPLE", "T", "Standard FITS file", NULL);
qfits_header_append (fh, "BITPIX", "8", "ASCII or bytes array", NULL);
qfits_header_append (fh, "NAXIS", "0", "Minimal header", NULL);
qfits_header_append (fh, "EXTEND", "T", "There may be FITS ext", NULL);
qfits_header_append (fh, "BLOCKED", "T", "The file may be blocked", NULL);
qfits_header_append (fh, "END", NULL, NULL, NULL);
return fh;
}
/*----------------------------------------------------------------------------*/
/**
@brief Generate a default extension header to store tables
@return the header object
*/
/*----------------------------------------------------------------------------*/
qfits_header *
qfits_table_ext_header_default (qfits_table * t)
{
qfits_header *fh;
qfits_col *curr_col;
char str_val[FITS_LINESZ];
char str_val2[FITS_LINESZ];
char *date;
int tab_width;
int col_pos;
int i;
/* Compute the table width */
if ((tab_width = qfits_compute_table_width (t)) == -1)
{
qfits_error ("cannot get the table width");
return NULL;
}
/* Create fits header */
if ((fh = qfits_header_new ()) == NULL)
{
qfits_error ("cannot create new fits header");
return NULL;
}
/* Check the kind of table */
if (t->tab_t == QFITS_BINTABLE)
{
/* Write extension header */
qfits_header_append (fh, "XTENSION", "BINTABLE",
"FITS Binary Table Extension", NULL);
qfits_header_append (fh, "BITPIX", "8", "8-bits character format",
NULL);
qfits_header_append (fh, "NAXIS", "2", "Tables are 2-D char. array",
NULL);
sprintf (str_val, "%d", tab_width);
qfits_header_append (fh, "NAXIS1", str_val, "Bytes in row", NULL);
sprintf (str_val, "%d", (int) (t->nr));
qfits_header_append (fh, "NAXIS2", str_val, "No. of rows in table",
NULL);
qfits_header_append (fh, "PCOUNT", "0", "Parameter count always 0",
NULL);
qfits_header_append (fh, "GCOUNT", "1", "Group count always 1", NULL);
sprintf (str_val, "%d", (int) (t->nc));
qfits_header_append (fh, "TFIELDS", str_val, "No. of col in table",
NULL);
/* Columns descriptors */
curr_col = t->col;
for (i = 0; i < t->nc; i++)
{
sprintf (str_val, "TFORM%d", i + 1);
sprintf (str_val2, "'%s'", qfits_build_format (curr_col));
qfits_header_append (fh, str_val, str_val2, "Format of field",
NULL);
sprintf (str_val, "TTYPE%d", i + 1);
sprintf (str_val2, "%s", curr_col->tlabel);
qfits_header_append (fh, str_val, str_val2, "Field label", NULL);
sprintf (str_val, "TUNIT%d", i + 1);
sprintf (str_val2, "%s", curr_col->tunit);
qfits_header_append (fh, str_val, str_val2,
"Physical unit of field", NULL);
if (curr_col->zero_present)
{
sprintf (str_val, "TZERO%d", i + 1);
sprintf (str_val2, "%f", curr_col->zero);
qfits_header_append (fh, str_val, str_val2,
"NULL value is defined", NULL);
}
if (curr_col->scale_present)
{
sprintf (str_val, "TSCAL%d", i + 1);
sprintf (str_val2, "%f", curr_col->scale);
qfits_header_append (fh, str_val, str_val2, "Scaling applied",
NULL);
}
curr_col++;
}
qfits_header_append (fh, "ORIGIN", "ESO-QFITS", "Written by QFITS",
NULL);
date = qfits_get_datetime_iso8601 ();
sprintf (str_val, "'%s'", date);
qfits_header_append (fh, "DATE", str_val, "[UTC] Date of writing",
NULL);
qfits_header_append (fh, "END", NULL, NULL, NULL);
}
else if (t->tab_t == QFITS_ASCIITABLE)
{
/* Write extension header */
qfits_header_append (fh, "XTENSION", "TABLE",
"FITS ASCII Table Extension", NULL);
qfits_header_append (fh, "BITPIX", "8", "8-bits character format",
NULL);
qfits_header_append (fh, "NAXIS", "2", "ASCII table has 2 axes", NULL);
/* Fill the header */
sprintf (str_val, "%d", tab_width);
qfits_header_append (fh, "NAXIS1", str_val, "Characters in a row",
NULL);
sprintf (str_val, "%d", (int) (t->nr));
qfits_header_append (fh, "NAXIS2", str_val, "No. of rows in table",
NULL);
qfits_header_append (fh, "PCOUNT", "0", "No group parameters", NULL);
qfits_header_append (fh, "GCOUNT", "1", "Only one group", NULL);
sprintf (str_val, "%d", (int) (t->nc));
qfits_header_append (fh, "TFIELDS", str_val, "No. of col in table",
NULL);
qfits_header_append (fh, "ORIGIN", "ESO-QFITS", "Written by QFITS",
NULL);
date = qfits_get_datetime_iso8601 ();
sprintf (str_val, "'%s'", date);
qfits_header_append (fh, "DATE", str_val, "[UTC] Date of writing",
NULL);
/* Columns descriptors */
curr_col = t->col;
col_pos = 1;
for (i = 0; i < t->nc; i++)
{
sprintf (str_val, "TTYPE%d", i + 1);
sprintf (str_val2, "%s", curr_col->tlabel);
qfits_header_append (fh, str_val, str_val2, "Field label", NULL);
sprintf (str_val, "TFORM%d", i + 1);
sprintf (str_val2, "'%s'", qfits_build_format (curr_col));
qfits_header_append (fh, str_val, str_val2, "Format of field",
NULL);
sprintf (str_val, "TBCOL%d", i + 1);
sprintf (str_val2, "%d", col_pos);
qfits_header_append (fh, str_val, str_val2, "Start column of field",
NULL);
col_pos += curr_col->atom_nb;
sprintf (str_val, "TUNIT%d", i + 1);
sprintf (str_val2, "%s", curr_col->tunit);
qfits_header_append (fh, str_val, str_val2,
"Physical unit of field", NULL);
if (curr_col->zero_present)
{
sprintf (str_val, "TZERO%d", i + 1);
sprintf (str_val2, "%f", curr_col->zero);
qfits_header_append (fh, str_val, str_val2,
"NULL value is defined", NULL);
}
if (curr_col->scale_present)
{
sprintf (str_val, "TSCAL%d", i + 1);
sprintf (str_val2, "%f", curr_col->scale);
qfits_header_append (fh, str_val, str_val2, "Scaling applied",
NULL);
}
curr_col++;
}
qfits_header_append (fh, "END", NULL, NULL, NULL);
}
else
{
qfits_error ("Table type not known");
qfits_header_destroy (fh);
return NULL;
}
return fh;
}
/*----------------------------------------------------------------------------*/
/**
@brief Table object constructor
@param filename Name of the FITS file associated to the table
@param table_type Type of the table (QFITS_ASCIITABLE or QFITS_BINTABLE)
@param table_width Width in bytes of the table
@param nb_cols Number of columns
@param nb_raws Number of raws
@return The table object
The columns are also allocated. The object has to be freed with
qfits_table_close()
*/
/*----------------------------------------------------------------------------*/
qfits_table *
qfits_table_new (char *filename,
int table_type, int table_width, int nb_cols, int nb_raws)
{
qfits_table *qt;
qt = malloc (sizeof (qfits_table));
(void) strcpy (qt->filename, filename);
qt->tab_t = table_type;
qt->nc = nb_cols;
qt->nr = nb_raws;
qt->col = calloc (qt->nc, sizeof (qfits_col));
qt->tab_w = table_width;
return qt;
}
/*----------------------------------------------------------------------------*/
/**
@brief Fill a column object with some provided informations
@param qc Pointer to the column that has to be filled
@param unit Unit of the data
@param label Label of the column
@param disp Way to display the data
@param nullval Null value
@param atom_nb Number of atoms per field. According to the type, an atom
is a double, an int, a char, ...
@param atom_dec_nb Number of decimals as specified in TFORM
@param atom_size Size in bytes of the field for ASCII tables, and of
an atom for BIN tables. ASCII tables only contain 1
atom per field (except for A type where you can of
course have more than one char per field)
@param atom_type Type of data (11 types for BIN, 5 for ASCII)
@param zero_present Flag to use or not zero
@param zero Zero value
@param scale_present Flag to use or not scale
@param scale Scale value
@param offset_beg Gives the position of the column
@return -1 in error case, 0 otherwise
*/
/*----------------------------------------------------------------------------*/
int
qfits_col_fill (qfits_col * qc,
int atom_nb,
int atom_dec_nb,
int atom_size,
tfits_type atom_type,
char *label,
char *unit,
char *nullval,
char *disp,
int zero_present,
float zero, int scale_present, float scale, int offset_beg)
{
/* Number of atoms per column */
qc->atom_nb = atom_nb;
/* Number of decimals in a field in ASCII table (0 in BINTABLE) */
qc->atom_dec_nb = atom_dec_nb;
/* Size in bytes of an atom */
qc->atom_size = atom_size;
/* Data type in the column */
qc->atom_type = atom_type;
/* Label of the column */
(void) strcpy (qc->tlabel, label);
/* Unit of the column data */
(void) strcpy (qc->tunit, unit);
/* Null value */
(void) strcpy (qc->nullval, nullval);
/* How to display the data */
(void) strcpy (qc->tdisp, disp);
/* Default values for zero and scales */
qc->zero_present = zero_present;
qc->scale_present = scale_present;
qc->zero = zero;
qc->scale = scale;
/* Number of bytes between two consecutive fields of the same column */
qc->off_beg = offset_beg;
/* A column is a priori readable */
qc->readable = 1;
return 0;
}
/*----------------------------------------------------------------------------*/
/**
@brief Read a FITS extension.
@param filename Name of the FITS file to examine.
@param xtnum Extension number to read (starting from 1).
@return Pointer to newly allocated qfits_table structure.
Read a FITS table from a given file name and extension, and return a
newly allocated qfits_table structure.
*/
/*----------------------------------------------------------------------------*/
qfits_table *
qfits_table_open (char *filename, int xtnum)
{
qfits_table *tload;
qfits_col *curr_col;
char *str_val;
char keyword[FITSVALSZ];
/* Table infos */
int table_type;
int nb_col;
int table_width;
int nb_raws;
/* Column infos */
char label[FITSVALSZ];
char unit[FITSVALSZ];
char disp[FITSVALSZ];
char nullval[FITSVALSZ];
int atom_nb;
int atom_dec_nb;
int atom_size;
tfits_type atom_type;
int offset_beg;
int data_size;
int theory_size;
int zero_present;
int scale_present;
float zero;
float scale;
/* For ASCII tables */
int col_pos;
int next_col_pos;
/* For X type */
int nb_bits;
int i;
/* See if 'filename' is a fits file */
if (is_fits_file (filename) != 1)
{
qfits_error ("[%s] is not FITS", filename);
return NULL;
}
/* Identify a table and get the table type : ASCII or BIN */
if ((table_type = qfits_is_table (filename, xtnum)) == 0)
{
qfits_error ("[%s] extension %d is not a table", filename, xtnum);
return NULL;
}
/* Get number of columns and allocate them: nc <-> TFIELDS */
if ((str_val = qfits_query_ext (filename, "TFIELDS", xtnum)) == NULL)
{
qfits_error ("cannot read TFIELDS in [%s]:[%d]", filename, xtnum);
return NULL;
}
nb_col = atoi (str_val);
/* Get the width in bytes of the table */
if ((str_val = qfits_query_ext (filename, "NAXIS1", xtnum)) == NULL)
{
qfits_error ("cannot read NAXIS1 in [%s]:[%d]", filename, xtnum);
return NULL;
}
table_width = atoi (str_val);
/* Get the number of raws */
if ((str_val = qfits_query_ext (filename, "NAXIS2", xtnum)) == NULL)
{
qfits_error ("cannot read NAXIS2 in [%s]:[%d]", filename, xtnum);
return NULL;
}
nb_raws = atoi (str_val);
/* Create the table object */
tload =
qfits_table_new (filename, table_type, table_width, nb_col, nb_raws);
/* Initialize offset_beg */
if (qfits_get_datinfo (filename, xtnum, &offset_beg, &data_size) != 0)
{
qfits_error ("cannot find data start in [%s]:[%d]", filename, xtnum);
qfits_table_close (tload);
return NULL;
}
/* Loop on all columns and get column descriptions */
curr_col = tload->col;
for (i = 0; i < tload->nc; i++)
{
/* label <-> TTYPE */
sprintf (keyword, "TTYPE%d", i + 1);
if ((str_val = qfits_query_ext (filename, keyword, xtnum)) == NULL)
{
label[0] = (char) 0;
}
else
strcpy (label, qfits_pretty_string (str_val));
/* unit <-> TUNIT */
sprintf (keyword, "TUNIT%d", i + 1);
if ((str_val = qfits_query_ext (filename, keyword, xtnum)) == NULL)
{
unit[0] = (char) 0;
}
else
strcpy (unit, qfits_pretty_string (str_val));
/* disp <-> TDISP */
sprintf (keyword, "TDISP%d", i + 1);
if ((str_val = qfits_query_ext (filename, keyword, xtnum)) == NULL)
{
disp[0] = (char) 0;
}
else
strcpy (disp, qfits_pretty_string (str_val));
/* nullval <-> TNULL */
sprintf (keyword, "TNULL%d", i + 1);
if ((str_val = qfits_query_ext (filename, keyword, xtnum)) == NULL)
{
nullval[0] = (char) 0;
}
else
strcpy (nullval, qfits_pretty_string (str_val));
/* atom_size, atom_nb, atom_dec_nb, atom_type <-> TFORM */
sprintf (keyword, "TFORM%d", i + 1);
if ((str_val = qfits_query_ext (filename, keyword, xtnum)) == NULL)
{
qfits_error ("cannot read [%s] in [%s]:[%d]", keyword, filename,
xtnum);
qfits_table_close (tload);
return NULL;
}
/* Interpret the type in header */
if (qfits_table_interpret_type (qfits_pretty_string (str_val),
&(atom_nb),
&(atom_dec_nb),
&(atom_type), table_type) == -1)
{
qfits_error ("cannot interpret the type: %s", str_val);
qfits_table_close (tload);
return NULL;
}
/* Set atom_size */
switch (atom_type)
{
case TFITS_BIN_TYPE_A:
case TFITS_BIN_TYPE_L:
case TFITS_BIN_TYPE_B:
atom_size = 1;
break;
case TFITS_BIN_TYPE_I:
atom_size = 2;
break;
case TFITS_BIN_TYPE_J:
case TFITS_BIN_TYPE_E:
case TFITS_ASCII_TYPE_I:
case TFITS_ASCII_TYPE_E:
case TFITS_ASCII_TYPE_F:
atom_size = 4;
break;
case TFITS_BIN_TYPE_C:
case TFITS_BIN_TYPE_P:
atom_size = 4;
atom_nb *= 2;
break;
case TFITS_BIN_TYPE_D:
case TFITS_ASCII_TYPE_D:
atom_size = 8;
break;
case TFITS_BIN_TYPE_M:
atom_size = 8;
atom_nb *= 2;
break;
case TFITS_BIN_TYPE_X:
atom_size = 1;
nb_bits = atom_nb;
atom_nb = (int) ((nb_bits - 1) / 8) + 1;
break;
case TFITS_ASCII_TYPE_A:
atom_size = atom_nb;
break;
default:
qfits_error ("unrecognized type");
qfits_table_close (tload);
return NULL;
break;
}
/* zero <-> TZERO */
sprintf (keyword, "TZERO%d", i + 1);
if ((str_val = qfits_query_ext (filename, keyword, xtnum)) != NULL)
{
zero = (float) atof (str_val);
zero_present = 1;
}
else
{
zero = (float) 0.0;
zero_present = 0;
}
/* scale <-> TSCAL */
sprintf (keyword, "TSCAL%d", i + 1);
if ((str_val = qfits_query_ext (filename, keyword, xtnum)) != NULL)
{
scale = (float) atof (str_val);
scale_present = 1;
}
else
{
scale = (float) 1.0;
scale_present = 0;
}
/* Fill the current column object */
qfits_col_fill (curr_col, atom_nb, atom_dec_nb, atom_size, atom_type,
label, unit, nullval, disp, zero_present, zero,
scale_present, scale, offset_beg);
/* Compute offset_beg but for the last column */
if (i < tload->nc - 1)
{
if (table_type == QFITS_ASCIITABLE)
{
/* column width <-> TBCOLi and TBCOLi+1 */
sprintf (keyword, "TBCOL%d", i + 1);
if ((str_val =
qfits_query_ext (filename, keyword, xtnum)) == NULL)
{
qfits_error ("cannot read [%s] in [%s]", keyword, filename);
qfits_table_close (tload);
return NULL;
}
col_pos = atoi (qfits_pretty_string (str_val));
sprintf (keyword, "TBCOL%d", i + 2);
if ((str_val =
qfits_query_ext (filename, keyword, xtnum)) == NULL)
{
qfits_error ("cannot read [%s] in [%s]", keyword, filename);
qfits_table_close (tload);
return NULL;
}
next_col_pos = atoi (qfits_pretty_string (str_val));
offset_beg += (int) (next_col_pos - col_pos);
}
else if (table_type == QFITS_BINTABLE)
{
offset_beg += atom_nb * atom_size;
}
}
curr_col++;
}
/* Check that the theoritical data size is not far from the measured */
/* one by more than 2880 */
theory_size = qfits_compute_table_width (tload) * tload->nr;
if (data_size < theory_size)
{
qfits_error ("Uncoherent data sizes");
qfits_table_close (tload);
return NULL;
}
/* Return */
return tload;
}
/*----------------------------------------------------------------------------*/
/**
@brief Free a FITS table and associated pointers
@param t qfits_table to free
@return void
Frees all memory associated to a qfits_table structure.
*/
/*----------------------------------------------------------------------------*/
void
qfits_table_close (qfits_table * t)
{
if (t == NULL)
return;
if (t->nc > 0)
if (t->col != NULL)
free (t->col);
free (t);
return;
}
/*----------------------------------------------------------------------------*/
/**
@brief Extract data from a column in a FITS table
@param th Allocated qfits_table
@param colnum Number of the column to extract (from 0 to colnum-1)
@param selection boolean array to define the selected rows
@return unsigned char array
If selection is NULL, select the complete column.
Extract a column from a FITS table and return the data as a bytes
array. The returned array type and size are determined by the
column object in the qfits_table and by the selection parameter.
Returned array size in bytes is:
nbselected * col->natoms * col->atom_size
Numeric types are correctly understood and byte-swapped if needed,
to be converted to the local machine type.
NULL values have to be handled by the caller.
The returned buffer has been allocated using one of the special memory
operators present in xmemory.c. To deallocate the buffer, you must call
the version of free() offered by xmemory, not the usual system free(). It
is enough to include "xmemory.h" in your code before you make calls to
the pixel loader here.
*/
/*----------------------------------------------------------------------------*/
unsigned char *
qfits_query_column (qfits_table * th, int colnum, int *selection)
{
char *start;
qfits_col *col;
int field_size;
unsigned char *array;
unsigned char *r;
unsigned char *inbuf;
int table_width;
int nb_rows;
size_t size;
int i;
if (th->tab_w == -1)
{
/* Compute the table width in bytes */
if ((table_width = qfits_compute_table_width (th)) == -1)
{
qfits_error ("cannot compute the table width");
return NULL;
}
}
else
table_width = th->tab_w;
/* Compute the number of selected rows */
nb_rows = 0;
if (selection == NULL)
{
nb_rows = th->nr;
}
else
{
for (i = 0; i < th->nr; i++)
if (selection[i] == 1)
nb_rows++;
}
/* Pointer to requested column */
col = th->col + colnum;
/* Test if column is empty */
if (nb_rows * col->atom_size * col->atom_nb == 0)
col->readable = 0;
/* Test if column is readable */
if (col->readable == 0)
return NULL;
/* Compute the size in bytes of one field stored in the file */
if ((field_size = qfits_table_get_field_size (th->tab_t, col)) == -1)
return NULL;
/* Load input file */
if ((start = falloc (th->filename, 0, &size)) == NULL)
{
qfits_error ("cannot open table for query [%s]", th->filename);
return NULL;
}
/* Allocate data array */
array = malloc (nb_rows * field_size * sizeof (char));
/* Position the input pointer at the begining of the column data */
r = array;
inbuf = (unsigned char *) start + col->off_beg;
/* Copy the values in array */
if (selection == NULL)
{
/* No selection : get the complete column */
for (i = 0; i < th->nr; i++)
{
/* Copy all atoms on this field into array */
memcpy (r, inbuf, field_size);
r += field_size;
/* Jump to next line */
inbuf += table_width;
}
}
else
{
/* Get only the selected rows */
for (i = 0; i < th->nr; i++)
{
if (selection[i] == 1)
{
/* Copy all atoms on this field into array */
memcpy (r, inbuf, field_size);
r += field_size;
}
/* Jump to next line */
inbuf += table_width;
}
}
fdealloc (start, 0, size);
/* SWAP the bytes if necessary */
#ifndef WORDS_BIGENDIAN
if (th->tab_t == QFITS_BINTABLE)
{
r = array;
for (i = 0; i < nb_rows * col->atom_nb; i++)
{
swap_bytes (r, col->atom_size);
r += col->atom_size;
}
}
#endif
/* Return allocated and converted array */
return array;
}
/*----------------------------------------------------------------------------*/
/**
@brief Extract consequtive values from a column in a FITS table
@param th Allocated qfits_table
@param colnum Number of the column to extract (from 0 to colnum-1)
@param start_ind Index of the first row (0 for the first)
@param nb_rows Number of rows to extract
@return unsigned char array
Does the same as qfits_query_column() but on a consequtive sequence of rows
Spares the overhead of the selection object allocation
*/
/*----------------------------------------------------------------------------*/
unsigned char *
qfits_query_column_seq (qfits_table * th,
int colnum, int start_ind, int nb_rows)
{
char *start;
qfits_col *col;
int field_size;
unsigned char *array;
unsigned char *r;
unsigned char *inbuf;
int table_width;
size_t size;
int i;
if (th->tab_w == -1)
{
/* Compute the table width in bytes */
if ((table_width = qfits_compute_table_width (th)) == -1)
{
qfits_error ("cannot compute the table width");
return NULL;
}
}
else
table_width = th->tab_w;
/* Check the validity of start_ind and nb_rows */
if ((start_ind < 0) || (start_ind + nb_rows > th->nr))
{
qfits_error ("bad start index and number of rows");
return NULL;
}
/* Pointer to requested column */
col = th->col + colnum;
/* Test if column is empty */
if (nb_rows * col->atom_size * col->atom_nb == 0)
col->readable = 0;
/* Test if column is readable */
if (col->readable == 0)
return NULL;
/* Compute the size in bytes of one field stored in the file */
if ((field_size = qfits_table_get_field_size (th->tab_t, col)) == -1)
return NULL;
/* Load input file */
if ((start = falloc (th->filename, 0, &size)) == NULL)
{
qfits_error ("cannot open table for query [%s]", th->filename);
return NULL;
}
/* Allocate data array */
array = malloc (nb_rows * field_size * sizeof (char));
/* Position the input pointer at the begining of the column data */
r = array;
inbuf = (unsigned char *) start + col->off_beg + table_width * start_ind;
/* Copy the values in array */
/* Get only the selected rows */
for (i = 0; i < nb_rows; i++)
{
/* Copy all atoms on this field into array */
memcpy (r, inbuf, field_size);
r += field_size;
/* Jump to next line */
inbuf += table_width;
}
fdealloc (start, 0, size);
/* SWAP the bytes if necessary */
#ifndef WORDS_BIGENDIAN
if (th->tab_t == QFITS_BINTABLE)
{
r = array;
for (i = 0; i < nb_rows * col->atom_nb; i++)
{
swap_bytes (r, col->atom_size);
r += col->atom_size;
}
}
#endif
/* Return allocated and converted array */
return array;
}
/*----------------------------------------------------------------------------*/
/**
@brief Compute the table width in bytes from the columns infos
@param th Allocated qfits_table
@return the width (-1 in error case)
*/
/*----------------------------------------------------------------------------*/
int
qfits_compute_table_width (qfits_table * th)
{
int width;
qfits_col *curr_col;
int i;
/* Initialize */
width = 0;
/* Loop on all columns and get column descriptions */
curr_col = th->col;
for (i = 0; i < th->nc; i++)
{
if (th->tab_t == QFITS_ASCIITABLE)
{
width += curr_col->atom_nb;
}
else if (th->tab_t == QFITS_BINTABLE)
{
width += curr_col->atom_nb * curr_col->atom_size;
}
curr_col++;
}
return width;
}
/*----------------------------------------------------------------------------*/
/**
@brief Extract binary data from a column in a FITS table
@param th Allocated qfits_table
@param colnum Number of the column to extract (from 0 to colnum-1)
@param selection bollean array to identify selected rows
@param null_value Value to return when a NULL value comes
@return Pointer to void *
Extract a column from a FITS table and return the data as a generic
void* array. The returned array type and size are determined by the
column object in the qfits_table.
Returned array size in bytes is:
nb_selected * col->atom_nb * col->atom_size
NULL values are recognized and replaced by the specified value.
The returned buffer has been allocated using one of the special memory
operators present in xmemory.c. To deallocate the buffer, you must call
the version of free() offered by xmemory, not the usual system free(). It
is enough to include "xmemory.h" in your code before you make calls to
the pixel loader here.
*/
/*----------------------------------------------------------------------------*/
void *
qfits_query_column_data (qfits_table * th,
int colnum, int *selection, void *null_value)
{
void *out_array;
qfits_col *col;
int nb_rows;
unsigned char *in_array;
char *field;
unsigned char ucnull;
short snull;
int inull;
double dnull;
float fnull;
int i;
/* Initialize */
if (null_value == NULL)
{
inull = (int) 0;
snull = (short) 0;
ucnull = (unsigned char) 0;
fnull = (float) 0.0;
dnull = (double) 0.0;
}
else
{
inull = *(int *) null_value;
snull = *(short *) null_value;
ucnull = *(unsigned char *) null_value;
fnull = *(float *) null_value;
dnull = *(double *) null_value;
}
/* Get the number of selected rows */
nb_rows = 0;
if (selection == NULL)
{
nb_rows = th->nr;
}
else
{
for (i = 0; i < th->nr; i++)
if (selection[i] == 1)
nb_rows++;
}
/* Pointer to requested column */
col = th->col + colnum;
/* Test if column is readable */
if (col->readable == 0)
return NULL;
/* Handle each type separately */
switch (col->atom_type)
{
case TFITS_ASCII_TYPE_A:
out_array = (char *) qfits_query_column (th, colnum, selection);
break;
case TFITS_ASCII_TYPE_I:
in_array = (unsigned char *) qfits_query_column (th, colnum, selection);
out_array = malloc (nb_rows * col->atom_size);
field = malloc ((col->atom_nb + 1) * sizeof (char));
for (i = 0; i < nb_rows; i++)
{
/* Copy all atoms of the field into 'field' */
memcpy (field, &in_array[i * col->atom_nb], col->atom_nb);
field[col->atom_nb] = (char) 0;
/* Write the data in out_array */
/* Test if a NULL val is encoutered */
if (!strcmp (col->nullval, qfits_strstrip (field)))
{
((int *) out_array)[i] = inull;
}
else
{
((int *) out_array)[i] = (int) atoi (field);
}
}
free (field);
free (in_array);
break;
case TFITS_ASCII_TYPE_E:
case TFITS_ASCII_TYPE_F:
in_array = (unsigned char *) qfits_query_column (th, colnum, selection);
out_array = malloc (nb_rows * col->atom_size);
field = malloc ((col->atom_nb + 1) * sizeof (char));
for (i = 0; i < nb_rows; i++)
{
/* Copy all atoms of the field into 'field' */
memcpy (field, &in_array[i * col->atom_nb], col->atom_nb);
field[col->atom_nb] = (char) 0;
/* Write the data in out_array */
/* Test if a NULL val is encoutered */
if (!strcmp (col->nullval, qfits_strstrip (field)))
{
((float *) out_array)[i] = fnull;
}
else
{
/* Add the decimal handling */
((float *) out_array)[i] = (float) qfits_str2dec (field,
col->atom_dec_nb);
}
}
free (field);
free (in_array);
break;
case TFITS_ASCII_TYPE_D:
in_array = (unsigned char *) qfits_query_column (th, colnum, selection);
out_array = malloc (nb_rows * col->atom_size);
field = malloc ((col->atom_nb + 1) * sizeof (char));
for (i = 0; i < nb_rows; i++)
{
/* Copy all atoms of the field into 'field' */
memcpy (field, &in_array[i * col->atom_nb], col->atom_nb);
field[col->atom_nb] = (char) 0;
/* Write the data in out_array */
/* Test if a NULL val is encoutered */
if (!strcmp (col->nullval, field))
{
((double *) out_array)[i] = dnull;
}
else
{
/* Add the decimal handling */
((double *) out_array)[i] =
qfits_str2dec (field, col->atom_dec_nb);
}
}
free (field);
free (in_array);
break;
case TFITS_BIN_TYPE_A:
case TFITS_BIN_TYPE_L:
out_array = (char *) qfits_query_column (th, colnum, selection);
break;
case TFITS_BIN_TYPE_D:
case TFITS_BIN_TYPE_M:
out_array = (double *) qfits_query_column (th, colnum, selection);
for (i = 0; i < nb_rows * col->atom_nb; i++)
{
if (qfits_isnan (((double *) out_array)[i]) ||
qfits_isinf (((double *) out_array)[i]))
{
((double *) out_array)[i] = dnull;
}
}
break;
case TFITS_BIN_TYPE_E:
case TFITS_BIN_TYPE_C:
out_array = (float *) qfits_query_column (th, colnum, selection);
for (i = 0; i < nb_rows * col->atom_nb; i++)
{
if (qfits_isnan (((float *) out_array)[i]) ||
qfits_isinf (((float *) out_array)[i]))
{
((float *) out_array)[i] = fnull;
}
}
break;
case TFITS_BIN_TYPE_X:
out_array =
(unsigned char *) qfits_query_column (th, colnum, selection);
break;
case TFITS_BIN_TYPE_B:
out_array =
(unsigned char *) qfits_query_column (th, colnum, selection);
for (i = 0; i < nb_rows * col->atom_nb; i++)
{
if (((col->nullval)[0] != (char) 0) &&
(atoi (col->nullval) == (int) ((unsigned char *) out_array)[i]))
{
((unsigned char *) out_array)[i] = ucnull;
}
}
break;
case TFITS_BIN_TYPE_I:
out_array = (short *) qfits_query_column (th, colnum, selection);
for (i = 0; i < nb_rows * col->atom_nb; i++)
{
if (((col->nullval)[0] != (char) 0) &&
(atoi (col->nullval) == (int) ((short *) out_array)[i]))
{
((short *) out_array)[i] = snull;
}
}
break;
case TFITS_BIN_TYPE_J:
out_array = (int *) qfits_query_column (th, colnum, selection);
for (i = 0; i < nb_rows * col->atom_nb; i++)
{
if (((col->nullval)[0] != (char) 0) &&
(atoi (col->nullval) == ((int *) out_array)[i]))
{
((int *) out_array)[i] = inull;
}
}
break;
case TFITS_BIN_TYPE_P:
out_array = (int *) qfits_query_column (th, colnum, selection);
break;
default:
qfits_error ("unrecognized data type");
return NULL;
}
return out_array;
}
/*----------------------------------------------------------------------------*/
/**
@brief Extract binary data from a column in a FITS table
@param th Allocated qfits_table
@param colnum Number of the column to extract (from 0 to colnum-1)
@param start_ind Index of the first row (0 for the first)
@param nb_rows Number of rows to extract
@param null_value Value to return when a NULL value comes
@return Pointer to void *
Does the same as qfits_query_column_data() but on a consequtive sequence
of rows. Spares the overhead of the selection object allocation
*/
/*----------------------------------------------------------------------------*/
void *
qfits_query_column_seq_data (qfits_table * th,
int colnum,
int start_ind, int nb_rows, void *null_value)
{
void *out_array;
qfits_col *col;
unsigned char *in_array;
char *field;
unsigned char ucnull;
short snull;
int inull;
double dnull;
float fnull;
int i;
/* Initialize */
if (null_value == NULL)
{
inull = (int) 0;
snull = (short) 0;
ucnull = (unsigned char) 0;
fnull = (float) 0.0;
dnull = (double) 0.0;
}
else
{
inull = *(int *) null_value;
snull = *(short *) null_value;
ucnull = *(unsigned char *) null_value;
fnull = *(float *) null_value;
dnull = *(double *) null_value;
}
/* Pointer to requested column */
col = th->col + colnum;
/* Test if column is readable */
if (col->readable == 0)
return NULL;
/* Handle each type separately */
switch (col->atom_type)
{
case TFITS_ASCII_TYPE_A:
out_array = (char *) qfits_query_column_seq (th, colnum, start_ind,
nb_rows);
break;
case TFITS_ASCII_TYPE_I:
in_array = (unsigned char *) qfits_query_column_seq (th, colnum,
start_ind,
nb_rows);
out_array = malloc (nb_rows * col->atom_size);
field = malloc ((col->atom_nb + 1) * sizeof (char));
for (i = 0; i < nb_rows; i++)
{
/* Copy all atoms of the field into 'field' */
memcpy (field, &in_array[i * col->atom_nb], col->atom_nb);
field[col->atom_nb] = (char) 0;
/* Write the data in out_array */
/* Test if a NULL val is encoutered */
if (!strcmp (col->nullval, qfits_strstrip (field)))
{
((int *) out_array)[i] = inull;
}
else
{
((int *) out_array)[i] = (int) atoi (field);
}
}
free (field);
free (in_array);
break;
case TFITS_ASCII_TYPE_E:
case TFITS_ASCII_TYPE_F:
in_array = (unsigned char *) qfits_query_column_seq (th, colnum,
start_ind,
nb_rows);
out_array = malloc (nb_rows * col->atom_size);
field = malloc ((col->atom_nb + 1) * sizeof (char));
for (i = 0; i < nb_rows; i++)
{
/* Copy all atoms of the field into 'field' */
memcpy (field, &in_array[i * col->atom_nb], col->atom_nb);
field[col->atom_nb] = (char) 0;
/* Write the data in out_array */
/* Test if a NULL val is encoutered */
if (!strcmp (col->nullval, qfits_strstrip (field)))
{
((float *) out_array)[i] = fnull;
}
else
{
/* Add the decimal handling */
((float *) out_array)[i] = (float) qfits_str2dec (field,
col->atom_dec_nb);
}
}
free (field);
free (in_array);
break;
case TFITS_ASCII_TYPE_D:
in_array = (unsigned char *) qfits_query_column_seq (th, colnum,
start_ind,
nb_rows);
out_array = malloc (nb_rows * col->atom_size);
field = malloc ((col->atom_nb + 1) * sizeof (char));
for (i = 0; i < nb_rows; i++)
{
/* Copy all atoms of the field into 'field' */
memcpy (field, &in_array[i * col->atom_nb], col->atom_nb);
field[col->atom_nb] = (char) 0;
/* Write the data in out_array */
/* Test if a NULL val is encoutered */
if (!strcmp (col->nullval, qfits_strstrip (field)))
{
((double *) out_array)[i] = dnull;
}
else
{
/* Add the decimal handling */
((double *) out_array)[i] =
qfits_str2dec (field, col->atom_dec_nb);
}
}
free (field);
free (in_array);
break;
case TFITS_BIN_TYPE_A:
case TFITS_BIN_TYPE_L:
out_array = (char *) qfits_query_column_seq (th, colnum,
start_ind, nb_rows);
break;
case TFITS_BIN_TYPE_D:
case TFITS_BIN_TYPE_M:
out_array = (double *) qfits_query_column_seq (th, colnum,
start_ind, nb_rows);
for (i = 0; i < nb_rows * col->atom_nb; i++)
{
if (qfits_isnan (((double *) out_array)[i]) ||
qfits_isinf (((double *) out_array)[i]))
{
((double *) out_array)[i] = dnull;
}
}
break;
case TFITS_BIN_TYPE_E:
case TFITS_BIN_TYPE_C:
out_array = (float *) qfits_query_column_seq (th, colnum,
start_ind, nb_rows);
for (i = 0; i < nb_rows * col->atom_nb; i++)
{
if (qfits_isnan (((float *) out_array)[i]) ||
qfits_isinf (((float *) out_array)[i]))
{
((float *) out_array)[i] = fnull;
}
}
break;
case TFITS_BIN_TYPE_X:
out_array = (unsigned char *) qfits_query_column_seq (th, colnum,
start_ind,
nb_rows);
break;
case TFITS_BIN_TYPE_B:
out_array = (unsigned char *) qfits_query_column_seq (th, colnum,
start_ind,
nb_rows);
for (i = 0; i < nb_rows * col->atom_nb; i++)
{
if (((col->nullval)[0] != (char) 0) &&
(atoi (col->nullval) == (int) ((unsigned char *) out_array)[i]))
{
((unsigned char *) out_array)[i] = ucnull;
}
}
break;
case TFITS_BIN_TYPE_I:
out_array = (short *) qfits_query_column_seq (th, colnum,
start_ind, nb_rows);
for (i = 0; i < nb_rows * col->atom_nb; i++)
{
if (((col->nullval)[0] != (char) 0) &&
(atoi (col->nullval) == (int) ((short *) out_array)[i]))
{
((short *) out_array)[i] = snull;
}
}
break;
case TFITS_BIN_TYPE_J:
out_array = (int *) qfits_query_column_seq (th, colnum,
start_ind, nb_rows);
for (i = 0; i < nb_rows * col->atom_nb; i++)
{
if (((col->nullval)[0] != (char) 0) &&
(atoi (col->nullval) == ((int *) out_array)[i]))
{
((int *) out_array)[i] = inull;
}
}
break;
case TFITS_BIN_TYPE_P:
out_array = (int *) qfits_query_column_seq (th, colnum,
start_ind, nb_rows);
break;
default:
qfits_error ("unrecognized data type");
return NULL;
}
return out_array;
}
/*----------------------------------------------------------------------------*/
/**
@brief Detect NULL values in a column
@param th Allocated qfits_table
@param colnum Number of the column to check (from 0 to colnum-1)
@param selection Array to identify selected rows
@param nb_vals Gives the size of the output array
@param nb_nulls Gives the number of detected null values
@return array with 1 for NULLs and 0 for non-NULLs
*/
/*----------------------------------------------------------------------------*/
int *
qfits_query_column_nulls (qfits_table * th,
int colnum,
int *selection, int *nb_vals, int *nb_nulls)
{
int *out_array;
qfits_col *col;
unsigned char *in_array;
void *tmp_array;
char *field;
int nb_rows;
int i;
/* Initialize */
*nb_nulls = 0;
*nb_vals = 0;
/* Get the number of selected rows */
nb_rows = 0;
if (selection == NULL)
{
nb_rows = th->nr;
}
else
{
for (i = 0; i < th->nr; i++)
if (selection[i] == 1)
nb_rows++;
}
/* Pointer to requested column */
col = th->col + colnum;
/* Test if column is readable */
if (col->readable == 0)
return NULL;
/* Handle each type separately */
switch (col->atom_type)
{
case TFITS_ASCII_TYPE_A:
case TFITS_ASCII_TYPE_D:
case TFITS_ASCII_TYPE_E:
case TFITS_ASCII_TYPE_F:
case TFITS_ASCII_TYPE_I:
in_array = (unsigned char *) qfits_query_column (th, colnum, selection);
out_array = calloc (nb_rows, sizeof (int));
*nb_vals = nb_rows;
field = malloc ((col->atom_nb + 1) * sizeof (char));
for (i = 0; i < nb_rows; i++)
{
/* Copy all atoms of the field into 'field' */
memcpy (field, &in_array[i * col->atom_nb], col->atom_nb);
field[col->atom_nb] = (char) 0;
/* Test if a NULL val is encoutered */
if (!strcmp (col->nullval, qfits_strstrip (field)))
{
out_array[i] = 1;
(*nb_nulls)++;
}
}
free (field);
if (in_array != NULL)
free (in_array);
break;
case TFITS_BIN_TYPE_A:
/* No NULL values */
out_array = calloc (nb_rows * col->atom_nb, sizeof (int));
*nb_vals = nb_rows * col->atom_nb;
break;
case TFITS_BIN_TYPE_L:
case TFITS_BIN_TYPE_X:
case TFITS_BIN_TYPE_P:
/* No NULL values */
out_array = calloc (nb_rows * col->atom_nb, sizeof (int));
*nb_vals = nb_rows * col->atom_nb;
break;
case TFITS_BIN_TYPE_D:
case TFITS_BIN_TYPE_M:
tmp_array = (double *) qfits_query_column (th, colnum, selection);
out_array = calloc (nb_rows * col->atom_nb, sizeof (int));
*nb_vals = nb_rows * col->atom_nb;
for (i = 0; i < nb_rows * col->atom_nb; i++)
{
if (qfits_isnan (((double *) tmp_array)[i]) ||
qfits_isinf (((double *) tmp_array)[i]))
{
out_array[i] = 1;
(*nb_nulls)++;
}
}
if (tmp_array != NULL)
free (tmp_array);
break;
case TFITS_BIN_TYPE_E:
case TFITS_BIN_TYPE_C:
tmp_array = (float *) qfits_query_column (th, colnum, selection);
out_array = calloc (nb_rows * col->atom_nb, sizeof (int));
*nb_vals = nb_rows * col->atom_nb;
for (i = 0; i < nb_rows * col->atom_nb; i++)
{
if (qfits_isnan (((float *) tmp_array)[i]) ||
qfits_isinf (((float *) tmp_array)[i]))
{
out_array[i] = 1;
(*nb_nulls)++;
}
}
if (tmp_array != NULL)
free (tmp_array);
break;
case TFITS_BIN_TYPE_B:
tmp_array =
(unsigned char *) qfits_query_column (th, colnum, selection);
out_array = calloc (nb_rows * col->atom_nb, sizeof (int));
*nb_vals = nb_rows * col->atom_nb;
for (i = 0; i < nb_rows * col->atom_nb; i++)
{
if (((col->nullval)[0] != (char) 0) &&
(atoi (col->nullval) == (int) ((unsigned char *) tmp_array)[i]))
{
out_array[i] = 1;
(*nb_nulls)++;
}
}
if (tmp_array != NULL)
free (tmp_array);
break;
case TFITS_BIN_TYPE_I:
tmp_array = (short *) qfits_query_column (th, colnum, selection);
out_array = calloc (nb_rows * col->atom_nb, sizeof (int));
*nb_vals = nb_rows * col->atom_nb;
for (i = 0; i < nb_rows * col->atom_nb; i++)
{
if (((col->nullval)[0] != (char) 0) &&
(atoi (col->nullval) == (int) ((short *) tmp_array)[i]))
{
out_array[i] = 1;
(*nb_nulls)++;
}
}
if (tmp_array != NULL)
free (tmp_array);
break;
case TFITS_BIN_TYPE_J:
tmp_array = (int *) qfits_query_column (th, colnum, selection);
out_array = calloc (nb_rows * col->atom_nb, sizeof (int));
*nb_vals = nb_rows * col->atom_nb;
for (i = 0; i < nb_rows * col->atom_nb; i++)
{
if (((col->nullval)[0] != (char) 0) &&
(atoi (col->nullval) == ((int *) tmp_array)[i]))
{
out_array[i] = 1;
(*nb_nulls)++;
}
}
if (tmp_array != NULL)
free (tmp_array);
break;
default:
qfits_error ("unrecognized data type");
return NULL;
}
return out_array;
}
/*----------------------------------------------------------------------------*/
/**
@brief Save a table to a FITS file with a given FITS header.
@param array Data array.
@param table table
@param fh FITS header to insert in the output file.
@return -1 in error case, 0 otherwise
*/
/*----------------------------------------------------------------------------*/
int
qfits_save_table_hdrdump (void **array,
qfits_table * table, qfits_header * fh)
{
FILE *outfile;
char *md5hash;
char md5card[81];
/* Open the destination file */
if ((outfile = fopen (table->filename, "w")) == NULL)
{
qfits_error ("cannot open file [%s]", table->filename);
return -1;
}
/* Write the fits header in the file 'outname' */
if (qfits_header_dump (fh, outfile) == -1)
{
qfits_error ("cannot dump header in file");
fclose (outfile);
return -1;
}
/* Append the extension */
if (table->tab_t == QFITS_BINTABLE)
{
if (qfits_table_append_bin_xtension (outfile, table, array) == -1)
{
qfits_error ("in writing fits table");
fclose (outfile);
return -1;
}
}
else if (table->tab_t == QFITS_ASCIITABLE)
{
if (qfits_table_append_ascii_xtension (outfile, table, array) == -1)
{
qfits_error ("in writing fits table");
fclose (outfile);
return -1;
}
}
else
{
qfits_error ("Unrecognized table type");
fclose (outfile);
return -1;
}
fclose (outfile);
/* Update MD5 keyword */
if (strcmp (table->filename, "STDOUT"))
{
md5hash = qfits_datamd5 (table->filename);
if (md5hash == NULL)
{
qfits_error ("computing MD5 signature for output file %s",
table->filename);
return -1;
}
sprintf (md5card, "DATAMD5 = '%s' / MD5 checksum", md5hash);
qfits_replace_card (table->filename, "DATAMD5", md5card);
}
return 0;
}
/*----------------------------------------------------------------------------*/
/**
@brief Appends a std extension header + data to a FITS table file.
@param outfile Pointer to (opened) file ready for writing.
@param t Pointer to qfits_table
@param data Table data to write
@return int 0 if Ok, -1 otherwise
Dumps a FITS table to a file. The whole table described by qfits_table, and
the data arrays contained in 'data' are dumped to the file. An extension
header is produced with all keywords needed to describe the table, then the
data is dumped to the file.
The output is then padded to reach a multiple of 2880 bytes in size.
Notice that no main header is produced, only the extension part.
*/
/*----------------------------------------------------------------------------*/
int
qfits_table_append_xtension (FILE * outfile, qfits_table * t, void **data)
{
/* Append the extension */
if (t->tab_t == QFITS_BINTABLE)
{
if (qfits_table_append_bin_xtension (outfile, t, data) == -1)
{
qfits_error ("in writing fits table");
return -1;
}
}
else if (t->tab_t == QFITS_ASCIITABLE)
{
if (qfits_table_append_ascii_xtension (outfile, t, data) == -1)
{
qfits_error ("in writing fits table");
return -1;
}
}
else
{
qfits_error ("Unrecognized table type");
return -1;
}
return 0;
}
/*----------------------------------------------------------------------------*/
/**
@brief Appends a specified extension header + data to a FITS table file.
@param outfile Pointer to (opened) file ready for writing.
@param t Pointer to qfits_table
@param data Table data to write
@param hdr Specified extension header
@return int 0 if Ok, -1 otherwise
Dumps a FITS table to a file. The whole table described by qfits_table, and
the data arrays contained in 'data' are dumped to the file following the
specified fits header.
The output is then padded to reach a multiple of 2880 bytes in size.
Notice that no main header is produced, only the extension part.
*/
/*----------------------------------------------------------------------------*/
int
qfits_table_append_xtension_hdr (FILE * outfile,
qfits_table * t,
void **data, qfits_header * hdr)
{
/* Write the fits header in the file */
if (qfits_header_dump (hdr, outfile) == -1)
{
qfits_error ("cannot dump header in file");
return -1;
}
/* Append the data to the file */
return qfits_table_append_data (outfile, t, data);
}
/*----------------------------------------------------------------------------*/
/**
@brief given a col and a row, find out the string to write for display
@param table table structure
@param col_id col id (0 -> nbcol-1)
@param row_id row id (0 -> nrow-1)
@param use_zero_scale Flag to use or not zero and scale
@return the string to write (to be freed)
This function is highly inefficient, it should not be used in loops to
display a complete table. It is more to get one field from time to
time, or for debugging puposes.
*/
/*----------------------------------------------------------------------------*/
char *
qfits_table_field_to_string (qfits_table * table,
int col_id, int row_id, int use_zero_scale)
{
char *str;
switch (table->tab_t)
{
case QFITS_BINTABLE:
str = qfits_bintable_field_to_string (table, col_id, row_id,
use_zero_scale);
break;
case QFITS_ASCIITABLE:
str = qfits_asciitable_field_to_string (table, col_id, row_id,
use_zero_scale);
break;
default:
qfits_error ("Table type not recognized");
return NULL;
break;
}
return str;
}
/*----------------------------------------------------------------------------*/
/**
@brief given a col and a row, find out the string to write for display
@param table table structure
@param col_id col id (0 -> nbcol-1)
@param row_id row id (0 -> nrow-1)
@param use_zero_scale Flag to use or not zero and scale
@return the string to write (to be freed)
ASCII tables specific
*/
/*----------------------------------------------------------------------------*/
static char *
qfits_asciitable_field_to_string (qfits_table * table,
int col_id, int row_id, int use_zero_scale)
{
qfits_col *col;
char *ccol;
int *icol;
float *fcol;
double *dcol;
char ctmp[512];
char *stmp;
int field_size;
void *field;
int *selection;
/* Test inputs */
if (table->tab_t != QFITS_ASCIITABLE)
return NULL;
/* Initialize */
ctmp[0] = (char) 0;
/* Set selection to select the requested row */
selection = calloc (table->nr, sizeof (int));
selection[row_id] = 1;
/* Load the column data */
if ((field = qfits_query_column_data (table, col_id, selection,
NULL)) == NULL)
return NULL;
free (selection);
/* Set reference to the column */
col = table->col + col_id;
/* Compute field size and allocate stmp */
if (col->atom_nb > ELEMENT_MAX_DISPLAY_SIZE)
field_size = col->atom_nb + 1;
else
field_size = ELEMENT_MAX_DISPLAY_SIZE;
stmp = malloc (field_size * sizeof (char));
stmp[0] = (char) 0;
/* Get the string to write according to the type */
switch (col->atom_type)
{
case TFITS_ASCII_TYPE_A:
ccol = (char *) field;
strncpy (ctmp, ccol, col->atom_nb);
ctmp[col->atom_nb] = (char) 0;
strcpy (stmp, ctmp);
break;
case TFITS_ASCII_TYPE_I:
icol = (int *) field;
/* Two cases: use col->zero and col->scale or not */
if (col->zero_present && col->scale_present && use_zero_scale)
{
sprintf (stmp, "%f", (float) (col->zero +
(float) icol[0] * col->scale));
}
else
{
sprintf (stmp, "%d", icol[0]);
}
break;
case TFITS_ASCII_TYPE_E:
case TFITS_ASCII_TYPE_F:
fcol = (float *) field;
/* Two cases: use col->zero and col->scale or not */
if (col->zero_present && col->scale_present && use_zero_scale)
{
sprintf (stmp, "%f", (float) (col->zero + fcol[0] * col->scale));
}
else
{
sprintf (stmp, "%f", fcol[0]);
}
break;
case TFITS_ASCII_TYPE_D:
dcol = (double *) field;
/* Two cases: use col->zero and col->scale or not */
if (col->zero_present && col->scale_present && use_zero_scale)
{
sprintf (stmp, "%f", (float) (col->zero +
(float) dcol[0] * col->scale));
}
else
{
sprintf (stmp, "%g", dcol[0]);
}
break;
default:
qfits_warning ("Type not recognized");
break;
}
/* Free and return */
free (field);
return stmp;
}
/*----------------------------------------------------------------------------*/
/**
@brief Given a col and a row, find out the string to write for display
@param table table structure
@param col_id col id (0 -> nbcol-1)
@param row_id row id (0 -> nrow-1)
@param use_zero_scale Flag to use or not zero and scale
@return the allocated string to write
BIN tables specific
*/
/*----------------------------------------------------------------------------*/
static char *
qfits_bintable_field_to_string (qfits_table * table,
int col_id, int row_id, int use_zero_scale)
{
qfits_col *col;
unsigned char *uccol;
char *ccol;
int *icol;
short *scol;
float *fcol;
double *dcol;
char ctmp[512];
char *stmp;
int field_size;
void *field;
int *selection;
int i;
/* Test inputs */
if (table->tab_t != QFITS_BINTABLE)
return NULL;
/* Initialize */
ctmp[0] = (char) 0;
/* Set selection to select the requested row */
selection = calloc (table->nr, sizeof (int));
selection[row_id] = 1;
/* Load the data column */
if ((field = qfits_query_column_data (table, col_id, selection,
NULL)) == NULL)
{
free (selection);
return NULL;
}
free (selection);
/* Set reference to the column */
col = table->col + col_id;
/* Compute field size and allocate stmp */
field_size = col->atom_nb * ELEMENT_MAX_DISPLAY_SIZE;
stmp = malloc (field_size * sizeof (char));
stmp[0] = (char) 0;
/* Get the string to write according to the type */
switch (col->atom_type)
{
case TFITS_BIN_TYPE_A:
ccol = (char *) field;
strncpy (ctmp, ccol, col->atom_size * col->atom_nb);
ctmp[col->atom_size * col->atom_nb] = (char) 0;
strcpy (stmp, ctmp);
break;
case TFITS_BIN_TYPE_B:
uccol = (unsigned char *) field;
/* Two cases: use col->zero and col->scale or not */
if (col->zero_present && col->scale_present && use_zero_scale)
{
/* For each atom of the column */
for (i = 0; i < col->atom_nb - 1; i++)
{
sprintf (ctmp, "%f, ", (float) (col->zero +
(float) uccol[i] * col->scale));
strcat (stmp, ctmp);
}
/* Handle the last atom differently: no ',' */
sprintf (ctmp, "%f", (float) (col->zero +
(float) uccol[col->atom_nb -
1] * col->scale));
strcat (stmp, ctmp);
}
else
{
/* For each atom of the column */
for (i = 0; i < col->atom_nb - 1; i++)
{
sprintf (ctmp, "%d, ", (int) uccol[i]);
strcat (stmp, ctmp);
}
/* Handle the last atom differently: no ',' */
sprintf (ctmp, "%d", (int) uccol[col->atom_nb - 1]);
strcat (stmp, ctmp);
}
break;
case TFITS_BIN_TYPE_D:
case TFITS_BIN_TYPE_M:
dcol = (double *) field;
/* Two cases: use col->zero and col->scale or not */
if (col->zero_present && col->scale_present && use_zero_scale)
{
/* For each atom of the column */
for (i = 0; i < col->atom_nb - 1; i++)
{
sprintf (ctmp, "%g, ", (double) ((double) col->zero +
dcol[i] *
(double) col->scale));
strcat (stmp, ctmp);
}
/* Handle the last atom differently: no ',' */
sprintf (ctmp, "%g", (double) ((double) col->zero +
dcol[col->atom_nb -
1] * (double) col->scale));
strcat (stmp, ctmp);
}
else
{
/* For each atom of the column */
for (i = 0; i < col->atom_nb - 1; i++)
{
sprintf (ctmp, "%g, ", dcol[i]);
strcat (stmp, ctmp);
}
/* Handle the last atom differently: no ',' */
sprintf (ctmp, "%g", dcol[col->atom_nb - 1]);
strcat (stmp, ctmp);
}
break;
case TFITS_BIN_TYPE_E:
case TFITS_BIN_TYPE_C:
fcol = (float *) field;
/* Two cases: use col->zero and col->scale or not */
if (col->zero_present && col->scale_present && use_zero_scale)
{
/* For each atom of the column */
for (i = 0; i < col->atom_nb - 1; i++)
{
sprintf (ctmp, "%f, ", (float) (col->zero +
(float) fcol[i] * col->scale));
strcat (stmp, ctmp);
}
/* Handle the last atom differently: no ',' */
sprintf (ctmp, "%f", (float) (col->zero +
(float) fcol[col->atom_nb -
1] * col->scale));
strcat (stmp, ctmp);
}
else
{
/* For each atom of the column */
for (i = 0; i < col->atom_nb - 1; i++)
{
sprintf (ctmp, "%f, ", fcol[i]);
strcat (stmp, ctmp);
}
/* Handle the last atom differently: no ',' */
sprintf (ctmp, "%f", fcol[col->atom_nb - 1]);
strcat (stmp, ctmp);
}
break;
case TFITS_BIN_TYPE_I:
scol = (short *) field;
/* Two cases: use col->zero and col->scale or not */
if (col->zero_present && col->scale_present && use_zero_scale)
{
/* For each atom of the column */
for (i = 0; i < col->atom_nb - 1; i++)
{
sprintf (ctmp, "%f, ", (float) (col->zero +
(float) scol[i] * col->scale));
strcat (stmp, ctmp);
}
/* Handle the last atom differently: no ',' */
sprintf (ctmp, "%f", (float) (col->zero +
(float) scol[col->atom_nb -
1] * col->scale));
strcat (stmp, ctmp);
}
else
{
/* For each atom of the column */
for (i = 0; i < col->atom_nb - 1; i++)
{
sprintf (ctmp, "%d, ", (int) scol[i]);
strcat (stmp, ctmp);
}
/* Handle the last atom differently: no ',' */
sprintf (ctmp, "%d", (int) scol[col->atom_nb - 1]);
strcat (stmp, ctmp);
}
break;
case TFITS_BIN_TYPE_J:
icol = (int *) field;
/* Two cases: use col->zero and col->scale or not */
if (col->zero_present && col->scale_present && use_zero_scale)
{
/* For each atom of the column */
for (i = 0; i < col->atom_nb - 1; i++)
{
sprintf (ctmp, "%f, ", (float) (col->zero +
(float) icol[i] * col->scale));
strcat (stmp, ctmp);
}
/* Handle the last atom differently: no ',' */
sprintf (ctmp, "%f", (float) (col->zero +
(float) icol[col->atom_nb -
1] * col->scale));
strcat (stmp, ctmp);
}
else
{
/* For each atom of the column */
for (i = 0; i < col->atom_nb - 1; i++)
{
sprintf (ctmp, "%d, ", (int) icol[i]);
strcat (stmp, ctmp);
}
/* Handle the last atom differently: no ',' */
sprintf (ctmp, "%d", (int) icol[col->atom_nb - 1]);
strcat (stmp, ctmp);
}
break;
case TFITS_BIN_TYPE_L:
ccol = (char *) field;
/* For each atom of the column */
for (i = 0; i < col->atom_nb - 1; i++)
{
sprintf (ctmp, "%c, ", ccol[i]);
strcat (stmp, ctmp);
}
/* Handle the last atom differently: no ',' */
sprintf (ctmp, "%c", ccol[col->atom_nb - 1]);
strcat (stmp, ctmp);
break;
case TFITS_BIN_TYPE_X:
uccol = (unsigned char *) field;
/* For each atom of the column */
for (i = 0; i < col->atom_nb - 1; i++)
{
sprintf (ctmp, "%d, ", uccol[i]);
strcat (stmp, ctmp);
}
/* Handle the last atom differently: no ',' */
sprintf (ctmp, "%d", uccol[col->atom_nb - 1]);
strcat (stmp, ctmp);
break;
case TFITS_BIN_TYPE_P:
icol = (int *) field;
/* For each atom of the column */
for (i = 0; i < col->atom_nb - 1; i++)
{
sprintf (ctmp, "%d, ", (int) icol[i]);
strcat (stmp, ctmp);
}
/* Handle the last atom differently: no ',' */
sprintf (ctmp, "%d", (int) icol[col->atom_nb - 1]);
strcat (stmp, ctmp);
break;
default:
qfits_warning ("Type not recognized");
break;
}
free (field);
return stmp;
}
/*----------------------------------------------------------------------------*/
/**
@brief Remove blanks at the beginning and the end of a string.
@param s String to parse.
@return ptr to statically allocated string.
This function returns a pointer to a statically allocated string,
which is identical to the input string, except that all blank
characters at the end and the beg. of the string have been removed.
Do not free or modify the returned string!
Since the returned string is statically allocated, it will be modified at
each function call (not re-entrant).
*/
/*----------------------------------------------------------------------------*/
static char *
qfits_strstrip (char *s)
{
static char l[ASCIILINESZ + 1];
char *last;
if (s == NULL)
return NULL;
while (isspace ((int) *s) && *s)
s++;
memset (l, 0, ASCIILINESZ + 1);
strcpy (l, s);
last = l + strlen (l);
while (last > l)
{
if (!isspace ((int) *(last - 1)))
break;
last--;
}
*last = (char) 0;
return (char *) l;
}
/*----------------------------------------------------------------------------*/
/**
@brief Make a double out of a string and a number of decimals
@param to_format the string to convert
@param nb_dec the number of decimals
@return the double
A field with 123 of type F3.1 actually contains 12.3
This is handled by this function.
*/
/*----------------------------------------------------------------------------*/
static double
qfits_str2dec (char *to_format, int nb_dec)
{
double val;
int i;
/* Test entries */
if (to_format == NULL)
return 0.00;
val = (double) atof (to_format);
/* First handle case where there are no decimals or the dot is there */
if ((strstr (to_format, ".") == NULL) && (nb_dec > 0))
{
for (i = 0; i < nb_dec; i++)
val /= 10;
}
return val;
}
/*----------------------------------------------------------------------------*/
/**
@brief Parse a FITS type
@param str string read in the FITS header (e.g. TFORM value)
@param nb pointer to the number
@param dec_nb pointer to the number of decimals
@param type pointer to the type
@param table_type Table type (BIN, ASCII, ...)
@return 0 if ok, -1 otherwise
This functions reads the input string and uses it to update nb and type
*/
/*----------------------------------------------------------------------------*/
static int
qfits_table_interpret_type (char *str,
int *nb,
int *dec_nb, tfits_type * type, int table_type)
{
char type_c;
*dec_nb = 0;
if (table_type == QFITS_BINTABLE)
{
if (sscanf (str, "%d%c", nb, &type_c) == 0)
{
/* nb is 1 by default */
if (sscanf (str, "%c", &type_c) == 0)
{
qfits_error ("cannot interpret this type: %s", str);
return -1;
}
*nb = 1;
}
switch (type_c)
{
case 'A':
*type = TFITS_BIN_TYPE_A;
break;
case 'B':
*type = TFITS_BIN_TYPE_B;
break;
case 'C':
*type = TFITS_BIN_TYPE_C;
break;
case 'D':
*type = TFITS_BIN_TYPE_D;
break;
case 'E':
*type = TFITS_BIN_TYPE_E;
break;
case 'I':
*type = TFITS_BIN_TYPE_I;
break;
case 'J':
*type = TFITS_BIN_TYPE_J;
break;
case 'L':
*type = TFITS_BIN_TYPE_L;
break;
case 'M':
*type = TFITS_BIN_TYPE_M;
break;
case 'P':
*type = TFITS_BIN_TYPE_P;
break;
case 'X':
*type = TFITS_BIN_TYPE_X;
break;
default:
return -1;
}
}
else if (table_type == QFITS_ASCIITABLE)
{
if (sscanf (str, "%c%d.%d", &type_c, nb, dec_nb) == 0)
{
qfits_error ("cannot interpret this type: %s", str);
return -1;
}
switch (type_c)
{
case 'A':
*type = TFITS_ASCII_TYPE_A;
break;
case 'D':
*type = TFITS_ASCII_TYPE_D;
break;
case 'E':
*type = TFITS_ASCII_TYPE_E;
break;
case 'F':
*type = TFITS_ASCII_TYPE_F;
break;
case 'I':
*type = TFITS_ASCII_TYPE_I;
break;
default:
return -1;
}
}
else
{
qfits_error ("unrecognized table type");
return -1;
}
return 0;
}
/*----------------------------------------------------------------------------*/
/**
@brief Generate a FITS type string
@param col input column
@return The string to write to TFORM
*/
/*----------------------------------------------------------------------------*/
static char *
qfits_build_format (qfits_col * col)
{
static char sval[10];
int nb;
switch (col->atom_type)
{
case TFITS_ASCII_TYPE_A:
nb = sprintf (sval, "A%d.%d", col->atom_nb, col->atom_dec_nb);
break;
case TFITS_ASCII_TYPE_D:
nb = sprintf (sval, "D%d.%d", col->atom_nb, col->atom_dec_nb);
break;
case TFITS_ASCII_TYPE_E:
nb = sprintf (sval, "E%d.%d", col->atom_nb, col->atom_dec_nb);
break;
case TFITS_ASCII_TYPE_I:
nb = sprintf (sval, "I%d.%d", col->atom_nb, col->atom_dec_nb);
break;
case TFITS_ASCII_TYPE_F:
nb = sprintf (sval, "F%d.%d", col->atom_nb, col->atom_dec_nb);
break;
case TFITS_BIN_TYPE_D:
nb = sprintf (sval, "%dD", col->atom_nb);
break;
case TFITS_BIN_TYPE_E:
nb = sprintf (sval, "%dE", col->atom_nb);
break;
case TFITS_BIN_TYPE_I:
nb = sprintf (sval, "%dI", col->atom_nb);
break;
case TFITS_BIN_TYPE_A:
nb = sprintf (sval, "%dA", col->atom_nb);
break;
case TFITS_BIN_TYPE_B:
nb = sprintf (sval, "%dB", col->atom_nb);
break;
case TFITS_BIN_TYPE_C:
nb = sprintf (sval, "%dC", (int) (col->atom_nb / 2));
break;
case TFITS_BIN_TYPE_J:
nb = sprintf (sval, "%dJ", col->atom_nb);
break;
case TFITS_BIN_TYPE_L:
nb = sprintf (sval, "%dL", col->atom_nb);
break;
case TFITS_BIN_TYPE_M:
nb = sprintf (sval, "%dM", (int) (col->atom_nb / 2));
break;
case TFITS_BIN_TYPE_P:
nb = sprintf (sval, "%dP", (int) (col->atom_nb / 2));
break;
case TFITS_BIN_TYPE_X:
nb = sprintf (sval, "%dX", 8 * col->atom_nb);
break;
default:
return NULL;
}
sval[nb] = (char) 0;
return sval;
}
/*----------------------------------------------------------------------------*/
/**
@brief Appends a std extension header + data to a FITS BIN table file.
@param outfile Pointer to (opened) file ready for writing.
@param t Pointer to qfits_table
@param data Table data to write
@return int 0 if Ok, -1 otherwise
Dumps a FITS table to a file. The whole table described by qfits_table, and
the data arrays contained in 'data' are dumped to the file. An extension
header is produced with all keywords needed to describe the table, then the
data is dumped to the file.
The output is then padded to reach a multiple of 2880 bytes in size.
Notice that no main header is produced, only the extension part.
*/
/*----------------------------------------------------------------------------*/
static int
qfits_table_append_bin_xtension (FILE * outfile, qfits_table * t, void **data)
{
qfits_header *fh;
if ((fh = qfits_table_ext_header_default (t)) == NULL)
{
qfits_error ("cannot create new fits header");
return -1;
}
/* Write the fits header in the file */
if (qfits_header_dump (fh, outfile) == -1)
{
qfits_error ("cannot dump header in file");
qfits_header_destroy (fh);
fclose (outfile);
return -1;
}
qfits_header_destroy (fh);
/* Append the data to the file */
return qfits_table_append_data (outfile, t, data);
}
/*----------------------------------------------------------------------------*/
/**
@brief Appends an extension header + data to a FITS ASCII table file.
@param outfile Pointer to (opened) file ready for writing.
@param t Pointer to qfits_table
@param data Table data to write
@return int 0 if Ok, -1 otherwise
Dumps a FITS table to a file. The whole table described by
qfits_table, and the data arrays contained in 'data' are dumped to
the file. An extension header is produced with all keywords needed
to describe the table, then the data is dumped to the file.
The output is then padded to reach a multiple of 2880 bytes in size.
Notice that no main header is produced, only the extension part.
*/
/*----------------------------------------------------------------------------*/
static int
qfits_table_append_ascii_xtension (FILE * outfile,
qfits_table * t, void **data)
{
qfits_header *fh;
if ((fh = qfits_table_ext_header_default (t)) == NULL)
{
qfits_error ("cannot create new fits header");
return -1;
}
/* Write the fits header in the file */
if (qfits_header_dump (fh, outfile) == -1)
{
qfits_error ("cannot dump header in file");
qfits_header_destroy (fh);
return -1;
}
qfits_header_destroy (fh);
/* Append the data to the file */
return qfits_table_append_data (outfile, t, data);
}
/*----------------------------------------------------------------------------*/
/**
@brief Appends data to a FITS table file.
@param outfile Pointer to (opened) file ready for writing.
@param t Pointer to qfits_table
@param data Table data to write
@return int 0 if Ok, -1 otherwise
Dumps the data part of a FITS table to a file. The primary header, as well as
the extension header are supposed to be already there (and properly padded).
The output is then padded to reach a multiple of 2880 bytes in size.
*/
/*----------------------------------------------------------------------------*/
static int
qfits_table_append_data (FILE * outfile, qfits_table * t, void **data)
{
qfits_col *curr_col;
char field[1024];
char *line;
unsigned char **array;
unsigned char *r;
unsigned char *inbuf;
int writt_char;
int nb_blanks;
int field_size;
int i, j;
/* Write DATA */
array = malloc (t->nc * sizeof (unsigned char *));
curr_col = t->col;
for (i = 0; i < t->nc; i++)
{
/* Compute the field size */
field_size = qfits_table_get_field_size (t->tab_t, curr_col);
/* Copy data from data to array (unsigned char) */
array[i] = malloc (t->nr * field_size);
r = (unsigned char *) array[i];
inbuf = (unsigned char *) (data[i]);
/* Copy the data */
if (t->tab_t == QFITS_ASCIITABLE)
{
/* ASCII table */
for (j = 0; j < t->nr; j++)
{
switch (curr_col->atom_type)
{
case TFITS_ASCII_TYPE_A:
strncpy (field, (char *) inbuf, curr_col->atom_nb);
field[curr_col->atom_nb] = (char) 0;
inbuf += curr_col->atom_nb;
break;
case TFITS_ASCII_TYPE_D:
memset (field, ' ', curr_col->atom_nb);
sprintf (field, "%g", ((double *) data[i])[j]);
field[curr_col->atom_nb] = (char) 0;
break;
case TFITS_ASCII_TYPE_E:
case TFITS_ASCII_TYPE_F:
memset (field, ' ', curr_col->atom_nb);
sprintf (field, "%f", ((float *) data[i])[j]);
field[curr_col->atom_nb] = (char) 0;
break;
case TFITS_ASCII_TYPE_I:
memset (field, ' ', curr_col->atom_nb);
sprintf (field, "%d", ((int *) data[i])[j]);
field[curr_col->atom_nb] = (char) 0;
break;
default:
break;
}
memcpy (r, field, curr_col->atom_nb);
r += (curr_col->atom_nb);
}
}
else if (t->tab_t == QFITS_BINTABLE)
{
/* BINARY table */
for (j = 0; j < t->nr; j++)
{
memcpy (r, inbuf, field_size);
inbuf += field_size;
r += field_size;
}
/* Byte swapping needed if on a little-endian machine */
#ifndef WORDS_BIGENDIAN
r = array[i];
for (j = 0; j < t->nr * curr_col->atom_nb; j++)
{
swap_bytes (r, curr_col->atom_size);
r += curr_col->atom_size;
}
#endif
}
else
return -1;
curr_col++;
}
/* Write to the outfile */
writt_char = 0;
for (i = 0; i < t->nr; i++)
{
curr_col = t->col;
for (j = 0; j < t->nc; j++)
{
field_size = qfits_table_get_field_size (t->tab_t, curr_col);
r = array[j] + field_size * i;
line = (char *) calloc (field_size + 1, sizeof (char));
memcpy (line, r, field_size);
line[field_size] = (char) 0;
fwrite (line, 1, field_size, outfile);
writt_char += field_size;
curr_col++;
free (line);
}
}
/* Complete with blanks to FITS_BLOCK_SIZE characters */
if (writt_char % FITS_BLOCK_SIZE)
{
nb_blanks = FITS_BLOCK_SIZE - (writt_char % FITS_BLOCK_SIZE);
for (i = 1; i <= nb_blanks; i++)
fwrite (" ", 1, 1, outfile);
}
/* Free and return */
for (i = 0; i < t->nc; i++)
{
if (array[i] != NULL)
free (array[i]);
}
free (array);
return 0;
}
/*----------------------------------------------------------------------------*/
/**
@brief Get the size in bytes of a field
@param type table type
@param col a column
@return the size
*/
/*----------------------------------------------------------------------------*/
static int
qfits_table_get_field_size (int type, qfits_col * col)
{
int field_size;
switch (type)
{
case QFITS_BINTABLE:
field_size = col->atom_nb * col->atom_size;
break;
case QFITS_ASCIITABLE:
field_size = col->atom_nb;
break;
default:
qfits_warning ("unrecognized table type");
field_size = -1;
}
return field_size;
}