1 /* Note: this file has been modified from its original form by the
2    Astrometry.net team.  For details see http://astrometry.net */
3 
4 /* $Id: qfits_header.c,v 1.10 2006/11/22 13:33:42 yjung Exp $
5  *
6  * This file is part of the ESO QFITS Library
7  * Copyright (C) 2001-2004 European Southern Observatory
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  */
23 
24 /*
25  * $Author: yjung $
26  * $Date: 2006/11/22 13:33:42 $
27  * $Revision: 1.10 $
28  * $Name: qfits-6_2_0 $
29  */
30 
31 /*-----------------------------------------------------------------------------
32                                    Includes
33  -----------------------------------------------------------------------------*/
34 
35 #include "qfits_header.h"
36 #include "qfits_std.h"
37 #include "qfits_tools.h"
38 #include "qfits_card.h"
39 #include "qfits_error.h"
40 #include "qfits_memory.h"
41 
42 struct qfits_header {
43     void    *   first;         /* Pointer to list start */
44     void    *   last;          /* Pointer to list end */
45     int         n;             /* Number of cards in list */
46     /* For efficient looping internally */
47     void    *   current;
48     int         current_idx;
49 };
50 
51 
52 /*----------------------------------------------------------------------------*/
53 /*
54   @brief    keytuple object (internal)
55 
56   This structure represents a FITS card (key, val, comment) in memory.
57   A FITS header is a list of such structs. Although the struct is here
58   made public for convenience, it is not supposed to be directly used.
59   High-level FITS routines should do the job just fine, without need
60   to know about this struct.
61  */
62 /*----------------------------------------------------------------------------*/
63 typedef struct _keytuple_ {
64 
65     char    *   key;   /** Key: unique string in a list */
66     char    *   val;   /** Value, always as a string */
67     char    *   com;   /** Comment associated to key */
68     char    *   lin;   /** Initial line in FITS header if applicable */
69     int         typ;   /** Key type */
70 
71     /** Implemented as a doubly-linked list */
72     struct _keytuple_ * next;
73     struct _keytuple_ * prev;
74 } keytuple;
75 
76 /*----------------------------------------------------------------------------*/
77 /**
78   @enum        keytype
79   @brief    Possible key types
80 
81   This enum stores all possible types for a FITS keyword. These determine
82   the order of appearance in a header, they are a crucial point for
83   DICB (ESO) compatibility. This classification is internal to this
84   module.
85  */
86 /*----------------------------------------------------------------------------*/
87 typedef enum _keytype_ {
88     keytype_undef            =0,
89 
90     keytype_top                =1,
91 
92     /* Mandatory keywords */
93     /* All FITS files */
94     keytype_bitpix            =2,
95     keytype_naxis            =3,
96 
97     keytype_naxis1            =11,
98     keytype_naxis2            =12,
99     keytype_naxis3            =13,
100     keytype_naxis4            =14,
101     keytype_naxisi            =20,
102     /* Random groups only */
103     keytype_group            =30,
104     /* Extensions */
105     keytype_pcount            =31,
106     keytype_gcount            =32,
107     /* Main header */
108     keytype_extend            =33,
109     /* Images */
110     keytype_bscale            =34,
111     keytype_bzero            =35,
112     /* Tables */
113     keytype_tfields            =36,
114     keytype_tbcoli            =40,
115     keytype_tformi            =41,
116 
117     /* Other primary keywords */
118     keytype_primary            =100,
119 
120     /* HIERARCH ESO keywords ordered according to DICB */
121     keytype_hierarch_dpr    =200,
122     keytype_hierarch_obs    =201,
123     keytype_hierarch_tpl    =202,
124     keytype_hierarch_gen    =203,
125     keytype_hierarch_tel    =204,
126     keytype_hierarch_ins    =205,
127     keytype_hierarch_det    =206,
128     keytype_hierarch_log    =207,
129     keytype_hierarch_pro    =208,
130     /* Other HIERARCH keywords */
131     keytype_hierarch        =300,
132 
133     /* HISTORY and COMMENT */
134     keytype_history            =400,
135     keytype_comment            =500,
136     keytype_continue           =600,
137     /* END */
138     keytype_end                =1000
139 } keytype;
140 
141 /*-----------------------------------------------------------------------------
142                         Private to this module
143  -----------------------------------------------------------------------------*/
144 
145 static keytuple * keytuple_new(const char *, const char *, const char *,
146         const char *);
147 static void keytuple_del(keytuple *);
148 //static void keytuple_dmp(const keytuple *);
149 static keytype keytuple_type(const char *);
150 static int qfits_header_makeline(char *, const keytuple *, int);
151 
152 /*----------------------------------------------------------------------------*/
153 /**
154  * @defgroup    qfits_header    FITS header handling
155  *
156  * This file contains definition and related methods for the FITS header
157  * structure. This structure is meant to remain opaque to the user, who
158  * only accesses it through the dedicated functions.
159  *
160  * The 'keytuple' type is strictly internal to this module.
161  * It describes FITS cards as tuples (key,value,comment,line), where key
162  * is always a non-NULL character string, value and comment are
163  * allowed to be NULL. 'line' is a string containing the line as it
164  * has been read from the input FITS file (raw). It is set to NULL if
165  * the card is modified later. This allows in output two options:
166  * either reconstruct the FITS lines by printing key = value / comment
167  * in a FITS-compliant way, or output the lines as they were found in
168  * input, except for the modified ones.
169  *
170  * The following functions are associated methods
171  * to this data structure:
172  *
173  * - keytuple_new()      constructor
174  * - keytuple_del()      destructor
175  * - keytuple_dmp()      dumps a keytuple to stdout
176  *
177  */
178 /*----------------------------------------------------------------------------*/
179 /**@{*/
180 
181 /*-----------------------------------------------------------------------------
182                               Public functions
183  -----------------------------------------------------------------------------*/
184 
185 /*----------------------------------------------------------------------------*/
186 /**
187   @brief    FITS header constructor
188   @return    1 newly allocated (empty) qfits_header object.
189 
190   This is the main constructor for a qfits_header object. It returns
191   an allocated linked-list handler with an empty card list.
192  */
193 /*----------------------------------------------------------------------------*/
qfits_header_new(void)194 qfits_header * qfits_header_new(void)
195 {
196     qfits_header    *    h;
197     h = qfits_malloc(sizeof(qfits_header));
198     h->first = NULL;
199     h->last  = NULL;
200     h->n = 0;
201 
202     h->current = NULL;
203     h->current_idx = -1;
204 
205     return h;
206 }
207 
qfits_header_n(const qfits_header * hdr)208 int qfits_header_n(const qfits_header* hdr) {
209     if (!hdr) return -1;
210     return hdr->n;
211 }
212 
213 /*----------------------------------------------------------------------------*/
214 /**
215   @brief    FITS header default constructor.
216   @return    1 newly allocated qfits_header object.
217 
218   This is a secondary constructor for a qfits_header object. It returns
219   an allocated linked-list handler containing two cards: the first one
220   (SIMPLE=T) and the last one (END).
221 
222  */
223 /*----------------------------------------------------------------------------*/
qfits_header_default(void)224 qfits_header * qfits_header_default(void)
225 {
226     qfits_header    *    h;
227     h = qfits_header_new();
228     qfits_header_append(h, "SIMPLE", "T", "Fits format", NULL);
229     qfits_header_append(h, "END", NULL, NULL, NULL);
230     return h;
231 }
232 
233 /*----------------------------------------------------------------------------*/
234 /**
235   @brief    Add a new card to a FITS header
236   @param    hdr qfits_header object to modify
237   @param    key FITS key
238   @param    val FITS value
239   @param    com FITS comment
240   @param    lin FITS original line if exists
241   @return    void
242 
243   This function adds a new card into a header, at the one-before-last
244   position, i.e. the entry just before the END entry if it is there.
245   The key must always be a non-NULL string, all other input parameters
246   are allowed to get NULL values.
247  */
248 /*----------------------------------------------------------------------------*/
qfits_header_add(qfits_header * hdr,const char * key,const char * val,const char * com,const char * lin)249 void qfits_header_add(
250         qfits_header    *   hdr,
251         const char      *   key,
252         const char      *   val,
253         const char      *   com,
254         const char      *   lin)
255 {
256     keytuple    *    k;
257     keytuple    *    kbf;
258     keytuple    *    first;
259     keytuple    *    last;
260 
261     if (hdr==NULL || key==NULL) return;
262     if (hdr->n<2) {
263 		fprintf(stderr, "Caution: qfits thinks it knows better than you: %s:%i key=\"%s\"\n", __FILE__, __LINE__, key);
264 		return;
265 	}
266 
267     first = (keytuple*)hdr->first;
268     last  = (keytuple*)hdr->last;
269 
270     if (((keytype)first->typ != keytype_top) ||
271         ((keytype)last->typ != keytype_end)) {
272 		fprintf(stderr, "Caution, qfits thinks it knows better than you: %s:%i\n", __FILE__, __LINE__);
273 		return;
274 	}
275 
276     /* Create new key tuple */
277     k = keytuple_new(key, val, com, lin);
278 
279 	/* Don't add duplicate SIMPLE, XTENSION or END entries. */
280 	if ((k->typ == keytype_top) || (k->typ == keytype_end)) {
281 		keytuple_del(k);
282 		return;
283 	}
284 
285     /* Find the last keytuple with same key type */
286     /* NO, DO WHAT THE DOCUMENTATION SAYS WE'RE SUPPOSED TO DO.
287      kbf = first;
288      while (kbf!=NULL) {
289      if ((k->typ>=kbf->typ) && (kbf->next) && (k->typ<kbf->next->typ)) break;
290      kbf = kbf->next;
291      }
292      if (kbf==NULL) kbf = last->prev;
293      */
294     kbf = last->prev;
295 
296     /* Hook it into list */
297     k->next = kbf->next;
298     (kbf->next)->prev = k;
299     kbf->next = k;
300     k->prev = kbf;
301 
302     hdr->n ++;
303     return;
304 }
305 
306 /*----------------------------------------------------------------------------*/
307 /**
308   @brief    add a new card to a FITS header
309   @param    hdr     qfits_header object to modify
310   @param    after    Key to specify insertion place
311   @param    key     FITS key
312   @param    val     FITS value
313   @param    com     FITS comment
314   @param    lin     FITS original line if exists
315   @return    void
316 
317   Adds a new card to a FITS header, after the specified key. Nothing
318   happens if the specified key is not found in the header. All fields
319   can be NULL, except after and key.
320  */
321 /*----------------------------------------------------------------------------*/
qfits_header_add_after(qfits_header * hdr,const char * after,const char * key,const char * val,const char * com,const char * lin)322 void qfits_header_add_after(
323         qfits_header    *   hdr,
324         const char      *   after,
325         const char      *   key,
326         const char      *   val,
327         const char      *   com,
328         const char      *   lin)
329 {
330     keytuple    *   kreq;
331     keytuple    *   k;
332     char           exp_after[FITS_LINESZ+1];
333 
334     if (hdr==NULL || after==NULL || key==NULL) return;
335 
336     qfits_expand_keyword_r(after, exp_after);
337     /* Locate where the entry is requested */
338     kreq = (keytuple*)(hdr->first);
339     while (kreq!=NULL) {
340         if (!strcmp(kreq->key, exp_after)) break;
341         kreq = kreq->next;
342     }
343     if (kreq==NULL) return;
344     k = keytuple_new(key, val, com, lin);
345 
346     k->next = kreq->next;
347     kreq->next->prev = k;
348     kreq->next = k;
349     k->prev = kreq;
350     hdr->n ++;
351     return;
352 }
353 
354 /*----------------------------------------------------------------------------*/
355 /**
356   @brief    Append a new card to a FITS header.
357   @param    hdr qfits_header object to modify
358   @param    key FITS key
359   @param    val FITS value
360   @param    com FITS comment
361   @param    lin FITS original line if exists
362   @return    void
363 
364   Adds a new card in a FITS header as the last one. All fields can be
365   NULL except key.
366  */
367 /*----------------------------------------------------------------------------*/
qfits_header_append(qfits_header * hdr,const char * key,const char * val,const char * com,const char * lin)368 void qfits_header_append(
369         qfits_header    *   hdr,
370         const char      *   key,
371         const char      *   val,
372         const char      *   com,
373         const char      *   lin)
374 {
375     keytuple    *    k;
376     keytuple    *    last;
377 
378     if (hdr==NULL || key==NULL) return;
379 
380     k = keytuple_new(key, val, com, lin);
381     if (hdr->n==0) {
382         hdr->first = hdr->last = k;
383         hdr->n = 1;
384         return;
385     }
386     last  = (keytuple*)hdr->last;
387     last->next = k;
388     k->prev = last;
389     hdr->last = k;
390     hdr->n++;
391     return;
392 }
393 
394 /*----------------------------------------------------------------------------*/
395 /**
396   @brief    Delete a card in a FITS header.
397   @param    hdr qfits_header to modify
398   @param    key specifies which card to remove
399   @return    void
400 
401   Removes a card from a FITS header. The first found card that matches
402   the key is removed.
403  */
404 /*----------------------------------------------------------------------------*/
qfits_header_del(qfits_header * hdr,const char * key)405 void qfits_header_del(qfits_header * hdr, const char * key)
406 {
407     keytuple    *   k;
408     char            xkey[FITS_LINESZ];
409 
410     if (hdr==NULL || key==NULL) return;
411 
412     qfits_expand_keyword_r(key, xkey);
413     k = (keytuple*)hdr->first;
414     while (k!=NULL) {
415         if (!strcmp(k->key, xkey)) break;
416         k = k->next;
417     }
418     if (k==NULL)
419         return;
420     if(k == hdr->first) {
421         hdr->first = k->next;
422     } else {
423         k->prev->next = k->next;
424         k->next->prev = k->prev;
425     }
426     keytuple_del(k);
427     return;
428 }
429 
430 /*----------------------------------------------------------------------------*/
431 /**
432   @brief    Modifies a FITS card.
433   @param    hdr qfits_header to modify
434   @param    key FITS key
435   @param    val FITS value
436   @param    com FITS comment
437   @return    void
438 
439   Finds the first card in the header matching 'key', and replaces its
440   value and comment fields by the provided values. The initial FITS
441   line is set to NULL in the card.
442  */
443 /*----------------------------------------------------------------------------*/
qfits_header_mod(qfits_header * hdr,const char * key,const char * val,const char * com)444 void qfits_header_mod(
445         qfits_header    *   hdr,
446         const char      *   key,
447         const char      *   val,
448         const char      *   com)
449 {
450     keytuple    *   k;
451     char            xkey[FITS_LINESZ+1];
452 
453     if (hdr==NULL || key==NULL) return;
454 
455     qfits_expand_keyword_r(key, xkey);
456     k = (keytuple*)hdr->first;
457     while (k!=NULL) {
458         if (!strcmp(k->key, xkey)) break;
459         k=k->next;
460     }
461     if (k==NULL) return;
462 
463     if (k->val) qfits_free(k->val);
464     if (k->com) qfits_free(k->com);
465     if (k->lin) qfits_free(k->lin);
466     k->val = NULL;
467     k->com = NULL;
468     k->lin = NULL;
469     if (val) {
470         if (strlen(val)>0) k->val = qfits_strdup(val);
471     }
472     if (com) {
473         if (strlen(com)>0) k->com = qfits_strdup(com);
474     }
475     return;
476 }
477 
478 /*----------------------------------------------------------------------------*/
479 /**
480   @brief    Sort a FITS header
481   @param    hdr     Header to sort (modified)
482   @return   -1 in error case, 0 otherwise
483  */
484 /*----------------------------------------------------------------------------*/
qfits_header_sort(qfits_header ** hdr)485 int qfits_header_sort(qfits_header ** hdr)
486 {
487     qfits_header    *   sorted;
488     keytuple        *   k;
489     keytuple        *   kbf;
490     keytuple        *   next;
491     keytuple        *   last;
492 
493     /* Test entries */
494     if (hdr == NULL) return -1;
495     if (*hdr == NULL) return -1;
496     if ((*hdr)->n < 2) return 0;
497 
498     /* Create the new FITS header */
499     sorted = qfits_header_new();
500 
501     /* Move the first keytuple to the sorted empty header */
502     k = (keytuple*)(*hdr)->first;
503     next = k->next;
504     sorted->first = sorted->last = k;
505     k->next = k->prev = NULL;
506     sorted->n = 1;
507 
508     /* Loop over the other tuples */
509     while (next != NULL) {
510         k = next;
511         next = k->next;
512 
513         /* Find k's place in sorted */
514         kbf = (keytuple*)sorted->first;
515         while (kbf!=NULL) {
516             if (k->typ < kbf->typ) break;
517             kbf = kbf->next;
518         }
519 
520         /* Hook k into sorted list */
521         if (kbf == NULL) {
522             /* k is last in sorted */
523             last = sorted->last;
524             sorted->last = k;
525             k->next = NULL;
526             k->prev = last;
527             last->next = k;
528         } else {
529             /* k goes just before kbf */
530             k->next = kbf;
531             k->prev = kbf->prev;
532             if (kbf->prev != NULL) (kbf->prev)->next = k;
533             else sorted->first = k;
534             kbf->prev = k;
535         }
536         (sorted->n) ++;
537     }
538 
539     /* Replace the input header by the sorted one */
540     (*hdr)->first = (*hdr)->last = NULL;
541     qfits_header_destroy(*hdr);
542     *hdr = sorted;
543 
544     return 0;
545 }
546 
547 /*----------------------------------------------------------------------------*/
548 /**
549   @brief    Copy a FITS header
550   @param    src    Header to replicate
551   @return    Pointer to newly allocated qfits_header object.
552 
553   Makes a strict copy of all information contained in the source
554   header. The returned header must be freed using qfits_header_destroy.
555  */
556 /*----------------------------------------------------------------------------*/
qfits_header_copy(const qfits_header * src)557 qfits_header * qfits_header_copy(const qfits_header * src)
558 {
559     qfits_header    *   fh_copy;
560     keytuple        *   k;
561 
562     if (src==NULL) return NULL;
563 
564     fh_copy = qfits_header_new();
565     k = (keytuple*)src->first;
566     while (k!=NULL) {
567         qfits_header_append(fh_copy, k->key, k->val, k->com, k->lin);
568         k = k->next;
569     }
570     return fh_copy;
571 }
572 
573 /*----------------------------------------------------------------------------*/
574 /**
575   @brief    qfits_header destructor
576   @param    hdr qfits_header to deallocate
577   @return    void
578 
579   Frees all memory associated to a given qfits_header object.
580  */
581 /*----------------------------------------------------------------------------*/
qfits_header_destroy(qfits_header * hdr)582 void qfits_header_destroy(qfits_header * hdr)
583 {
584     keytuple * k;
585     keytuple * kn;
586 
587     if (hdr==NULL) return;
588 
589     k = (keytuple*)hdr->first;
590     while (k!=NULL) {
591         kn = k->next;
592         keytuple_del(k);
593         k = kn;
594     }
595     qfits_free(hdr);
596     return;
597 }
598 
599 /*----------------------------------------------------------------------------*/
600 /**
601   @brief    Return the value associated to a key, as a string
602   @param    hdr qfits_header to parse
603   @param    key key to find
604   @return    pointer to statically allocated string
605 
606   Finds the value associated to the given key and return it as a
607   string. The returned pointer is statically allocated, so do not
608   modify its contents or try to free it.
609 
610   Returns NULL if no matching key is found or no value is attached.
611  */
612 /*----------------------------------------------------------------------------*/
qfits_header_getstr(const qfits_header * hdr,const char * key)613 char * qfits_header_getstr(const qfits_header * hdr, const char * key)
614 {
615     keytuple    *   k;
616     char            xkey[FITS_LINESZ+1];
617 
618     if (hdr==NULL || key==NULL) return NULL;
619 
620     qfits_expand_keyword_r(key, xkey);
621     k = (keytuple*)hdr->first;
622     while (k!=NULL) {
623         if (!strcmp(k->key, xkey)) break;
624         k=k->next;
625     }
626     if (k==NULL) return NULL;
627     return k->val;
628 }
629 
qfits_header_getstr_pretty(const qfits_header * hdr,const char * key,char * pretty,const char * defaultval)630 int qfits_header_getstr_pretty(const qfits_header* hdr, const char* key, char* pretty, const char* defaultval) {
631 	char* val = qfits_header_getstr(hdr, key);
632 	if (!val) {
633 		if (defaultval)
634 			strcpy(pretty, defaultval);
635 		return -1;
636 	}
637 	qfits_pretty_string_r(val, pretty);
638 	return 0;
639 }
640 
get_keytuple(qfits_header * hdr,int idx)641 static keytuple* get_keytuple(qfits_header* hdr, int idx) {
642     if (idx == 0) {
643 	    hdr->current_idx = 0;
644 	    hdr->current = hdr->first;
645 	    return hdr->current;
646 	} else if (idx == hdr->current_idx + 1) {
647 	    hdr->current = ((keytuple*) (hdr->current))->next;
648 	    hdr->current_idx++;
649 	    return hdr->current;
650 	} else {
651         keytuple* k = (keytuple*)hdr->first;
652 	    int count=0;
653 	    while (count<idx) {
654             k = k->next;
655             count++;
656         }
657         return k;
658 	}
659 }
660 
661 /*----------------------------------------------------------------------------*/
662 /**
663   @brief    Return the i-th key/val/com/line tuple in a header.
664   @param    hdr        Header to consider
665   @param    idx        Index of the requested card
666   @param    key        Output key
667   @param    val        Output value
668   @param    com        Output comment
669   @param    lin        Output initial line
670   @return    int 0 if Ok, -1 if error occurred.
671 
672   This function is useful to browse a FITS header object card by card.
673   By iterating on the number of cards (available in the 'n' field of
674   the qfits_header struct), you can retrieve the FITS lines and their
675   components one by one. Indexes run from 0 to n-1. You can pass NULL
676   values for key, val, com or lin if you are not interested in a
677   given field.
678 
679   @code
680   int i;
681   char key[FITS_LINESZ+1];
682   char val[FITS_LINESZ+1];
683   char com[FITS_LINESZ+1];
684   char lin[FITS_LINESZ+1];
685 
686   for (i=0; i<hdr->n; i++) {
687       qfits_header_getitem(hdr, i, key, val, com, lin);
688     printf("card[%d] key[%s] val[%s] com[%s]\n", i, key, val, com);
689   }
690   @endcode
691 
692   This function has primarily been written to interface a qfits_header
693   object to other languages (C++/Python). If you are working within a
694   C program, you should use the other header manipulation routines
695   available in this module.
696  */
697 /*----------------------------------------------------------------------------*/
qfits_header_getitem(const qfits_header * hdr,int idx,char * key,char * val,char * com,char * lin)698 int qfits_header_getitem(
699         const qfits_header  *   hdr,
700         int                     idx,
701         char                *   key,
702         char                *   val,
703         char                *   com,
704         char                *   lin)
705 {
706     keytuple    *   k;
707 
708     if (hdr==NULL) return -1;
709     if (key==NULL && val==NULL && com==NULL && lin==NULL) return 0;
710     if (idx<0 || idx>=hdr->n) return -1;
711 
712     k = get_keytuple((qfits_header*)hdr, idx);
713 
714     /* Fill return values */
715     if (key!=NULL) strcpy(key, k->key);
716     if (val!=NULL) {
717         if (k->val!=NULL) strcpy(val, k->val);
718         else val[0]=0;
719     }
720     if (com!=NULL) {
721         if (k->com!=NULL) strcpy(com, k->com);
722         else com[0]=0;
723     }
724     if (lin!=NULL) {
725         if (k->lin!=NULL) strcpy(lin, k->lin);
726         else lin[0]=0;
727     }
728     return 0;
729 }
730 
qfits_header_setitem(qfits_header * hdr,int idx,char * key,char * val,char * com,char * lin)731 int qfits_header_setitem(
732                          qfits_header  *   hdr,
733                          int                     idx,
734                          char                *   key,
735                          char                *   val,
736                          char                *   com,
737                          char                *   lin) {
738     keytuple    *   k;
739 
740     if (!hdr) return -1;
741     if (!key && !val && !com && !lin) return 0;
742     if (idx<0 || idx>=hdr->n) return -1;
743 
744     k = get_keytuple(hdr, idx);
745 
746     // free existing strings as per keytuple_del
747     if (k->key)
748         qfits_free(k->key);
749     if (k->val)
750         qfits_free(k->val);
751     if (k->com)
752         qfits_free(k->com);
753     if (k->lin)
754         qfits_free(k->lin);
755 
756     // copy input strings.
757     if (key)
758         k->key = qfits_strdup(key);
759     else
760         k->key = NULL;
761 
762     if (val)
763         k->val = qfits_strdup(val);
764     else
765         k->val = NULL;
766 
767     if (com)
768         k->com = qfits_strdup(com);
769     else
770         k->com = NULL;
771 
772     // the rest of the code expects this to be exactly 80 chars.
773     if (lin) {
774         k->lin = qfits_malloc(80);
775         memcpy(k->lin, lin, 80);
776     } else
777         k->lin = NULL;
778 
779     return 0;
780 }
781 
782 
783 /*----------------------------------------------------------------------------*/
784 /**
785   @brief    Return the comment associated to a key, as a string
786   @param    hdr qfits_header to parse
787   @param    key key to find
788   @return    pointer to statically allocated string
789 
790   Finds the comment associated to the given key and return it as a
791   string. The returned pointer is statically allocated, so do not
792   modify its contents or try to free it.
793 
794   Returns NULL if no matching key is found or no comment is attached.
795  */
796 /*----------------------------------------------------------------------------*/
qfits_header_getcom(const qfits_header * hdr,const char * key)797 char * qfits_header_getcom(const qfits_header * hdr, const char * key)
798 {
799     keytuple    *   k;
800     char            xkey[FITS_LINESZ+1];
801 
802     if (hdr==NULL || key==NULL) return NULL;
803 
804     qfits_expand_keyword_r(key, xkey);
805     k = (keytuple*)hdr->first;
806     while (k!=NULL) {
807         if (!strcmp(k->key, xkey)) break;
808         k=k->next;
809     }
810     if (k==NULL) return NULL;
811     return k->com;
812 }
813 
814 /*----------------------------------------------------------------------------*/
815 /**
816   @brief    Return the value associated to a key, as an int
817   @param    hdr qfits_header to parse
818   @param    key key to find
819   @param    errval default value to return if nothing is found
820   @return    int
821 
822   Finds the value associated to the given key and return it as an
823   int. Returns errval if no matching key is found or no value is
824   attached.
825  */
826 /*----------------------------------------------------------------------------*/
qfits_header_getint(const qfits_header * hdr,const char * key,int errval)827 int qfits_header_getint(
828         const qfits_header  *   hdr,
829         const char          *   key,
830         int                     errval)
831 {
832     char    *   c;
833     int         d;
834 
835     if (hdr==NULL || key==NULL) return errval;
836 
837     c = qfits_header_getstr(hdr, key);
838     if (c==NULL) return errval;
839     if (sscanf(c, "%d", &d)!=1) return errval;
840     return d;
841 }
842 
843 /*----------------------------------------------------------------------------*/
844 /**
845   @brief    Return the value associated to a key, as a double
846   @param    hdr qfits_header to parse
847   @param    key key to find
848   @param    errval default value to return if nothing is found
849   @return    double
850 
851   Finds the value associated to the given key and return it as a
852   double. Returns errval if no matching key is found or no value is
853   attached.
854  */
855 /*----------------------------------------------------------------------------*/
qfits_header_getdouble(const qfits_header * hdr,const char * key,double errval)856 double qfits_header_getdouble(
857         const qfits_header  *   hdr,
858         const char          *   key,
859         double                  errval)
860 {
861     char    *    c;
862     char* endptr;
863     double d;
864 
865     if (hdr==NULL || key==NULL) return errval;
866 
867     c = qfits_header_getstr(hdr, key);
868     if (c==NULL) return errval;
869 
870     d = strtod(c, &endptr);
871     if (endptr == c)
872         return errval;
873     return d;
874     //return atof(c);
875 }
876 
877 /*----------------------------------------------------------------------------*/
878 /**
879   @brief    Return the value associated to a key, as a boolean (int).
880   @param    hdr qfits_header to parse
881   @param    key key to find
882   @param    errval default value to return if nothing is found
883   @return    int
884 
885   Finds the value associated to the given key and return it as a
886   boolean. Returns errval if no matching key is found or no value is
887   attached. A boolean is here understood as an int taking the value 0
888   or 1. errval can be set to any other integer value to reflect that
889   nothing was found.
890 
891   errval is returned if no matching key is found or no value is
892   attached.
893 
894   A true value is any character string beginning with a 'y' (yes), a
895   't' (true) or the digit '1'. A false value is any character string
896   beginning with a 'n' (no), a 'f' (false) or the digit '0'.
897  */
898 /*----------------------------------------------------------------------------*/
qfits_header_getboolean(const qfits_header * hdr,const char * key,int errval)899 int qfits_header_getboolean(
900         const qfits_header  *   hdr,
901         const char          *   key,
902         int                     errval)
903 {
904     char    *    c;
905     int            ret;
906 
907     if (hdr==NULL || key==NULL) return errval;
908 
909     c = qfits_header_getstr(hdr, key);
910     if (c==NULL) return errval;
911     if (strlen(c)<1) return errval;
912 
913     if (c[0]=='y' || c[0]=='Y' || c[0]=='1' || c[0]=='t' || c[0]=='T') {
914         ret = 1;
915     } else if (c[0]=='n' || c[0]=='N' || c[0]=='0' || c[0]=='f' || c[0]=='F') {
916         ret = 0;
917     } else {
918         ret = errval;
919     }
920     return ret;
921 }
922 
qfits_header_write_line(const qfits_header * hdr,int line,char * result)923 int qfits_header_write_line(const qfits_header* hdr, int line, char* result) {
924     keytuple* k;
925     int i;
926 
927     k = hdr->first;
928     for (i=0; i<line; i++) {
929         k = k->next;
930         if (!k)
931             return -1;
932     }
933     qfits_header_makeline(result, k, 1);
934     return 0;
935 }
936 
937 
938 /*----------------------------------------------------------------------------*/
939 /**
940   @brief    Dump a FITS header to an opened file.
941   @param    hdr     FITS header to dump
942   @param    out     Opened file pointer
943   @return   int 0 if Ok, -1 otherwise
944   Dumps a FITS header to an opened file pointer.
945  */
946 /*----------------------------------------------------------------------------*/
qfits_header_dump(const qfits_header * hdr,FILE * out)947 int qfits_header_dump(
948         const qfits_header  *   hdr,
949         FILE                *   out)
950 {
951     keytuple    *   k;
952     char            line[81];
953     int             n_out;
954 
955     if (hdr==NULL) return -1;
956     if (out==NULL) out=stdout;
957 
958     k = (keytuple*)hdr->first;
959     n_out = 0;
960     while (k!=NULL) {
961         /* Make line from information in the node */
962         qfits_header_makeline(line, k, 1);
963         if ((fwrite(line, 1, 80, out))!=80) {
964             fprintf(stderr, "error dumping FITS header");
965             return -1;
966         }
967         n_out ++;
968         k=k->next;
969     }
970     /* Blank-pad the output */
971     memset(line, ' ', 80);
972     while (n_out % 36) {
973         fwrite(line, 1, 80, out);
974         n_out++;
975     }
976     return 0;
977 }
978 
979 
qfits_header_list(const qfits_header * hdr,FILE * out)980 int qfits_header_list(
981         const qfits_header  *   hdr,
982         FILE                *   out)
983 {
984     keytuple    *   k;
985     char            line[81];
986     int             n_out;
987 
988     if (hdr==NULL) return -1;
989     if (out==NULL) out=stdout;
990 
991     k = (keytuple*)hdr->first;
992     n_out = 0;
993     while (k!=NULL) {
994         /* Make line from information in the node */
995         qfits_header_makeline(line, k, 1);
996         if ((fwrite(line, 1, 80, out))!=80) {
997             fprintf(stderr, "error dumping FITS header");
998             return -1;
999         }
1000         fprintf(out, "\n");
1001         n_out ++;
1002         k=k->next;
1003     }
1004     return 0;
1005 }
1006 
1007 /**@}*/
1008 
1009 /*----------------------------------------------------------------------------*/
1010 /**
1011   @brief    keytuple constructor
1012   @param    key        Key associated to key tuple (cannot be NULL).
1013   @param    val        Value associated to key tuple.
1014   @param    com        Comment associated to key tuple.
1015   @param    lin        Initial line read from FITS header (if applicable).
1016   @return    1 pointer to newly allocated keytuple.
1017 
1018   This function is a keytuple creator. NULL values and zero-length strings
1019   are valid parameters for all but the key field. The returned object must
1020   be deallocated using keytuple_del().
1021 
1022  */
1023 /*----------------------------------------------------------------------------*/
keytuple_new(const char * key,const char * val,const char * com,const char * lin)1024 static keytuple * keytuple_new(
1025         const char * key,
1026         const char * val,
1027         const char * com,
1028         const char * lin)
1029 {
1030     char xkey[FITS_LINESZ+1];
1031     keytuple    *    k;
1032 
1033     if (key==NULL) return NULL;
1034 
1035     /* Allocate space for new structure */
1036     k = qfits_malloc(sizeof(keytuple));
1037     /* Hook a copy of the new key */
1038     qfits_expand_keyword_r(key, xkey);
1039     k->key = qfits_strdup(xkey);
1040     /* Hook a copy of the value if defined */
1041     k->val = NULL;
1042     if (val!=NULL) {
1043 		// Why was this here?
1044         //if (strlen(val)>0)
1045 		k->val = qfits_strdup(val);
1046     }
1047     /* Hook a copy of the comment if defined */
1048     k->com = NULL;
1049     if (com!=NULL) {
1050         if (strlen(com)>0) k->com = qfits_strdup(com);
1051     }
1052     /* Hook a copy of the initial line if defined */
1053     k->lin = NULL;
1054     if (lin!=NULL) {
1055         if (strlen(lin)>0) k->lin = qfits_strdup(lin);
1056     }
1057     k->next = NULL;
1058     k->prev = NULL;
1059     k->typ = keytuple_type(key);
1060 
1061     return k;
1062 }
1063 
1064 /*----------------------------------------------------------------------------*/
1065 /**
1066   @brief    keytuple type identification routine
1067   @param    key        String representing a FITS keyword.
1068   @return    A key type (see keytype enum)
1069 
1070   This function identifies the type of a FITS keyword when given the
1071   keyword as a string. Keywords are expected literally as they are
1072   found in a FITS header on disk.
1073 
1074  */
1075 /*----------------------------------------------------------------------------*/
keytuple_type(const char * key)1076 static keytype keytuple_type(const char * key)
1077 {
1078     keytype kt;
1079 
1080     kt = keytype_undef;
1081     /* Assign type to key tuple */
1082     if (!strcmp(key, "SIMPLE") || !strcmp(key, "XTENSION")) kt = keytype_top;
1083     else if (!strcmp(key, "END"))                   kt = keytype_end;
1084     else if (!strcmp(key, "BITPIX"))                kt = keytype_bitpix;
1085     else if (!strcmp(key, "NAXIS"))                 kt = keytype_naxis;
1086     else if (!strcmp(key, "NAXIS1"))                kt = keytype_naxis1;
1087     else if (!strcmp(key, "NAXIS2"))                kt = keytype_naxis2;
1088     else if (!strcmp(key, "NAXIS3"))                kt = keytype_naxis3;
1089     else if (!strcmp(key, "NAXIS4"))                kt = keytype_naxis4;
1090     else if (!strncmp(key, "NAXIS", 5))             kt = keytype_naxisi;
1091     else if (!strcmp(key, "GROUP"))                 kt = keytype_group;
1092     else if (!strcmp(key, "PCOUNT"))                kt = keytype_pcount;
1093     else if (!strcmp(key, "GCOUNT"))                kt = keytype_gcount;
1094     else if (!strcmp(key, "EXTEND"))                kt = keytype_extend;
1095     else if (!strcmp(key, "BSCALE"))                kt = keytype_bscale;
1096     else if (!strcmp(key, "BZERO"))                 kt = keytype_bzero;
1097     else if (!strcmp(key, "TFIELDS"))               kt = keytype_tfields;
1098     else if (!strncmp(key, "TBCOL", 5))             kt = keytype_tbcoli;
1099     else if (!strncmp(key, "TFORM", 5))             kt = keytype_tformi;
1100     else if (!strncmp(key, "HIERARCH ESO DPR", 16)) kt = keytype_hierarch_dpr;
1101     else if (!strncmp(key, "HIERARCH ESO OBS", 16)) kt = keytype_hierarch_obs;
1102     else if (!strncmp(key, "HIERARCH ESO TPL", 16)) kt = keytype_hierarch_tpl;
1103     else if (!strncmp(key, "HIERARCH ESO GEN", 16)) kt = keytype_hierarch_gen;
1104     else if (!strncmp(key, "HIERARCH ESO TEL", 16)) kt = keytype_hierarch_tel;
1105     else if (!strncmp(key, "HIERARCH ESO INS", 16)) kt = keytype_hierarch_ins;
1106     else if (!strncmp(key, "HIERARCH ESO LOG", 16)) kt = keytype_hierarch_log;
1107     else if (!strncmp(key, "HIERARCH ESO PRO", 16)) kt = keytype_hierarch_pro;
1108     else if (!strncmp(key, "HIERARCH", 8))          kt = keytype_hierarch;
1109     else if (!strcmp(key, "HISTORY"))               kt = keytype_history;
1110     else if (!strcmp(key, "COMMENT"))               kt = keytype_comment;
1111     else if (!strcmp(key, "CONTINUE"))              kt = keytype_continue;
1112     else if ((int)strlen(key)<9)                    kt = keytype_primary;
1113     return kt;
1114 }
1115 
1116 /*----------------------------------------------------------------------------*/
1117 /**
1118   @brief    Keytuple destructor.
1119   @param    k    Keytuple to deallocate.
1120   @return    void
1121   Keytuple destructor.
1122  */
1123 /*----------------------------------------------------------------------------*/
keytuple_del(keytuple * k)1124 static void keytuple_del(keytuple * k)
1125 {
1126     if (k==NULL) return;
1127     if (k->key) qfits_free(k->key);
1128     if (k->val) qfits_free(k->val);
1129     if (k->com) qfits_free(k->com);
1130     if (k->lin) qfits_free(k->lin);
1131     qfits_free(k);
1132 }
1133 
1134 /*----------------------------------------------------------------------------*/
1135 /**
1136   @brief    Keytuple dumper.
1137   @param    k    Keytuple to dump
1138   @return    void
1139 
1140   This function dumps a key tuple to stdout. It is meant for debugging
1141   purposes only.
1142  */
1143 /*----------------------------------------------------------------------------*/
keytuple_dmp(const keytuple * k)1144 static void keytuple_dmp(const keytuple * k) {
1145     if (!k) return;
1146     printf("[%s]=[", k->key);
1147     if (k->val) printf("%s", k->val);
1148     printf("]");
1149     if (k->com) printf("/[%s]", k->com);
1150     printf("\n");
1151     return;
1152 }
1153 
qfits_header_debug_dump(const qfits_header * hdr)1154 void qfits_header_debug_dump(const qfits_header* hdr) {
1155 	keytuple* k;
1156 	if (hdr==NULL) return;
1157 	k = (keytuple*)hdr->first;
1158 	while (k) {
1159         keytuple_dmp(k);
1160 		k=k->next;
1161 	}
1162 }
1163 
1164 /*----------------------------------------------------------------------------*/
1165 /**
1166   @brief    Build a FITS line from the information contained in a card.
1167   @param    line pointer to allocated string to be filled
1168   @param    node pointer to card node in qfits_header linked-list
1169   @param    conservative flag to indicate conservative behaviour
1170   @return    int 0 if Ok, anything else otherwise
1171 
1172   Build a FITS line (80 chars) from the information contained in a
1173   node of a qfits_header linked-list. If the mode is set to
1174   conservative, the original FITS line will be used wherever present.
1175   If conservative is set to 0, a new line will be formatted.
1176  */
1177 /*----------------------------------------------------------------------------*/
qfits_header_makeline(char * line,const keytuple * k,int conservative)1178 static int qfits_header_makeline(
1179         char            *   line,
1180         const keytuple  *   k,
1181         int                 conservative)
1182 {
1183     char blankline[81];
1184     int     i;
1185 
1186     if (line==NULL || k==NULL) return -1;
1187 
1188     /* If a previous line information is there, use it as is */
1189     if (conservative) {
1190         if (k->lin != NULL) {
1191             memcpy(line, k->lin, 80);
1192             line[80]='\0';
1193             return 0;
1194         }
1195     }
1196     /* Got to build keyword from scratch */
1197     memset(blankline, 0, 81);
1198     qfits_card_build(blankline, k->key, k->val, k->com);
1199     memset(line, ' ', 80);
1200     i=0;
1201     while (blankline[i] != '\0') {
1202         line[i] = blankline[i];
1203         i++;
1204     }
1205     line[80]='\0';
1206     return 0;
1207 }
1208 
1209 /*----------------------------------------------------------------------------*/
1210 /**
1211   @brief	Find a matching key in a header.
1212   @param	hdr	qfits_header to parse
1213   @param	key	Key prefix to match
1214   @return	pointer to statically allocated string.
1215 
1216   This function finds the first keyword in the given header for
1217   which the given 'key' is a prefix, and returns the full name
1218   of the matching key (NOT ITS VALUE). This is useful to locate
1219   any keyword starting with a given prefix. Careful with HIERARCH
1220   keywords, the shortFITS notation is not likely to be accepted here.
1221 
1222   Examples:
1223 
1224   @verbatim
1225   s = qfits_header_findmatch(hdr, "SIMP") returns "SIMPLE"
1226   s = qfits_header_findmatch(hdr, "HIERARCH ESO DET") returns
1227   the first detector keyword among the HIERACH keys.
1228   @endverbatim
1229  */
1230 /*----------------------------------------------------------------------------*/
qfits_header_findmatch(const qfits_header * hdr,const char * key)1231 char * qfits_header_findmatch(const qfits_header * hdr, const char * key)
1232 {
1233 	keytuple    *   k;
1234 
1235 	if (hdr==NULL || key==NULL) return NULL;
1236 
1237 	k = (keytuple*)hdr->first;
1238 	while (k!=NULL) {
1239 		if (!strncmp(k->key, key, (int)strlen(key))) break;
1240 		k=k->next;
1241 	}
1242 	if (k==NULL) return NULL;
1243 	return k->key;
1244 }
1245