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