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: fitshdr.h,v 7.7 2021/07/12 06:36:49 mcalabre Exp $ 23 *============================================================================= 24 * 25 * WCSLIB 7.7 - 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 450