2406 lines
78 KiB
C
2406 lines
78 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 ;
|
|
}
|