wcslib (8.2.2)
1 /*============================================================================
2 WCSLIB 8.2 - an implementation of the FITS WCS standard.
3 Copyright (C) 1995-2023, 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: fitshdr.h,v 8.2.1.1 2023/11/16 10:05:57 mcalabre Exp mcalabre $
23 *=============================================================================
24 *
25 * WCSLIB 8.2 - C routines that implement the FITS World Coordinate System
26 * (WCS) standard. Refer to the README file provided with WCSLIB for an
27 * overview of the library.
28 *
29 *
30 * Summary of the fitshdr routines
31 * -------------------------------
32 * The Flexible Image Transport System (FITS), is a data format widely used in
33 * astronomy for data interchange and archive. It is described in
34 *
35 = "Definition of the Flexible Image Transport System (FITS), version 3.0",
36 = Pence, W.D., Chiappetti, L., Page, C.G., Shaw, R.A., & Stobie, E. 2010,
37 = A&A, 524, A42 - http://dx.doi.org/10.1051/0004-6361/201015362
38 *
39 * See also http://fits.gsfc.nasa.gov
40 *
41 * fitshdr() is a generic FITS header parser provided to handle keyrecords that
42 * are ignored by the WCS header parsers, wcspih() and wcsbth(). Typically the
43 * latter may be set to remove WCS keyrecords from a header leaving fitshdr()
44 * to handle the remainder.
45 *
46 *
47 * fitshdr() - FITS header parser routine
48 * --------------------------------------
49 * fitshdr() parses a character array containing a FITS header, extracting
50 * all keywords and their values into an array of fitskey structs.
51 *
52 * Given:
53 * header const char []
54 * Character array containing the (entire) FITS header,
55 * for example, as might be obtained conveniently via the
56 * CFITSIO routine fits_hdr2str().
57 *
58 * Each header "keyrecord" (formerly "card image")
59 * consists of exactly 80 7-bit ASCII printing characters
60 * in the range 0x20 to 0x7e (which excludes NUL, BS,
61 * TAB, LF, FF and CR) especially noting that the
62 * keyrecords are NOT null-terminated.
63 *
64 * nkeyrec int Number of keyrecords in header[].
65 *
66 * nkeyids int Number of entries in keyids[].
67 *
68 * Given and returned:
69 * keyids struct fitskeyid []
70 * While all keywords are extracted from the header,
71 * keyids[] provides a convienient way of indexing them.
72 * The fitskeyid struct contains three members;
73 * fitskeyid::name must be set by the user while
74 * fitskeyid::count and fitskeyid::idx are returned by
75 * fitshdr(). All matched keywords will have their
76 * fitskey::keyno member negated.
77 *
78 * Returned:
79 * nreject int* Number of header keyrecords rejected for syntax
80 * errors.
81 *
82 * keys struct fitskey**
83 * Pointer to an array of nkeyrec fitskey structs
84 * containing all keywords and keyvalues extracted from
85 * the header.
86 *
87 * Memory for the array is allocated by fitshdr() and
88 * this must be freed by the user. See wcsdealloc().
89 *
90 * Function return value:
91 * int Status return value:
92 * 0: Success.
93 * 1: Null fitskey pointer passed.
94 * 2: Memory allocation failed.
95 * 3: Fatal error returned by Flex parser.
96 * 4: Unrecognised data type.
97 *
98 * Notes:
99 * 1: Keyword parsing is done in accordance with the syntax defined by
100 * NOST 100-2.0, noting the following points in particular:
101 *
102 * a: Sect. 5.1.2.1 specifies that keywords be left-justified in columns
103 * 1-8, blank-filled with no embedded spaces, composed only of the
104 * ASCII characters ABCDEFGHJKLMNOPQRSTUVWXYZ0123456789-_
105 *
106 * fitshdr() accepts any characters in columns 1-8 but flags keywords
107 * that do not conform to standard syntax.
108 *
109 * b: Sect. 5.1.2.2 defines the "value indicator" as the characters "= "
110 * occurring in columns 9 and 10. If these are absent then the
111 * keyword has no value and columns 9-80 may contain any ASCII text
112 * (but see note 2 for CONTINUE keyrecords). This is copied to the
113 * comment member of the fitskey struct.
114 *
115 * c: Sect. 5.1.2.3 states that a keyword may have a null (undefined)
116 * value if the value/comment field, columns 11-80, consists entirely
117 * of spaces, possibly followed by a comment.
118 *
119 * d: Sect. 5.1.1 states that trailing blanks in a string keyvalue are
120 * not significant and the parser always removes them. A string
121 * containing nothing but blanks will be replaced with a single
122 * blank.
123 *
124 * Sect. 5.2.1 also states that a quote character (') in a string
125 * value is to be represented by two successive quote characters and
126 * the parser removes the repeated quote.
127 *
128 * e: The parser recognizes free-format character (NOST 100-2.0,
129 * Sect. 5.2.1), integer (Sect. 5.2.3), and floating-point values
130 * (Sect. 5.2.4) for all keywords.
131 *
132 * f: Sect. 5.2.3 offers no comment on the size of an integer keyvalue
133 * except indirectly in limiting it to 70 digits. The parser will
134 * translate an integer keyvalue to a 32-bit signed integer if it
135 * lies in the range -2147483648 to +2147483647, otherwise it
136 * interprets it as a 64-bit signed integer if possible, or else a
137 * "very long" integer (see fitskey::type).
138 *
139 * g: END not followed by 77 blanks is not considered to be a legitimate
140 * end keyrecord.
141 *
142 * 2: The parser supports a generalization of the OGIP Long String Keyvalue
143 * Convention (v1.0) whereby strings may be continued onto successive
144 * header keyrecords. A keyrecord contains a segment of a continued
145 * string if and only if
146 *
147 * a: it contains the pseudo-keyword CONTINUE,
148 *
149 * b: columns 9 and 10 are both blank,
150 *
151 * c: columns 11 to 80 contain what would be considered a valid string
152 * keyvalue, including optional keycomment, if column 9 had contained
153 * '=',
154 *
155 * d: the previous keyrecord contained either a valid string keyvalue or
156 * a valid CONTINUE keyrecord.
157 *
158 * If any of these conditions is violated, the keyrecord is considered in
159 * isolation.
160 *
161 * Syntax errors in keycomments in a continued string are treated more
162 * permissively than usual; the '/' delimiter may be omitted provided that
163 * parsing of the string keyvalue is not compromised. However, the
164 * FITSHDR_COMMENT status bit will be set for the keyrecord (see
165 * fitskey::status).
166 *
167 * As for normal strings, trailing blanks in a continued string are not
168 * significant.
169 *
170 * In the OGIP convention "the '&' character is used as the last non-blank
171 * character of the string to indicate that the string is (probably)
172 * continued on the following keyword". This additional syntax is not
173 * required by fitshdr(), but if '&' does occur as the last non-blank
174 * character of a continued string keyvalue then it will be removed, along
175 * with any trailing blanks. However, blanks that occur before the '&'
176 * will be preserved.
177 *
178 *
179 * fitskeyid struct - Keyword indexing
180 * -----------------------------------
181 * fitshdr() uses the fitskeyid struct to return indexing information for
182 * specified keywords. The struct contains three members, the first of which,
183 * fitskeyid::name, must be set by the user with the remainder returned by
184 * fitshdr().
185 *
186 * char name[12]:
187 * (Given) Name of the required keyword. This is to be set by the user;
188 * the '.' character may be used for wildcarding. Trailing blanks will be
189 * replaced with nulls.
190 *
191 * int count:
192 * (Returned) The number of matches found for the keyword.
193 *
194 * int idx[2]:
195 * (Returned) Indices into keys[], the array of fitskey structs returned by
196 * fitshdr(). Note that these are 0-relative array indices, not keyrecord
197 * numbers.
198 *
199 * If the keyword is found in the header the first index will be set to the
200 * array index of its first occurrence, otherwise it will be set to -1.
201 *
202 * If multiples of the keyword are found, the second index will be set to
203 * the array index of its last occurrence, otherwise it will be set to -1.
204 *
205 *
206 * fitskey struct - Keyword/value information
207 * ------------------------------------------
208 * fitshdr() returns an array of fitskey structs, each of which contains the
209 * result of parsing one FITS header keyrecord. All members of the fitskey
210 * struct are returned by fitshdr(), none are given by the user.
211 *
212 * int keyno
213 * (Returned) Keyrecord number (1-relative) in the array passed as input to
214 * fitshdr(). This will be negated if the keyword matched any specified in
215 * the keyids[] index.
216 *
217 * int keyid
218 * (Returned) Index into the first entry in keyids[] with which the
219 * keyrecord matches, else -1.
220 *
221 * int status
222 * (Returned) Status flag bit-vector for the header keyrecord employing the
223 * following bit masks defined as preprocessor macros:
224 *
225 * - FITSHDR_KEYWORD: Illegal keyword syntax.
226 * - FITSHDR_KEYVALUE: Illegal keyvalue syntax.
227 * - FITSHDR_COMMENT: Illegal keycomment syntax.
228 * - FITSHDR_KEYREC: Illegal keyrecord, e.g. an END keyrecord with
229 * trailing text.
230 * - FITSHDR_TRAILER: Keyrecord following a valid END keyrecord.
231 *
232 * The header keyrecord is syntactically correct if no bits are set.
233 *
234 * char keyword[12]
235 * (Returned) Keyword name, null-filled for keywords of less than eight
236 * characters (trailing blanks replaced by nulls).
237 *
238 * Use
239 *
240 = sprintf(dst, "%.8s", keyword)
241 *
242 * to copy it to a character array with null-termination, or
243 *
244 = sprintf(dst, "%8.8s", keyword)
245 *
246 * to blank-fill to eight characters followed by null-termination.
247 *
248 * int type
249 * (Returned) Keyvalue data type:
250 * - 0: No keyvalue (both the value and type are undefined).
251 * - 1: Logical, represented as int.
252 * - 2: 32-bit signed integer.
253 * - 3: 64-bit signed integer (see below).
254 * - 4: Very long integer (see below).
255 * - 5: Floating point (stored as double).
256 * - 6: Integer complex (stored as double[2]).
257 * - 7: Floating point complex (stored as double[2]).
258 * - 8: String.
259 * - 8+10*n: Continued string (described below and in fitshdr() note 2).
260 *
261 * A negative type indicates that a syntax error was encountered when
262 * attempting to parse a keyvalue of the particular type.
263 *
264 * Comments on particular data types:
265 * - 64-bit signed integers lie in the range
266 *
267 = (-9223372036854775808 <= int64 < -2147483648) ||
268 = (+2147483647 < int64 <= +9223372036854775807)
269 *
270 * A native 64-bit data type may be defined via preprocessor macro
271 * WCSLIB_INT64 defined in wcsconfig.h, e.g. as 'long long int'; this
272 * will be typedef'd to 'int64' here. If WCSLIB_INT64 is not set, then
273 * int64 is typedef'd to int[3] instead and fitskey::keyvalue is to be
274 * computed as
275 *
276 = ((keyvalue.k[2]) * 1000000000 +
277 = keyvalue.k[1]) * 1000000000 +
278 = keyvalue.k[0]
279 *
280 * and may reported via
281 *
282 = if (keyvalue.k[2]) {
283 = printf("%d%09d%09d", keyvalue.k[2], abs(keyvalue.k[1]),
284 = abs(keyvalue.k[0]));
285 = } else {
286 = printf("%d%09d", keyvalue.k[1], abs(keyvalue.k[0]));
287 = }
288 *
289 * where keyvalue.k[0] and keyvalue.k[1] range from -999999999 to
290 * +999999999.
291 *
292 * - Very long integers, up to 70 decimal digits in length, are encoded
293 * in keyvalue.l as an array of int[8], each of which stores 9 decimal
294 * digits. fitskey::keyvalue is to be computed as
295 *
296 = (((((((keyvalue.l[7]) * 1000000000 +
297 = keyvalue.l[6]) * 1000000000 +
298 = keyvalue.l[5]) * 1000000000 +
299 = keyvalue.l[4]) * 1000000000 +
300 = keyvalue.l[3]) * 1000000000 +
301 = keyvalue.l[2]) * 1000000000 +
302 = keyvalue.l[1]) * 1000000000 +
303 = keyvalue.l[0]
304 *
305 * - Continued strings are not reconstructed, they remain split over
306 * successive fitskey structs in the keys[] array returned by
307 * fitshdr(). fitskey::keyvalue data type, 8 + 10n, indicates the
308 * segment number, n, in the continuation.
309 *
310 * int padding
311 * (An unused variable inserted for alignment purposes only.)
312 *
313 * union keyvalue
314 * (Returned) A union comprised of
315 *
316 * - fitskey::i,
317 * - fitskey::k,
318 * - fitskey::l,
319 * - fitskey::f,
320 * - fitskey::c,
321 * - fitskey::s,
322 *
323 * used by the fitskey struct to contain the value associated with a
324 * keyword.
325 *
326 * int i
327 * (Returned) Logical (fitskey::type == 1) and 32-bit signed integer
328 * (fitskey::type == 2) data types in the fitskey::keyvalue union.
329 *
330 * int64 k
331 * (Returned) 64-bit signed integer (fitskey::type == 3) data type in the
332 * fitskey::keyvalue union.
333 *
334 * int l[8]
335 * (Returned) Very long integer (fitskey::type == 4) data type in the
336 * fitskey::keyvalue union.
337 *
338 * double f
339 * (Returned) Floating point (fitskey::type == 5) data type in the
340 * fitskey::keyvalue union.
341 *
342 * double c[2]
343 * (Returned) Integer and floating point complex (fitskey::type == 6 || 7)
344 * data types in the fitskey::keyvalue union.
345 *
346 * char s[72]
347 * (Returned) Null-terminated string (fitskey::type == 8) data type in the
348 * fitskey::keyvalue union.
349 *
350 * int ulen
351 * (Returned) Where a keycomment contains a units string in the standard
352 * form, e.g. [m/s], the ulen member indicates its length, inclusive of
353 * square brackets. Otherwise ulen is zero.
354 *
355 * char comment[84]
356 * (Returned) Keycomment, i.e. comment associated with the keyword or, for
357 * keyrecords rejected because of syntax errors, the compete keyrecord
358 * itself with null-termination.
359 *
360 * Comments are null-terminated with trailing spaces removed. Leading
361 * spaces are also removed from keycomments (i.e. those immediately
362 * following the '/' character), but not from COMMENT or HISTORY keyrecords
363 * or keyrecords without a value indicator ("= " in columns 9-80).
364 *
365 *
366 * Global variable: const char *fitshdr_errmsg[] - Status return messages
367 * ----------------------------------------------------------------------
368 * Error messages to match the status value returned from each function.
369 *
370 *===========================================================================*/
371
372 #ifndef WCSLIB_FITSHDR
373 #define WCSLIB_FITSHDR
374
375 #include "wcsconfig.h"
376
377 #ifdef __cplusplus
378 extern "C" {
379 #endif
380
381 #define FITSHDR_KEYWORD 0x01
382 #define FITSHDR_KEYVALUE 0x02
383 #define FITSHDR_COMMENT 0x04
384 #define FITSHDR_KEYREC 0x08
385 #define FITSHDR_CARD 0x08 // Alias for backwards compatibility.
386 #define FITSHDR_TRAILER 0x10
387
388
389 extern const char *fitshdr_errmsg[];
390
391 enum fitshdr_errmsg_enum {
392 FITSHDRERR_SUCCESS = 0, // Success.
393 FITSHDRERR_NULL_POINTER = 1, // Null fitskey pointer passed.
394 FITSHDRERR_MEMORY = 2, // Memory allocation failed.
395 FITSHDRERR_FLEX_PARSER = 3, // Fatal error returned by Flex parser.
396 FITSHDRERR_DATA_TYPE = 4 // Unrecognised data type.
397 };
398
399 #ifdef WCSLIB_INT64
400 typedef WCSLIB_INT64 int64;
401 #else
402 typedef int int64[3];
403 #endif
404
405
406 // Struct used for indexing the keywords.
407 struct fitskeyid {
408 char name[12]; // Keyword name, null-terminated.
409 int count; // Number of occurrences of keyword.
410 int idx[2]; // Indices into fitskey array.
411 };
412
413 // Size of the fitskeyid struct in int units, used by the Fortran wrappers.
414 #define KEYIDLEN (sizeof(struct fitskeyid)/sizeof(int))
415
416
417 // Struct used for storing FITS keywords.
418 struct fitskey {
419 int keyno; // Header keyrecord sequence number (1-rel).
420 int keyid; // Index into fitskeyid[].
421 int status; // Header keyrecord status bit flags.
422 char keyword[12]; // Keyword name, null-filled.
423 int type; // Keyvalue type (see above).
424 int padding; // (Dummy inserted for alignment purposes.)
425 union {
426 int i; // 32-bit integer and logical values.
427 int64 k; // 64-bit integer values.
428 int l[8]; // Very long signed integer values.
429 double f; // Floating point values.
430 double c[2]; // Complex values.
431 char s[72]; // String values, null-terminated.
432 } keyvalue; // Keyvalue.
433 int ulen; // Length of units string.
434 char comment[84]; // Comment (or keyrecord), null-terminated.
435 };
436
437 // Size of the fitskey struct in int units, used by the Fortran wrappers.
438 #define KEYLEN (sizeof(struct fitskey)/sizeof(int))
439
440
441 int fitshdr(const char header[], int nkeyrec, int nkeyids,
442 struct fitskeyid keyids[], int *nreject, struct fitskey **keys);
443
444
445 #ifdef __cplusplus
446 }
447 #endif
448
449 #endif // WCSLIB_FITSHDR