1 /*============================================================================
2   WCSLIB 7.7 - an implementation of the FITS WCS standard.
3   Copyright (C) 1995-2021, Mark Calabretta
4 
5   This file is part of WCSLIB.
6 
7   WCSLIB is free software: you can redistribute it and/or modify it under the
8   terms of the GNU Lesser General Public License as published by the Free
9   Software Foundation, either version 3 of the License, or (at your option)
10   any later version.
11 
12   WCSLIB is distributed in the hope that it will be useful, but WITHOUT ANY
13   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14   FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
15   more details.
16 
17   You should have received a copy of the GNU Lesser General Public License
18   along with WCSLIB.  If not, see http://www.gnu.org/licenses.
19 
20   Author: Mark Calabretta, Australia Telescope National Facility, CSIRO.
21   http://www.atnf.csiro.au/people/Mark.Calabretta
22   $Id: tfitshdr.c,v 7.7 2021/07/12 06:36:49 mcalabre Exp $
23 *=============================================================================
24 *
25 * tfitshdr tests fitshdr(), the FITS parser for image headers, by reading a
26 * test header and printing the resulting fitskey structs.
27 *
28 * Input comes from file 'fitshdr.fits' using either fits_hdr2str() from
29 * CFITSIO if the DO_CFITSIO preprocessor is defined, or read directly using
30 * fgets() otherwise.
31 *
32 * wcshdr() is called first to extract all WCS-related keyrecords from the
33 * input header before passing it on to fitshdr().
34 *
35 *---------------------------------------------------------------------------*/
36 
37 #include <wcsconfig_tests.h>
38 
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 
43 #if defined HAVE_CFITSIO && defined DO_CFITSIO
44 #include <fitsio.h>
45 #endif
46 
47 #include <fitshdr.h>
48 #include <wcshdr.h>
49 #include <wcsutil.h>
50 
main()51 int main()
52 
53 {
54   char infile[] = "fitshdr.fits";
55   char text[80];
56   int  i, j, k, nkeyrec, nkeyids, nreject, status;
57   struct fitskey *keys, *kptr;
58   struct fitskeyid keyids[8];
59 #if defined HAVE_CFITSIO && defined DO_CFITSIO
60   char *header;
61   fitsfile *fptr;
62 #else
63   char keyrec[81], header[288001];
64   int  end;
65   FILE *fptr;
66 #endif
67 
68   struct wcsprm *wcs;
69   int  ctrl, nwcs, relax;
70 
71 
72   // Set line buffering in case stdout is redirected to a file, otherwise
73   // stdout and stderr messages will be jumbled (stderr is unbuffered).
74   setvbuf(stdout, NULL, _IOLBF, 0);
75 
76   printf("Testing FITS image header parser (tfitshdr.c)\n"
77          "---------------------------------------------\n\n");
78 
79   // Read in the FITS header.
80 #if defined HAVE_CFITSIO && defined DO_CFITSIO
81   status = 0;
82 
83   if (fits_open_file(&fptr, infile, READONLY, &status)) {
84     fits_report_error(stderr, status);
85     return 1;
86   }
87 
88   if (fits_hdr2str(fptr, 0, NULL, 0, &header, &nkeyrec, &status)) {
89     fits_report_error(stderr, status);
90     return 1;
91   }
92 
93   fits_close_file(fptr, &status);
94 #else
95   if ((fptr = fopen(infile, "r")) == 0) {
96     printf("ERROR opening %s\n", infile);
97     return 1;
98   }
99 
100   k = 0;
101   end = 0;
102   nkeyrec = 0;
103   for (j = 0; j < 100; j++) {
104     for (i = 0; i < 36; i++) {
105       if (fgets(keyrec, 81, fptr) == 0) {
106         break;
107       }
108 
109       memcpy(header+k, keyrec, 80);
110       k += 80;
111       nkeyrec++;
112 
113       if (strncmp(keyrec, "END       ", 10) == 0) {
114         // An END keyrecord was read, but read the rest of the block.
115         end = 1;
116       }
117     }
118 
119     if (end) break;
120   }
121   fclose(fptr);
122 #endif
123 
124   printf("Found %d header keyrecords.\n", nkeyrec);
125 
126 
127   // Cull recognized, syntactically valid WCS keyrecords from the header.
128   relax = WCSHDR_all;
129   ctrl = -1;
130   if ((status = wcspih(header, nkeyrec, relax, ctrl, &nreject, &nwcs,
131                        &wcs))) {
132     fprintf(stderr, "wcspih ERROR %d: %s.\n", status, wcs_errmsg[status]);
133     return 1;
134   }
135   wcsvfree(&nwcs, &wcs);
136 
137   // Number remaining.
138   nkeyrec = strlen(header) / 80;
139 
140 
141   // Specific keywords to be located or culled.
142   strcpy(keyids[0].name, "SIMPLE  ");
143   strcpy(keyids[1].name, "BITPIX  ");
144   strcpy(keyids[2].name, "NAXIS   ");
145   strcpy(keyids[3].name, "COMMENT ");
146   strcpy(keyids[4].name, "HISTORY ");
147   strcpy(keyids[5].name, "        ");
148   strcpy(keyids[6].name, "END     ");
149   nkeyids = 7;
150 
151   if (nkeyids) {
152     printf("\nThe following keyrecords will not be listed:\n");
153     for (i = 0; i < nkeyids; i++) {
154       printf("  \"%8s\"\n", keyids[i].name);
155     }
156   }
157 
158 
159   // Parse the header.
160   if ((status = fitshdr(header, nkeyrec, nkeyids, keyids, &nreject, &keys))) {
161     printf("fitskey ERROR %d: %s.\n", status, fitshdr_errmsg[status]);
162   }
163 #if defined HAVE_CFITSIO && defined DO_CFITSIO
164   fits_free_memory(header, &status);
165 #endif
166 
167   // Report the results.
168   printf("\n%d header keyrecords parsed by fitshdr(), %d rejected:\n\n",
169     nkeyrec, nreject);
170   kptr = keys;
171   for (i = 0; i < nkeyrec; i++, kptr++) {
172     // Skip syntactically valid keyrecords that were indexed.
173     if (kptr->keyno < 0 && !kptr->status) continue;
174 
175     // Basic keyrecord info.
176     printf("%4d%5d  %-8s%3d", kptr->keyno, kptr->status, kptr->keyword,
177                               kptr->type);
178 
179     // Format the keyvalue for output.
180     switch (abs(kptr->type)%10) {
181     case 1:
182       // Logical.
183       sprintf(text, "%c", kptr->keyvalue.i?'T':'F');
184       break;
185     case 2:
186       // 32-bit signed integer.
187       sprintf(text, "%d", kptr->keyvalue.i);
188       break;
189     case 3:
190       // 64-bit signed integer.
191 #ifdef WCSLIB_INT64
192          sprintf(text, "%+lld", kptr->keyvalue.k);
193 #else
194          if (kptr->keyvalue.k[2]) {
195            sprintf(text, "%+d%09d%09d", kptr->keyvalue.k[2],
196                                     abs(kptr->keyvalue.k[1]),
197                                     abs(kptr->keyvalue.k[0]));
198          } else {
199            sprintf(text, "%+d%09d",     kptr->keyvalue.k[1],
200                                     abs(kptr->keyvalue.k[0]));
201          }
202 #endif
203        break;
204     case 4:
205       // Very long integer.
206       k = 0;
207       for (j = 7; j > 0; j--) {
208         if (kptr->keyvalue.l[j]) {
209           k = j;
210           break;
211         }
212       }
213 
214       sprintf(text, "%+d", kptr->keyvalue.l[k]);
215       for (j = k-1; j >= 0; j--) {
216         sprintf(text+strlen(text), "%09d", abs(kptr->keyvalue.l[j]));
217       }
218 
219       break;
220     case 5:
221       // Float.
222       sprintf(text, "%+13.6e", kptr->keyvalue.f);
223       break;
224     case 6:
225       // Int complex.
226       sprintf(text, "%.0f  %.0f", kptr->keyvalue.c[0],
227                                   kptr->keyvalue.c[1]);
228       break;
229     case 7:
230       // Float complex.
231       sprintf(text, "%+13.6e  %+13.6e", kptr->keyvalue.c[0],
232                                         kptr->keyvalue.c[1]);
233       break;
234     case 8:
235       // String.
236       sprintf(text, "\"%s\"", kptr->keyvalue.s);
237       break;
238     default:
239       // No value.
240       *text = '\0';
241       break;
242     }
243 
244     if (kptr->type > 0) {
245       // Keyvalue successfully extracted.
246       printf("  %s", text);
247     } else if (kptr->type < 0) {
248       // Syntax error of some type while extracting the keyvalue.
249       printf("  (%s)", text);
250     }
251 
252     // Units?
253     if (kptr->ulen) {
254       printf(" %.*s", kptr->ulen-2, kptr->comment+1);
255     }
256 
257     // Comment text or reject keyrecord.
258     printf("\n%s\n", kptr->comment);
259   }
260 
261 
262   // Print indexes.
263   printf("\n\nIndexes of selected keywords:\n");
264   for (i = 0; i < nkeyids; i++) {
265     printf("%-8s%5d%5d%5d", keyids[i].name, keyids[i].count, keyids[i].idx[0],
266       keyids[i].idx[1]);
267 
268     // Print logical (SIMPLE) and integer (BITPIX, NAXIS) values.
269     if (keyids[i].count) {
270       kptr = keys + keyids[i].idx[0];
271       printf("%4d", kptr->type);
272 
273       if (kptr->type == 1) {
274         printf("%5c", kptr->keyvalue.i?'T':'F');
275       } else if (kptr->type == 2) {
276         printf("%5d", kptr->keyvalue.i);
277       }
278     }
279     printf("\n");
280   }
281 
282   wcsdealloc(keys);
283 
284   return 0;
285 }
286