/*============================================================================ 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: wcsbth.l,v 4.3 2007/12/27 05:41:36 cal103 Exp $ *============================================================================= * * wcsbth.l is a Flex description file containing the definition of a lexical * scanner for parsing the WCS keyrecords for one or more image arrays and/or * pixel lists in a FITS binary table header. It can also handle primary * image and image extension headers. * * wcsbth.l requires Flex v2.5.4 or later. Refer to wcshdr.h for a * description of the user interface and operating notes. * * Implementation notes * -------------------- * wcsbth() may be invoked with an option that causes it to recognise the * image-header form of WCS keywords as defaults for each alternate * coordinate representation (up to 27). By design, with this option enabled * wcsbth() can also handle primary image and image extension headers, * effectively treating them as a single-column binary table though with WCS * keywords of a different form. * * NAXIS is always 2 for binary tables, it refers to the two-dimensional * nature of the table. Thus NAXIS does not count the number of image axes * in either image arrays or pixels lists and for the latter there is not * even a formal equivalent of WCSAXESa. Hence NAXIS is always ignored and a * first pass through the header is required to determine the number of * images, the number of alternate coordinate representations for each image * (up to 27), and the number of coordinate axes in each representation; this * pass also counts the number of iPVn_ma and iPSn_ma or TVk_ma and TSk_ma * keywords in each representation. * * On completion of the first pass, the association between column number * and axis number is defined for each representation of a pixel list. * Memory is allocated for an array of the required number of wcsprm structs * and each of these is initialized appropriately. These structs are filled * in the second pass. * * It is permissible for a scalar table column to contain degenerate (single- * point) image arrays and simultaneously form one axis of a pixel list. * * The parser does not check for duplicated keywords, for most keywords it * accepts the last encountered. * * wcsbth() does not currently handle the Greenbank convention. * *===========================================================================*/ /* Options. */ %option full %option never-interactive %option noyywrap %option outfile="wcsbth.c" %option prefix="wcsbth" /* Indices for parameterized keywords. */ I0 [0-9] I1 [1-9] I2 [1-9][0-9] I3 [1-9][0-9]{2} I4 [1-9][0-9]{3} /* Alternate coordinate system identifier. */ ALT [ A-Z] /* Keyvalue data types. */ INTEGER [+-]?[0-9]+ FLOAT [+-]?([0-9]+\.?[0-9]*|\.[0-9]+)([eE][+-]?[0-9]+)? STRING '([^']|'')*' /* Exclusive start states. */ %x CCCCCia iCCCna iCCCCn TCCCna TCCCCn %x CCi_ja ijCCna TCn_ka TCCn_ka %x CROTAi iCROTn TCROTn %x CCi_ma iCn_ma iCCn_ma TCn_ma TCCn_ma %x PROJPm %x CCCCCCCC CCCCCCCa %x CCCCna CCCCCna %x CCCCn CCCCCn %x VALUE INTEGER_VAL FLOAT_VAL STRING_VAL %x COMMENT DISCARD ERROR FLUSH %{ #include #include #include #include #include "wcs.h" #include "wcshdr.h" #include "wcsmath.h" /* Codes used for keyvalue data types. */ #define INTEGER 0 #define FLOAT 1 #define STRING 2 /* Bit masks used for keyword types: */ #define IMGAUX 0x1 /* Auxiliary image header, e.g. LONPOLEa or */ /* DATE-OBS. */ #define IMGAXIS 0x2 /* Image header with axis number, e.g. */ /* CTYPEia. */ #define IMGHEAD 0x3 /* Image header of either type. */ #define BIMGARR 0x4 /* Binary table image array with axis */ /* number, e.g. iCTYna. */ #define PIXLIST 0x8 /* Pixel list, e.g. TCTYna. */ #define BINTAB 0xC /* Shared binary table image array (without */ /* axis number) or pixel list, e.g. LONPna */ /* or OBSGXn. */ #define YY_DECL int wcsbth(char *header, int nkeyrec, int relax, int ctrl, \ int keysel, int *colsel, int *nreject, int *nwcs, \ struct wcsprm **wcs) #define YY_INPUT(inbuff, count, bufsize) \ { \ if (wcsbth_nkeyrec) { \ strncpy(inbuff, wcsbth_hdr, 80); \ inbuff[80] = '\n'; \ wcsbth_hdr += 80; \ wcsbth_nkeyrec--; \ count = 81; \ } else { \ count = YY_NULL; \ } \ } /* A convenience macro to get around incompatibilities between unput() and yyless(): put yytext followed by a blank back onto the input stream. */ #define WCSBTH_PUTBACK \ sprintf(stmp, "%s ", yytext); \ itmp = strlen(stmp); \ while (itmp) unput(stmp[--itmp]); /* These global variables are required by YY_INPUT. */ char *wcsbth_hdr; int wcsbth_nkeyrec; /* Struct used internally for header bookkeeping. */ struct wcsbth_alts { int ncol, iax, icol, imgherit; short int (*arridx)[27]; short int pixidx[27]; short int pad1; unsigned int *pixlist; unsigned char (*npv)[27]; unsigned char (*nps)[27]; unsigned char pixnpv[27]; unsigned char pixnps[27]; unsigned char pad2[2]; }; int wcsbth_pass1(int keytype, int i, int j, int n, int k, char a, char ptype, struct wcsbth_alts *alts); int wcsbth_init1(struct wcsbth_alts *alts, int *nwcs, struct wcsprm **wcs); struct wcsprm *wcsbth_idx(struct wcsprm *wcs, struct wcsbth_alts *alts, int keytype, int n, char a); int wcsbth_colax(struct wcsprm *wcs, struct wcsbth_alts *alts, int k, char a); int wcsbth_epoch(void *wptr); int wcsbth_velref(void *wptr); int wcsbth_vsource(void *wptr); int wcsbth_final(struct wcsbth_alts *alts, int *nwcs, struct wcsprm **wcs); %} %% /* Keyword indices, as used in the WCS papers, e.g. iVn_ma, TPn_ka. */ char a; int i, j, k, m, n; char *cptr, *errmsg, errtxt[80], exclude[1000], *extkey, *hptr, ptype, stmp[16]; int altlin, iax, icol, incl, ipass, ipx, itmp, ix, jx, keytype, nsel, npass, status, valtype, voff; void *vptr, *wptr; struct wcsbth_alts alts; struct wcsprm *wcsp, wcstem; int (*special)(void *); int yylex_destroy (void); /* The data structures produced. */ *nwcs = 0; *wcs = 0x0; /* Parameters used to implement YY_INPUT. */ wcsbth_hdr = header; wcsbth_nkeyrec = nkeyrec; /* Our handle on the input stream. */ hptr = header; *nreject = 0; /* Keyword parameters. */ i = j = 0; n = k = 0; m = 0; a = ' '; /* Header bookkeeping. */ alts.ncol = 0; alts.arridx = 0x0; alts.pixlist = 0x0; alts.npv = 0x0; alts.nps = 0x0; for (iax = 0; iax < 27; iax++) { alts.pixidx[iax] = 0; alts.pixnpv[iax] = 0; alts.pixnps[iax] = 0; } /* For decoding the keyvalue. */ keytype = 0; valtype = -1; vptr = 0x0; /* For keywords that require special handling. */ altlin = 0; ptype = ' '; special = 0x0; /* Selection by column number. */ nsel = colsel ? colsel[0] : 0; incl = (nsel > 0); for (icol = 0; icol < 1000; icol++) { exclude[icol] = incl; } for (icol = 1; icol <= abs(nsel); icol++) { itmp = colsel[icol]; if (0 < itmp && itmp < 1000) { exclude[itmp] = !incl; } } exclude[0] = 0; /* Selection by keyword type. */ itmp = keysel; keysel = 0; if (itmp) { if (itmp & WCSHDR_IMGHEAD) keysel |= IMGHEAD; if (itmp & WCSHDR_BIMGARR) keysel |= BIMGARR; if (itmp & WCSHDR_PIXLIST) keysel |= PIXLIST; } if (keysel == 0) { keysel = IMGHEAD | BINTAB; } /* Control variables. */ ipass = 1; npass = 2; BEGIN(INITIAL); ^TFIELDS" = "" "*{INTEGER} { if (ipass == 1) { if (alts.ncol == 0) { sscanf(yytext, "TFIELDS = %d", &(alts.ncol)); BEGIN(FLUSH); } else { errmsg = "Duplicate or out-of-sequence TFIELDS keyword"; BEGIN(ERROR); } } else { BEGIN(FLUSH); } } ^WCSAXES{ALT}=" "" "*{INTEGER} { keytype = IMGAXIS; if (!(keytype & keysel)) { /* Ignore this key type. */ BEGIN(DISCARD); } else { if (relax & WCSHDR_ALLIMG) { if (ipass == 1) { sscanf(yytext, "WCSAXES%c= %d", &a, &i); wcsbth_pass1(IMGAXIS, i, 0, 0, 0, a, ' ', &alts); } BEGIN(FLUSH); } else if (relax & WCSHDR_reject) { errmsg = "Image-header keyword WCSAXESa in binary table"; BEGIN(ERROR); } else { /* Pretend we don't recognize it. */ BEGIN(DISCARD); } } } ^WCAX{I1}{ALT}" = "" "*{INTEGER} | ^WCAX{I2}{ALT}" = "" "*{INTEGER} | ^WCAX{I3}{ALT}"= "" "*{INTEGER} { keytype = BIMGARR; /* Note that a blank in the sscanf() format string matches zero or more of them in the input. */ sscanf(yytext, "WCAX%d%c = %d", &n, &a, &i); if (!(keytype & keysel) || exclude[n]) { /* Ignore this key type or column. */ BEGIN(DISCARD); } else { if (ipass == 1) { wcsbth_pass1(BIMGARR, i, 0, n, 0, a, ' ', &alts); } BEGIN(FLUSH); } } ^WCST{I1}{ALT}" = "" "*{STRING} | ^WCST{I2}{ALT}" = "" "*{STRING} | ^WCST{I3}{ALT}"= "" "*{STRING} { /* Cross-reference supplier. */ keytype = BIMGARR; errmsg = "Cross-references are not currently implemented"; BEGIN(ERROR); } ^WCSX{I1}{ALT}" = "" "*{STRING} | ^WCSX{I2}{ALT}" = "" "*{STRING} | ^WCSX{I3}{ALT}"= "" "*{STRING} { /* Cross-reference consumer. */ keytype = BIMGARR; errmsg = "Cross-references are not currently implemented"; BEGIN(ERROR); } ^CRPIX { valtype = FLOAT; vptr = &(wcstem.crpix); extkey = "CRPIXja"; BEGIN(CCCCCia); } ^{I1}CRP | ^{I1}CRPX { valtype = FLOAT; vptr = &(wcstem.crpix); sscanf(yytext, "%d", &i); if (yyleng == 4) { BEGIN(iCCCna); } else { extkey = "jCRPXn"; BEGIN(iCCCCn); } } ^TCRP | ^TCRPX { valtype = FLOAT; vptr = &(wcstem.crpix); if (yyleng == 4) { BEGIN(TCCCna); } else { extkey = "TCRPXn"; BEGIN(TCCCCn); } } ^PC { valtype = FLOAT; vptr = &(wcstem.pc); altlin = 1; extkey = "PCi_ja"; BEGIN(CCi_ja); } ^{I2}PC { valtype = FLOAT; vptr = &(wcstem.pc); altlin = 1; sscanf(yytext, "%1d%1d", &i, &j); BEGIN(ijCCna); } ^TP | ^TPC { valtype = FLOAT; vptr = &(wcstem.pc); altlin = 1; if (yyleng == 2) { BEGIN(TCn_ka); } else { extkey = "TPCn_ka"; BEGIN(TCCn_ka); } } ^CD { valtype = FLOAT; vptr = &(wcstem.cd); altlin = 2; extkey = "CDi_ja"; BEGIN(CCi_ja); } ^{I2}CD { valtype = FLOAT; vptr = &(wcstem.cd); altlin = 2; sscanf(yytext, "%1d%1d", &i, &j); BEGIN(ijCCna); } ^TC | ^TCD { valtype = FLOAT; vptr = &(wcstem.cd); altlin = 2; if (yyleng == 2) { BEGIN(TCn_ka); } else { extkey = "TCDn_ka"; BEGIN(TCCn_ka); } } ^CDELT { valtype = FLOAT; vptr = &(wcstem.cdelt); extkey = "CDELTia"; BEGIN(CCCCCia); } ^{I1}CDE | ^{I1}CDLT { valtype = FLOAT; vptr = &(wcstem.cdelt); sscanf(yytext, "%d", &i); if (yyleng == 4) { BEGIN(iCCCna); } else { extkey = "iCDLTn"; BEGIN(iCCCCn); } } ^TCDE | ^TCDLT { valtype = FLOAT; vptr = &(wcstem.cdelt); if (yyleng == 4) { BEGIN(TCCCna); } else { extkey = "TCDLTn"; BEGIN(TCCCCn); } } ^CROTA { valtype = FLOAT; vptr = &(wcstem.crota); altlin = 4; extkey = "CROTAi"; BEGIN(CROTAi); } ^{I1}CROT { valtype = FLOAT; vptr = &(wcstem.crota); altlin = 4; sscanf(yytext, "%d", &i); extkey = "iCROTn"; BEGIN(iCROTn); } ^TCROT { valtype = FLOAT; vptr = &(wcstem.crota); altlin = 4; extkey = "TCROTn"; BEGIN(TCROTn); } ^CUNIT { valtype = STRING; vptr = &(wcstem.cunit); extkey = "CUNITia"; BEGIN(CCCCCia); } ^{I1}CUN | ^{I1}CUNI { valtype = STRING; vptr = &(wcstem.cunit); sscanf(yytext, "%d", &i); if (yyleng == 4) { BEGIN(iCCCna); } else { extkey = "iCUNIn"; BEGIN(iCCCCn); } } ^TCUN | ^TCUNI { valtype = STRING; vptr = &(wcstem.cunit); if (yyleng == 4) { BEGIN(TCCCna); } else { extkey = "TCUNIn"; BEGIN(TCCCCn); } } ^CTYPE { valtype = STRING; vptr = &(wcstem.ctype); extkey = "CTYPEia"; BEGIN(CCCCCia); } ^{I1}CTY | ^{I1}CTYP { valtype = STRING; vptr = &(wcstem.ctype); sscanf(yytext, "%d", &i); if (yyleng == 4) { BEGIN(iCCCna); } else { extkey = "iCTYPn"; BEGIN(iCCCCn); } } ^TCTY | ^TCTYP { valtype = STRING; vptr = &(wcstem.ctype); if (yyleng == 4) { BEGIN(TCCCna); } else { extkey = "TCTYPn"; BEGIN(TCCCCn); } } ^CRVAL { valtype = FLOAT; vptr = &(wcstem.crval); extkey = "CRVALia"; BEGIN(CCCCCia); } ^{I1}CRV | ^{I1}CRVL { valtype = FLOAT; vptr = &(wcstem.crval); sscanf(yytext, "%d", &i); if (yyleng == 4) { BEGIN(iCCCna); } else { extkey = "iCRVLn"; BEGIN(iCCCCn); } } ^TCRV | ^TCRVL { valtype = FLOAT; vptr = &(wcstem.crval); if (yyleng == 4) { BEGIN(TCCCna); } else { extkey = "TCRVLn"; BEGIN(TCCCCn); } } ^LONPOLE | ^LONP { valtype = FLOAT; vptr = &(wcstem.lonpole); if (yyleng == 7) { extkey = "LONPOLEa"; BEGIN(CCCCCCCa); } else { BEGIN(CCCCna); } } ^LATPOLE | ^LATP { valtype = FLOAT; vptr = &(wcstem.latpole); if (yyleng == 7) { extkey = "LATPOLEa"; BEGIN(CCCCCCCa); } else { BEGIN(CCCCna); } } ^RESTFRQ | ^RESTFREQ | ^RFRQ { valtype = FLOAT; vptr = &(wcstem.restfrq); if (yyleng == 8) { unput(' '); extkey = "RESTFREQ"; BEGIN(CCCCCCCa); } else if (yyleng == 7) { extkey = "RESTFRQa"; BEGIN(CCCCCCCa); } else { BEGIN(CCCCna); } } ^RESTWAV | ^RWAV { valtype = FLOAT; vptr = &(wcstem.restwav); if (yyleng == 7) { extkey = "RESTWAVa"; BEGIN(CCCCCCCa); } else { BEGIN(CCCCna); } } ^PV { valtype = FLOAT; vptr = &(wcstem.pv); ptype = 'v'; extkey = "PVi_ma"; BEGIN(CCi_ma); } ^{I1}V | ^{I1}PV { valtype = FLOAT; vptr = &(wcstem.pv); ptype = 'v'; sscanf(yytext, "%d", &i); if (yyleng == 2) { BEGIN(iCn_ma); } else { extkey = "iPVn_ma"; BEGIN(iCCn_ma); } } ^TV | ^TPV { valtype = FLOAT; vptr = &(wcstem.pv); ptype = 'v'; if (yyleng == 2) { BEGIN(TCn_ma); } else { extkey = "TPVn_ma"; BEGIN(TCCn_ma); } } ^PROJP { valtype = FLOAT; vptr = &(wcstem.pv); ptype = 'v'; BEGIN(PROJPm); } ^PS { valtype = STRING; vptr = &(wcstem.ps); ptype = 's'; extkey = "PSi_ma"; BEGIN(CCi_ma); } ^{I1}S | ^{I1}PS { valtype = STRING; vptr = &(wcstem.ps); ptype = 's'; sscanf(yytext, "%d", &i); if (yyleng == 2) { BEGIN(iCn_ma); } else { extkey = "iPSn_ma"; BEGIN(iCCn_ma); } } ^TS | ^TPS { valtype = STRING; vptr = &(wcstem.ps); ptype = 's'; if (yyleng == 2) { BEGIN(TCn_ma); } else { extkey = "TPSn_ma"; BEGIN(TCCn_ma); } } ^CNAME { valtype = STRING; vptr = &(wcstem.cname); extkey = "CNAMEia"; BEGIN(CCCCCia); } ^{I1}CNA | ^{I1}CNAM { valtype = STRING; vptr = &(wcstem.cname); sscanf(yytext, "%d", &i); if (yyleng == 4) { BEGIN(iCCCna); } else { if (!(relax & WCSHDR_CNAMn)) vptr = 0x0; extkey = "iCNAMn"; BEGIN(iCCCCn); } } ^TCNA | ^TCNAM { valtype = STRING; vptr = &(wcstem.cname); if (yyleng == 4) { BEGIN(TCCCna); } else { if (!(relax & WCSHDR_CNAMn)) vptr = 0x0; extkey = "TCNAMn"; BEGIN(TCCCCn); } } ^CRDER { valtype = FLOAT; vptr = &(wcstem.crder); extkey = "CRDERia"; BEGIN(CCCCCia); } ^{I1}CRD | ^{I1}CRDE { valtype = FLOAT; vptr = &(wcstem.crder); sscanf(yytext, "%d", &i); if (yyleng == 4) { BEGIN(iCCCna); } else { if (!(relax & WCSHDR_CNAMn)) vptr = 0x0; extkey = "iCRDEn"; BEGIN(iCCCCn); } } ^TCRD | ^TCRDE { valtype = FLOAT; vptr = &(wcstem.crder); if (yyleng == 4) { BEGIN(TCCCna); } else { if (!(relax & WCSHDR_CNAMn)) vptr = 0x0; extkey = "TCRDEn"; BEGIN(TCCCCn); } } ^CSYER { valtype = FLOAT; vptr = &(wcstem.csyer); extkey = "CSYERia"; BEGIN(CCCCCia); } ^{I1}CSY | ^{I1}CSYE { valtype = FLOAT; vptr = &(wcstem.csyer); sscanf(yytext, "%d", &i); if (yyleng == 4) { BEGIN(iCCCna); } else { if (!(relax & WCSHDR_CNAMn)) vptr = 0x0; extkey = "iCSYEn"; BEGIN(iCCCCn); } } ^TCSY | ^TCSYE { valtype = FLOAT; vptr = &(wcstem.csyer); if (yyleng == 4) { BEGIN(TCCCna); } else { if (!(relax & WCSHDR_CNAMn)) vptr = 0x0; extkey = "TCSYEn"; BEGIN(TCCCCn); } } ^DATE-AVG | ^DAVG { valtype = STRING; vptr = wcstem.dateavg; if (yyleng == 8) { extkey = "DATE-AVG"; BEGIN(CCCCCCCC); } else { BEGIN(CCCCn); } } ^DATE-OBS { valtype = STRING; vptr = wcstem.dateobs; extkey = "DATE-OBS"; BEGIN(CCCCCCCC); } ^DOBS{I1}" " | ^DOBS{I2}" " | ^DOBS{I3}" " { if (relax & WCSHDR_DOBSn) { valtype = STRING; vptr = wcstem.dateobs; yyless(4); BEGIN(CCCCn); } else { keytype = BINTAB; if (relax & WCSHDR_reject) { errmsg = "DOBSna keyword is non-standard"; BEGIN(ERROR); } else { BEGIN(DISCARD); } } } ^EPOCH{ALT}" " { sscanf(yytext, "EPOCH%c", &a); if (a == ' ' || (relax & WCSHDR_EPOCHa)) { valtype = FLOAT; vptr = &(wcstem.equinox); special = wcsbth_epoch; unput(a); extkey = "EPOCH"; BEGIN(CCCCCCCa); } else { keytype = IMGAUX; if (relax & WCSHDR_reject) { errmsg = "EPOCH keyword may not have an alternate version code"; BEGIN(ERROR); } else { BEGIN(DISCARD); } } } ^EQUINOX | ^EQUI { valtype = FLOAT; vptr = &(wcstem.equinox); if (yyleng == 7) { extkey = "EQUINOXa"; BEGIN(CCCCCCCa); } else { BEGIN(CCCCna); } } ^MJD-AVG" " | ^MJDA { valtype = FLOAT; vptr = &(wcstem.mjdavg); if (yyleng == 8) { extkey = "MJD-AVG"; BEGIN(CCCCCCCC); } else { BEGIN(CCCCn); } } ^MJD-OBS" " | ^MJDOB { valtype = FLOAT; vptr = &(wcstem.mjdobs); if (yyleng == 8) { extkey = "MJD-OBS"; BEGIN(CCCCCCCC); } else { BEGIN(CCCCCn); } } ^OBSGEO-X | ^OBSGX { valtype = FLOAT; vptr = wcstem.obsgeo; if (yyleng == 8) { extkey = "OBSGEO-X"; BEGIN(CCCCCCCC); } else { BEGIN(CCCCCn); } } ^OBSGEO-Y | ^OBSGY { valtype = FLOAT; vptr = wcstem.obsgeo + 1; if (yyleng == 8) { extkey = "OBSGEO-Y"; BEGIN(CCCCCCCC); } else { BEGIN(CCCCCn); } } ^OBSGEO-Z | ^OBSGZ { valtype = FLOAT; vptr = wcstem.obsgeo + 2; if (yyleng == 8) { extkey = "OBSGEO-Z"; BEGIN(CCCCCCCC); } else { BEGIN(CCCCCn); } } ^RADESYS | ^RADE { valtype = STRING; vptr = wcstem.radesys; if (yyleng == 7) { extkey = "RADESYSa"; BEGIN(CCCCCCCa); } else { BEGIN(CCCCna); } } ^RADECSYS { if (relax & WCSHDR_RADECSYS) { valtype = STRING; vptr = wcstem.radesys; unput(' '); extkey = "RADECSYS"; BEGIN(CCCCCCCa); } else { keytype = IMGAUX; if (relax & WCSHDR_reject) { errmsg = "RADECSYS keyword is non-standard"; BEGIN(ERROR); } else { BEGIN(DISCARD); } } } ^SPECSYS | ^SPEC { valtype = STRING; vptr = wcstem.specsys; if (yyleng == 7) { extkey = "SPECSYSa"; BEGIN(CCCCCCCa); } else { BEGIN(CCCCna); } } ^SSYSOBS | ^SOBS { valtype = STRING; vptr = wcstem.ssysobs; if (yyleng == 7) { extkey = "SSYSOBSa"; BEGIN(CCCCCCCa); } else { BEGIN(CCCCna); } } ^SSYSSRC | ^SSRC { valtype = STRING; vptr = wcstem.ssyssrc; if (yyleng == 7) { extkey = "SSYSSRCa"; BEGIN(CCCCCCCa); } else { BEGIN(CCCCna); } } ^VELOSYS | ^VSYS { valtype = FLOAT; vptr = &(wcstem.velosys); if (yyleng == 7) { extkey = "VELOSYSa"; BEGIN(CCCCCCCa); } else { BEGIN(CCCCna); } } ^VELANGL | ^VANG { valtype = FLOAT; vptr = &(wcstem.velangl); if (yyleng == 7) { extkey = "VELANGLa"; BEGIN(CCCCCCCa); } else { BEGIN(CCCCna); } } ^VELREF{ALT}" " { sscanf(yytext, "VELREF%c", &a); if (a == ' ' || (relax & WCSHDR_VELREFa)) { valtype = INTEGER; vptr = wcstem.specsys; special = wcsbth_velref; unput(a); extkey = "VELREF"; BEGIN(CCCCCCCa); } else { keytype = IMGAUX; if (relax & WCSHDR_reject) { errmsg = "VELREF keyword may not have an alternate version code"; BEGIN(ERROR); } else { BEGIN(DISCARD); } } } ^VSOURCE{ALT} { if (relax & WCSHDR_VSOURCEa) { valtype = FLOAT; vptr = &(wcstem.zsource); special = wcsbth_vsource; yyless(7); extkey = "VSOURCEa"; BEGIN(CCCCCCCa); } else { keytype = IMGAUX; if (relax & WCSHDR_reject) { errmsg = "VSOURCEa keyword is deprecated"; BEGIN(ERROR); } else { BEGIN(DISCARD); } } } ^VSOU{I1}{ALT}" " | ^VSOU{I2}{ALT}" " | ^VSOU{I3}{ALT} { if (relax & WCSHDR_VSOURCEa) { valtype = FLOAT; vptr = &(wcstem.zsource); special = wcsbth_vsource; yyless(4); BEGIN(CCCCna); } else { keytype = BINTAB; if (relax & WCSHDR_reject) { errmsg = "VSOUna keyword is deprecated"; BEGIN(ERROR); } else { /* Pretend we don't recognize it. */ BEGIN(DISCARD); } } } ^WCSNAME | ^WCSN | ^TWCS { valtype = STRING; vptr = wcstem.wcsname; if (yyleng == 7) { extkey = "WCSNAMEa"; BEGIN(CCCCCCCa); } else { BEGIN(CCCCna); } } ^ZSOURCE | ^ZSOU { valtype = FLOAT; vptr = &(wcstem.zsource); if (yyleng == 7) { extkey = "ZSOURCEa"; BEGIN(CCCCCCCa); } else { BEGIN(CCCCna); } } ^END" "{77} { yyless(0); if (wcsbth_nkeyrec) { wcsbth_nkeyrec = 0; errmsg = "Keyrecords following the END keyrecord were ignored"; BEGIN(ERROR); } else { BEGIN(DISCARD); } } ^. { yyless(0); BEGIN(DISCARD); } {I1}{ALT}" " | {I2}{ALT} { /* Image-header keyword. */ keytype = IMGAXIS; if (relax & WCSHDR_ALLIMG) { sscanf(yytext, "%d%c", &i, &a); BEGIN(VALUE); } else if (relax & WCSHDR_reject) { errmsg = errtxt; sprintf(errmsg, "Image-header keyword %s in binary table", extkey); BEGIN(ERROR); } else { /* Pretend we don't recognize it. */ BEGIN(DISCARD); } } {I3} { /* Invalid axis number in image-header keyword. */ keytype = IMGAXIS; if (relax & WCSHDR_ALLIMG) { /* Will also be flagged by as invalid. */ sscanf(yytext, "%3d", &i); BEGIN(VALUE); } else { /* Pretend we don't recognize it. */ BEGIN(DISCARD); } } {I1}" " | {I2}" " | {I3} | {I1}" " | {I2}" " | {I3} { if (vptr) { WCSBTH_PUTBACK; BEGIN((YY_START == iCCCCn) ? iCCCna : TCCCna); } else { keytype = (YY_START == iCCCCn) ? BIMGARR : PIXLIST; if (relax & WCSHDR_reject) { errmsg = errtxt; sprintf(errmsg, "%s keyword is non-standard", extkey); BEGIN(ERROR); } else { BEGIN(DISCARD); } } } {I1}[A-Z]" " | {I2}[A-Z] | {I1}[A-Z]" " | {I2}[A-Z] { if (vptr && (relax & WCSHDR_LONGKEY)) { WCSBTH_PUTBACK; BEGIN((YY_START == iCCCCn) ? iCCCna : TCCCna); } else { keytype = (YY_START == iCCCna) ? BIMGARR : PIXLIST; if (relax & WCSHDR_reject) { errmsg = errtxt; if (!vptr) { sprintf(errmsg, "%s keyword is non-standard", extkey); } else { sprintf(errmsg, "%s keyword may not have an alternate version code", extkey); } BEGIN(ERROR); } else { /* Pretend we don't recognize it. */ BEGIN(DISCARD); } } } . | . { BEGIN(DISCARD); } {I1}{ALT}" " | {I2}{ALT}" " | {I3}{ALT} | {I1}{ALT}" " | {I2}{ALT}" " | {I3}{ALT} { sscanf(yytext, "%d%c", &n, &a); if (YY_START == TCCCna) i = wcsbth_colax(*wcs, &alts, n, a); keytype = (YY_START == iCCCna) ? BIMGARR : PIXLIST; BEGIN(VALUE); } . | . { BEGIN(DISCARD); } {I1}_{I1}{ALT}" " | {I1}_{I2}{ALT}" " | {I2}_{I1}{ALT}" " | {I2}_{I2}{ALT} { /* Image-header keyword. */ if (relax & WCSHDR_ALLIMG) { sscanf(yytext, "%d_%d%c", &i, &j, &a); keytype = IMGAXIS; BEGIN(VALUE); } else if (relax & WCSHDR_reject) { errmsg = errtxt; sprintf(errmsg, "Image-header keyword %s in binary table", extkey); BEGIN(ERROR); } else { /* Pretend we don't recognize it. */ BEGIN(DISCARD); } } {I1}_{I3}{ALT} | {I3}_{I1}{ALT} | {I1}_{I4} | {I2}_{I3} | {I3}_{I2} | {I4}_{I1} { /* Invalid axis number in image-header keyword. */ if (relax & WCSHDR_ALLIMG) { /* Will be flagged by as invalid. */ sscanf(yytext, "%d_%d", &i, &j); keytype = IMGAXIS; BEGIN(VALUE); } else { /* Pretend we don't recognize it. */ BEGIN(DISCARD); } } {I0}{6} { /* This covers the defunct forms CD00i00j and PC00i00j. */ if (((relax & WCSHDR_PC00i00j) && (altlin == 1)) || ((relax & WCSHDR_CD00i00j) && (altlin == 2))) { sscanf(yytext, "%3d%3d", &i, &j); a = ' '; keytype = IMGAXIS; BEGIN(VALUE); } else if (relax & WCSHDR_reject) { errmsg = errtxt; sprintf(errmsg, "Defunct form of %si_ja keyword", (altlin==1) ? "PC" : "CD"); BEGIN(ERROR); } else { /* Pretend we don't recognize it. */ BEGIN(DISCARD); } } . { BEGIN(DISCARD); } {I1}{ALT}" " | {I2}{ALT}" " | {I3}{ALT} { sscanf(yytext, "%d%c", &n, &a); keytype = BIMGARR; BEGIN(VALUE); } {I1}_{I1}{ALT}" " | {I1}_{I2}{ALT} | {I2}_{I1}{ALT} | {I1}_{I3} | {I2}_{I2} | {I3}_{I1} { if (relax & WCSHDR_LONGKEY) { WCSBTH_PUTBACK; BEGIN(TCn_ka); } else if (relax & WCSHDR_reject) { errmsg = errtxt; sprintf(errmsg, "%s keyword is non-standard", extkey); BEGIN(ERROR); } else { /* Pretend we don't recognize it. */ BEGIN(DISCARD); } } . { BEGIN(DISCARD); } {I1}_{I1}{ALT}" " | {I1}_{I2}{ALT}" " | {I2}_{I1}{ALT}" " | {I1}_{I3}{ALT} | {I2}_{I2}{ALT} | {I3}_{I1}{ALT} { sscanf(yytext, "%d_%d%c", &n, &k, &a); i = wcsbth_colax(*wcs, &alts, n, a); j = wcsbth_colax(*wcs, &alts, k, a); keytype = PIXLIST; BEGIN(VALUE); } {I1}_{I4} | {I2}_{I3} | {I3}_{I2} | {I4}_{I1} { sscanf(yytext, "%d_%d", &n, &k); a = ' '; i = wcsbth_colax(*wcs, &alts, n, a); j = wcsbth_colax(*wcs, &alts, k, a); keytype = PIXLIST; BEGIN(VALUE); } . { BEGIN(DISCARD); } {I1}" " | {I2}" " { yyless(0); BEGIN(CCCCCia); } {I1}[A-Z]" " | {I2}[A-Z] { if (relax & WCSHDR_CROTAia) { yyless(0); BEGIN(CCCCCia); } else if (relax & WCSHDR_reject) { errmsg = "CROTAn keyword may not have an alternate version code"; BEGIN(ERROR); } else { /* Pretend we don't recognize it. */ BEGIN(DISCARD); } } . { BEGIN(DISCARD); } {I1}" " | {I2}" " | {I3} | {I1}" " | {I2}" " | {I3} { WCSBTH_PUTBACK; BEGIN((YY_START == iCROTn) ? iCCCna : TCCCna); } {I1}[A-Z]" " | {I2}[A-Z] | {I1}[A-Z]" " | {I2}[A-Z] { if (relax & WCSHDR_CROTAia) { WCSBTH_PUTBACK; BEGIN((YY_START == iCROTn) ? iCCCna : TCCCna); } else if (relax & WCSHDR_reject) { errmsg = errtxt; sprintf(errmsg, "%s keyword may not have an alternate version code", extkey); BEGIN(ERROR); } else { /* Pretend we don't recognize it. */ BEGIN(DISCARD); } } . | . { BEGIN(DISCARD); } {ALT} | . { /* Image-header keyword. */ if (relax & (WCSHDR_AUXIMG | WCSHDR_ALLIMG)) { if (YY_START == CCCCCCCa) { sscanf(yytext, "%c", &a); } else { a = 0; unput(yytext[0]); } keytype = IMGAUX; BEGIN(VALUE); } else if (relax & WCSHDR_reject) { errmsg = errtxt; sprintf(errmsg, "Image-header keyword %s in binary table", extkey); BEGIN(ERROR); } else { /* Pretend we don't recognize it. */ BEGIN(DISCARD); } } . { BEGIN(DISCARD); } {I1}{ALT}" " | {I2}{ALT}" " | {I3}{ALT} | {I1}{ALT}" " | {I2}{ALT} { sscanf(yytext, "%d%c", &n, &a); keytype = BINTAB; BEGIN(VALUE); } {I3} { sscanf(yytext, "%d", &n); a = ' '; keytype = BINTAB; BEGIN(VALUE); } . | . { BEGIN(DISCARD); } {I1}" " | {I2}" " | {I3}" " | {I4} | {I1}" " | {I2}" " | {I3} { sscanf(yytext, "%d", &n); a = 0; keytype = BINTAB; BEGIN(VALUE); } . | . { BEGIN(DISCARD); } {I1}_{I0}{ALT}" " | {I1}_{I2}{ALT}" " | {I2}_{I0}{ALT}" " | {I2}_{I2}{ALT} { /* Image-header keyword. */ if (relax & WCSHDR_ALLIMG) { sscanf(yytext, "%d_%d%c", &i, &m, &a); keytype = IMGAXIS; BEGIN(VALUE); } else if (relax & WCSHDR_reject) { errmsg = errtxt; sprintf(errmsg, "Image-header keyword %s in binary table", extkey); BEGIN(ERROR); } else { /* Pretend we don't recognize it. */ BEGIN(DISCARD); } } {I1}_{I3}{ALT} | {I3}_{I0}{ALT} | {I1}_{I4} | {I2}_{I3} | {I3}_{I2} | {I4}_{I0} { /* Invalid parameter in image-header keyword. */ if (relax & WCSHDR_ALLIMG) { /* Will be flagged by as invalid. */ sscanf(yytext, "%d_%d", &i, &m); keytype = IMGAXIS; BEGIN(VALUE); } else { /* Pretend we don't recognize it. */ BEGIN(DISCARD); } } . { BEGIN(DISCARD); } {I1}_{I0}{ALT}" " | {I1}_{I2}{ALT} | {I1}_{I3} | {I2}_{I0}{ALT} | {I2}_{I2} | {I3}_{I0} | {I1}_{I0}{ALT}" " | {I1}_{I2}{ALT} | {I1}_{I3} | {I2}_{I0}{ALT} | {I2}_{I2} | {I3}_{I0} { if (relax & WCSHDR_LONGKEY) { WCSBTH_PUTBACK; BEGIN((YY_START == iCCn_ma) ? iCn_ma : TCn_ma); } else if (relax & WCSHDR_reject) { errmsg = errtxt; sprintf(errmsg, "%s keyword is non-standard", extkey); BEGIN(ERROR); } else { /* Pretend we don't recognize it. */ BEGIN(DISCARD); } } . | . { BEGIN(DISCARD); } {I1}_{I0}{ALT}" " | {I1}_{I2}{ALT}" " | {I1}_{I3}{ALT} | {I2}_{I0}{ALT}" " | {I2}_{I2}{ALT} | {I3}_{I0}{ALT} | {I1}_{I0}{ALT}" " | {I1}_{I2}{ALT}" " | {I1}_{I3}{ALT} | {I2}_{I0}{ALT}" " | {I2}_{I2}{ALT} | {I3}_{I0}{ALT} { sscanf(yytext, "%d_%d%c", &n, &m, &a); if (YY_START == TCn_ma) i = wcsbth_colax(*wcs, &alts, n, a); keytype = (YY_START == iCn_ma) ? BIMGARR : PIXLIST; BEGIN(VALUE); } {I1}_{I4} | {I2}_{I3} | {I3}_{I2} | {I4}_{I0} | {I1}_{I4} | {I2}_{I3} | {I3}_{I2} | {I4}_{I0} { /* Invalid combinations will be flagged by . */ sscanf(yytext, "%d_%d", &n, &m); a = ' '; if (YY_START == TCn_ma) i = wcsbth_colax(*wcs, &alts, n, a); keytype = (YY_START == iCn_ma) ? BIMGARR : PIXLIST; BEGIN(VALUE); } . | . { BEGIN(DISCARD); } {I0}" " { if (relax & WCSHDR_PROJPn) { sscanf(yytext, "%d", &m); i = 0; a = ' '; keytype = IMGAXIS; BEGIN(VALUE); } else if (relax & WCSHDR_reject) { errmsg = "PROJPn keyword is defunct"; BEGIN(ERROR); } else { /* Pretend we don't recognize it. */ BEGIN(DISCARD); } } . { BEGIN(DISCARD); } =" "+ { /* Do checks on i, j, m, n, k. */ if (!(keytype & keysel)) { /* Selection by keyword type. */ BEGIN(DISCARD); } else if (exclude[n] || exclude[k]) { /* One or other column is not selected. */ if (k && (exclude[n] != exclude[k])) { /* For keywords such as TCn_ka, both columns must be excluded. User error, so return immediately. */ yylex_destroy(); return 3; } else { BEGIN(DISCARD); } } else if (i > 99 || j > 99 || m > 99 || n > 999 || k > 999) { if (relax & WCSHDR_reject) { errmsg = errtxt; if (i > 99 || j > 99) { sprintf(errmsg, "Axis number exceeds 99"); } else if (m > 99) { sprintf(errmsg, "Parameter number exceeds 99"); } else if (n > 999 || k > 999) { sprintf(errmsg, "Column number exceeds 999"); } BEGIN(ERROR); } else { /* Pretend we don't recognize it. */ BEGIN(DISCARD); } } else if (ipass == 2 && npass == 3 && (keytype & BINTAB)) { /* Skip keyvalues that won't be inherited. */ BEGIN(FLUSH); } else if (ipass == 3 && (keytype & IMGHEAD)) { /* IMGHEAD keytypes are always dealt with on the second pass. */ BEGIN(FLUSH); } else if (vptr) { alts.icol = 0; alts.iax = 0; voff = (char *)vptr - (char *)(&wcstem); if (valtype == INTEGER) { BEGIN(INTEGER_VAL); } else if (valtype == FLOAT) { BEGIN(FLOAT_VAL); } else if (valtype == STRING) { BEGIN(STRING_VAL); } else { errmsg = errtxt; sprintf(errmsg, "Internal parser ERROR, bad data type: %d", valtype); BEGIN(ERROR); } } else { errmsg = "Internal parser ERROR, null pointer"; BEGIN(ERROR); } } . { errmsg = "Invalid KEYWORD = VALUE syntax"; BEGIN(ERROR); } {INTEGER} { if (ipass == 1) { /* Do first-pass bookkeeping. */ wcsbth_pass1(keytype, i, j, n, k, a, ptype, &alts); if (alts.imgherit) npass = 3; BEGIN(FLUSH); } else { /* Update each coordinate representation. */ while ((wcsp = wcsbth_idx(*wcs, &alts, keytype, n, a))) { wptr = (void *)((char *)wcsp + voff); /* Read the keyvalue. */ if (special) { special(wptr); } else { sscanf(yytext, "%d", (int *)wptr); } } BEGIN(COMMENT); } } . { errmsg = "An integer value was expected"; BEGIN(ERROR); } {FLOAT} { if (ipass == 1) { /* Do first-pass bookkeeping. */ wcsbth_pass1(keytype, i, j, n, k, a, ptype, &alts); if (alts.imgherit) npass = 3; BEGIN(FLUSH); } else { /* Update each coordinate representation. */ while ((wcsp = wcsbth_idx(*wcs, &alts, keytype, n, a))) { wptr = (void *)((char *)wcsp + voff); /* Apply keyword parameterization. */ if (ptype == 'v') { ipx = wcsp->npv++; wcsp->pv[ipx].i = i; wcsp->pv[ipx].m = m; wptr = &(wcsp->pv[ipx].value); } else if (j) { /* Is the de-reference necessary? */ wptr = *((double **)wptr) + (i - 1)*(wcsp->naxis) + (j - 1); } else if (i) { wptr = *((double **)wptr) + (i - 1); } /* Read the keyvalue. */ if (special) { special(wptr); } else { sscanf(yytext, "%lf", (double *)wptr); } /* Flag the presence of PC, or CD and/or CROTA. */ if (altlin) { wcsp->altlin |= altlin; altlin = 0; } } BEGIN(COMMENT); } } . { errmsg = "A floating-point value was expected"; BEGIN(ERROR); } {STRING} { if (ipass == 1) { /* Do first-pass bookkeeping. */ wcsbth_pass1(keytype, i, j, n, k, a, ptype, &alts); if (alts.imgherit) npass = 3; BEGIN(FLUSH); } else { /* Update each coordinate representation. */ while ((wcsp = wcsbth_idx(*wcs, &alts, keytype, n, a))) { wptr = (void *)((char *)wcsp + voff); /* Apply keyword parameterization. */ if (ptype == 's') { ipx = wcsp->nps++; wcsp->ps[ipx].i = i; wcsp->ps[ipx].m = m; wptr = wcsp->ps[ipx].value; } else if (j) { wptr = *((char (**)[72])wptr) + (i - 1)*(wcsp->naxis) + (j - 1); } else if (i) { wptr = *((char (**)[72])wptr) + (i - 1); } /* Read the keyvalue. */ cptr = (char *)wptr; strcpy(cptr, yytext+1); /* Squeeze out repeated quotes. */ ix = 0; for (jx = 0; jx < 72; jx++) { if (ix < jx) { cptr[ix] = cptr[jx]; } if (cptr[jx] == '\0') { if (ix) cptr[ix-1] = '\0'; break; } else if (cptr[jx] == '\'' && cptr[jx+1] == '\'') { jx++; } ix++; } } BEGIN(COMMENT); } } . { errmsg = "A string value was expected"; BEGIN(ERROR); } " "*\/.* | " "* { BEGIN(FLUSH); } . { errmsg = "Malformed keycomment"; BEGIN(ERROR); } .* { if (ipass == npass) { if (ctrl < 0) { /* Preserve discards. */ if (hptr < wcsbth_hdr-80) { strncpy(hptr, wcsbth_hdr-80, 80); } hptr += 80; } else if (ctrl > 2) { fprintf(stderr, "%.80s\n Discarded.\n", wcsbth_hdr-80); } } BEGIN(FLUSH); } .* { (*nreject)++; if (ipass == npass) { if (ctrl == -1) { if (hptr < wcsbth_hdr-80) { /* Preserve rejects. */ strncpy(hptr, wcsbth_hdr-80, 80); } hptr += 80; } if (abs(ctrl) > 1) { fprintf(stderr, "%.80s\n%4d: %s.\n", wcsbth_hdr-80, *nreject, errmsg); } } BEGIN(FLUSH); } .*\n { /* Throw away the rest of the line and reset for the next one. */ i = j = 0; n = k = 0; m = 0; a = ' '; keytype = 0; valtype = -1; vptr = 0x0; altlin = 0; ptype = ' '; special = 0x0; BEGIN(INITIAL); } <> { /* End-of-input. */ if (ipass == 1) { if ((status = wcsbth_init1(&alts, nwcs, wcs)) || *nwcs == 0) { yylex_destroy(); return status; } if (abs(ctrl) > 2) { if (*nwcs == 1) { fprintf(stderr, "Found one coordinate representation.\n"); } else { fprintf(stderr, "Found %d coordinate representations.\n", *nwcs); } } } if (ipass++ < npass) { wcsbth_hdr = header; wcsbth_nkeyrec = nkeyrec; *nreject = 0; i = j = 0; k = n = 0; m = 0; a = ' '; keytype = 0; valtype = -1; vptr = 0x0; altlin = 0; ptype = ' '; special = 0x0; yyrestart(yyin); } else { yylex_destroy(); if (ctrl < 0) { *hptr = '\0'; } else if (ctrl == 1) { fprintf(stderr, "%d WCS keyrecords were rejected.\n", *nreject); } return wcsbth_final(&alts, nwcs, wcs); } } %% /*---------------------------------------------------------------------------- * Perform first-pass tasks: * * 1) Count the number of coordinate axes in each of the 27 possible * alternate image-header coordinate representations. Also count the * number of PVi_ma and PSi_ma keywords in each representation. * * 2) Determine the number of binary table columns that have an image array * with a coordinate representation (up to 999), and count the number of * coordinate axes in each of the 27 possible alternates. Also count the * number of iVn_ma and iSn_ma keywords in each representation. * * 3) Determine the number of alternate pixel list coordinate representations * (up to 27) and the table columns associated with each. Also count the * number of TVn_ma and TSn_ma keywords in each representation. * * In the first pass alts->arridx[icol][27] is used to determine the number * of axes in each of 27 possible image-header coordinate descriptions * (icol == 0) and each of the 27 possible coordinate representations for an * image array in each column. * * The elements of alts->pixlist[icol] are used as bit arrays to flag which * of the 27 possible pixel list coordinate representations are associated * each table column. *---------------------------------------------------------------------------*/ int wcsbth_pass1( int keytype, int i, int j, int n, int k, char a, char ptype, struct wcsbth_alts *alts) { int iax, icol, mask, ncol; if (a == 0) { /* Keywords such as DATE-OBS go along for the ride. */ return 0; } ncol = alts->ncol; /* Do we need to allocate memory for alts? */ if (alts->arridx == 0x0) { if (ncol == 0) { /* Can only happen if TFIELDS is missing or out-of-sequence. If n and k are both zero then we may be processing an image header so leave ncol alone - the array will be realloc'd later if required. */ if (n || k) { /* The header is mangled, assume the worst. */ ncol = 999; } } if (!(alts->arridx = calloc((1 + ncol)*27, sizeof(short int))) || !(alts->npv = calloc((1 + ncol)*27, sizeof(unsigned char))) || !(alts->nps = calloc((1 + ncol)*27, sizeof(unsigned char))) || !(alts->pixlist = calloc((1 + ncol), sizeof(unsigned int)))) { return 2; } alts->ncol = ncol; } else if (n > ncol || k > ncol) { /* Can only happen if TFIELDS or the WCS keyword is wrong; carry on. */ ncol = 999; if (!(alts->arridx = realloc(alts->arridx, 27*(1 + ncol)*sizeof(short int))) || !(alts->npv = realloc(alts->npv, 27*(1 + ncol)*sizeof(unsigned char))) || !(alts->nps = realloc(alts->nps, 27*(1 + ncol)*sizeof(unsigned char))) || !(alts->pixlist = realloc(alts->pixlist, (1 + ncol)*sizeof(unsigned int)))) { return 2; } /* Since realloc() doesn't initialize the extra memory. */ for (icol = (1 + alts->ncol); icol < (1 + ncol); icol++) { for (iax = 0; iax < 27; iax++) { alts->arridx[icol][iax] = 0; alts->npv[icol][iax] = 0; alts->nps[icol][iax] = 0; alts->pixlist[icol] = 0; } } alts->ncol = ncol; } iax = 0; if (a != ' ') { iax = a - 'A' + 1; } /* A BINTAB keytype such as LONPna, in conjunction with an IMGAXIS keytype causes a table column to be recognized as an image array. */ if (keytype & IMGHEAD || keytype & BIMGARR) { /* n == 0 is expected for IMGHEAD keywords. */ if (i == 0 && j == 0) { if (alts->arridx[n][iax] == 0) { /* Flag that an auxiliary keyword was seen. */ alts->arridx[n][iax] = -1; } } else { /* Record the maximum axis number found. */ if (alts->arridx[n][iax] < i) { alts->arridx[n][iax] = i; } if (alts->arridx[n][iax] < j) { alts->arridx[n][iax] = j; } } if (ptype == 'v') { alts->npv[n][iax]++; } else if (ptype == 's') { alts->nps[n][iax]++; } } /* BINTAB keytypes, which apply both to pixel lists as well as binary table image arrays, never contribute to recognizing a table column as a pixel list axis. A PIXLIST keytype is required for that. */ if (keytype == PIXLIST) { mask = 1 << iax; /* n > 0 for PIXLIST keytypes. */ alts->pixlist[n] |= mask; if (k) alts->pixlist[k] |= mask; /* Used as a flag over all columns. */ alts->pixlist[0] |= mask; if (ptype == 'v') { alts->pixnpv[iax]++; } else if (ptype == 's') { alts->pixnps[iax]++; } } return 0; } /*---------------------------------------------------------------------------- * Perform initializations at the end of the first pass: * * 1) Determine the required number of wcsprm structs, allocate memory for * an array of them and initialize each one. * *---------------------------------------------------------------------------*/ int wcsbth_init1( struct wcsbth_alts *alts, int *nwcs, struct wcsprm **wcs) { int iax, icol, inherit[27], ix, mask, ncol, npsmax, npvmax, status = 0; struct wcsprm *wcsp; if (alts->arridx == 0x0) { *nwcs = 0; return 0; } /* Determine the number of axes in each pixel list representation. */ ncol = alts->ncol; for (iax = 0, mask = 1; iax < 27; iax++, mask <<= 1) { alts->pixidx[iax] = 0; if (alts->pixlist[0] | mask) { for (icol = 1; icol <= ncol; icol++) { if (alts->pixlist[icol] & mask) { alts->pixidx[iax]++; } } } } /* Find the total number of coordinate representations. */ *nwcs = 0; alts->imgherit = 0; for (iax = 0; iax < 27; iax++) { inherit[iax] = 0; for (icol = 1; icol <= ncol; icol++) { if (alts->arridx[icol][iax] < 0) { /* No BIMGARR keytype but there's at least one BINTAB. */ if (alts->arridx[0][iax] > 0) { /* There is an IMGAXIS keytype that we will inherit, so count this representation. */ alts->arridx[icol][iax] = alts->arridx[0][iax]; } else { alts->arridx[icol][iax] = 0; } } if (alts->arridx[icol][iax]) { if (alts->arridx[0][iax]) { /* All IMGHEAD keywords are inherited for this iax. */ inherit[iax] = 1; if (alts->arridx[icol][iax] < alts->arridx[0][iax]) { /* The extra axes are also inherited. */ alts->arridx[icol][iax] = alts->arridx[0][iax]; } } (*nwcs)++; } } /* Count every "a" found in any IMGHEAD keyword... */ if (alts->arridx[0][iax]) { if (inherit[iax]) { /* ...but not if the IMGHEAD keywords will be inherited. */ alts->arridx[0][iax] = 0; alts->imgherit = 1; } else { (*nwcs)++; } } /* We need a struct for every "a" found in a PIXLIST keyword. */ if (alts->pixidx[iax]) { (*nwcs)++; } } if (*nwcs) { /* Allocate memory for the required number of wcsprm structs. */ if (!(*wcs = calloc(*nwcs, sizeof(struct wcsprm)))) { return 2; } /* Record the current values of NPVMAX and NPSMAX. */ npvmax = wcsnpv(-1); npsmax = wcsnps(-1); /* Initialize each wcsprm struct. */ wcsp = *wcs; *nwcs = 0; for (icol = 0; icol <= ncol; icol++) { for (iax = 0; iax < 27; iax++) { if (alts->arridx[icol][iax]) { /* Image-header representations that are not for inheritance (icol == 0) or binary table image array representations. */ wcsp->flag = -1; wcsnpv(alts->npv[icol][iax]); wcsnps(alts->nps[icol][iax]); if ((status = wcsini(1, (int)(alts->arridx[icol][iax]), wcsp))) { wcsvfree(nwcs, wcs); break; } /* Record the alternate version code. */ if (iax) { wcsp->alt[0] = 'A' + iax - 1; } /* Record the table column number. */ wcsp->colnum = icol; /* On the second pass alts->arridx[icol][27] indexes the array of wcsprm structs. */ alts->arridx[icol][iax] = (*nwcs)++; wcsp++; } else { /* Signal that this column has no WCS for this "a". */ alts->arridx[icol][iax] = -1; } } } for (iax = 0; iax < 27; iax++) { if (alts->pixidx[iax]) { /* Pixel lists representations. */ wcsp->flag = -1; wcsnpv(alts->pixnpv[iax]); wcsnps(alts->pixnps[iax]); if ((status = wcsini(1, (int)(alts->pixidx[iax]), wcsp))) { wcsvfree(nwcs, wcs); break; } /* Record the alternate version code. */ if (iax) { wcsp->alt[0] = 'A' + iax - 1; } /* Record the pixel list column numbers. */ mask = (1 << iax); for (icol = 1, ix = 0; icol <= ncol; icol++) { if (alts->pixlist[icol] & mask) { wcsp->colax[ix++] = icol; } } /* alts->pixidx[] indexes the array of wcsprm structs. */ alts->pixidx[iax] = (*nwcs)++; wcsp++; } else { /* Signal that this column is not a pixel list axis for this "a". */ alts->pixidx[iax] = -1; } } /* Restore the original values of NPVMAX and NPSMAX. */ wcsnpv(npvmax); wcsnps(npsmax); } return status; } /*---------------------------------------------------------------------------- * Return a pointer to the next wcsprm struct for a particular column number * and alternate. *---------------------------------------------------------------------------*/ struct wcsprm *wcsbth_idx( struct wcsprm *wcs, struct wcsbth_alts *alts, int keytype, int n, char a) { const char as[] = " ABCDEFGHIJKLMNOPQRSTUVWXYZ"; int iwcs; if (!wcs) return 0x0; iwcs = -1; for (; iwcs < 0 && alts->iax < 27; alts->iax++) { /* Note that a == 0 applies to every alternate, otherwise this loop simply determines the appropriate value of alts->iax. */ if (a && a != as[alts->iax]) continue; if (keytype & (IMGHEAD | BIMGARR)) { for (; iwcs < 0 && alts->icol <= alts->ncol; alts->icol++) { /* Image header keywords, n == 0, apply to all columns, otherwise this loop simply determines the appropriate value of alts->icol. */ if (n && n != alts->icol) continue; iwcs = alts->arridx[alts->icol][alts->iax]; } /* Break out of the loop to stop alts->iax from being incremented. */ if (iwcs >= 0) break; /* Start from scratch for the next alts->iax. */ alts->icol = 0; } if (keytype & (IMGAUX | PIXLIST)) { iwcs = alts->pixidx[alts->iax]; } } return (iwcs >= 0) ? (wcs + iwcs) : 0x0; } /*---------------------------------------------------------------------------- * Return the axis number associated with the specified column number in a * particular pixel list coordinate representation. *---------------------------------------------------------------------------*/ int wcsbth_colax( struct wcsprm *wcs, struct wcsbth_alts *alts, int n, char a) { int ix; struct wcsprm *wcsp; if (!wcs) return 0; wcsp = wcs; if (a != ' ') { wcsp += alts->pixidx[a-'A'+1]; } for (ix = 0; ix < wcsp->naxis; ix++) { if (wcsp->colax[ix] == n) { return ++ix; } } return 0; } /*---------------------------------------------------------------------------- * Interpret EPOCH keywords. *---------------------------------------------------------------------------*/ int wcsbth_epoch(void *wptr) { double *equinox; /* If EQUINOXa is currently undefined then set it from EPOCHa. */ equinox = (double *)wptr; if (undefined(*equinox)) { sscanf(yytext, "%lf", equinox); } return 0; } /*---------------------------------------------------------------------------- * Interpret VELREF keywords. *---------------------------------------------------------------------------*/ int wcsbth_velref(void *wptr) { const char *frames[] = {"LSRK", "BARYCENT", "TOPOCENT", "LSRD", "GEOCENTR", "SOURCE", "GALACTOC"}; char *specsys; int ivf, velref; /* If SPECSYSa is currently undefined then set it from VELREF. */ specsys = (char *)wptr; if (specsys[0] == '\0') { sscanf(yytext, "%d", &velref); ivf = velref%256 - 1; if (0 <= ivf && ivf < 7) { sprintf(specsys, "%s", frames[ivf]); } } return 0; } /*---------------------------------------------------------------------------- * Interpret VSOURCE keywords. *---------------------------------------------------------------------------*/ int wcsbth_vsource(void *wptr) { double beta, c = 299792458.0, vsource, *zsource; /* If ZSOURCEa is currently undefined then set it from VSOURCEa. */ zsource = (double *)wptr; if (undefined(*zsource)) { sscanf(yytext, "%lf", &vsource); /* Convert relativistic Doppler velocity to redshift. */ beta = vsource/c; *zsource = (1.0+beta)/sqrt(1.0 - beta*beta) - 1.0; } return 0; } /*---------------------------------------------------------------------------- * Tie up loose ends. *---------------------------------------------------------------------------*/ int wcsbth_final( struct wcsbth_alts *alts, int *nwcs, struct wcsprm **wcs) { int iax, status; for (iax = 0; iax < *nwcs; iax++) { /* Interpret -TAB header keywords. */ if ((status = wcstab(*wcs+iax))) { wcsvfree(nwcs, wcs); return status; } } return 0; }