/*============================================================================ WCSLIB 4.3 - an implementation of the FITS WCS standard. Copyright (C) 1995-2007, Mark Calabretta This file is part of WCSLIB. WCSLIB is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. WCSLIB is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with WCSLIB. If not, see . Correspondence concerning WCSLIB may be directed to: Internet email: mcalabre@atnf.csiro.au Postal address: Dr. Mark Calabretta Australia Telescope National Facility, CSIRO PO Box 76 Epping NSW 1710 AUSTRALIA Author: Mark Calabretta, Australia Telescope National Facility http://www.atnf.csiro.au/~mcalabre/index.html $Id: fitshdr.l,v 4.3 2007/12/27 05:41:36 cal103 Exp $ *============================================================================= * * fitshdr.l is a Flex description file containing a lexical scanner * definition for extracting keywords and keyvalues from a FITS header. * * It requires Flex v2.5.4 or later. * * Refer to fitshdr.h for a description of the user interface and operating * notes. * *===========================================================================*/ /* Options. */ %option full %option never-interactive %option nounput %option noyywrap %option outfile="fitshdr.c" %option prefix="fitshdr" /* Keywords. */ KEYCHR [-_A-Z0-9] KW1 {KEYCHR}{1}" "{7} KW2 {KEYCHR}{2}" "{6} KW3 {KEYCHR}{3}" "{5} KW4 {KEYCHR}{4}" "{4} KW5 {KEYCHR}{5}" "{3} KW6 {KEYCHR}{6}" "{2} KW7 {KEYCHR}{7}" "{1} KW8 {KEYCHR}{8} KEYWORD ({KW1}|{KW2}|{KW3}|{KW4}|{KW5}|{KW6}|{KW7}|{KW8}) /* Keyvalue data types. */ LOGICAL [TF] INT32 [+-]?0*[0-9]{1,9} INT64 [+-]?0*[0-9]{10,18} INTVL [+-]?0*[0-9]{19,} INTEGER [+-]?[0-9]+ FLOAT [+-]?([0-9]+\.?[0-9]*|\.[0-9]+)([eE][+-]?[0-9]+)? ICOMPLX \(" "*{INTEGER}" "*," "*{INTEGER}" "*\) FCOMPLX \(" "*{FLOAT}" "*," "*{FLOAT}" "*\) STRING '([^']|'')*' /* Characters forming standard unit strings (jwBIQX are not used). */ UNITSTR \[[-+*/^(). 0-9a-zA-Z]+\] /* Exclusive start states. */ %x VALUE INLINE UNITS COMMENT ERROR FLUSH %{ #include #include #include #include #include "fitshdr.h" #define YY_DECL int fitshdr(const char header[], int nkeyrec, int nkeyids, \ struct fitskeyid keyids[], int *nreject, \ struct fitskey **keys) #define YY_INPUT(inbuff, count, bufsize) \ { \ if (fitshdr_nkeyrec) { \ strncpy(inbuff, fitshdr_hdr, 80); \ inbuff[80] = '\n'; \ fitshdr_hdr += 80; \ fitshdr_nkeyrec--; \ count = 81; \ } else { \ count = YY_NULL; \ } \ } #ifdef DEBUG /* Print text as it is matched. */ #define YY_USER_ACTION printf("Rule %03d: \"%s\"\n", yy_act, yytext); #endif /* These global variables are required by YY_INPUT. */ const char *fitshdr_hdr; int fitshdr_nkeyrec; /* Map status return value to message. */ const char *fitshdr_errmsg[] = { "Success", "Null fitskey pointer-pointer passed", "Memory allocation failed"}; void fitshdr_nullfill(char cptr[], int len); %} %% char *cptr, ctmp[72]; int blank, continuation, end, j, k, keyno; double dtmp; struct fitskey *kptr; struct fitskeyid *iptr; int yylex_destroy(void); fitshdr_hdr = header; fitshdr_nkeyrec = nkeyrec; *nreject = 0; keyno = 0; if (keys == 0x0) { return 1; } /* Allocate memory for the required number of fitskey structs. */ /* Recall that calloc() initializes allocated memory to zero. */ if (!(kptr = *keys = calloc(nkeyrec, sizeof(struct fitskey)))) { return 2; } /* Initialize keyids[]. */ iptr = keyids; for (j = 0; j < nkeyids; j++, iptr++) { iptr->count = 0; iptr->idx[0] = -1; iptr->idx[1] = -1; } blank = 0; continuation = 0; end = 0; BEGIN(INITIAL); ^" "{80} { /* Rule 001: A completely blank keyrecord. */ strncpy(kptr->keyword, yytext, 8); yyless(0); blank = 1; BEGIN(COMMENT); } ^(COMMENT|HISTORY|" "{8}) { /* Rule 002. */ strncpy(kptr->keyword, yytext, 8); BEGIN(COMMENT); } ^END" "{77} { /* Rule 003. */ strncpy(kptr->keyword, yytext, 8); end = 1; BEGIN(FLUSH); } ^END" "{5}=" "+ { /* Rule 004: Illegal END keyrecord. */ strncpy(kptr->keyword, yytext, 8); kptr->status |= FITSHDR_KEYREC; BEGIN(VALUE); } ^END" "{5} { /* Rule 005: Illegal END keyrecord. */ strncpy(kptr->keyword, yytext, 8); kptr->status |= FITSHDR_KEYREC; BEGIN(COMMENT); } ^{KEYWORD}=" "+ { /* Rule 006. */ strncpy(kptr->keyword, yytext, 8); BEGIN(VALUE); } ^CONTINUE" "+{STRING} { /* Rule 007: Continued string keyvalue. */ strncpy(kptr->keyword, yytext, 8); if (keyno > 0 && (kptr-1)->type%10 == 8) { /* Put back the string keyvalue. */ for (k = 10; yytext[k] != '\''; k++); yyless(k); continuation = 1; BEGIN(VALUE); } else { /* Not a valid continuation. */ yyless(8); BEGIN(COMMENT); } } ^{KEYWORD} { /* Rule 008: Keyword without value. */ strncpy(kptr->keyword, yytext, 8); BEGIN(COMMENT); } ^.{8}=" "+ { /* Rule 009: Illegal keyword, carry on regardless. */ strncpy(kptr->keyword, yytext, 8); kptr->status |= FITSHDR_KEYWORD; BEGIN(VALUE); } ^.{8} { /* Rule 010: Illegal keyword, carry on regardless. */ strncpy(kptr->keyword, yytext, 8); kptr->status |= FITSHDR_KEYWORD; BEGIN(COMMENT); } " "*/\/ { /* Rule 011: Null keyvalue. */ BEGIN(INLINE); } {LOGICAL} { /* Rule 012: Logical keyvalue. */ kptr->type = 1; kptr->keyvalue.i = (*yytext == 'T'); BEGIN(INLINE); } {INT32} { /* Rule 013: 32-bit signed integer keyvalue. */ kptr->type = 2; if (sscanf(yytext, "%d", &(kptr->keyvalue.i)) < 1) { kptr->status |= FITSHDR_KEYVALUE; BEGIN(ERROR); } BEGIN(INLINE); } {INT64} { /* Rule 014: 64-bit signed integer keyvalue (up to 18 digits). */ if (sscanf(yytext, "%lf", &dtmp) < 1) { kptr->status |= FITSHDR_KEYVALUE; BEGIN(ERROR); } else if (INT_MIN <= dtmp && dtmp <= INT_MAX) { /* Can be accomodated as a 32-bit signed integer. */ kptr->type = 2; if (sscanf(yytext, "%d", &(kptr->keyvalue.i)) < 1) { kptr->status |= FITSHDR_KEYVALUE; BEGIN(ERROR); } } else { /* 64-bit signed integer. */ kptr->type = 3; #ifdef WCSLIB_INT64 /* Native 64-bit integer is available. */ if (sscanf(yytext, "%lld", &(kptr->keyvalue.k)) < 1) { kptr->status |= FITSHDR_KEYVALUE; BEGIN(ERROR); } #else /* 64-bit integer (up to 18 digits) implemented as int[3]. */ kptr->keyvalue.k[2] = 0; sprintf(ctmp, "%%%dd%%9d", yyleng-9); if (sscanf(yytext, ctmp, kptr->keyvalue.k+1, kptr->keyvalue.k) < 1) { kptr->status |= FITSHDR_KEYVALUE; BEGIN(ERROR); } else if (*yytext == '-') { kptr->keyvalue.k[0] *= -1; } #endif } BEGIN(INLINE); } {INTVL} { /* Rule 015: Very long integer keyvalue (and 19-digit int64). */ kptr->type = 4; strcpy(ctmp, yytext); k = yyleng; for (j = 0; j < 8; j++) { /* Read it backwards. */ k -= 9; if (k < 0) k = 0; if (sscanf(ctmp+k, "%d", kptr->keyvalue.l+j) < 1) { kptr->status |= FITSHDR_KEYVALUE; BEGIN(ERROR); } if (*yytext == '-') { kptr->keyvalue.l[j] = -abs(kptr->keyvalue.l[j]); } if (k == 0) break; ctmp[k] = '\0'; } /* Can it be accomodated as a 64-bit signed integer? */ if (j == 2 && abs(kptr->keyvalue.l[2]) <= 9 && abs(kptr->keyvalue.l[1]) <= 223372036 && kptr->keyvalue.l[0] <= 854775807 && kptr->keyvalue.l[0] >= -854775808) { kptr->type = 3; #ifdef WCSLIB_INT64 /* Native 64-bit integer is available. */ kptr->keyvalue.l[2] = 0; if (sscanf(yytext, "%lld", &(kptr->keyvalue.k)) < 1) { kptr->status |= FITSHDR_KEYVALUE; BEGIN(ERROR); } #endif } BEGIN(INLINE); } {FLOAT} { /* Rule 016: Float keyvalue. */ kptr->type = 5; if (sscanf(yytext, "%lf", &(kptr->keyvalue.f)) < 1) { kptr->status |= FITSHDR_KEYVALUE; BEGIN(ERROR); } BEGIN(INLINE); } {ICOMPLX} { /* Rule 017: Integer complex keyvalue. */ kptr->type = 6; if (sscanf(yytext, "(%lf,%lf)", kptr->keyvalue.c, kptr->keyvalue.c+1) < 2) { kptr->status |= FITSHDR_KEYVALUE; BEGIN(ERROR); } BEGIN(INLINE); } {FCOMPLX} { /* Rule 018: Floating point complex keyvalue. */ kptr->type = 7; if (sscanf(yytext, "(%lf,%lf)", kptr->keyvalue.c, kptr->keyvalue.c+1) < 2) { kptr->status |= FITSHDR_KEYVALUE; BEGIN(ERROR); } BEGIN(INLINE); } {STRING} { /* Rule 019: String keyvalue. */ kptr->type = 8; cptr = kptr->keyvalue.s; strcpy(cptr, yytext+1); /* Squeeze out repeated quotes. */ k = 0; for (j = 0; j < 72; j++) { if (k < j) { cptr[k] = cptr[j]; } if (cptr[j] == '\0') { if (k) cptr[k-1] = '\0'; break; } else if (cptr[j] == '\'' && cptr[j+1] == '\'') { j++; } k++; } if (*cptr) { /* Retain the initial blank in all-blank strings. */ fitshdr_nullfill(cptr+1, 71); } else { fitshdr_nullfill(cptr, 72); } BEGIN(INLINE); } . { /* Rule 020. */ kptr->status |= FITSHDR_KEYVALUE; BEGIN(ERROR); } " "*$ { /* Rule 021. */ BEGIN(FLUSH); } " "*\/" "*$ { /* Rule 022. */ BEGIN(FLUSH); } " "*\/" "* { /* Rule 023. */ BEGIN(UNITS); } " " { /* Rule 024. */ kptr->status |= FITSHDR_COMMENT; BEGIN(ERROR); } . { /* Rule 025: Keyvalue parsing must now also be suspect. */ kptr->status |= FITSHDR_COMMENT; kptr->type = 0; BEGIN(ERROR); } {UNITSTR} { /* Rule 026. */ kptr->ulen = yyleng; yymore(); BEGIN(COMMENT); } . { /* Rule 027. */ yymore(); BEGIN(COMMENT); } .* { /* Rule 028. */ strcpy(kptr->comment, yytext); fitshdr_nullfill(kptr->comment, 84); BEGIN(FLUSH); } .* { /* Rule 029. */ if (!continuation) kptr->type = -abs(kptr->type); sprintf(kptr->comment, "%.80s", fitshdr_hdr-80); kptr->comment[80] = '\0'; fitshdr_nullfill(kptr->comment+80, 4); BEGIN(FLUSH); } .*\n { /* Rule 030: Discard the rest of the input line. */ kptr->keyno = ++keyno; /* Null-fill the keyword. */ kptr->keyword[8] = '\0'; fitshdr_nullfill(kptr->keyword, 12); /* Do indexing. */ iptr = keyids; kptr->keyid = -1; for (j = 0; j < nkeyids; j++, iptr++) { cptr = iptr->name; cptr[8] = '\0'; fitshdr_nullfill(cptr, 12); for (k = 0; k < 8; k++, cptr++) { if (*cptr != '.' && *cptr != kptr->keyword[k]) break; } if (k == 8) { /* Found a match. */ iptr->count++; if (iptr->idx[0] == -1) { iptr->idx[0] = keyno-1; } else { iptr->idx[1] = keyno-1; } kptr->keyno = -abs(kptr->keyno); if (kptr->keyid < 0) kptr->keyid = j; } } /* Deal with continued strings. */ if (continuation) { /* Tidy up the previous string keyvalue. */ if ((kptr-1)->type == 8) (kptr-1)->type += 10; cptr = (kptr-1)->keyvalue.s; if (cptr[strlen(cptr)-1] == '&') cptr[strlen(cptr)-1] = '\0'; kptr->type = (kptr-1)->type + 10; } /* Check for keyrecords following the END keyrecord. */ if (end && (end++ > 1) && !blank) { kptr->status |= FITSHDR_TRAILER; } if (kptr->status) (*nreject)++; kptr++; blank = 0; continuation = 0; BEGIN(INITIAL); } <> { /* Rule unnumbered: End-of-input. */ yylex_destroy(); return 0; } %% /*--------------------------------------------------------------------------*/ void fitshdr_nullfill(char cptr[], int len) { int j, k; /* Null-fill the string. */ for (j = 0; j < len; j++) { if (cptr[j] == '\0') { for (k = j+1; k < len; k++) { cptr[k] = '\0'; } break; } } for (k = j-1; k >= 0; k--) { if (cptr[k] != ' ') break; cptr[k] = '\0'; } return; }