1511 lines
38 KiB
C
1511 lines
38 KiB
C
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@file fits_h.c
|
|
@author N. Devillard
|
|
@date Mar 2000
|
|
@version $Revision: 1.27 $
|
|
@brief FITS header handling
|
|
|
|
This file contains definition and related methods for the FITS header
|
|
structure. This structure is meant to remain opaque to the user, who
|
|
only accesses it through the dedicated functions.
|
|
|
|
The 'keytuple' type is strictly internal to this module.
|
|
It describes FITS cards as tuples (key,value,comment,line), where key
|
|
is always a non-NULL character string, value and comment are
|
|
allowed to be NULL. 'line' is a string containing the line as it
|
|
has been read from the input FITS file (raw). It is set to NULL if
|
|
the card is modified later. This allows in output two options:
|
|
either reconstruct the FITS lines by printing key = value / comment
|
|
in a FITS-compliant way, or output the lines as they were found in
|
|
input, except for the modified ones.
|
|
|
|
The following functions are associated methods
|
|
to this data structure:
|
|
|
|
- keytuple_new() constructor
|
|
- keytuple_del() destructor
|
|
- keytuple_dmp() dumps a keytuple to stdout
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
|
|
/*
|
|
$Id: fits_h.c,v 1.27 2005/06/06 12:14:15 yjung Exp $
|
|
$Author: yjung $
|
|
$Date: 2005/06/06 12:14:15 $
|
|
$Revision: 1.27 $
|
|
*/
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
Includes
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
#include "fits_p.h"
|
|
#include "fits_h.h"
|
|
#include "simple.h"
|
|
#include "xmemory.h"
|
|
#include "expkey.h"
|
|
#include "qerror.h"
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief keytuple object (internal)
|
|
|
|
This structure represents a FITS card (key, val, comment) in memory.
|
|
A FITS header is a list of such structs. Although the struct is here
|
|
made public for convenience, it is not supposed to be directly used.
|
|
High-level FITS routines should do the job just fine, without need
|
|
to know about this struct.
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
typedef struct _keytuple_
|
|
{
|
|
|
|
char *key; /** Key: unique string in a list */
|
|
char *val; /** Value, always as a string */
|
|
char *com; /** Comment associated to key */
|
|
char *lin; /** Initial line in FITS header if applicable */
|
|
int typ; /** Key type */
|
|
|
|
/** Implemented as a doubly-linked list */
|
|
struct _keytuple_ *next;
|
|
struct _keytuple_ *prev;
|
|
} keytuple;
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@enum keytype
|
|
@brief Possible key types
|
|
|
|
This enum stores all possible types for a FITS keyword. These determine
|
|
the order of appearance in a header, they are a crucial point for
|
|
DICB (ESO) compatibility. This classification is internal to this
|
|
module.
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
typedef enum _keytype_
|
|
{
|
|
keytype_undef = 0,
|
|
|
|
keytype_top = 1,
|
|
|
|
/* Mandatory keywords */
|
|
/* All FITS files */
|
|
keytype_bitpix = 2,
|
|
keytype_naxis = 3,
|
|
|
|
keytype_naxis1 = 11,
|
|
keytype_naxis2 = 12,
|
|
keytype_naxis3 = 13,
|
|
keytype_naxis4 = 14,
|
|
keytype_naxisi = 20,
|
|
/* Random groups only */
|
|
keytype_group = 30,
|
|
/* Extensions */
|
|
keytype_pcount = 31,
|
|
keytype_gcount = 32,
|
|
/* Main header */
|
|
keytype_extend = 33,
|
|
/* Images */
|
|
keytype_bscale = 34,
|
|
keytype_bzero = 35,
|
|
/* Tables */
|
|
keytype_tfields = 36,
|
|
keytype_tbcoli = 40,
|
|
keytype_tformi = 41,
|
|
|
|
/* Other primary keywords */
|
|
keytype_primary = 100,
|
|
|
|
/* HIERARCH ESO keywords ordered according to DICB */
|
|
keytype_hierarch_dpr = 200,
|
|
keytype_hierarch_obs = 201,
|
|
keytype_hierarch_tpl = 202,
|
|
keytype_hierarch_gen = 203,
|
|
keytype_hierarch_tel = 204,
|
|
keytype_hierarch_ins = 205,
|
|
keytype_hierarch_det = 206,
|
|
keytype_hierarch_log = 207,
|
|
keytype_hierarch_pro = 208,
|
|
/* Other HIERARCH keywords */
|
|
keytype_hierarch = 300,
|
|
|
|
/* HISTORY and COMMENT */
|
|
keytype_history = 400,
|
|
keytype_comment = 500,
|
|
/* END */
|
|
keytype_end = 1000
|
|
} keytype;
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
Private to this module
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
static keytuple *keytuple_new (const char *, const char *, const char
|
|
*, const char *);
|
|
static void keytuple_del (keytuple * k);
|
|
static void keytuple_dmp (keytuple * k);
|
|
static keytype keytuple_type (const char *key);
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
Private functions
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief keytuple constructor
|
|
@param key Key associated to key tuple (cannot be NULL).
|
|
@param val Value associated to key tuple.
|
|
@param com Comment associated to key tuple.
|
|
@param lin Initial line read from FITS header (if applicable).
|
|
@return 1 pointer to newly allocated keytuple.
|
|
|
|
This function is a keytuple creator. NULL values and zero-length strings
|
|
are valid parameters for all but the key field. The returned object must
|
|
be deallocated using keytuple_del().
|
|
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
static keytuple *
|
|
keytuple_new (const char *key,
|
|
const char *val, const char *com, const char *lin)
|
|
{
|
|
keytuple *k;
|
|
|
|
if (key == NULL)
|
|
return NULL;
|
|
|
|
/* Allocate space for new structure */
|
|
k = malloc (sizeof (keytuple));
|
|
/* Hook a copy of the new key */
|
|
k->key = strdup (qfits_expand_keyword (key));
|
|
/* Hook a copy of the value if defined */
|
|
k->val = NULL;
|
|
if (val != NULL)
|
|
{
|
|
if (strlen (val) > 0)
|
|
k->val = strdup (val);
|
|
}
|
|
/* Hook a copy of the comment if defined */
|
|
k->com = NULL;
|
|
if (com != NULL)
|
|
{
|
|
if (strlen (com) > 0)
|
|
k->com = strdup (com);
|
|
}
|
|
/* Hook a copy of the initial line if defined */
|
|
k->lin = NULL;
|
|
if (lin != NULL)
|
|
{
|
|
if (strlen (lin) > 0)
|
|
k->lin = strdup (lin);
|
|
}
|
|
k->next = NULL;
|
|
k->prev = NULL;
|
|
k->typ = keytuple_type (key);
|
|
|
|
return k;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief keytuple type identification routine
|
|
@param key String representing a FITS keyword.
|
|
@return A key type (see keytype enum)
|
|
|
|
This function identifies the type of a FITS keyword when given the
|
|
keyword as a string. Keywords are expected literally as they are
|
|
found in a FITS header on disk.
|
|
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
static keytype
|
|
keytuple_type (const char *key)
|
|
{
|
|
keytype kt;
|
|
|
|
kt = keytype_undef;
|
|
/* Assign type to key tuple */
|
|
if (!strcmp (key, "SIMPLE") || !strcmp (key, "XTENSION"))
|
|
kt = keytype_top;
|
|
else if (!strcmp (key, "END"))
|
|
kt = keytype_end;
|
|
else if (!strcmp (key, "BITPIX"))
|
|
kt = keytype_bitpix;
|
|
else if (!strcmp (key, "NAXIS"))
|
|
kt = keytype_naxis;
|
|
else if (!strcmp (key, "NAXIS1"))
|
|
kt = keytype_naxis1;
|
|
else if (!strcmp (key, "NAXIS2"))
|
|
kt = keytype_naxis2;
|
|
else if (!strcmp (key, "NAXIS3"))
|
|
kt = keytype_naxis3;
|
|
else if (!strcmp (key, "NAXIS4"))
|
|
kt = keytype_naxis4;
|
|
else if (!strncmp (key, "NAXIS", 5))
|
|
kt = keytype_naxisi;
|
|
else if (!strcmp (key, "GROUP"))
|
|
kt = keytype_group;
|
|
else if (!strcmp (key, "PCOUNT"))
|
|
kt = keytype_pcount;
|
|
else if (!strcmp (key, "GCOUNT"))
|
|
kt = keytype_gcount;
|
|
else if (!strcmp (key, "EXTEND"))
|
|
kt = keytype_extend;
|
|
else if (!strcmp (key, "BSCALE"))
|
|
kt = keytype_bscale;
|
|
else if (!strcmp (key, "BZERO"))
|
|
kt = keytype_bzero;
|
|
else if (!strcmp (key, "TFIELDS"))
|
|
kt = keytype_tfields;
|
|
else if (!strncmp (key, "TBCOL", 5))
|
|
kt = keytype_tbcoli;
|
|
else if (!strncmp (key, "TFORM", 5))
|
|
kt = keytype_tformi;
|
|
else if (!strncmp (key, "HIERARCH ESO DPR", 16))
|
|
kt = keytype_hierarch_dpr;
|
|
else if (!strncmp (key, "HIERARCH ESO OBS", 16))
|
|
kt = keytype_hierarch_obs;
|
|
else if (!strncmp (key, "HIERARCH ESO TPL", 16))
|
|
kt = keytype_hierarch_tpl;
|
|
else if (!strncmp (key, "HIERARCH ESO GEN", 16))
|
|
kt = keytype_hierarch_gen;
|
|
else if (!strncmp (key, "HIERARCH ESO TEL", 16))
|
|
kt = keytype_hierarch_tel;
|
|
else if (!strncmp (key, "HIERARCH ESO INS", 16))
|
|
kt = keytype_hierarch_ins;
|
|
else if (!strncmp (key, "HIERARCH ESO LOG", 16))
|
|
kt = keytype_hierarch_log;
|
|
else if (!strncmp (key, "HIERARCH ESO PRO", 16))
|
|
kt = keytype_hierarch_pro;
|
|
else if (!strncmp (key, "HIERARCH", 8))
|
|
kt = keytype_hierarch;
|
|
else if (!strcmp (key, "HISTORY"))
|
|
kt = keytype_history;
|
|
else if (!strcmp (key, "COMMENT"))
|
|
kt = keytype_comment;
|
|
else if ((int) strlen (key) < 9)
|
|
kt = keytype_primary;
|
|
return kt;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief Keytuple destructor.
|
|
@param k Keytuple to deallocate.
|
|
@return void
|
|
Keytuple destructor.
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
static void
|
|
keytuple_del (keytuple * k)
|
|
{
|
|
if (k == NULL)
|
|
return;
|
|
if (k->key)
|
|
free (k->key);
|
|
if (k->val)
|
|
free (k->val);
|
|
if (k->com)
|
|
free (k->com);
|
|
if (k->lin)
|
|
free (k->lin);
|
|
free (k);
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief Keytuple dumper.
|
|
@param k Keytuple to dump
|
|
@return void
|
|
|
|
This function dumps a key tuple to stdout. It is meant for debugging
|
|
purposes only.
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
static void
|
|
keytuple_dmp (keytuple * k)
|
|
{
|
|
if (!k)
|
|
return;
|
|
printf ("[%s]=[", k->key);
|
|
if (k->val)
|
|
printf ("%s", k->val);
|
|
printf ("]");
|
|
if (k->com)
|
|
printf ("/[%s]", k->com);
|
|
printf ("\n");
|
|
return;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
Public functions
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief FITS header constructor
|
|
@return 1 newly allocated (empty) qfits_header object.
|
|
|
|
This is the main constructor for a qfits_header object. It returns
|
|
an allocated linked-list handler with an empty card list.
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
qfits_header *
|
|
qfits_header_new (void)
|
|
{
|
|
qfits_header *h;
|
|
h = malloc (sizeof (qfits_header));
|
|
h->first = NULL;
|
|
h->last = NULL;
|
|
h->n = 0;
|
|
return h;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief FITS header default constructor.
|
|
@return 1 newly allocated qfits_header object.
|
|
|
|
This is a secondary constructor for a qfits_header object. It returns
|
|
an allocated linked-list handler containing two cards: the first one
|
|
(SIMPLE=T) and the last one (END).
|
|
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
qfits_header *
|
|
qfits_header_default (void)
|
|
{
|
|
qfits_header *h;
|
|
h = qfits_header_new ();
|
|
qfits_header_append (h, "SIMPLE", "T", "Fits format", NULL);
|
|
qfits_header_append (h, "END", NULL, NULL, NULL);
|
|
return h;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief Add a new card to a FITS header
|
|
@param hdr qfits_header object to modify
|
|
@param key FITS key
|
|
@param val FITS value
|
|
@param com FITS comment
|
|
@param lin FITS original line if exists
|
|
@return void
|
|
|
|
This function adds a new card into a header, at the one-before-last
|
|
position, i.e. the entry just before the END entry if it is there.
|
|
The key must always be a non-NULL string, all other input parameters
|
|
are allowed to get NULL values.
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
void
|
|
qfits_header_add (qfits_header * hdr,
|
|
char *key, char *val, char *com, char *lin)
|
|
{
|
|
keytuple *k;
|
|
keytuple *kbf;
|
|
keytuple *first;
|
|
keytuple *last;
|
|
|
|
if (hdr == NULL || key == NULL)
|
|
return;
|
|
if (hdr->n < 2)
|
|
return;
|
|
|
|
first = (keytuple *) hdr->first;
|
|
last = (keytuple *) hdr->last;
|
|
|
|
if (((keytype) first->typ != keytype_top) ||
|
|
((keytype) last->typ != keytype_end))
|
|
return;
|
|
|
|
/* Create new key tuple */
|
|
k = keytuple_new (key, val, com, lin);
|
|
|
|
/* Find the last keytuple with same key type */
|
|
kbf = first;
|
|
while (kbf != NULL)
|
|
{
|
|
if ((k->typ >= kbf->typ) && (k->typ < kbf->next->typ))
|
|
break;
|
|
kbf = kbf->next;
|
|
}
|
|
if (kbf == NULL)
|
|
kbf = last->prev;
|
|
|
|
/* Hook it into list */
|
|
k->next = kbf->next;
|
|
(kbf->next)->prev = k;
|
|
kbf->next = k;
|
|
k->prev = kbf;
|
|
|
|
hdr->n++;
|
|
return;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief add a new card to a FITS header
|
|
@param hdr qfits_header object to modify
|
|
@param after Key to specify insertion place
|
|
@param key FITS key
|
|
@param val FITS value
|
|
@param com FITS comment
|
|
@param lin FITS original line if exists
|
|
@return void
|
|
|
|
Adds a new card to a FITS header, after the specified key. Nothing
|
|
happens if the specified key is not found in the header. All fields
|
|
can be NULL, except after and key.
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
void
|
|
qfits_header_add_after (qfits_header * hdr,
|
|
char *after,
|
|
char *key, char *val, char *com, char *lin)
|
|
{
|
|
keytuple *kreq;
|
|
keytuple *k;
|
|
char *exp_after;
|
|
|
|
if (hdr == NULL || after == NULL || key == NULL)
|
|
return;
|
|
|
|
exp_after = qfits_expand_keyword (after);
|
|
/* Locate where the entry is requested */
|
|
kreq = (keytuple *) (hdr->first);
|
|
while (kreq != NULL)
|
|
{
|
|
if (!strcmp (kreq->key, exp_after))
|
|
break;
|
|
kreq = kreq->next;
|
|
}
|
|
if (kreq == NULL)
|
|
return;
|
|
k = keytuple_new (key, val, com, lin);
|
|
|
|
k->next = kreq->next;
|
|
kreq->next->prev = k;
|
|
kreq->next = k;
|
|
k->prev = kreq;
|
|
hdr->n++;
|
|
return;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief Append a new card to a FITS header.
|
|
@param hdr qfits_header object to modify
|
|
@param key FITS key
|
|
@param val FITS value
|
|
@param com FITS comment
|
|
@param lin FITS original line if exists
|
|
@return void
|
|
|
|
Adds a new card in a FITS header as the last one. All fields can be
|
|
NULL except key.
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
void
|
|
qfits_header_append (qfits_header * hdr,
|
|
const char *key,
|
|
const char *val, const char *com, const char *lin)
|
|
{
|
|
keytuple *k;
|
|
keytuple *last;
|
|
|
|
if (hdr == NULL || key == NULL)
|
|
return;
|
|
|
|
k = keytuple_new (key, val, com, lin);
|
|
if (hdr->n == 0)
|
|
{
|
|
hdr->first = hdr->last = k;
|
|
hdr->n = 1;
|
|
return;
|
|
}
|
|
last = (keytuple *) hdr->last;
|
|
last->next = k;
|
|
k->prev = last;
|
|
hdr->last = k;
|
|
hdr->n++;
|
|
return;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief Delete a card in a FITS header.
|
|
@param hdr qfits_header to modify
|
|
@param key specifies which card to remove
|
|
@return void
|
|
|
|
Removes a card from a FITS header. The first found card that matches
|
|
the key is removed.
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
void
|
|
qfits_header_del (qfits_header * hdr, char *key)
|
|
{
|
|
keytuple *k;
|
|
char *xkey;
|
|
|
|
if (hdr == NULL || key == NULL)
|
|
return;
|
|
|
|
xkey = qfits_expand_keyword (key);
|
|
k = (keytuple *) hdr->first;
|
|
while (k != NULL)
|
|
{
|
|
if (!strcmp (k->key, xkey))
|
|
break;
|
|
k = k->next;
|
|
}
|
|
if (k == NULL)
|
|
return;
|
|
if (k == hdr->first)
|
|
{
|
|
hdr->first = k->next;
|
|
}
|
|
else
|
|
{
|
|
k->prev->next = k->next;
|
|
k->next->prev = k->prev;
|
|
}
|
|
keytuple_del (k);
|
|
return;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief Modifies a FITS card.
|
|
@param hdr qfits_header to modify
|
|
@param key FITS key
|
|
@param val FITS value
|
|
@param com FITS comment
|
|
@return void
|
|
|
|
Finds the first card in the header matching 'key', and replaces its
|
|
value and comment fields by the provided values. The initial FITS
|
|
line is set to NULL in the card.
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
void
|
|
qfits_header_mod (qfits_header * hdr, char *key, char *val, char *com)
|
|
{
|
|
keytuple *k;
|
|
char *xkey;
|
|
|
|
if (hdr == NULL || key == NULL)
|
|
return;
|
|
|
|
xkey = qfits_expand_keyword (key);
|
|
k = (keytuple *) hdr->first;
|
|
while (k != NULL)
|
|
{
|
|
if (!strcmp (k->key, xkey))
|
|
break;
|
|
k = k->next;
|
|
}
|
|
if (k == NULL)
|
|
return;
|
|
|
|
if (k->val)
|
|
free (k->val);
|
|
if (k->com)
|
|
free (k->com);
|
|
if (k->lin)
|
|
free (k->lin);
|
|
k->val = NULL;
|
|
k->com = NULL;
|
|
k->lin = NULL;
|
|
if (val)
|
|
{
|
|
if (strlen (val) > 0)
|
|
k->val = strdup (val);
|
|
}
|
|
if (com)
|
|
{
|
|
if (strlen (com) > 0)
|
|
k->com = strdup (com);
|
|
}
|
|
return;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief Sort a FITS header
|
|
@param hdr Header to sort (modified)
|
|
@return -1 in error case, 0 otherwise
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
int
|
|
qfits_header_sort (qfits_header ** hdr)
|
|
{
|
|
qfits_header *sorted;
|
|
keytuple *k;
|
|
keytuple *kbf;
|
|
keytuple *next;
|
|
keytuple *last;
|
|
|
|
/* Test entries */
|
|
if (hdr == NULL)
|
|
return -1;
|
|
if (*hdr == NULL)
|
|
return -1;
|
|
if ((*hdr)->n < 2)
|
|
return 0;
|
|
|
|
/* Create the new FITS header */
|
|
sorted = qfits_header_new ();
|
|
|
|
/* Move the first keytuple to the sorted empty header */
|
|
k = (keytuple *) (*hdr)->first;
|
|
next = k->next;
|
|
sorted->first = sorted->last = k;
|
|
k->next = k->prev = NULL;
|
|
sorted->n = 1;
|
|
|
|
/* Loop over the other tuples */
|
|
while (next != NULL)
|
|
{
|
|
k = next;
|
|
next = k->next;
|
|
|
|
/* Find k's place in sorted */
|
|
kbf = (keytuple *) sorted->first;
|
|
while (kbf != NULL)
|
|
{
|
|
if (k->typ < kbf->typ)
|
|
break;
|
|
kbf = kbf->next;
|
|
}
|
|
|
|
/* Hook k into sorted list */
|
|
if (kbf == NULL)
|
|
{
|
|
/* k is last in sorted */
|
|
last = sorted->last;
|
|
sorted->last = k;
|
|
k->next = NULL;
|
|
k->prev = last;
|
|
last->next = k;
|
|
}
|
|
else
|
|
{
|
|
/* k goes just before kbf */
|
|
k->next = kbf;
|
|
k->prev = kbf->prev;
|
|
if (kbf->prev != NULL)
|
|
(kbf->prev)->next = k;
|
|
else
|
|
sorted->first = k;
|
|
kbf->prev = k;
|
|
}
|
|
(sorted->n)++;
|
|
}
|
|
|
|
/* Replace the input header by the sorted one */
|
|
(*hdr)->first = (*hdr)->last = NULL;
|
|
qfits_header_destroy (*hdr);
|
|
*hdr = sorted;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief Copy a FITS header
|
|
@param src Header to replicate
|
|
@return Pointer to newly allocated qfits_header object.
|
|
|
|
Makes a strict copy of all information contained in the source
|
|
header. The returned header must be freed using qfits_header_destroy.
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
qfits_header *
|
|
qfits_header_copy (qfits_header * src)
|
|
{
|
|
qfits_header *fh_copy;
|
|
keytuple *k;
|
|
|
|
if (src == NULL)
|
|
return NULL;
|
|
|
|
fh_copy = qfits_header_new ();
|
|
k = (keytuple *) src->first;
|
|
while (k != NULL)
|
|
{
|
|
qfits_header_append (fh_copy, k->key, k->val, k->com, k->lin);
|
|
k = k->next;
|
|
}
|
|
return fh_copy;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief Touch all cards in a FITS header
|
|
@param hdr qfits_header to modify
|
|
@return void
|
|
|
|
Touches all cards in a FITS header, i.e. all original FITS lines are
|
|
freed and set to NULL. Useful when a header needs to be reformatted.
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
void
|
|
qfits_header_touchall (qfits_header * hdr)
|
|
{
|
|
keytuple *k;
|
|
|
|
if (hdr == NULL)
|
|
return;
|
|
k = (keytuple *) hdr->first;
|
|
while (k != NULL)
|
|
{
|
|
if (k->lin != NULL)
|
|
{
|
|
free (k->lin);
|
|
k->lin = NULL;
|
|
}
|
|
k = k->next;
|
|
}
|
|
return;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief Dump a FITS header to stdout
|
|
@param hdr qfits_header to dump
|
|
@return void
|
|
Dump a FITS header to stdout. Mostly for debugging purposes.
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
void
|
|
qfits_header_consoledump (qfits_header * hdr)
|
|
{
|
|
keytuple *k;
|
|
|
|
if (hdr == NULL)
|
|
return;
|
|
k = (keytuple *) hdr->first;
|
|
printf ("------------------------------------\n");
|
|
while (k != NULL)
|
|
{
|
|
keytuple_dmp (k);
|
|
k = k->next;
|
|
}
|
|
return;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief qfits_header destructor
|
|
@param hdr qfits_header to deallocate
|
|
@return void
|
|
|
|
Frees all memory associated to a given qfits_header object.
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
void
|
|
qfits_header_destroy (qfits_header * hdr)
|
|
{
|
|
keytuple *k;
|
|
keytuple *kn;
|
|
|
|
if (hdr == NULL)
|
|
return;
|
|
|
|
k = (keytuple *) hdr->first;
|
|
while (k != NULL)
|
|
{
|
|
kn = k->next;
|
|
keytuple_del (k);
|
|
k = kn;
|
|
}
|
|
free (hdr);
|
|
return;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief Return the value associated to a key, as a string
|
|
@param hdr qfits_header to parse
|
|
@param key key to find
|
|
@return pointer to statically allocated string
|
|
|
|
Finds the value associated to the given key and return it as a
|
|
string. The returned pointer is statically allocated, so do not
|
|
modify its contents or try to free it.
|
|
|
|
Returns NULL if no matching key is found or no value is attached.
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
char *
|
|
qfits_header_getstr (qfits_header * hdr, const char *key)
|
|
{
|
|
keytuple *k;
|
|
char *xkey;
|
|
|
|
if (hdr == NULL || key == NULL)
|
|
return NULL;
|
|
|
|
xkey = qfits_expand_keyword (key);
|
|
k = (keytuple *) hdr->first;
|
|
while (k != NULL)
|
|
{
|
|
if (!strcmp (k->key, xkey))
|
|
break;
|
|
k = k->next;
|
|
}
|
|
if (k == NULL)
|
|
return NULL;
|
|
return k->val;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief Find a matching key in a header.
|
|
@param hdr qfits_header to parse
|
|
@param key Key prefix to match
|
|
@return pointer to statically allocated string.
|
|
|
|
This function finds the first keyword in the given header for
|
|
which the given 'key' is a prefix, and returns the full name
|
|
of the matching key (NOT ITS VALUE). This is useful to locate
|
|
any keyword starting with a given prefix. Careful with HIERARCH
|
|
keywords, the shortFITS notation is not likely to be accepted here.
|
|
|
|
Examples:
|
|
|
|
@verbatim
|
|
s = qfits_header_findmatch(hdr, "SIMP") returns "SIMPLE"
|
|
s = qfits_header_findmatch(hdr, "HIERARCH ESO DET") returns
|
|
the first detector keyword among the HIERACH keys.
|
|
@endverbatim
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
char *
|
|
qfits_header_findmatch (qfits_header * hdr, char *key)
|
|
{
|
|
keytuple *k;
|
|
|
|
if (hdr == NULL || key == NULL)
|
|
return NULL;
|
|
|
|
k = (keytuple *) hdr->first;
|
|
while (k != NULL)
|
|
{
|
|
if (!strncmp (k->key, key, (int) strlen (key)))
|
|
break;
|
|
k = k->next;
|
|
}
|
|
if (k == NULL)
|
|
return NULL;
|
|
return k->key;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief Return the i-th key/val/com/line tuple in a header.
|
|
@param hdr Header to consider
|
|
@param idx Index of the requested card
|
|
@param key Output key
|
|
@param val Output value
|
|
@param com Output comment
|
|
@param lin Output initial line
|
|
@return int 0 if Ok, -1 if error occurred.
|
|
|
|
This function is useful to browse a FITS header object card by card.
|
|
By iterating on the number of cards (available in the 'n' field of
|
|
the qfits_header struct), you can retrieve the FITS lines and their
|
|
components one by one. Indexes run from 0 to n-1. You can pass NULL
|
|
values for key, val, com or lin if you are not interested in a
|
|
given field.
|
|
|
|
@code
|
|
int i ;
|
|
char key[FITS_LINESZ+1] ;
|
|
char val[FITS_LINESZ+1] ;
|
|
char com[FITS_LINESZ+1] ;
|
|
char lin[FITS_LINESZ+1] ;
|
|
|
|
for (i=0 ; i<hdr->n ; i++) {
|
|
qfits_header_getitem(hdr, i, key, val, com, lin);
|
|
printf("card[%d] key[%s] val[%s] com[%s]\n", i, key, val, com);
|
|
}
|
|
@endcode
|
|
|
|
This function has primarily been written to interface a qfits_header
|
|
object to other languages (C++/Python). If you are working within a
|
|
C program, you should use the other header manipulation routines
|
|
available in this module.
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
int
|
|
qfits_header_getitem (qfits_header * hdr,
|
|
int idx, char *key, char *val, char *com, char *lin)
|
|
{
|
|
keytuple *k;
|
|
int count;
|
|
|
|
if (hdr == NULL)
|
|
return -1;
|
|
if (key == NULL && val == NULL && com == NULL && lin == NULL)
|
|
return 0;
|
|
if (idx < 0 || idx > hdr->n)
|
|
return -1;
|
|
|
|
count = 0;
|
|
k = (keytuple *) hdr->first;
|
|
while (count < idx)
|
|
{
|
|
k = k->next;
|
|
count++;
|
|
}
|
|
if (key != NULL)
|
|
strcpy (key, k->key);
|
|
if (val != NULL)
|
|
{
|
|
if (k->val != NULL)
|
|
strcpy (val, k->val);
|
|
else
|
|
val[0] = 0;
|
|
}
|
|
if (com != NULL)
|
|
{
|
|
if (k->com != NULL)
|
|
strcpy (com, k->com);
|
|
else
|
|
com[0] = 0;
|
|
}
|
|
if (lin != NULL)
|
|
{
|
|
if (k->lin != NULL)
|
|
strcpy (lin, k->lin);
|
|
else
|
|
lin[0] = 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief Return the FITS line associated to a key, as a string
|
|
@param hdr qfits_header to parse
|
|
@param key key to find
|
|
@return pointer to statically allocated string
|
|
|
|
Finds the FITS line associated to the given key and return it as a
|
|
string. The returned pointer is statically allocated, so do not
|
|
modify its contents or try to free it.
|
|
|
|
Returns NULL if no matching key is found or no line is attached.
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
char *
|
|
qfits_header_getline (qfits_header * hdr, char *key)
|
|
{
|
|
keytuple *k;
|
|
char *xkey;
|
|
|
|
if (hdr == NULL || key == NULL)
|
|
return NULL;
|
|
|
|
xkey = qfits_expand_keyword (key);
|
|
k = (keytuple *) hdr->first;
|
|
while (k != NULL)
|
|
{
|
|
if (!strcmp (k->key, xkey))
|
|
break;
|
|
k = k->next;
|
|
}
|
|
if (k == NULL)
|
|
return NULL;
|
|
return k->lin;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief Return the comment associated to a key, as a string
|
|
@param hdr qfits_header to parse
|
|
@param key key to find
|
|
@return pointer to statically allocated string
|
|
@doc
|
|
|
|
Finds the comment associated to the given key and return it as a
|
|
string. The returned pointer is statically allocated, so do not
|
|
modify its contents or try to free it.
|
|
|
|
Returns NULL if no matching key is found or no comment is attached.
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
char *
|
|
qfits_header_getcom (qfits_header * hdr, char *key)
|
|
{
|
|
keytuple *k;
|
|
char *xkey;
|
|
|
|
if (hdr == NULL || key == NULL)
|
|
return NULL;
|
|
|
|
xkey = qfits_expand_keyword (key);
|
|
k = (keytuple *) hdr->first;
|
|
while (k != NULL)
|
|
{
|
|
if (!strcmp (k->key, xkey))
|
|
break;
|
|
k = k->next;
|
|
}
|
|
if (k == NULL)
|
|
return NULL;
|
|
return k->com;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief Return the value associated to a key, as an int
|
|
@param hdr qfits_header to parse
|
|
@param key key to find
|
|
@param errval default value to return if nothing is found
|
|
@return int
|
|
|
|
Finds the value associated to the given key and return it as an
|
|
int. Returns errval if no matching key is found or no value is
|
|
attached.
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
int
|
|
qfits_header_getint (qfits_header * hdr, const char *key, int errval)
|
|
{
|
|
char *c;
|
|
int d;
|
|
|
|
if (hdr == NULL || key == NULL)
|
|
return errval;
|
|
|
|
c = qfits_header_getstr (hdr, key);
|
|
if (c == NULL)
|
|
return errval;
|
|
if (sscanf (c, "%d", &d) != 1)
|
|
return errval;
|
|
return d;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief Return the value associated to a key, as a double
|
|
@param hdr qfits_header to parse
|
|
@param key key to find
|
|
@param errval default value to return if nothing is found
|
|
@return double
|
|
|
|
Finds the value associated to the given key and return it as a
|
|
double. Returns errval if no matching key is found or no value is
|
|
attached.
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
double
|
|
qfits_header_getdouble (qfits_header * hdr, const char *key, double errval)
|
|
{
|
|
char *c;
|
|
|
|
if (hdr == NULL || key == NULL)
|
|
return errval;
|
|
|
|
c = qfits_header_getstr (hdr, key);
|
|
if (c == NULL)
|
|
return errval;
|
|
return atof (c);
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief Return the value associated to a key, as a boolean (int).
|
|
@param hdr qfits_header to parse
|
|
@param key key to find
|
|
@param errval default value to return if nothing is found
|
|
@return int
|
|
|
|
Finds the value associated to the given key and return it as a
|
|
boolean. Returns errval if no matching key is found or no value is
|
|
attached. A boolean is here understood as an int taking the value 0
|
|
or 1. errval can be set to any other integer value to reflect that
|
|
nothing was found.
|
|
|
|
errval is returned if no matching key is found or no value is
|
|
attached.
|
|
|
|
A true value is any character string beginning with a 'y' (yes), a
|
|
't' (true) or the digit '1'. A false value is any character string
|
|
beginning with a 'n' (no), a 'f' (false) or the digit '0'.
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
int
|
|
qfits_header_getboolean (qfits_header * hdr, const char *key, int errval)
|
|
{
|
|
char *c;
|
|
int ret;
|
|
|
|
if (hdr == NULL || key == NULL)
|
|
return errval;
|
|
|
|
c = qfits_header_getstr (hdr, key);
|
|
if (c == NULL)
|
|
return errval;
|
|
if (strlen (c) < 1)
|
|
return errval;
|
|
|
|
if (c[0] == 'y' || c[0] == 'Y' || c[0] == '1' || c[0] == 't' || c[0] == 'T')
|
|
{
|
|
ret = 1;
|
|
}
|
|
else if (c[0] == 'n' || c[0] == 'N' || c[0] == '0' || c[0] == 'f'
|
|
|| c[0] == 'F')
|
|
{
|
|
ret = 0;
|
|
}
|
|
else
|
|
{
|
|
ret = errval;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief Build a FITS line from the information contained in a card.
|
|
@param line pointer to allocated string to be filled
|
|
@param node pointer to card node in qfits_header linked-list
|
|
@param conservative flag to indicate conservative behaviour
|
|
@return int 0 if Ok, anything else otherwise
|
|
|
|
Build a FITS line (80 chars) from the information contained in a
|
|
node of a qfits_header linked-list. If the mode is set to
|
|
conservative, the original FITS line will be used wherever present.
|
|
If conservative is set to 0, a new line will be formatted.
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
static int
|
|
qfits_header_makeline (char *line, keytuple * k, int conservative)
|
|
{
|
|
char blankline[81];
|
|
int i;
|
|
|
|
if (line == NULL || k == NULL)
|
|
return -1;
|
|
|
|
/* If a previous line information is there, use it as is */
|
|
if (conservative)
|
|
{
|
|
if (k->lin != NULL)
|
|
{
|
|
memcpy (line, k->lin, 80);
|
|
line[80] = (char) 0;
|
|
return 0;
|
|
}
|
|
}
|
|
/* Got to build keyword from scratch */
|
|
memset (blankline, 0, 81);
|
|
keytuple2str (blankline, k->key, k->val, k->com);
|
|
memset (line, ' ', 80);
|
|
i = 0;
|
|
while (blankline[i] != (char) 0)
|
|
{
|
|
line[i] = blankline[i];
|
|
i++;
|
|
}
|
|
line[80] = (char) 0;
|
|
return 0;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief Write out a key tuple to a string on 80 chars.
|
|
@param line Allocated output character buffer.
|
|
@param key Key to write.
|
|
@param val Value to write.
|
|
@param com Comment to write.
|
|
@return void
|
|
|
|
Write out a key, value and comment into an allocated character buffer.
|
|
The buffer must be at least 80 chars to receive the information.
|
|
Formatting is done according to FITS standard.
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
void
|
|
keytuple2str (char *line, char *key, char *val, char *com)
|
|
{
|
|
int len;
|
|
int hierarch = 0;
|
|
char cval[81];
|
|
char cval2[81];
|
|
char cval_q[81];
|
|
char ccom[81];
|
|
char safe_line[512];
|
|
int i, j;
|
|
|
|
if (line == NULL || key == NULL)
|
|
return;
|
|
|
|
/* Set the line with zeroes */
|
|
memset (line, ' ', 80);
|
|
if (key == NULL)
|
|
return;
|
|
|
|
/* END keyword */
|
|
if (!strcmp (key, "END"))
|
|
{
|
|
/* Write key and return */
|
|
sprintf (line, "END");
|
|
return;
|
|
}
|
|
/* HISTORY, COMMENT and blank keywords */
|
|
if (!strcmp (key, "HISTORY") ||
|
|
!strcmp (key, "COMMENT") || !strncmp (key, " ", 8))
|
|
{
|
|
/* Write key */
|
|
sprintf (line, "%s ", key);
|
|
if (val == NULL)
|
|
return;
|
|
|
|
/* There is a value to write, copy it correctly */
|
|
len = strlen (val);
|
|
/* 72 is 80 (FITS line size) - 8 (sizeof COMMENT or HISTORY) */
|
|
if (len > 72)
|
|
len = 72;
|
|
strncpy (line + 8, val, len);
|
|
return;
|
|
}
|
|
|
|
/* Check for NULL values */
|
|
if (val == NULL)
|
|
cval[0] = (char) 0;
|
|
else if (strlen (val) < 1)
|
|
cval[0] = (char) 0;
|
|
else
|
|
strcpy (cval, val);
|
|
|
|
/* Check for NULL comments */
|
|
if (com == NULL)
|
|
strcpy (ccom, "no comment");
|
|
else
|
|
strcpy (ccom, com);
|
|
|
|
/* Set hierarch flag */
|
|
if (!strncmp (key, "HIERARCH", 8))
|
|
hierarch++;
|
|
|
|
/* Boolean, int, float or complex */
|
|
if (qfits_is_int (cval) ||
|
|
qfits_is_float (cval) ||
|
|
qfits_is_boolean (cval) || qfits_is_complex (cval))
|
|
{
|
|
if (hierarch)
|
|
sprintf (safe_line, "%-29s= %s / %s", key, cval, ccom);
|
|
else
|
|
sprintf (safe_line, "%-8.8s= %20s / %-48s", key, cval, ccom);
|
|
strncpy (line, safe_line, 80);
|
|
line[80] = (char) 0;
|
|
return;
|
|
}
|
|
|
|
/* Blank or NULL values */
|
|
if (cval[0] == 0)
|
|
{
|
|
if (hierarch)
|
|
{
|
|
sprintf (safe_line, "%-29s= / %s", key, ccom);
|
|
}
|
|
else
|
|
{
|
|
sprintf (safe_line, "%-8.8s= / %-48s", key,
|
|
ccom);
|
|
}
|
|
strncpy (line, safe_line, 80);
|
|
line[80] = (char) 0;
|
|
return;
|
|
}
|
|
|
|
/* Can only be a string - Make simple quotes ['] as double [''] */
|
|
memset (cval_q, 0, 81);
|
|
strcpy (cval2, qfits_pretty_string (cval));
|
|
j = 0;
|
|
i = 0;
|
|
while (cval2[i] != (char) 0)
|
|
{
|
|
if (cval2[i] == '\'')
|
|
{
|
|
cval_q[j] = '\'';
|
|
j++;
|
|
cval_q[j] = '\'';
|
|
}
|
|
else
|
|
{
|
|
cval_q[j] = cval2[i];
|
|
}
|
|
i++;
|
|
j++;
|
|
}
|
|
|
|
if (hierarch)
|
|
{
|
|
sprintf (safe_line, "%-29s= '%s' / %s", key, cval_q, ccom);
|
|
if (strlen (key) + strlen (cval_q) + 3 >= 80)
|
|
safe_line[79] = '\'';
|
|
}
|
|
else
|
|
{
|
|
sprintf (safe_line, "%-8.8s= '%-8s' / %s", key, cval_q, ccom);
|
|
}
|
|
strncpy (line, safe_line, 80);
|
|
|
|
/* Null-terminate in any case */
|
|
line[80] = (char) 0;
|
|
return;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief Dump a FITS header to an opened file.
|
|
@param hdr FITS header to dump
|
|
@param out Opened file pointer
|
|
@return int 0 if Ok, -1 otherwise
|
|
Dumps a FITS header to an opened file pointer.
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
int
|
|
qfits_header_dump (qfits_header * hdr, FILE * out)
|
|
{
|
|
keytuple *k;
|
|
char line[81];
|
|
int n_out;
|
|
|
|
if (hdr == NULL)
|
|
return -1;
|
|
if (out == NULL)
|
|
out = stdout;
|
|
|
|
k = (keytuple *) hdr->first;
|
|
n_out = 0;
|
|
while (k != NULL)
|
|
{
|
|
/* Make line from information in the node */
|
|
qfits_header_makeline (line, k, 1);
|
|
if ((fwrite (line, 1, 80, out)) != 80)
|
|
{
|
|
fprintf (stderr, "error dumping FITS header");
|
|
return -1;
|
|
}
|
|
n_out++;
|
|
k = k->next;
|
|
}
|
|
/* If printing out to a regular file, blank pad */
|
|
if (out != stdout && out != stderr)
|
|
{
|
|
/* Blank-pad the output */
|
|
memset (line, ' ', 80);
|
|
while (n_out % 36)
|
|
{
|
|
fwrite (line, 1, 80, out);
|
|
n_out++;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief Dump a FITS header to an opened file (one card per line).
|
|
@param hdr FITS header to dump
|
|
@param out Opened file pointer
|
|
@return int 0 if Ok, -1 otherwise
|
|
@see qfits_header_dump()
|
|
Dumps a FITS header to an opened file pointer.
|
|
This function is meant to create hdr files.
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
int
|
|
qfits_header_dump_hdr (qfits_header * hdr, FILE * out)
|
|
{
|
|
keytuple *k;
|
|
char line[81];
|
|
int n_out;
|
|
|
|
if (hdr == NULL)
|
|
return -1;
|
|
if (out == NULL)
|
|
out = stdout;
|
|
|
|
k = (keytuple *) hdr->first;
|
|
n_out = 0;
|
|
while (k != NULL)
|
|
{
|
|
/* Make line from information in the node */
|
|
qfits_header_makeline (line, k, 1);
|
|
fprintf (out, line);
|
|
fprintf (out, "\n");
|
|
n_out++;
|
|
k = k->next;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief Dump a fits header into a memory block.
|
|
@param fh FITS header to dump
|
|
@param hsize Size of the returned header, in bytes (output).
|
|
@return 1 newly allocated memory block containing the FITS header.
|
|
|
|
This function dumps a FITS header structure into a newly allocated
|
|
memory block. The block is composed of characters, just as they would
|
|
appear in a FITS file. This function is useful to make a FITS header
|
|
in memory.
|
|
|
|
The returned block size is indicated in the passed output variable
|
|
'hsize'. The returned block must be deallocated using free().
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
char *
|
|
qfits_header_to_memblock (qfits_header * fh, int *hsize)
|
|
{
|
|
char *buf;
|
|
int sz;
|
|
int nblocks;
|
|
int ncards;
|
|
keytuple *k;
|
|
char *start;
|
|
|
|
if (fh == NULL || hsize == NULL)
|
|
return NULL;
|
|
|
|
/* Count number of blocks in input (1 block is 36 cards) */
|
|
ncards = fh->n;
|
|
nblocks = 1;
|
|
while (ncards > 36)
|
|
{
|
|
nblocks++;
|
|
ncards -= 36;
|
|
}
|
|
sz = nblocks * 2880;
|
|
/* Allocate buffer and fill it with blanks */
|
|
buf = malloc (sz * sizeof (char));
|
|
memset (buf, ' ', sz);
|
|
|
|
/* Iterate on all cards in the header, dump them into buf */
|
|
start = buf;
|
|
k = (keytuple *) fh->first;
|
|
while (k != NULL)
|
|
{
|
|
qfits_header_makeline (start, k, 1);
|
|
k = k->next;
|
|
start += 80;
|
|
}
|
|
/* Update output buffer size */
|
|
*hsize = sz;
|
|
return buf;
|
|
}
|
|
|
|
/* vim: set ts=4 et sw=4 tw=75 */
|