/*
* fitstab.c
*
* Handle FITS extensions and tables.
*
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*
* This file part of: AstrOmatic FITS/LDAC library
*
* Copyright: (C) 1995-2023 CFHT/IAP/CNRS/SorbonneU
*
* License: GNU General Public License
*
* AstrOmatic software is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
* AstrOmatic software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with AstrOmatic software.
* If not, see .
*
* Last modified: 25/02/2023
*
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include
#include
#include
#ifdef HAVE_CFITSIO
#include CFITSIO_H
#endif
#include "fitscat_defs.h"
#include "fitscat.h"
/****** about_tab **************************************************************
PROTO int about_tab(catstruct *cat, char *tabname, FILE *stream)
PURPOSE Print information concerning a tab structure.
INPUT Pointer to the input catalog,
table name,
an output stream.
OUTPUT RETURN_OK if the table was found, RETURN_ERROR otherwise.
NOTES -.
AUTHOR E.R. Deul(Leiden observatory),
E. Bertin (IAP & Leiden observatory): return value modified.
E.R. Deul(Leiden observatory): output units
VERSION 28/10/2009
***/
int about_tab(catstruct *cat, char *tabname, FILE *stream)
{
tabstruct *tab;
keystruct *key;
int i, j;
if ((tab = name_to_tab(cat, tabname, 0))) {
fprintf(stream, "Table %s\n", tabname);
for (i=0, key=tab->key; inkey; i++,key=key->nextkey)
{
fprintf(stream,
"****** Key #%d\n", i+1);
fprintf(stream,
" Key name:...............%s\n", key->name);
fprintf(stream,
" Key comment:............%s\n", key->comment);
fprintf(stream,
" Key type:...............");
switch (key->ttype) {
case T_BYTE: fprintf(stream,"Byte"); break;
case T_SHORT: fprintf(stream,"Short Int"); break;
case T_LONG: fprintf(stream,"Long Int"); break;
case T_LONGLONG: fprintf(stream,"Long Long Int"); break;
case T_FLOAT: fprintf(stream,"Float"); break;
case T_DOUBLE: fprintf(stream,"Double"); break;
case T_STRING: fprintf(stream,"String"); break;
}
fprintf(stream,"\n");
fprintf(stream,
" Key dimension:..........%d ", key->naxis);
if (key->naxis) fprintf(stream, "(");
for (j=0;jnaxis;j++) {
if (j>0) fprintf(stream, " ");
fprintf(stream, "%d", key->naxisn[j]);
}
if (key->naxis) fprintf(stream, ")");
fprintf(stream, "\n");
if (key->unit[0] != '\0')
fprintf(stream,
" Key unit:...............%s\n", key->unit);
}
} else return RETURN_ERROR;
return RETURN_OK;
}
/****** add_tab ****************************************************************
PROTO int add_tab(tabstruct *tab, catstruct *cat, int pos)
PURPOSE Add a table to a catalog.
INPUT Pointer to the table,
Pointer to the destination catalog,
Position (1= first after the primary HDU, <=0 = at the end).
OUTPUT RETURN_OK if everything went as expected, and RETURN_ERROR otherwise.
NOTES Only 1-segment tables are accepted. To copy multi-segment tables,
use copy_tab() instead.
If a table with the same name and basic attributes already exists in
the destination catalog, then the new table is appended to it.
AUTHOR E. Bertin (IAP & Leiden observatory)
VERSION 15/08/2003
***/
int add_tab(tabstruct *tab, catstruct *cat, int pos)
{
tabstruct *outtab, *prevtab;
int i;
/*Check if a similar table doesn't already exist in the dest. cat */
if ((outtab = name_to_tab(cat, tab->extname, 0)))
{
if ((outtab->naxis != 2)
|| (outtab->bitpix!=8)
|| strcmp(outtab->xtension,tab->xtension)
|| (outtab->tfields != tab->tfields)
|| (outtab->naxisn[0] != tab->naxisn[0]))
return RETURN_ERROR;
prevtab = outtab;
for (i=outtab->nseg-1; i--;)
prevtab = prevtab->nexttab;
tab->seg = prevtab->seg+1;
tab->nseg = 0;
outtab->nseg++;
}
else
{
if ((prevtab = pos_to_tab(cat, pos, 0)))
prevtab = prevtab->prevtab;
else
tab->nexttab = tab->prevtab = prevtab = tab;
cat->ntab++;
}
(tab->nexttab = (tab->prevtab = prevtab)->nexttab)->prevtab = tab;
prevtab->nexttab = tab;
return RETURN_OK;
}
/****** copy_tab **************************************************************
PROTO int copy_tab(catstruct *catin, char *tabname, int seg,
catstruct *catout, int pos)
PURPOSE Copy a table from one catalog to another.
INPUT Pointer to the original catalog,
Name of the table,
Table segment (0 = all),
Pointer to the destination catalog,
Position (1= first after the primary HDU, <=0 = at the end)
OUTPUT RETURN_OK if everything went as expected, and RETURN_ERROR otherwise.
NOTES If a table with the same name and basic attributes already exists in
the destination catalog, then the original table is appended to it.
AUTHOR E. Bertin (IAP & Leiden observatory)
VERSION 15/08/2003
***/
int copy_tab(catstruct *catin, char *tabname, int seg,
catstruct *catout, int pos)
{
keystruct *key;
tabstruct *outtab, *prevtab, *nexttab, *tabin,*tabout;
int i,j, nseg;
/*Convert the table name to a pointer*/
if (!(tabin = name_to_tab(catin, tabname, seg)))
return RETURN_ERROR;
nseg = seg?1:tabin->nseg;
/*Check if a similar table doesn't already exist in the dest. cat */
if (*tabname && (outtab = name_to_tab(catout, tabname, 0)))
{
if ((outtab->naxis != 2)
|| (outtab->bitpix!=8)
|| strcmp(outtab->xtension,tabin->xtension)
|| (outtab->tfields != tabin->tfields)
|| (outtab->naxisn[0] != tabin->naxisn[0]))
return RETURN_ERROR;
prevtab = outtab;
for (i=0; inseg-1; i++)
prevtab = prevtab->nexttab;
nexttab = prevtab->nexttab;
outtab->nseg += nseg;
}
else
{
prevtab = nexttab = outtab = NULL;
catout->ntab++;
}
/*Now copy each segment of the original table*/
tabout = NULL; /* to satisfy gcc -Wall */
for (i=nseg; i--;)
{
/*---First, allocate memory and copy data */
QCALLOC(tabout, tabstruct, 1);
*tabout = *tabin;
if (tabin->naxis)
QMEMCPY(tabin->naxisn, tabout->naxisn, int, tabin->naxis);
if (tabin->headbuf)
QMEMCPY(tabin->headbuf, tabout->headbuf, char, tabin->headnblock*FBSIZE);
if (tabin->bodybuf)
QMEMCPY(tabin->bodybuf, tabout->bodybuf, char, tabin->tabsize);
key = tabin->key;
tabout->key = NULL;
tabout->nkey = 0;
for (j=tabin->nkey; j--;)
{
copy_key(tabin, key->name, tabout, 0);
key = key->nextkey;
}
/*---Then, update the links */
if (prevtab)
{
prevtab->nexttab = tabout;
tabout->prevtab = prevtab;
tabout->seg = prevtab->seg+1;
tabout->nseg = 0;
}
else
{
outtab = tabout;
outtab->prevtab = NULL;
tabout->seg = 1;
}
tabin = tabin->nexttab;
prevtab = tabout;
}
/*place the new chain of table-segments within the catalog (tricky, isn't it?)*/
if (!nexttab)
/*--if the table is new */
{
nexttab = pos_to_tab(catout, pos, 0);
if (!nexttab)
nexttab = catout->tab = tabout;
else
{
outtab->prevtab = nexttab->prevtab;
nexttab->prevtab->nexttab = outtab;
}
}
prevtab->nexttab = nexttab;
nexttab->prevtab = prevtab;
return RETURN_OK;
}
/****** copy_tab_fromptr ******************************************************
PROTO void copy_tab_fromptr(tabstruct *tabin, catstruct *catout, int pos)
PURPOSE Copy a table from one catalog to another.
INPUT Pointer to the original catalog,
Pointer to the table,
Pointer to the destination catalog,
Position (1= first after the primary HDU, <=0 = at the end)
OUTPUT -.
NOTES -.
AUTHOR E. Bertin (IAP/SorbonneU)
VERSION 25/02/2023
***/
void copy_tab_fromptr(tabstruct *tabin, catstruct *catout, int pos)
{
keystruct *key;
tabstruct *prevtab, *nexttab,*tabout;
int j;
catout->ntab++;
/* First, allocate memory and copy data */
QCALLOC(tabout, tabstruct, 1);
*tabout = *tabin;
if (tabin->naxis)
QMEMCPY(tabin->naxisn, tabout->naxisn, int, tabin->naxis);
if (tabin->headbuf)
QMEMCPY(tabin->headbuf, tabout->headbuf, char, tabin->headnblock*FBSIZE);
if (tabin->bodybuf)
QMEMCPY(tabin->bodybuf, tabout->bodybuf, char, tabin->tabsize);
key = tabin->key;
tabout->key = NULL;
tabout->nkey = 0;
for (j=tabin->nkey; j--;)
{
copy_key(tabin, key->name, tabout, 0);
key = key->nextkey;
}
/* Then, update the links */
tabout->prevtab = NULL;
tabout->seg = 1;
tabin = tabin->nexttab;
prevtab = tabout;
if (!(nexttab = pos_to_tab(catout, pos, 0)))
nexttab = catout->tab = tabout;
else
{
tabout->prevtab = nexttab->prevtab;
nexttab->prevtab->nexttab = tabout;
}
prevtab->nexttab = nexttab;
nexttab->prevtab = prevtab;
#ifdef HAVE_CFITSIO
// Do not copy CFitsIO file pointer
tabout->infptr = NULL;
#endif
return;
}
/****** copy_tabs **************************************************************
PROTO int copy_tabs(catstruct *catin, catstruct *catout)
PURPOSE Copy all tables from one catalog to another.
INPUT Pointer to the original catalog,
Pointer to the destination catalog,
OUTPUT RETURN_OK if everything went as expected, and RETURN_ERROR otherwise
(for instance if there were tabs that were not binary-tables, and
therefore that were not copied).
NOTES If a table with the same name and basic attributes already exists in
the destination catalog, then the original table is appended to it.
AUTHOR E. Bertin (IAP & Leiden observatory)
VERSION 12/06/2001
***/
int copy_tabs(catstruct *catin, catstruct *catout)
{
tabstruct *tab;
int i, flag, ntab;
if (!catin->tab)
return RETURN_ERROR;
tab = catin->tab->nexttab; /* skip the primary header */
flag = RETURN_OK;
ntab = catin->ntab-1;
if (!ntab)
ntab = 1;
for (i=ntab; i--;)
{
flag |= copy_tab(catin, tab->extname, 0, catout, 0);
while (!(tab=tab->nexttab)->nseg);
}
return flag;
}
/****** copy_tabs_blind *******************************************************
PROTO int copy_tabs(catstruct *catin, catstruct *catout)
PURPOSE Copy all tables from one catalog to another, without trying to append.
INPUT Pointer to the original catalog,
Pointer to the destination catalog,
OUTPUT RETURN_OK if everything went as expected, and RETURN_ERROR otherwise.
NOTES -.
AUTHOR E. Bertin (IAP & Leiden observatory)
VERSION 07/05/2002
***/
int copy_tabs_blind(catstruct *catin, catstruct *catout)
{
tabstruct *tab;
int i, ntab;
if (!catin->tab)
return RETURN_ERROR;
tab = catin->tab; /* don't skip the primary header */
ntab = catin->ntab;
for (i=ntab; i--;)
{
copy_tab_fromptr(tab, catout, 0);
tab=tab->nexttab;
}
return RETURN_OK;
}
/****** free_tab ***************************************************************
PROTO void free_tab(tabstruct *tab)
PURPOSE Free memory associated to a table pointer.
INPUT Pointer to the table.
OUTPUT -.
NOTES -.
AUTHOR E. Bertin (CFHT/IAP/CNRS/SorbonneU)
VERSION 25/02/2023
***/
void free_tab(tabstruct *tab)
{
free_body(tab);
free(tab->naxisn);
free(tab->headbuf);
free(tab->compress_buf);
remove_keys(tab);
free(tab);
return;
}
/****** new_tab ****************************************************************
PROTO tabstruct *new_tab(char *tabname)
PURPOSE Create a new binary table.
INPUT Name.
OUTPUT A pointer to the new table.
NOTES A defaut header is also created.
No links are initialized.
AUTHOR E. Bertin (IAP & Leiden observatory)
VERSION 25/04/97
***/
tabstruct *new_tab(char *tabname)
{
static char bintabtemplate[][80] = {
"XTENSION= 'BINTABLE' / THIS IS A BINARY TABLE (FROM THE LDACTOOLS)",
"BITPIX = 8 / ",
"NAXIS = 2 / ",
"NAXIS1 = 0 / BYTES PER ROW",
"NAXIS2 = 0 / NUMBER OF ROWS",
"PCOUNT = 0 / RANDOM PARAMETER COUNT",
"GCOUNT = 1 / GROUP COUNT",
"TFIELDS = 0 / FIELDS PER ROWS",
"EXTNAME = 'WHOCARES' / TABLE NAME",
"END "};
tabstruct *tab;
char *buf;
int i;
QCALLOC(tab, tabstruct, 1);
strcpy(tab->xtension, "BINTABLE");
strcpy(tab->extname, tabname);
tab->naxis = 2;
QCALLOC(tab->naxisn, int, tab->naxis);
tab->bitpix = 8;
tab->bytepix = 1;
tab->pcount = 0;
tab->gcount = 1;
tab->seg = 1;
tab->nseg = 1;
/*Provide a new header*/
QCALLOC(tab->headbuf, char, FBSIZE);
memcpy(tab->headbuf, bintabtemplate, sizeof(bintabtemplate));
for (buf = tab->headbuf, i=FBSIZE; i--; buf++)
if (!*buf)
*buf = ' ';
tab->headnblock = 1;
return tab;
}
/****** remove_tab *************************************************************
PROTO int remove_tab(catstruct *cat, char *tabname, int seg)
PURPOSE Remove a table from a catalog.
INPUT Pointer to the catalog,
Name of the table,
Table segment (0 = all).
OUTPUT RETURN_OK if everything went as expected, and RETURN_ERROR otherwise.
NOTES If tabname = "", the last table from the list is removed.
AUTHOR E. Bertin (IAP & Leiden observatory)
VERSION 15/08/2003
***/
int remove_tab(catstruct *cat, char *tabname, int seg)
{
tabstruct *tab, *prevtab, *nexttab;
int i,nseg;
if (!tabname || !cat->ntab || !cat->tab)
return RETURN_ERROR;
if (tabname[0])
{
/*--Convert the table name to a pointer*/
if (!(tab = name_to_tab(cat, tabname, seg)))
return RETURN_ERROR;
/*--a small trick to simplify decisions afterwards*/
if (seg && tab->nseg==1)
seg = 0;
}
else
{
tab = cat->tab->prevtab;
if (!seg)
for (;!tab->nseg; tab = tab->prevtab);
}
prevtab = tab->prevtab;
nseg = seg?1:tab->nseg;
/*Free memory for each table segment*/
nexttab = NULL; /* to satisfy gcc -Wall */
for (i=nseg; i--;)
{
nexttab = tab->nexttab;
if (cat->tab == tab)
cat->tab = nexttab;
free_tab(tab);
tab = nexttab;
}
if (!seg)
if (!--cat->ntab)
{
cat->tab = NULL;
return RETURN_OK;
}
/*update the links of neighbours*/
nexttab->prevtab = prevtab;
prevtab->nexttab = nexttab;
if (seg)
/*--update status for each table segment*/
{
for (tab=prevtab;!tab->nseg; tab = tab->prevtab);
for (nexttab=tab->nexttab,i=2;!nexttab->nseg;nexttab=nexttab->nexttab,i++);
nexttab->seg = i;
tab->nseg = i;
tab->seg = 1;
}
return RETURN_OK;
}
/****** remove_tabs ************************************************************
PROTO int remove_tabs(catstruct *cat)
PURPOSE Remove all tables from a catalog.
INPUT Pointer to the catalog.
OUTPUT RETURN_OK if tabs were found, and RETURN_ERROR otherwise.
NOTES -.
AUTHOR E. Bertin (IAP & Leiden observatory)
VERSION 25/05/97
***/
int remove_tabs(catstruct *cat)
{
int t;
if (!cat->tab)
return RETURN_ERROR;
for (t=cat->ntab; t--;)
remove_tab(cat, "",0);
return RETURN_OK;
}
/****** update_tab ************************************************************
PROTO int update_tab(tabstruct *tab)
PURPOSE Update a table according to what's in the keys.
INPUT Table structure.
OUTPUT RETURN_OK if tab is a binary table, or RETURN_ERROR otherwise.
NOTES The headbuf pointer in the catstruct might be reallocated.
AUTHOR E. Bertin (IAP & Leiden observatory)
VERSION 11/09/2012
***/
int update_tab(tabstruct *tab)
{
tabstruct *keytab;
keystruct *key;
int i,j, nobj, nbytes;
/*Just pass if not a binary table*/
if ((tab->naxis != 2)
|| (tab->bitpix!=8)
|| strncmp(tab->xtension, "BINTABLE", 8))
return RETURN_ERROR;
/*Well, not much to do if there are no keys!*/
if (!(key = tab->key))
return RETURN_OK;
nobj = -1;
keytab = NULL;
nbytes = 0;
for (i=tab->nkey; i--;)
{
if (keytab && !key->ptr && key->tab != keytab)
error(EXIT_FAILURE, "*Error*: wrong reference table in ",
key->name);
if (nobj!=-1 && (nobj != key->nobj))
error(EXIT_FAILURE, "*Error*: wrong number of elements in key ",
key->name);
keytab = key->tab;
nobj = key->nobj;
/*-- If the number of bytes per element is not set, recover it */
if (!key->nbytes)
{
key->nbytes = t_size[key->ttype];
for (j=key->naxis; j--;)
key->nbytes *= key->naxisn[j];
}
nbytes += key->nbytes;
key = key->nextkey;
}
tab->tabsize = (KINGSIZE_T)nobj*nbytes;
tab->naxisn[0] = nbytes;
tab->naxisn[1] = nobj;
tab->tfields = tab->nkey;
return RETURN_OK;
}
/****** name_to_tab ***********************************************************
PROTO tabstruct *name_to_tab(catstruct *cat, char *tabname, int seg)
PURPOSE Name search of a table in a catalog.
INPUT Pointer to the catalog,
Table name,
Table segment (0 = first).
OUTPUT The table pointer if the name was matched, and NULL otherwise.
NOTES -
VERSION 12/06/2001
***/
tabstruct *name_to_tab(catstruct *cat, char *tabname, int seg)
{
tabstruct *tab;
int i;
if (!(tab = cat->tab))
return NULL;
for (i=cat->ntab; strcmp(tabname,tab->extname) && i--;)
while (!(tab=tab->nexttab)->nseg);
if (i<0)
return NULL;
if (seg)
{
for (;tab->seg!=seg && !tab->nexttab->nseg; tab=tab->nexttab);
return tab->seg==seg?tab:NULL;
}
return tab;
}
/****** pos_to_tab *************************************************************
PROTO tabstruct *pos_to_tab(catstruct *cat, int pos, int seg)
PURPOSE Position search of a table in a catalog.
INPUT Pointer to the catalog,
Position of the table,
Table segment (0 = first).
OUTPUT The table pointer if the table exists at the given position, and the
pointer to the primary ``table'' otherwise.
NOTES pos = 1 means the first table after the primary one.
AUTHOR E. Bertin (IAP & Leiden observatory)
VERSION 15/02/96
***/
tabstruct *pos_to_tab(catstruct *cat, int pos, int seg)
{
tabstruct *tab;
int i;
tab = cat->tab;
for (i=0; i!=pos && intab; i++)
while (!(tab=tab->nexttab)->nseg);
if (seg)
for (;tab->seg!=seg && !tab->nexttab->nseg; tab=tab->nexttab);
return intab?tab:cat->tab;
}
/****** tabs_list **************************************************************
PROTO char **tabs_list(catstruct *cat, int *n)
PURPOSE List all tables in a catalog.
INPUT Pointer to the catalog,
Pointer to the number of names in that list.
OUTPUT A list of all table names.
NOTES -.
AUTHOR E.R. Deul (Leiden observatory)
VERSION ??/??/96
***/
char **tabs_list(catstruct *cat, int *n)
{
tabstruct *tab;
int i;
char **names;
tab = cat->tab;
QCALLOC(names, char *, cat->ntab);
for (i=0; intab; i++) {
QCALLOC(names[i], char, MAXCHARS);
strcpy(names[i],tab->extname);
while (!(tab=tab->nexttab)->nseg);
}
*n = cat->ntab;
return names;
}
/****** tabs_row_len ***********************************************************
PROTO int tab_row_len(char *file, char *tabname)
PURPOSE Return the row length in bytes of a given table in a given catalog.
INPUT File pointer.
OUTPUT Table size (bytes)
NOTES -.
AUTHOR E.R. Deul (Leiden observatory)
VERSION 05/06/200`
***/
int tab_row_len(char *file, char *tabname)
{
catstruct *tcat;
tabstruct *tab;
int retcode = -1;
if ((tcat = read_cat(file)) != NULL) {
if ((tab = name_to_tab(tcat, tabname, 0)) != NULL) {
retcode = tab->naxisn[0];
free_tab(tab);
}
close_cat(tcat);
free_cat(&tcat,1);
}
return retcode;
}