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: wcspih.l,v 7.7 2021/07/12 06:36:49 mcalabre Exp $ 23 *============================================================================= 24 * 25 * wcspih.l is a Flex description file containing the definition of a lexical 26 * scanner for parsing the WCS keyrecords from a FITS primary image or image 27 * extension header. 28 * 29 * wcspih.l requires Flex v2.5.4 or later. Refer to wcshdr.h for a description 30 * of the user interface and operating notes. 31 * 32 * Implementation notes 33 * -------------------- 34 * Use of the WCSAXESa keyword is not mandatory. Its default value is "the 35 * larger of NAXIS and the largest index of these keywords [i.e. CRPIXj, PCi_j 36 * or CDi_j, CDELTi, CTYPEi, CRVALi, and CUNITi] found in the FITS header". 37 * Consequently the definition of WCSAXESa effectively invalidates the use of 38 * NAXIS for determining the number of coordinate axes and forces a preliminary 39 * pass through the header to determine the "largest index" in headers where 40 * WCSAXESa was omitted. 41 * 42 * Furthermore, since the use of WCSAXESa is optional, there is no way to 43 * determine the number of coordinate representations (the "a" value) other 44 * than by parsing all of the WCS keywords in the header; even if WCSAXESa was 45 * specified for some representations it cannot be known in advance whether it 46 * was specified for all of those present in the header. 47 * 48 * Hence the definition of WCSAXESa forces the scanner to be implemented in two 49 * passes. The first pass is used to determine the number of coordinate 50 * representations (up to 27) and the number of coordinate axes in each. 51 * Effectively WCSAXESa is ignored unless it exceeds the "largest index" in 52 * which case the keywords for the extra axes assume their default values. The 53 * number of PVi_ma and PSi_ma keywords in each representation is also counted 54 * in the first pass. 55 * 56 * On completion of the first pass, memory is allocated for an array of the 57 * required number of wcsprm structs and each of these is initialized 58 * appropriately. These structs are filled in the second pass. 59 * 60 * The parser does not check for duplicated keywords, it accepts the last 61 * encountered. 62 * 63 *===========================================================================*/ 64 65 /* Options. */ 66 %option full 67 %option never-interactive 68 %option noinput 69 %option noyywrap 70 %option outfile="wcspih.c" 71 %option prefix="wcspih" 72 %option reentrant 73 %option extra-type="struct wcspih_extra *" 74 75 /* Indices for parameterized keywords. */ 76 Z1 [0-9] 77 Z2 [0-9]{2} 78 Z3 [0-9]{3} 79 Z4 [0-9]{4} 80 Z5 [0-9]{5} 81 Z6 [0-9]{6} 82 83 I1 [1-9] 84 I2 [1-9][0-9] 85 I3 [1-9][0-9]{2} 86 I4 [1-9][0-9]{3} 87 88 /* Alternate coordinate system identifier. */ 89 ALT [ A-Z] 90 91 /* Keyvalue data types. */ 92 INTEGER [+-]?[0-9]+ 93 FLOAT [+-]?([0-9]+\.?[0-9]*|\.[0-9]+)([eEdD][+-]?[0-9]+)? 94 STRING '([^']|'')*' 95 RECORD '[^']*' 96 FIELD [a-zA-Z_][a-zA-Z_0-9.]* 97 98 /* Inline comment syntax. */ 99 INLINE " "*(\/.*)? 100 101 /* Exclusive start states. */ 102 %x CCia CCi_ja CCCCCia CCi_ma CCCCCCCa CCCCCCCC 103 %x CROTAi PROJPn SIP2 SIP3 DSSAMDXY PLTDECSN 104 %x VALUE INTEGER_VAL FLOAT_VAL FLOAT2_VAL STRING_VAL 105 %x RECORD_VAL RECFIELD RECCOLON RECVALUE RECEND 106 %x COMMENT 107 %x DISCARD ERROR FLUSH 108 109 %{ 110 #include <math.h> 111 #include <setjmp.h> 112 #include <stddef.h> 113 #include <stdio.h> 114 #include <stdlib.h> 115 #include <string.h> 116 117 #include "wcsmath.h" 118 #include "wcsprintf.h" 119 #include "wcsutil.h" 120 121 #include "dis.h" 122 #include "wcs.h" 123 #include "wcshdr.h" 124 125 #define INTEGER 0 126 #define FLOAT 1 127 #define FLOAT2 2 128 #define STRING 3 129 #define RECORD 4 130 131 #define PRIOR 1 132 #define SEQUENT 2 133 134 #define SIP 1 135 #define DSS 2 136 #define WAT 3 137 138 // User data associated with yyscanner. 139 struct wcspih_extra { 140 // Values passed to YY_INPUT. 141 char *hdr; 142 int nkeyrec; 143 144 // Used in preempting the call to exit() by yy_fatal_error(). 145 jmp_buf abort_jmp_env; 146 }; 147 148 #define YY_DECL int wcspih_scanner(char *header, int nkeyrec, int relax, \ 149 int ctrl, int *nreject, int *nwcs, struct wcsprm **wcs, yyscan_t yyscanner) 150 151 #define YY_INPUT(inbuff, count, bufsize) \ 152 { \ 153 if (yyextra->nkeyrec) { \ 154 strncpy(inbuff, yyextra->hdr, 80); \ 155 inbuff[80] = '\n'; \ 156 yyextra->hdr += 80; \ 157 yyextra->nkeyrec--; \ 158 count = 81; \ 159 } else { \ 160 count = YY_NULL; \ 161 } \ 162 } 163 164 // Preempt the call to exit() by yy_fatal_error(). 165 #define exit(status) longjmp(yyextra->abort_jmp_env, status); 166 167 // Internal helper functions. 168 static YY_DECL; 169 static int wcspih_final(int ndp[], int ndq[], int distran, double dsstmp[], 170 char *wat[], int *nwcs, struct wcsprm **wcs); 171 static int wcspih_init1(int naxis, int alts[], int dpq[], int npv[], 172 int nps[], int ndp[], int ndq[], int auxprm, int distran, 173 int *nwcs, struct wcsprm **wcs); 174 static void wcspih_pass1(int naxis, int i, int j, char a, int distype, 175 int alts[], int dpq[], int *npptr); 176 177 static int wcspih_jdref(double *wptr, const double *jdref); 178 static int wcspih_jdrefi(double *wptr, const double *jdrefi); 179 static int wcspih_jdreff(double *wptr, const double *jdreff); 180 static int wcspih_epoch(double *wptr, const double *epoch); 181 static int wcspih_vsource(double *wptr, const double *vsource); 182 183 static int wcspih_timepixr(double timepixr); 184 185 %} 186 187 %% 188 int p, q; 189 char *errmsg, errtxt[80], *keyname, strtmp[80], *wat[2], *watstr; 190 int alts[27], dpq[27], inttmp, ndp[27], ndq[27], nps[27], npv[27], 191 rectype; 192 double dbltmp, dbl2tmp[2], dsstmp[20]; 193 struct auxprm auxtem; 194 struct disprm distem; 195 struct wcsprm wcstem; 196 197 int naxis = 0; 198 for (int ialt = 0; ialt < 27; ialt++) { 199 alts[ialt] = 0; 200 dpq[ialt] = 0; 201 npv[ialt] = 0; 202 nps[ialt] = 0; 203 ndp[ialt] = 0; 204 ndq[ialt] = 0; 205 } 206 207 // Our handle on the input stream. 208 char *keyrec = header; 209 char *hptr = header; 210 char *keep = 0x0; 211 212 // For keeping tallies of keywords found. 213 *nreject = 0; 214 int nvalid = 0; 215 int nother = 0; 216 217 // If strict, then also reject. 218 if (relax & WCSHDR_strict) relax |= WCSHDR_reject; 219 220 // Keyword indices, as used in the WCS papers, e.g. PCi_ja, PVi_ma. 221 int i = 0; 222 int j = 0; 223 int m = 0; 224 char a = ' '; 225 226 // For decoding the keyvalue. 227 int valtype = -1; 228 int distype = 0; 229 void *vptr = 0x0; 230 231 // For keywords that require special handling. 232 int altlin = 0; 233 int *npptr = 0x0; 234 int (*chekval)(double) = 0x0; 235 int (*special)(double *, const double *) = 0x0; 236 int auxprm = 0; 237 int naux = 0; 238 int distran = 0; 239 int sipflag = 0; 240 int dssflag = 0; 241 int watflag = 0; 242 int watn = 0; 243 244 // The data structures produced. 245 *nwcs = 0; 246 *wcs = 0x0; 247 248 // Control variables. 249 int ipass = 1; 250 int npass = 2; 251 252 // User data associated with yyscanner. 253 yyextra->hdr = header; 254 yyextra->nkeyrec = nkeyrec; 255 256 // Return here via longjmp() invoked by yy_fatal_error(). 257 if (setjmp(yyextra->abort_jmp_env)) { 258 return WCSHDRERR_PARSER; 259 } 260 261 BEGIN(INITIAL); 262 263 264 ^NAXIS" = "" "*{INTEGER}{INLINE} { 265 keyname = "NAXISn"; 266 267 if (ipass == 1) { 268 sscanf(yytext, "NAXIS = %d", &naxis); 269 if (naxis < 0) naxis = 0; 270 BEGIN(FLUSH); 271 272 } else { 273 sscanf(yytext, "NAXIS = %d", &i); 274 275 if (i < 0) { 276 errmsg = "negative value of NAXIS ignored"; 277 BEGIN(ERROR); 278 } else { 279 BEGIN(DISCARD); 280 } 281 } 282 } 283 284 ^WCSAXES{ALT}=" "" "*{INTEGER} { 285 sscanf(yytext, "WCSAXES%c= %d", &a, &i); 286 287 if (i < 0) { 288 errmsg = "negative value of WCSAXESa ignored"; 289 BEGIN(ERROR); 290 291 } else { 292 valtype = INTEGER; 293 vptr = 0x0; 294 295 keyname = "WCSAXESa"; 296 BEGIN(COMMENT); 297 } 298 } 299 300 ^CRPIX { 301 valtype = FLOAT; 302 vptr = &(wcstem.crpix); 303 304 keyname = "CRPIXja"; 305 BEGIN(CCCCCia); 306 } 307 308 ^PC { 309 valtype = FLOAT; 310 vptr = &(wcstem.pc); 311 altlin = 1; 312 313 keyname = "PCi_ja"; 314 BEGIN(CCi_ja); 315 } 316 317 ^CD { 318 valtype = FLOAT; 319 vptr = &(wcstem.cd); 320 altlin = 2; 321 322 keyname = "CDi_ja"; 323 BEGIN(CCi_ja); 324 } 325 326 ^CDELT { 327 valtype = FLOAT; 328 vptr = &(wcstem.cdelt); 329 330 keyname = "CDELTia"; 331 BEGIN(CCCCCia); 332 } 333 334 ^CROTA { 335 valtype = FLOAT; 336 vptr = &(wcstem.crota); 337 altlin = 4; 338 339 keyname = "CROTAn"; 340 BEGIN(CROTAi); 341 } 342 343 ^CUNIT { 344 valtype = STRING; 345 vptr = &(wcstem.cunit); 346 347 keyname = "CUNITia"; 348 BEGIN(CCCCCia); 349 } 350 351 ^CTYPE { 352 valtype = STRING; 353 vptr = &(wcstem.ctype); 354 355 keyname = "CTYPEia"; 356 BEGIN(CCCCCia); 357 } 358 359 ^CRVAL { 360 valtype = FLOAT; 361 vptr = &(wcstem.crval); 362 363 keyname = "CRVALia"; 364 BEGIN(CCCCCia); 365 } 366 367 ^LONPOLE { 368 valtype = FLOAT; 369 vptr = &(wcstem.lonpole); 370 371 keyname = "LONPOLEa"; 372 BEGIN(CCCCCCCa); 373 } 374 375 ^LATPOLE { 376 valtype = FLOAT; 377 vptr = &(wcstem.latpole); 378 379 keyname = "LATPOLEa"; 380 BEGIN(CCCCCCCa); 381 } 382 383 ^RESTFRQ { 384 valtype = FLOAT; 385 vptr = &(wcstem.restfrq); 386 387 keyname = "RESTFRQa"; 388 BEGIN(CCCCCCCa); 389 } 390 391 ^RESTFREQ { 392 if (relax & WCSHDR_strict) { 393 errmsg = "the RESTFREQ keyword is deprecated, use RESTFRQa"; 394 BEGIN(ERROR); 395 396 } else { 397 valtype = FLOAT; 398 vptr = &(wcstem.restfrq); 399 400 unput(' '); 401 402 keyname = "RESTFREQ"; 403 BEGIN(CCCCCCCa); 404 } 405 } 406 407 ^RESTWAV { 408 valtype = FLOAT; 409 vptr = &(wcstem.restwav); 410 411 keyname = "RESTWAVa"; 412 BEGIN(CCCCCCCa); 413 } 414 415 ^PV { 416 valtype = FLOAT; 417 vptr = &(wcstem.pv); 418 npptr = npv; 419 420 keyname = "PVi_ma"; 421 BEGIN(CCi_ma); 422 } 423 424 ^PROJP { 425 valtype = FLOAT; 426 vptr = &(wcstem.pv); 427 npptr = npv; 428 429 keyname = "PROJPn"; 430 BEGIN(PROJPn); 431 } 432 433 ^PS { 434 valtype = STRING; 435 vptr = &(wcstem.ps); 436 npptr = nps; 437 438 keyname = "PSi_ma"; 439 BEGIN(CCi_ma); 440 } 441 442 ^VELREF{ALT}" " { 443 sscanf(yytext, "VELREF%c", &a); 444 445 if (relax & WCSHDR_strict) { 446 errmsg = "the VELREF keyword is deprecated, use SPECSYSa"; 447 BEGIN(ERROR); 448 449 } else if ((a == ' ') || (relax & WCSHDR_VELREFa)) { 450 valtype = INTEGER; 451 vptr = &(wcstem.velref); 452 453 unput(a); 454 455 keyname = "VELREF"; 456 BEGIN(CCCCCCCa); 457 458 } else if (relax & WCSHDR_reject) { 459 errmsg = "VELREF keyword may not have an alternate version code"; 460 BEGIN(ERROR); 461 462 } else { 463 BEGIN(DISCARD); 464 } 465 } 466 467 ^CNAME { 468 valtype = STRING; 469 vptr = &(wcstem.cname); 470 471 keyname = "CNAMEia"; 472 BEGIN(CCCCCia); 473 } 474 475 ^CRDER { 476 valtype = FLOAT; 477 vptr = &(wcstem.crder); 478 479 keyname = "CRDERia"; 480 BEGIN(CCCCCia); 481 } 482 483 ^CSYER { 484 valtype = FLOAT; 485 vptr = &(wcstem.csyer); 486 487 keyname = "CSYERia"; 488 BEGIN(CCCCCia); 489 } 490 491 ^CZPHS { 492 valtype = FLOAT; 493 vptr = &(wcstem.czphs); 494 495 keyname = "CZPHSia"; 496 BEGIN(CCCCCia); 497 } 498 499 ^CPERI { 500 valtype = FLOAT; 501 vptr = &(wcstem.cperi); 502 503 keyname = "CPERIia"; 504 BEGIN(CCCCCia); 505 } 506 507 ^WCSNAME { 508 valtype = STRING; 509 vptr = wcstem.wcsname; 510 511 keyname = "WCSNAMEa"; 512 BEGIN(CCCCCCCa); 513 } 514 515 ^TIMESYS" " { 516 valtype = STRING; 517 vptr = wcstem.timesys; 518 519 keyname = "TIMESYS"; 520 BEGIN(CCCCCCCC); 521 } 522 523 ^TREFPOS" " { 524 valtype = STRING; 525 vptr = wcstem.trefpos; 526 527 keyname = "TREFPOS"; 528 BEGIN(CCCCCCCC); 529 } 530 531 ^TREFDIR" " { 532 valtype = STRING; 533 vptr = wcstem.trefdir; 534 535 keyname = "TREFDIR"; 536 BEGIN(CCCCCCCC); 537 } 538 539 ^PLEPHEM" " { 540 valtype = STRING; 541 vptr = wcstem.plephem; 542 543 keyname = "PLEPHEM"; 544 BEGIN(CCCCCCCC); 545 } 546 547 ^TIMEUNIT { 548 valtype = STRING; 549 vptr = wcstem.timeunit; 550 551 keyname = "TIMEUNIT"; 552 BEGIN(CCCCCCCC); 553 } 554 555 ^DATEREF" " | 556 ^DATE-REF { 557 if ((yytext[4] == 'R') || (relax & WCSHDR_DATEREF)) { 558 valtype = STRING; 559 vptr = wcstem.dateref; 560 561 keyname = "DATEREF"; 562 BEGIN(CCCCCCCC); 563 564 } else if (relax & WCSHDR_reject) { 565 errmsg = "the DATE-REF keyword is non-standard"; 566 BEGIN(ERROR); 567 568 } else { 569 BEGIN(DISCARD); 570 } 571 } 572 573 ^MJDREF" " | 574 ^MJD-REF" " { 575 if ((yytext[3] == 'R') || (relax & WCSHDR_DATEREF)) { 576 valtype = FLOAT2; 577 vptr = wcstem.mjdref; 578 579 keyname = "MJDREF"; 580 BEGIN(CCCCCCCC); 581 582 } else if (relax & WCSHDR_reject) { 583 errmsg = "the MJD-REF keyword is non-standard"; 584 BEGIN(ERROR); 585 586 } else { 587 BEGIN(DISCARD); 588 } 589 } 590 591 ^MJDREFI" " | 592 ^MJD-REFI { 593 if ((yytext[3] == 'R') || (relax & WCSHDR_DATEREF)) { 594 // Actually integer, but treated as float. 595 valtype = FLOAT; 596 vptr = wcstem.mjdref; 597 598 keyname = "MJDREFI"; 599 BEGIN(CCCCCCCC); 600 601 } else if (relax & WCSHDR_reject) { 602 errmsg = "the MJD-REFI keyword is non-standard"; 603 BEGIN(ERROR); 604 605 } else { 606 BEGIN(DISCARD); 607 } 608 } 609 610 ^MJDREFF" " | 611 ^MJD-REFF { 612 if ((yytext[3] == 'R') || (relax & WCSHDR_DATEREF)) { 613 valtype = FLOAT; 614 vptr = wcstem.mjdref + 1; 615 616 keyname = "MJDREFF"; 617 BEGIN(CCCCCCCC); 618 619 } else if (relax & WCSHDR_reject) { 620 errmsg = "the MJD-REFF keyword is non-standard"; 621 BEGIN(ERROR); 622 623 } else { 624 BEGIN(DISCARD); 625 } 626 } 627 628 ^JDREF" " | 629 ^JD-REF" " { 630 if ((yytext[2] == 'R') || (relax & WCSHDR_DATEREF)) { 631 valtype = FLOAT2; 632 vptr = wcstem.mjdref; 633 special = wcspih_jdref; 634 635 keyname = "JDREF"; 636 BEGIN(CCCCCCCC); 637 638 } else if (relax & WCSHDR_reject) { 639 errmsg = "the JD-REF keyword is non-standard"; 640 BEGIN(ERROR); 641 642 } else { 643 BEGIN(DISCARD); 644 } 645 } 646 647 ^JDREFI" " | 648 ^JD-REFI { 649 if ((yytext[2] == 'R') || (relax & WCSHDR_DATEREF)) { 650 // Actually integer, but treated as float. 651 valtype = FLOAT; 652 vptr = wcstem.mjdref; 653 special = wcspih_jdrefi; 654 655 keyname = "JDREFI"; 656 BEGIN(CCCCCCCC); 657 658 } else if (relax & WCSHDR_reject) { 659 errmsg = "the JD-REFI keyword is non-standard"; 660 BEGIN(ERROR); 661 662 } else { 663 BEGIN(DISCARD); 664 } 665 } 666 667 ^JDREFF" " | 668 ^JD-REFF { 669 if ((yytext[2] == 'R') || (relax & WCSHDR_DATEREF)) { 670 valtype = FLOAT; 671 vptr = wcstem.mjdref; 672 special = wcspih_jdreff; 673 674 keyname = "JDREFF"; 675 BEGIN(CCCCCCCC); 676 677 } else if (relax & WCSHDR_reject) { 678 errmsg = "the JD-REFF keyword is non-standard"; 679 BEGIN(ERROR); 680 681 } else { 682 BEGIN(DISCARD); 683 } 684 } 685 686 ^TIMEOFFS { 687 valtype = FLOAT; 688 vptr = &(wcstem.timeoffs); 689 690 keyname = "TIMEOFFS"; 691 BEGIN(CCCCCCCC); 692 } 693 694 ^DATE-OBS { 695 valtype = STRING; 696 vptr = wcstem.dateobs; 697 if (ctrl < -10) keep = keyrec; 698 699 keyname = "DATE-OBS"; 700 BEGIN(CCCCCCCC); 701 } 702 703 ^DATE-BEG { 704 valtype = STRING; 705 vptr = wcstem.datebeg; 706 if (ctrl < -10) keep = keyrec; 707 708 keyname = "DATE-BEG"; 709 BEGIN(CCCCCCCC); 710 } 711 712 ^DATE-AVG { 713 valtype = STRING; 714 vptr = wcstem.dateavg; 715 if (ctrl < -10) keep = keyrec; 716 717 keyname = "DATE-AVG"; 718 BEGIN(CCCCCCCC); 719 } 720 721 ^DATE-END { 722 valtype = STRING; 723 vptr = wcstem.dateend; 724 if (ctrl < -10) keep = keyrec; 725 726 keyname = "DATE-END"; 727 BEGIN(CCCCCCCC); 728 } 729 730 ^MJD-OBS" " { 731 valtype = FLOAT; 732 vptr = &(wcstem.mjdobs); 733 if (ctrl < -10) keep = keyrec; 734 735 keyname = "MJD-OBS"; 736 BEGIN(CCCCCCCC); 737 } 738 739 ^MJD-BEG" " { 740 valtype = FLOAT; 741 vptr = &(wcstem.mjdbeg); 742 if (ctrl < -10) keep = keyrec; 743 744 keyname = "MJD-BEG"; 745 BEGIN(CCCCCCCC); 746 } 747 748 ^MJD-AVG" " { 749 valtype = FLOAT; 750 vptr = &(wcstem.mjdavg); 751 if (ctrl < -10) keep = keyrec; 752 753 keyname = "MJD-AVG"; 754 BEGIN(CCCCCCCC); 755 } 756 757 ^MJD-END" " { 758 valtype = FLOAT; 759 vptr = &(wcstem.mjdend); 760 if (ctrl < -10) keep = keyrec; 761 762 keyname = "MJD-END"; 763 BEGIN(CCCCCCCC); 764 } 765 766 ^JEPOCH" " { 767 valtype = FLOAT; 768 vptr = &(wcstem.jepoch); 769 if (ctrl < -10) keep = keyrec; 770 771 keyname = "JEPOCH"; 772 BEGIN(CCCCCCCC); 773 } 774 775 ^BEPOCH" " { 776 valtype = FLOAT; 777 vptr = &(wcstem.bepoch); 778 if (ctrl < -10) keep = keyrec; 779 780 keyname = "BEPOCH"; 781 BEGIN(CCCCCCCC); 782 } 783 784 ^TSTART" " { 785 valtype = FLOAT; 786 vptr = &(wcstem.tstart); 787 if (ctrl < -10) keep = keyrec; 788 789 keyname = "TSTART"; 790 BEGIN(CCCCCCCC); 791 } 792 793 ^TSTOP" " { 794 valtype = FLOAT; 795 vptr = &(wcstem.tstop); 796 if (ctrl < -10) keep = keyrec; 797 798 keyname = "TSTOP"; 799 BEGIN(CCCCCCCC); 800 } 801 802 ^XPOSURE" " { 803 valtype = FLOAT; 804 vptr = &(wcstem.xposure); 805 if (ctrl < -10) keep = keyrec; 806 807 keyname = "XPOSURE"; 808 BEGIN(CCCCCCCC); 809 } 810 811 ^TELAPSE" " { 812 valtype = FLOAT; 813 vptr = &(wcstem.telapse); 814 if (ctrl < -10) keep = keyrec; 815 816 keyname = "TELAPSE"; 817 BEGIN(CCCCCCCC); 818 } 819 820 ^TIMSYER" " { 821 valtype = FLOAT; 822 vptr = &(wcstem.timsyer); 823 if (ctrl < -10) keep = keyrec; 824 825 keyname = "TIMSYER"; 826 BEGIN(CCCCCCCC); 827 } 828 829 ^TIMRDER" " { 830 valtype = FLOAT; 831 vptr = &(wcstem.timrder); 832 if (ctrl < -10) keep = keyrec; 833 834 keyname = "TIMRDER"; 835 BEGIN(CCCCCCCC); 836 } 837 838 ^TIMEDEL" " { 839 valtype = FLOAT; 840 vptr = &(wcstem.timedel); 841 if (ctrl < -10) keep = keyrec; 842 843 keyname = "TIMEDEL"; 844 BEGIN(CCCCCCCC); 845 } 846 847 ^TIMEPIXR { 848 valtype = FLOAT; 849 vptr = &(wcstem.timepixr); 850 chekval = wcspih_timepixr; 851 if (ctrl < -10) keep = keyrec; 852 853 keyname = "TIMEPIXR"; 854 BEGIN(CCCCCCCC); 855 } 856 857 ^OBSGEO-X { 858 valtype = FLOAT; 859 vptr = wcstem.obsgeo; 860 if (ctrl < -10) keep = keyrec; 861 862 keyname = "OBSGEO-X"; 863 BEGIN(CCCCCCCC); 864 } 865 866 ^OBSGEO-Y { 867 valtype = FLOAT; 868 vptr = wcstem.obsgeo + 1; 869 if (ctrl < -10) keep = keyrec; 870 871 keyname = "OBSGEO-Y"; 872 BEGIN(CCCCCCCC); 873 } 874 875 ^OBSGEO-Z { 876 valtype = FLOAT; 877 vptr = wcstem.obsgeo + 2; 878 if (ctrl < -10) keep = keyrec; 879 880 keyname = "OBSGEO-Z"; 881 BEGIN(CCCCCCCC); 882 } 883 884 ^OBSGEO-L { 885 valtype = FLOAT; 886 vptr = wcstem.obsgeo + 3; 887 if (ctrl < -10) keep = keyrec; 888 889 keyname = "OBSGEO-L"; 890 BEGIN(CCCCCCCC); 891 } 892 893 ^OBSGEO-B { 894 valtype = FLOAT; 895 vptr = wcstem.obsgeo + 4; 896 if (ctrl < -10) keep = keyrec; 897 898 keyname = "OBSGEO-B"; 899 BEGIN(CCCCCCCC); 900 } 901 902 ^OBSGEO-H { 903 valtype = FLOAT; 904 vptr = wcstem.obsgeo + 5; 905 if (ctrl < -10) keep = keyrec; 906 907 keyname = "OBSGEO-H"; 908 BEGIN(CCCCCCCC); 909 } 910 911 ^OBSORBIT { 912 valtype = STRING; 913 vptr = wcstem.obsorbit; 914 915 keyname = "OBSORBIT"; 916 BEGIN(CCCCCCCC); 917 } 918 919 ^RADESYS { 920 valtype = STRING; 921 vptr = wcstem.radesys; 922 923 keyname = "RADESYSa"; 924 BEGIN(CCCCCCCa); 925 } 926 927 ^RADECSYS { 928 if (relax & WCSHDR_RADECSYS) { 929 valtype = STRING; 930 vptr = wcstem.radesys; 931 932 unput(' '); 933 934 keyname = "RADECSYS"; 935 BEGIN(CCCCCCCa); 936 937 } else if (relax & WCSHDR_reject) { 938 errmsg = "the RADECSYS keyword is deprecated, use RADESYSa"; 939 BEGIN(ERROR); 940 941 } else { 942 BEGIN(DISCARD); 943 } 944 } 945 946 ^EPOCH{ALT}" " { 947 sscanf(yytext, "EPOCH%c", &a); 948 949 if (relax & WCSHDR_strict) { 950 errmsg = "the EPOCH keyword is deprecated, use EQUINOXa"; 951 BEGIN(ERROR); 952 953 } else if (a == ' ' || relax & WCSHDR_EPOCHa) { 954 valtype = FLOAT; 955 vptr = &(wcstem.equinox); 956 special = wcspih_epoch; 957 958 unput(a); 959 960 keyname = "EPOCH"; 961 BEGIN(CCCCCCCa); 962 963 } else if (relax & WCSHDR_reject) { 964 errmsg = "EPOCH keyword may not have an alternate version code"; 965 BEGIN(ERROR); 966 967 } else { 968 BEGIN(DISCARD); 969 } 970 } 971 972 ^EQUINOX { 973 valtype = FLOAT; 974 vptr = &(wcstem.equinox); 975 976 keyname = "EQUINOXa"; 977 BEGIN(CCCCCCCa); 978 } 979 980 ^SPECSYS { 981 valtype = STRING; 982 vptr = wcstem.specsys; 983 984 keyname = "SPECSYSa"; 985 BEGIN(CCCCCCCa); 986 } 987 988 ^SSYSOBS { 989 valtype = STRING; 990 vptr = wcstem.ssysobs; 991 992 keyname = "SSYSOBSa"; 993 BEGIN(CCCCCCCa); 994 } 995 996 ^VELOSYS { 997 valtype = FLOAT; 998 vptr = &(wcstem.velosys); 999 1000 keyname = "VELOSYSa"; 1001 BEGIN(CCCCCCCa); 1002 } 1003 1004 ^VSOURCE{ALT} { 1005 if (relax & WCSHDR_VSOURCE) { 1006 valtype = FLOAT; 1007 vptr = &(wcstem.zsource); 1008 special = wcspih_vsource; 1009 1010 yyless(7); 1011 1012 keyname = "VSOURCEa"; 1013 BEGIN(CCCCCCCa); 1014 1015 } else if (relax & WCSHDR_reject) { 1016 errmsg = "the VSOURCEa keyword is deprecated, use ZSOURCEa"; 1017 BEGIN(ERROR); 1018 1019 } else { 1020 BEGIN(DISCARD); 1021 } 1022 } 1023 1024 ^ZSOURCE { 1025 valtype = FLOAT; 1026 vptr = &(wcstem.zsource); 1027 1028 keyname = "ZSOURCEa"; 1029 BEGIN(CCCCCCCa); 1030 } 1031 1032 ^SSYSSRC { 1033 valtype = STRING; 1034 vptr = wcstem.ssyssrc; 1035 1036 keyname = "SSYSSRCa"; 1037 BEGIN(CCCCCCCa); 1038 } 1039 1040 ^VELANGL { 1041 valtype = FLOAT; 1042 vptr = &(wcstem.velangl); 1043 1044 keyname = "VELANGLa"; 1045 BEGIN(CCCCCCCa); 1046 } 1047 1048 ^RSUN_REF { 1049 valtype = FLOAT; 1050 auxprm = 1; 1051 vptr = &(auxtem.rsun_ref); 1052 1053 keyname = "RSUN_REF"; 1054 BEGIN(CCCCCCCC); 1055 } 1056 1057 ^DSUN_OBS { 1058 valtype = FLOAT; 1059 auxprm = 1; 1060 vptr = &(auxtem.dsun_obs); 1061 1062 keyname = "DSUN_OBS"; 1063 BEGIN(CCCCCCCC); 1064 } 1065 1066 ^CRLN_OBS { 1067 valtype = FLOAT; 1068 auxprm = 1; 1069 vptr = &(auxtem.crln_obs); 1070 1071 keyname = "CRLN_OBS"; 1072 BEGIN(CCCCCCCC); 1073 } 1074 1075 ^HGLN_OBS { 1076 valtype = FLOAT; 1077 auxprm = 1; 1078 vptr = &(auxtem.hgln_obs); 1079 1080 keyname = "HGLN_OBS"; 1081 BEGIN(CCCCCCCC); 1082 } 1083 1084 ^CRLT_OBS | 1085 ^HGLT_OBS { 1086 valtype = FLOAT; 1087 auxprm = 1; 1088 vptr = &(auxtem.hglt_obs); 1089 1090 keyname = "HGLT_OBS"; 1091 BEGIN(CCCCCCCC); 1092 } 1093 1094 ^CPDIS { 1095 valtype = STRING; 1096 distype = PRIOR; 1097 vptr = &(distem.dtype); 1098 1099 keyname = "CPDISja"; 1100 BEGIN(CCCCCia); 1101 } 1102 1103 ^CQDIS { 1104 valtype = STRING; 1105 distype = SEQUENT; 1106 vptr = &(distem.dtype); 1107 1108 keyname = "CQDISia"; 1109 BEGIN(CCCCCia); 1110 } 1111 1112 ^DP { 1113 valtype = RECORD; 1114 distype = PRIOR; 1115 vptr = &(distem.dp); 1116 npptr = ndp; 1117 1118 keyname = "DPja"; 1119 BEGIN(CCia); 1120 } 1121 1122 ^DQ { 1123 valtype = RECORD; 1124 distype = SEQUENT; 1125 vptr = &(distem.dp); 1126 npptr = ndq; 1127 1128 keyname = "DQia"; 1129 BEGIN(CCia); 1130 } 1131 1132 ^CPERR { 1133 valtype = FLOAT; 1134 distype = PRIOR; 1135 vptr = &(distem.maxdis); 1136 1137 keyname = "CPERRja"; 1138 BEGIN(CCCCCia); 1139 } 1140 1141 ^CQERR { 1142 valtype = FLOAT; 1143 distype = SEQUENT; 1144 vptr = &(distem.maxdis); 1145 1146 keyname = "CQERRia"; 1147 BEGIN(CCCCCia); 1148 } 1149 1150 ^DVERR { 1151 valtype = FLOAT; 1152 distype = PRIOR; 1153 vptr = &(distem.totdis); 1154 1155 keyname = "DVERRa"; 1156 BEGIN(CCCCCCCa); 1157 } 1158 1159 ^A_ORDER" " { 1160 // SIP: axis 1 polynomial degree (not stored). 1161 valtype = INTEGER; 1162 distype = PRIOR; 1163 vptr = 0x0; 1164 1165 i = 1; 1166 a = ' '; 1167 1168 keyname = "A_ORDER"; 1169 BEGIN(VALUE); 1170 } 1171 1172 ^B_ORDER" " { 1173 // SIP: axis 2 polynomial degree (not stored). 1174 valtype = INTEGER; 1175 distype = PRIOR; 1176 vptr = 0x0; 1177 1178 i = 2; 1179 a = ' '; 1180 1181 keyname = "B_ORDER"; 1182 BEGIN(VALUE); 1183 } 1184 1185 ^AP_ORDER { 1186 // SIP: axis 1 inverse polynomial degree (not stored). 1187 valtype = INTEGER; 1188 distype = PRIOR; 1189 vptr = 0x0; 1190 1191 i = 1; 1192 a = ' '; 1193 1194 keyname = "AP_ORDER"; 1195 BEGIN(VALUE); 1196 } 1197 1198 ^BP_ORDER { 1199 // SIP: axis 2 inverse polynomial degree (not stored). 1200 valtype = INTEGER; 1201 distype = PRIOR; 1202 vptr = 0x0; 1203 1204 i = 2; 1205 a = ' '; 1206 1207 keyname = "BP_ORDER"; 1208 BEGIN(VALUE); 1209 } 1210 1211 ^A_DMAX" " { 1212 // SIP: axis 1 maximum distortion. 1213 valtype = FLOAT; 1214 distype = PRIOR; 1215 vptr = &(distem.maxdis); 1216 1217 i = 1; 1218 a = ' '; 1219 1220 keyname = "A_DMAX"; 1221 BEGIN(VALUE); 1222 } 1223 1224 ^B_DMAX" " { 1225 // SIP: axis 2 maximum distortion. 1226 valtype = FLOAT; 1227 distype = PRIOR; 1228 vptr = &(distem.maxdis); 1229 1230 i = 2; 1231 a = ' '; 1232 1233 keyname = "B_DMAX"; 1234 BEGIN(VALUE); 1235 } 1236 1237 ^A_ { 1238 // SIP: axis 1 polynomial coefficient. 1239 i = 1; 1240 sipflag = 2; 1241 1242 keyname = "A_p_q"; 1243 BEGIN(SIP2); 1244 } 1245 1246 ^B_ { 1247 // SIP: axis 2 polynomial coefficient. 1248 i = 2; 1249 sipflag = 2; 1250 1251 keyname = "B_p_q"; 1252 BEGIN(SIP2); 1253 } 1254 1255 ^AP_ { 1256 // SIP: axis 1 inverse polynomial coefficient. 1257 i = 1; 1258 sipflag = 3; 1259 1260 keyname = "AP_p_q"; 1261 BEGIN(SIP3); 1262 } 1263 1264 ^BP_ { 1265 // SIP: axis 2 inverse polynomial coefficient. 1266 i = 2; 1267 sipflag = 3; 1268 1269 keyname = "BP_p_q"; 1270 BEGIN(SIP3); 1271 } 1272 1273 ^CNPIX1" " { 1274 // DSS: LLH corner pixel coordinate 1. 1275 valtype = FLOAT; 1276 distype = SEQUENT; 1277 vptr = dsstmp; 1278 dssflag = 1; 1279 distran = DSS; 1280 1281 keyname = "CNPIX1"; 1282 BEGIN(VALUE); 1283 } 1284 1285 ^CNPIX2" " { 1286 // DSS: LLH corner pixel coordinate 2. 1287 valtype = FLOAT; 1288 distype = SEQUENT; 1289 vptr = dsstmp+1; 1290 dssflag = 1; 1291 distran = DSS; 1292 1293 keyname = "CNPIX1"; 1294 BEGIN(VALUE); 1295 } 1296 1297 ^PPO3" " { 1298 // DSS: plate centre x-coordinate in micron. 1299 valtype = FLOAT; 1300 distype = SEQUENT; 1301 vptr = dsstmp+2; 1302 dssflag = 1; 1303 distran = DSS; 1304 1305 keyname = "PPO3"; 1306 BEGIN(VALUE); 1307 } 1308 1309 ^PPO6" " { 1310 // DSS: plate centre y-coordinate in micron. 1311 valtype = FLOAT; 1312 distype = SEQUENT; 1313 vptr = dsstmp+3; 1314 dssflag = 1; 1315 distran = DSS; 1316 1317 keyname = "PPO6"; 1318 BEGIN(VALUE); 1319 } 1320 1321 ^XPIXELSZ { 1322 // DSS: pixel x-dimension in micron. 1323 valtype = FLOAT; 1324 distype = SEQUENT; 1325 vptr = dsstmp+4; 1326 dssflag = 1; 1327 distran = DSS; 1328 1329 keyname = "XPIXELSZ"; 1330 BEGIN(VALUE); 1331 } 1332 1333 ^YPIXELSZ { 1334 // DSS: pixel y-dimension in micron. 1335 valtype = FLOAT; 1336 distype = SEQUENT; 1337 vptr = dsstmp+5; 1338 dssflag = 1; 1339 distran = DSS; 1340 1341 keyname = "YPIXELSZ"; 1342 BEGIN(VALUE); 1343 } 1344 1345 ^PLTRAH" " { 1346 // DSS: plate centre, right ascension - hours. 1347 valtype = FLOAT; 1348 distype = SEQUENT; 1349 vptr = dsstmp+6; 1350 dssflag = 1; 1351 distran = DSS; 1352 1353 keyname = "PLTRAH"; 1354 BEGIN(VALUE); 1355 } 1356 1357 ^PLTRAM" " { 1358 // DSS: plate centre, right ascension - minutes. 1359 valtype = FLOAT; 1360 distype = SEQUENT; 1361 vptr = dsstmp+7; 1362 dssflag = 1; 1363 distran = DSS; 1364 1365 keyname = "PLTRAM"; 1366 BEGIN(VALUE); 1367 } 1368 1369 ^PLTRAS" " { 1370 // DSS: plate centre, right ascension - seconds. 1371 valtype = FLOAT; 1372 distype = SEQUENT; 1373 vptr = dsstmp+8; 1374 dssflag = 1; 1375 distran = DSS; 1376 1377 keyname = "PLTRAS"; 1378 BEGIN(VALUE); 1379 } 1380 1381 ^PLTDECSN { 1382 // DSS: plate centre, declination - sign. 1383 valtype = STRING; 1384 distype = SEQUENT; 1385 vptr = dsstmp+9; 1386 dssflag = 1; 1387 distran = DSS; 1388 1389 keyname = "PLTDECSN"; 1390 BEGIN(PLTDECSN); 1391 } 1392 1393 ^PLTDECD" " { 1394 // DSS: plate centre, declination - degrees. 1395 valtype = FLOAT; 1396 distype = SEQUENT; 1397 vptr = dsstmp+10; 1398 dssflag = 1; 1399 distran = DSS; 1400 1401 keyname = "PLTDECD"; 1402 BEGIN(VALUE); 1403 } 1404 1405 ^PLTDECM" " { 1406 // DSS: plate centre, declination - arcmin. 1407 valtype = FLOAT; 1408 distype = SEQUENT; 1409 vptr = dsstmp+11; 1410 dssflag = 1; 1411 distran = DSS; 1412 1413 keyname = "PLTDECM"; 1414 BEGIN(VALUE); 1415 } 1416 1417 ^PLTDECS" " { 1418 // DSS: plate centre, declination - arcsec. 1419 valtype = FLOAT; 1420 distype = SEQUENT; 1421 vptr = dsstmp+12; 1422 dssflag = 1; 1423 distran = DSS; 1424 1425 keyname = "PLTDECS"; 1426 BEGIN(VALUE); 1427 } 1428 1429 ^PLATEID" " { 1430 // DSS: plate identification (insufficient to trigger DSS). 1431 valtype = STRING; 1432 distype = SEQUENT; 1433 vptr = dsstmp+13; 1434 dssflag = 2; 1435 distran = 0; 1436 1437 keyname = "PLATEID"; 1438 BEGIN(VALUE); 1439 } 1440 1441 ^AMDX { 1442 // DSS: axis 1 polynomial coefficient. 1443 i = 1; 1444 dssflag = 3; 1445 1446 keyname = "AMDXm"; 1447 BEGIN(DSSAMDXY); 1448 } 1449 1450 ^AMDY { 1451 // DSS: axis 2 polynomial coefficient. 1452 i = 2; 1453 dssflag = 3; 1454 1455 keyname = "AMDYm"; 1456 BEGIN(DSSAMDXY); 1457 } 1458 1459 ^WAT[12]_{Z3} { 1460 // TNX or ZPX: string-encoded data array. 1461 sscanf(yytext, "WAT%d_%d", &i, &m); 1462 if (watn < m) watn = m; 1463 watflag = 1; 1464 1465 valtype = STRING; 1466 distype = SEQUENT; 1467 vptr = wat[i-1] + 68*(m-1); 1468 1469 a = ' '; 1470 distran = WAT; 1471 1472 keyname = "WATi_m"; 1473 BEGIN(VALUE); 1474 } 1475 1476 ^END" "{77} { 1477 if (yyextra->nkeyrec) { 1478 yyextra->nkeyrec = 0; 1479 errmsg = "keyrecords following the END keyrecord were ignored"; 1480 BEGIN(ERROR); 1481 } else { 1482 BEGIN(DISCARD); 1483 } 1484 } 1485 1486 ^. { 1487 BEGIN(DISCARD); 1488 } 1489 1490 <CCia>{I1}{ALT}" " | 1491 <CCia>{I2}{ALT}" " | 1492 <CCCCCia>{I1}{ALT}" " | 1493 <CCCCCia>{I2}{ALT} { 1494 sscanf(yytext, "%d%c", &i, &a); 1495 BEGIN(VALUE); 1496 } 1497 1498 <CCia>0{I1}{ALT}" " | 1499 <CCia>0{Z1}{I1}{ALT}" " | 1500 <CCia>0{Z2}{I1}{ALT}" " | 1501 <CCia>0{Z3}{I1}{ALT} | 1502 <CCia>0{Z4}{I1} | 1503 <CCCCCia>0{I1}{ALT} | 1504 <CCCCCia>0{Z1}{I1} { 1505 if (relax & WCSHDR_reject) { 1506 // Violates the basic FITS standard. 1507 errmsg = "indices in parameterized keywords must not have " 1508 "leading zeroes"; 1509 BEGIN(ERROR); 1510 1511 } else { 1512 // Pretend we don't recognize it. 1513 BEGIN(DISCARD); 1514 } 1515 } 1516 1517 <CCia>{Z1}{ALT}" " | 1518 <CCia>{Z2}{ALT}" " | 1519 <CCia>{Z3}{ALT}" " | 1520 <CCia>{Z4}{ALT}" " | 1521 <CCia>{Z5}{ALT} | 1522 <CCia>{Z6} | 1523 <CCCCCia>{Z1}{ALT}" " | 1524 <CCCCCia>{Z2}{ALT} | 1525 <CCCCCia>{Z3} { 1526 // Anything that has fallen through to this point must contain 1527 // an invalid axis number. 1528 errmsg = "axis number must exceed 0"; 1529 BEGIN(ERROR); 1530 } 1531 1532 <CCia>. { 1533 // Let it go. 1534 BEGIN(DISCARD); 1535 } 1536 1537 <CCCCCia>. { 1538 if (relax & WCSHDR_reject) { 1539 // Looks too much like a FITS WCS keyword not to flag it. 1540 errmsg = errtxt; 1541 sprintf(errmsg, "keyword looks very much like %s but isn't", 1542 keyname); 1543 BEGIN(ERROR); 1544 1545 } else { 1546 // Let it go. 1547 BEGIN(DISCARD); 1548 } 1549 } 1550 1551 <CCi_ja>{I1}_{I1}{ALT}" " | 1552 <CCi_ja>{I1}_{I2}{ALT}" " | 1553 <CCi_ja>{I2}_{I1}{ALT}" " | 1554 <CCi_ja>{I2}_{I2}{ALT} { 1555 sscanf(yytext, "%d_%d%c", &i, &j, &a); 1556 BEGIN(VALUE); 1557 } 1558 1559 1560 <CCi_ja>0{I1}_{I1}{ALT}" " | 1561 <CCi_ja>{I1}_0{I1}{ALT}" " | 1562 <CCi_ja>00{I1}_{I1}{ALT} | 1563 <CCi_ja>0{I1}_0{I1}{ALT} | 1564 <CCi_ja>{I1}_00{I1}{ALT} | 1565 <CCi_ja>000{I1}_{I1} | 1566 <CCi_ja>00{I1}_0{I1} | 1567 <CCi_ja>0{I1}_00{I1} | 1568 <CCi_ja>{I1}_000{I1} | 1569 <CCi_ja>0{I1}_{I2}{ALT} | 1570 <CCi_ja>{I1}_0{I2}{ALT} | 1571 <CCi_ja>00{I1}_{I2} | 1572 <CCi_ja>0{I1}_0{I2} | 1573 <CCi_ja>{I1}_00{I2} | 1574 <CCi_ja>0{I2}_{I1}{ALT} | 1575 <CCi_ja>{I2}_0{I1}{ALT} | 1576 <CCi_ja>00{I2}_{I1} | 1577 <CCi_ja>0{I2}_0{I1} | 1578 <CCi_ja>{I2}_00{I1} | 1579 <CCi_ja>0{I2}_{I2} | 1580 <CCi_ja>{I2}_0{I2} { 1581 if (((altlin == 1) && (relax & WCSHDR_PC0i_0ja)) || 1582 ((altlin == 2) && (relax & WCSHDR_CD0i_0ja))) { 1583 sscanf(yytext, "%d_%d%c", &i, &j, &a); 1584 BEGIN(VALUE); 1585 1586 } else if (relax & WCSHDR_reject) { 1587 errmsg = "indices in parameterized keywords must not have " 1588 "leading zeroes"; 1589 BEGIN(ERROR); 1590 1591 } else { 1592 // Pretend we don't recognize it. 1593 BEGIN(DISCARD); 1594 } 1595 } 1596 1597 <CCi_ja>{Z1}_{Z1}{ALT}" " | 1598 <CCi_ja>{Z2}_{Z1}{ALT}" " | 1599 <CCi_ja>{Z1}_{Z2}{ALT}" " | 1600 <CCi_ja>{Z3}_{Z1}{ALT} | 1601 <CCi_ja>{Z2}_{Z2}{ALT} | 1602 <CCi_ja>{Z1}_{Z3}{ALT} | 1603 <CCi_ja>{Z4}_{Z1} | 1604 <CCi_ja>{Z3}_{Z2} | 1605 <CCi_ja>{Z2}_{Z3} | 1606 <CCi_ja>{Z1}_{Z4} { 1607 // Anything that has fallen through to this point must contain 1608 // an invalid axis number. 1609 errmsg = "axis number must exceed 0"; 1610 BEGIN(ERROR); 1611 } 1612 1613 <CCi_ja>{Z1}-{Z1}{ALT}" " | 1614 <CCi_ja>{Z2}-{Z1}{ALT}" " | 1615 <CCi_ja>{Z1}-{Z2}{ALT}" " | 1616 <CCi_ja>{Z3}-{Z1}{ALT} | 1617 <CCi_ja>{Z2}-{Z2}{ALT} | 1618 <CCi_ja>{Z1}-{Z3}{ALT} | 1619 <CCi_ja>{Z4}-{Z1} | 1620 <CCi_ja>{Z3}-{Z2} | 1621 <CCi_ja>{Z2}-{Z3} | 1622 <CCi_ja>{Z1}-{Z4} { 1623 errmsg = errtxt; 1624 sprintf(errmsg, "%s keyword must use an underscore, not a dash", 1625 keyname); 1626 BEGIN(ERROR); 1627 } 1628 1629 <CCi_ja>{Z2}{I1}{Z2}{I1} { 1630 // This covers the defunct forms CD00i00j and PC00i00j. 1631 if (((altlin == 1) && (relax & WCSHDR_PC00i00j)) || 1632 ((altlin == 2) && (relax & WCSHDR_CD00i00j))) { 1633 sscanf(yytext, "%3d%3d", &i, &j); 1634 a = ' '; 1635 BEGIN(VALUE); 1636 1637 } else if (relax & WCSHDR_reject) { 1638 errmsg = errtxt; 1639 sprintf(errmsg, 1640 "this form of the %s keyword is deprecated, use %s", 1641 keyname, keyname); 1642 BEGIN(ERROR); 1643 1644 } else { 1645 // Pretend we don't recognize it. 1646 BEGIN(DISCARD); 1647 } 1648 } 1649 1650 <CCi_ja>. { 1651 BEGIN(DISCARD); 1652 } 1653 1654 <CCCCCCCa>{ALT} | 1655 <CCCCCCCC>. { 1656 if (YY_START == CCCCCCCa) { 1657 sscanf(yytext, "%c", &a); 1658 } else { 1659 unput(yytext[0]); 1660 a = 0; 1661 } 1662 1663 BEGIN(VALUE); 1664 } 1665 1666 <CCCCCCCa>. { 1667 if (relax & WCSHDR_reject) { 1668 // Looks too much like a FITS WCS keyword not to flag it. 1669 errmsg = errtxt; 1670 sprintf(errmsg, "invalid alternate code, keyword resembles %s " 1671 "but isn't", keyname); 1672 BEGIN(ERROR); 1673 1674 } else { 1675 // Pretend we don't recognize it. 1676 BEGIN(DISCARD); 1677 } 1678 } 1679 1680 <CCi_ma>{I1}_{Z1}{ALT}" " | 1681 <CCi_ma>{I1}_{I2}{ALT}" " | 1682 <CCi_ma>{I2}_{Z1}{ALT}" " | 1683 <CCi_ma>{I2}_{I2}{ALT} { 1684 sscanf(yytext, "%d_%d%c", &i, &m, &a); 1685 BEGIN(VALUE); 1686 } 1687 1688 <CCi_ma>0{I1}_{Z1}{ALT}" " | 1689 <CCi_ma>{I1}_0{Z1}{ALT}" " | 1690 <CCi_ma>00{I1}_{Z1}{ALT} | 1691 <CCi_ma>0{I1}_0{Z1}{ALT} | 1692 <CCi_ma>{I1}_00{Z1}{ALT} | 1693 <CCi_ma>000{I1}_{Z1} | 1694 <CCi_ma>00{I1}_0{Z1} | 1695 <CCi_ma>0{I1}_00{Z1} | 1696 <CCi_ma>{I1}_000{Z1} | 1697 <CCi_ma>0{I1}_{I2}{ALT} | 1698 <CCi_ma>{I1}_0{I2}{ALT} | 1699 <CCi_ma>00{I1}_{I2} | 1700 <CCi_ma>0{I1}_0{I2} | 1701 <CCi_ma>{I1}_00{I2} | 1702 <CCi_ma>0{I2}_{Z1}{ALT} | 1703 <CCi_ma>{I2}_0{Z1}{ALT} | 1704 <CCi_ma>00{I2}_{Z1} | 1705 <CCi_ma>0{I2}_0{Z1} | 1706 <CCi_ma>{I2}_00{Z1} | 1707 <CCi_ma>0{I2}_{I2} | 1708 <CCi_ma>{I2}_0{I2} { 1709 if (((valtype == FLOAT) && (relax & WCSHDR_PV0i_0ma)) || 1710 ((valtype == STRING) && (relax & WCSHDR_PS0i_0ma))) { 1711 sscanf(yytext, "%d_%d%c", &i, &m, &a); 1712 BEGIN(VALUE); 1713 1714 } else if (relax & WCSHDR_reject) { 1715 errmsg = "indices in parameterized keywords must not have " 1716 "leading zeroes"; 1717 BEGIN(ERROR); 1718 1719 } else { 1720 // Pretend we don't recognize it. 1721 BEGIN(DISCARD); 1722 } 1723 } 1724 1725 <CCi_ma>{Z1}_{Z1}{ALT}" " | 1726 <CCi_ma>{Z2}_{Z1}{ALT}" " | 1727 <CCi_ma>{Z1}_{Z2}{ALT}" " | 1728 <CCi_ma>{Z3}_{Z1}{ALT} | 1729 <CCi_ma>{Z2}_{Z2}{ALT} | 1730 <CCi_ma>{Z1}_{Z3}{ALT} | 1731 <CCi_ma>{Z4}_{Z1} | 1732 <CCi_ma>{Z3}_{Z2} | 1733 <CCi_ma>{Z2}_{Z3} | 1734 <CCi_ma>{Z1}_{Z4} { 1735 // Anything that has fallen through to this point must contain 1736 // an invalid axis number. 1737 errmsg = "axis number must exceed 0"; 1738 BEGIN(ERROR); 1739 } 1740 1741 <CCi_ma>{Z1}-{Z1}{ALT}" " | 1742 <CCi_ma>{Z2}-{Z1}{ALT}" " | 1743 <CCi_ma>{Z1}-{Z2}{ALT}" " | 1744 <CCi_ma>{Z3}-{Z1}{ALT} | 1745 <CCi_ma>{Z2}-{Z2}{ALT} | 1746 <CCi_ma>{Z1}-{Z3}{ALT} | 1747 <CCi_ma>{Z4}-{Z1} | 1748 <CCi_ma>{Z3}-{Z2} | 1749 <CCi_ma>{Z2}-{Z3} | 1750 <CCi_ma>{Z1}-{Z4} { 1751 errmsg = errtxt; 1752 sprintf(errmsg, "%s keyword must use an underscore, not a dash", 1753 keyname); 1754 BEGIN(ERROR); 1755 } 1756 1757 <CCi_ma>. { 1758 BEGIN(DISCARD); 1759 } 1760 1761 <CROTAi>{Z1}{ALT}" " | 1762 <CROTAi>{Z2}{ALT} | 1763 <CROTAi>{Z3} { 1764 a = ' '; 1765 sscanf(yytext, "%d%c", &i, &a); 1766 1767 if (relax & WCSHDR_strict) { 1768 errmsg = "the CROTAn keyword is deprecated, use PCi_ja"; 1769 BEGIN(ERROR); 1770 1771 } else if ((a == ' ') || (relax & WCSHDR_CROTAia)) { 1772 yyless(0); 1773 BEGIN(CCCCCia); 1774 1775 } else if (relax & WCSHDR_reject) { 1776 errmsg = "CROTAn keyword may not have an alternate version code"; 1777 BEGIN(ERROR); 1778 1779 } else { 1780 // Pretend we don't recognize it. 1781 BEGIN(DISCARD); 1782 } 1783 } 1784 1785 <CROTAi>. { 1786 yyless(0); 1787 BEGIN(CCCCCia); 1788 } 1789 1790 <PROJPn>{Z1}" " { 1791 if (relax & WCSHDR_PROJPn) { 1792 sscanf(yytext, "%d", &m); 1793 i = 0; 1794 a = ' '; 1795 BEGIN(VALUE); 1796 1797 } else if (relax & WCSHDR_reject) { 1798 errmsg = "the PROJPn keyword is deprecated, use PVi_ma"; 1799 BEGIN(ERROR); 1800 1801 } else { 1802 BEGIN(DISCARD); 1803 } 1804 } 1805 1806 <PROJPn>{Z2}" " | 1807 <PROJPn>{Z3} { 1808 if (relax & (WCSHDR_PROJPn | WCSHDR_reject)) { 1809 errmsg = "invalid PROJPn keyword"; 1810 BEGIN(ERROR); 1811 1812 } else { 1813 BEGIN(DISCARD); 1814 } 1815 } 1816 1817 <PROJPn>. { 1818 BEGIN(DISCARD); 1819 } 1820 1821 <SIP2>{Z1}_{Z1}" " | 1822 <SIP3>{Z1}_{Z1}" " { 1823 // SIP keywords. 1824 valtype = FLOAT; 1825 distype = PRIOR; 1826 vptr = &(distem.dp); 1827 npptr = ndp; 1828 1829 a = ' '; 1830 distran = SIP; 1831 1832 sscanf(yytext, "%d_%d", &p, &q); 1833 BEGIN(VALUE); 1834 } 1835 1836 <SIP2>. | 1837 <SIP3>. { 1838 BEGIN(DISCARD); 1839 } 1840 1841 <DSSAMDXY>{I1}" " | 1842 <DSSAMDXY>{I2}" " { 1843 // DSS keywords. 1844 valtype = FLOAT; 1845 distype = SEQUENT; 1846 vptr = &(distem.dp); 1847 npptr = ndq; 1848 1849 a = ' '; 1850 distran = DSS; 1851 1852 sscanf(yytext, "%d", &m); 1853 BEGIN(VALUE); 1854 } 1855 1856 <DSSAMDXY>. { 1857 BEGIN(DISCARD); 1858 } 1859 1860 <PLTDECSN>=" "+{STRING} { 1861 // Special handling for this iconic DSS keyword. 1862 if (1 < ipass) { 1863 // Look for a minus sign. 1864 sscanf(yytext, "= '%s", strtmp); 1865 dbltmp = strcmp(strtmp, "-") ? 1.0 : -1.0; 1866 } 1867 1868 BEGIN(COMMENT); 1869 } 1870 1871 <PLTDECSN>. { 1872 BEGIN(DISCARD); 1873 } 1874 1875 <VALUE>=" "+ { 1876 // Do checks on i, j & m. 1877 if (99 < i || 99 < j || 99 < m) { 1878 if (relax & WCSHDR_reject) { 1879 if (99 < i || 99 < j) { 1880 errmsg = "axis number exceeds 99"; 1881 } else if (m > 99) { 1882 errmsg = "parameter number exceeds 99"; 1883 } 1884 BEGIN(ERROR); 1885 1886 } else { 1887 // Pretend we don't recognize it. 1888 BEGIN(DISCARD); 1889 } 1890 1891 } else { 1892 if (valtype == INTEGER) { 1893 BEGIN(INTEGER_VAL); 1894 } else if (valtype == FLOAT) { 1895 BEGIN(FLOAT_VAL); 1896 } else if (valtype == FLOAT2) { 1897 BEGIN(FLOAT2_VAL); 1898 } else if (valtype == STRING) { 1899 BEGIN(STRING_VAL); 1900 } else if (valtype == RECORD) { 1901 BEGIN(RECORD_VAL); 1902 } else { 1903 errmsg = errtxt; 1904 sprintf(errmsg, "internal parser ERROR, bad data type: %d", 1905 valtype); 1906 BEGIN(ERROR); 1907 } 1908 } 1909 } 1910 1911 <VALUE>. { 1912 errmsg = "invalid KEYWORD = VALUE syntax"; 1913 BEGIN(ERROR); 1914 } 1915 1916 <INTEGER_VAL>{INTEGER} { 1917 if (ipass == 1) { 1918 BEGIN(COMMENT); 1919 1920 } else { 1921 // Read the keyvalue. 1922 sscanf(yytext, "%d", &inttmp); 1923 1924 BEGIN(COMMENT); 1925 } 1926 } 1927 1928 <INTEGER_VAL>. { 1929 errmsg = "an integer value was expected"; 1930 BEGIN(ERROR); 1931 } 1932 1933 <FLOAT_VAL>{FLOAT} { 1934 if (ipass == 1) { 1935 BEGIN(COMMENT); 1936 1937 } else { 1938 // Read the keyvalue. 1939 wcsutil_str2double(yytext, &dbltmp); 1940 1941 if (chekval && chekval(dbltmp)) { 1942 errmsg = "invalid keyvalue"; 1943 BEGIN(ERROR); 1944 } else { 1945 BEGIN(COMMENT); 1946 } 1947 } 1948 } 1949 1950 <FLOAT_VAL>. { 1951 errmsg = "a floating-point value was expected"; 1952 BEGIN(ERROR); 1953 } 1954 1955 <FLOAT2_VAL>{FLOAT} { 1956 if (ipass == 1) { 1957 BEGIN(COMMENT); 1958 1959 } else { 1960 // Read the keyvalue as integer and fractional parts. 1961 wcsutil_str2double2(yytext, dbl2tmp); 1962 1963 BEGIN(COMMENT); 1964 } 1965 } 1966 1967 <FLOAT2_VAL>. { 1968 errmsg = "a floating-point value was expected"; 1969 BEGIN(ERROR); 1970 } 1971 1972 <STRING_VAL>{STRING} { 1973 if (ipass == 1) { 1974 BEGIN(COMMENT); 1975 1976 } else { 1977 // Read the keyvalue. 1978 strcpy(strtmp, yytext+1); 1979 1980 // Squeeze out repeated quotes. 1981 int ix = 0; 1982 for (int jx = 0; jx < 72; jx++) { 1983 if (ix < jx) { 1984 strtmp[ix] = strtmp[jx]; 1985 } 1986 1987 if (strtmp[jx] == '\0') { 1988 if (ix) strtmp[ix-1] = '\0'; 1989 break; 1990 } else if (strtmp[jx] == '\'' && strtmp[jx+1] == '\'') { 1991 jx++; 1992 } 1993 1994 ix++; 1995 } 1996 1997 BEGIN(COMMENT); 1998 } 1999 } 2000 2001 <STRING_VAL>. { 2002 errmsg = "a string value was expected"; 2003 BEGIN(ERROR); 2004 } 2005 2006 <RECORD_VAL>{RECORD} { 2007 if (ipass == 1) { 2008 BEGIN(COMMENT); 2009 2010 } else { 2011 yyless(1); 2012 2013 BEGIN(RECFIELD); 2014 } 2015 } 2016 2017 <RECORD_VAL>. { 2018 errmsg = "a record was expected"; 2019 BEGIN(ERROR); 2020 } 2021 2022 <RECFIELD>{FIELD} { 2023 strcpy(strtmp, yytext); 2024 BEGIN(RECCOLON); 2025 } 2026 2027 <RECFIELD>. { 2028 errmsg = "invalid record field"; 2029 BEGIN(ERROR); 2030 } 2031 2032 <RECCOLON>:" "+ { 2033 BEGIN(RECVALUE); 2034 } 2035 2036 <RECCOLON>. { 2037 errmsg = "invalid record syntax"; 2038 BEGIN(ERROR); 2039 } 2040 2041 <RECVALUE>{INTEGER} { 2042 rectype = 0; 2043 sscanf(yytext, "%d", &inttmp); 2044 BEGIN(RECEND); 2045 } 2046 2047 <RECVALUE>{FLOAT} { 2048 rectype = 1; 2049 wcsutil_str2double(yytext, &dbltmp); 2050 BEGIN(RECEND); 2051 } 2052 2053 <RECVALUE>. { 2054 errmsg = "invalid record value"; 2055 BEGIN(ERROR); 2056 } 2057 2058 <RECEND>' { 2059 BEGIN(COMMENT); 2060 } 2061 2062 <COMMENT>{INLINE}$ { 2063 if (ipass == 1) { 2064 // Do first-pass bookkeeping. 2065 wcspih_pass1(naxis, i, j, a, distype, alts, dpq, npptr); 2066 BEGIN(FLUSH); 2067 2068 } else if (*wcs) { 2069 // Store the value now that the keyrecord has been validated. 2070 int gotone = 0; 2071 for (int ialt = 0; ialt < *nwcs; ialt++) { 2072 // The loop here is for keywords that apply 2073 // to every alternate; these have a == 0. 2074 if (a >= 'A') { 2075 ialt = alts[a-'A'+1]; 2076 if (ialt < 0) break; 2077 } 2078 gotone = 1; 2079 2080 if (vptr) { 2081 if (sipflag) { 2082 // Translate a SIP keyword into DPja. 2083 struct disprm *disp = (*wcs)->lin.dispre; 2084 int ipx = (disp->ndp)++; 2085 2086 // SIP doesn't have alternates. 2087 char keyword[16]; 2088 sprintf(keyword, "DP%d", i); 2089 sprintf(strtmp, "SIP.%s.%d_%d", (sipflag==2)?"FWD":"REV", 2090 p, q); 2091 if (valtype == INTEGER) { 2092 dpfill(disp->dp+ipx, keyword, strtmp, i, 0, inttmp, 0.0); 2093 } else { 2094 dpfill(disp->dp+ipx, keyword, strtmp, i, 1, 0, dbltmp); 2095 } 2096 2097 } else if (dssflag) { 2098 // All DSS keywords require special handling. 2099 if (dssflag == 1) { 2100 // Temporary parameter for DSS used by wcspih_final(). 2101 *((double *)vptr) = dbltmp; 2102 2103 } else if (dssflag == 2) { 2104 // Temporary parameter for DSS used by wcspih_final(). 2105 strcpy((char *)vptr, strtmp); 2106 2107 } else { 2108 // Translate a DSS keyword into DQia. 2109 if (m <= 13 || dbltmp != 0.0) { 2110 struct disprm *disp = (*wcs)->lin.disseq; 2111 int ipx = (disp->ndp)++; 2112 2113 // DSS doesn't have alternates. 2114 char keyword[16]; 2115 sprintf(keyword, "DQ%d", i); 2116 sprintf(strtmp, "DSS.AMD.%d", m); 2117 dpfill(disp->dp+ipx, keyword, strtmp, i, 1, 0, dbltmp); 2118 2119 // Also required by wcspih_final(). 2120 if (m <= 3) { 2121 dsstmp[13+(i-1)*3+m] = dbltmp; 2122 } 2123 } 2124 } 2125 2126 } else if (watflag) { 2127 // String array for TNX and ZPX used by wcspih_final(). 2128 strcpy((char *)vptr, strtmp); 2129 2130 } else { 2131 // An "ordinary" keyword. 2132 struct wcsprm *wcsp = *wcs + ialt; 2133 struct disprm *disp; 2134 void *wptr; 2135 ptrdiff_t voff; 2136 if (auxprm) { 2137 // Additional auxiliary parameter. 2138 struct auxprm *auxp = wcsp->aux; 2139 voff = (char *)vptr - (char *)(&auxtem); 2140 wptr = (void *)((char *)auxp + voff); 2141 2142 } else if (distype) { 2143 // Distortion parameter of some kind. 2144 if (distype == PRIOR) { 2145 // Prior distortion. 2146 disp = wcsp->lin.dispre; 2147 } else { 2148 // Sequent distortion. 2149 disp = wcsp->lin.disseq; 2150 } 2151 voff = (char *)vptr - (char *)(&distem); 2152 wptr = (void *)((char *)disp + voff); 2153 2154 } else { 2155 // A parameter that lives directly in wcsprm. 2156 voff = (char *)vptr - (char *)(&wcstem); 2157 wptr = (void *)((char *)wcsp + voff); 2158 } 2159 2160 if (valtype == INTEGER) { 2161 *((int *)wptr) = inttmp; 2162 2163 } else if (valtype == FLOAT) { 2164 // Apply keyword parameterization. 2165 if (npptr == npv) { 2166 int ipx = (wcsp->npv)++; 2167 wcsp->pv[ipx].i = i; 2168 wcsp->pv[ipx].m = m; 2169 wptr = &(wcsp->pv[ipx].value); 2170 2171 } else if (j) { 2172 wptr = *((double **)wptr) + (i - 1)*(wcsp->naxis) 2173 + (j - 1); 2174 2175 } else if (i) { 2176 wptr = *((double **)wptr) + (i - 1); 2177 } 2178 2179 if (special) { 2180 special(wptr, &dbltmp); 2181 } else { 2182 *((double *)wptr) = dbltmp; 2183 } 2184 2185 // Flag presence of PCi_ja, or CDi_ja and/or CROTAia. 2186 if (altlin) { 2187 wcsp->altlin |= altlin; 2188 altlin = 0; 2189 } 2190 2191 } else if (valtype == FLOAT2) { 2192 // Split MJDREF and JDREF into integer and fraction. 2193 if (special) { 2194 special(wptr, dbl2tmp); 2195 } else { 2196 *((double *)wptr) = dbl2tmp[0]; 2197 *((double *)wptr + 1) = dbl2tmp[1]; 2198 } 2199 2200 } else if (valtype == STRING) { 2201 // Apply keyword parameterization. 2202 if (npptr == nps) { 2203 int ipx = (wcsp->nps)++; 2204 wcsp->ps[ipx].i = i; 2205 wcsp->ps[ipx].m = m; 2206 wptr = wcsp->ps[ipx].value; 2207 2208 } else if (j) { 2209 wptr = *((char (**)[72])wptr) + 2210 (i - 1)*(wcsp->naxis) + (j - 1); 2211 2212 } else if (i) { 2213 wptr = *((char (**)[72])wptr) + (i - 1); 2214 } 2215 2216 char *cptr = (char *)wptr; 2217 strcpy(cptr, strtmp); 2218 2219 } else if (valtype == RECORD) { 2220 int ipx = (disp->ndp)++; 2221 2222 char keyword[16]; 2223 if (a == ' ') { 2224 sprintf(keyword, "%.2s%d", keyname, i); 2225 } else { 2226 sprintf(keyword, "%.2s%d%c", keyname, i, a); 2227 } 2228 2229 dpfill(disp->dp+ipx, keyword, strtmp, i, rectype, inttmp, 2230 dbltmp); 2231 } 2232 } 2233 } 2234 2235 if (a) break; 2236 } 2237 2238 if (gotone) { 2239 nvalid++; 2240 if (ctrl == 4) { 2241 if (distran || dssflag) { 2242 wcsfprintf(stderr, "%.80s\n Accepted (%d) as a " 2243 "recognized WCS convention.\n", keyrec, nvalid); 2244 } else { 2245 wcsfprintf(stderr, "%.80s\n Accepted (%d) as a " 2246 "valid WCS keyrecord.\n", keyrec, nvalid); 2247 } 2248 } 2249 2250 BEGIN(FLUSH); 2251 2252 } else { 2253 errmsg = "syntactically valid WCS keyrecord has no effect"; 2254 BEGIN(ERROR); 2255 } 2256 2257 } else { 2258 BEGIN(FLUSH); 2259 } 2260 } 2261 2262 <COMMENT>.*" "*\/.*$ { 2263 errmsg = "invalid keyvalue"; 2264 BEGIN(ERROR); 2265 } 2266 2267 <COMMENT>[^ \/\n]*{INLINE}$ { 2268 errmsg = "invalid keyvalue"; 2269 BEGIN(ERROR); 2270 } 2271 2272 <COMMENT>" "+[^\/\n].*{INLINE}$ { 2273 errmsg = "invalid keyvalue or malformed keycomment"; 2274 BEGIN(ERROR); 2275 } 2276 2277 <COMMENT>.*$ { 2278 errmsg = "malformed keycomment"; 2279 BEGIN(ERROR); 2280 } 2281 2282 <DISCARD>.*$ { 2283 if (ipass == npass) { 2284 if (ctrl < 0) { 2285 // Preserve discards. 2286 keep = keyrec; 2287 2288 } else if (2 < ctrl) { 2289 nother++; 2290 wcsfprintf(stderr, "%.80s\n Not a recognized WCS keyword.\n", 2291 keyrec); 2292 } 2293 } 2294 BEGIN(FLUSH); 2295 } 2296 2297 <ERROR>.*$ { 2298 if (ipass == npass) { 2299 (*nreject)++; 2300 2301 if (ctrl%10 == -1) { 2302 // Preserve rejects. 2303 keep = keyrec; 2304 } 2305 2306 if (1 < abs(ctrl%10)) { 2307 wcsfprintf(stderr, "%.80s\n Rejected (%d), %s.\n", 2308 keyrec, *nreject, errmsg); 2309 } 2310 } 2311 BEGIN(FLUSH); 2312 } 2313 2314 <FLUSH>.*\n { 2315 if (ipass == npass && keep) { 2316 if (hptr < keep) { 2317 strncpy(hptr, keep, 80); 2318 } 2319 hptr += 80; 2320 } 2321 2322 naux += auxprm; 2323 2324 // Throw away the rest of the line and reset for the next one. 2325 i = j = 0; 2326 m = 0; 2327 a = ' '; 2328 2329 keyrec += 80; 2330 2331 valtype = -1; 2332 distype = 0; 2333 vptr = 0x0; 2334 keep = 0x0; 2335 2336 altlin = 0; 2337 npptr = 0x0; 2338 chekval = 0x0; 2339 special = 0x0; 2340 auxprm = 0; 2341 sipflag = 0; 2342 dssflag = 0; 2343 watflag = 0; 2344 2345 BEGIN(INITIAL); 2346 } 2347 2348 <<EOF>> { 2349 // End-of-input. 2350 int status; 2351 if (ipass == 1) { 2352 if ((status = wcspih_init1(naxis, alts, dpq, npv, nps, ndp, ndq, 2353 naux, distran, nwcs, wcs)) || 2354 (*nwcs == 0 && ctrl == 0)) { 2355 return status; 2356 } 2357 2358 if (2 < abs(ctrl%10)) { 2359 if (*nwcs == 1) { 2360 if (strcmp(wcs[0]->wcsname, "DEFAULTS") != 0) { 2361 wcsfprintf(stderr, "Found one coordinate representation.\n"); 2362 } 2363 } else { 2364 wcsfprintf(stderr, "Found %d coordinate representations.\n", 2365 *nwcs); 2366 } 2367 } 2368 2369 watstr = calloc(2*(watn*68 + 1), sizeof(char)); 2370 wat[0] = watstr; 2371 wat[1] = watstr + watn*68 + 1; 2372 } 2373 2374 if (ipass++ < npass) { 2375 yyextra->hdr = header; 2376 yyextra->nkeyrec = nkeyrec; 2377 keyrec = header; 2378 *nreject = 0; 2379 2380 i = j = 0; 2381 m = 0; 2382 a = ' '; 2383 2384 valtype = -1; 2385 distype = 0; 2386 vptr = 0x0; 2387 2388 altlin = 0; 2389 npptr = 0x0; 2390 chekval = 0x0; 2391 special = 0x0; 2392 auxprm = 0; 2393 sipflag = 0; 2394 dssflag = 0; 2395 watflag = 0; 2396 2397 yyrestart(yyin, yyscanner); 2398 2399 } else { 2400 2401 if (ctrl < 0) { 2402 *hptr = '\0'; 2403 } else if (ctrl == 1) { 2404 wcsfprintf(stderr, "%d WCS keyrecord%s rejected.\n", 2405 *nreject, (*nreject==1)?" was":"s were"); 2406 } else if (ctrl == 4) { 2407 wcsfprintf(stderr, "\n"); 2408 wcsfprintf(stderr, "%5d keyrecord%s rejected for syntax or " 2409 "other errors,\n", *nreject, (*nreject==1)?" was":"s were"); 2410 wcsfprintf(stderr, "%5d %s recognized as syntactically valid, " 2411 "and\n", nvalid, (nvalid==1)?"was":"were"); 2412 wcsfprintf(stderr, "%5d other%s were not recognized as WCS " 2413 "keyrecords.\n", nother, (nother==1)?"":"s"); 2414 } 2415 2416 status = wcspih_final(ndp, ndq, distran, dsstmp, wat, nwcs, wcs); 2417 free(watstr); 2418 return status; 2419 } 2420 } 2421 2422 %% 2423 2424 /*---------------------------------------------------------------------------- 2425 * External interface to the scanner. 2426 *---------------------------------------------------------------------------*/ 2427 2428 int wcspih( 2429 char *header, 2430 int nkeyrec, 2431 int relax, 2432 int ctrl, 2433 int *nreject, 2434 int *nwcs, 2435 struct wcsprm **wcs) 2436 2437 { 2438 // Function prototypes. 2439 int yylex_init_extra(YY_EXTRA_TYPE extra, yyscan_t *yyscanner); 2440 int yylex_destroy(yyscan_t yyscanner); 2441 2442 struct wcspih_extra extra; 2443 yyscan_t yyscanner; 2444 yylex_init_extra(&extra, &yyscanner); 2445 int status = wcspih_scanner(header, nkeyrec, relax, ctrl, nreject, nwcs, 2446 wcs, yyscanner); 2447 yylex_destroy(yyscanner); 2448 2449 return status; 2450 } 2451 2452 2453 /*---------------------------------------------------------------------------- 2454 * Determine the number of coordinate representations (up to 27) and the 2455 * number of coordinate axes in each, which distortions are present, and the 2456 * number of PVi_ma, PSi_ma, DPja, and DQia keywords in each representation. 2457 *---------------------------------------------------------------------------*/ 2458 2459 void wcspih_pass1( 2460 int naxis, 2461 int i, 2462 int j, 2463 char a, 2464 int distype, 2465 int alts[], 2466 int dpq[], 2467 int *npptr) 2468 2469 { 2470 // On the first pass alts[] is used to determine the number of axes 2471 // for each of the 27 possible alternate coordinate descriptions. 2472 if (a == 0) { 2473 return; 2474 } 2475 2476 int ialt = 0; 2477 if (a != ' ') { 2478 ialt = a - 'A' + 1; 2479 } 2480 2481 int *ip = alts + ialt; 2482 2483 if (*ip < naxis) { 2484 *ip = naxis; 2485 } 2486 2487 // i or j can be greater than naxis. 2488 if (*ip < i) { 2489 *ip = i; 2490 } 2491 2492 if (*ip < j) { 2493 *ip = j; 2494 } 2495 2496 // Type of distortions present. 2497 dpq[ialt] |= distype; 2498 2499 // Count PVi_ma, PSi_ma, DPja, or DQia keywords. 2500 if (npptr) { 2501 npptr[ialt]++; 2502 } 2503 } 2504 2505 2506 /*---------------------------------------------------------------------------- 2507 * Allocate memory for an array of the required number of wcsprm structs and 2508 * initialize each of them. 2509 *---------------------------------------------------------------------------*/ 2510 2511 int wcspih_init1( 2512 int naxis, 2513 int alts[], 2514 int dpq[], 2515 int npv[], 2516 int nps[], 2517 int ndp[], 2518 int ndq[], 2519 int naux, 2520 int distran, 2521 int *nwcs, 2522 struct wcsprm **wcs) 2523 2524 { 2525 int status = 0; 2526 2527 // Find the number of coordinate descriptions. 2528 *nwcs = 0; 2529 for (int ialt = 0; ialt < 27; ialt++) { 2530 if (alts[ialt]) (*nwcs)++; 2531 } 2532 2533 int defaults; 2534 if ((defaults = !(*nwcs) && naxis)) { 2535 // NAXIS is non-zero but there were no WCS keywords with an alternate 2536 // version code; create a default WCS with blank alternate version. 2537 wcspih_pass1(naxis, 0, 0, ' ', 0, alts, dpq, 0x0); 2538 *nwcs = 1; 2539 } 2540 2541 if (*nwcs) { 2542 // Allocate memory for the required number of wcsprm structs. 2543 if ((*wcs = calloc(*nwcs, sizeof(struct wcsprm))) == 0x0) { 2544 return WCSHDRERR_MEMORY; 2545 } 2546 2547 int ndis = 0; 2548 if (distran == SIP) { 2549 // DPja.NAXES and DPja.OFFSET.j to be added for SIP (see below and 2550 // wcspih_final()). 2551 ndp[0] += 6; 2552 2553 } else if (distran == DSS) { 2554 // DPja.NAXES to be added for DSS (see below and wcspih_final()). 2555 ndq[0] += 2; 2556 } 2557 2558 // Initialize each wcsprm struct. 2559 struct wcsprm *wcsp = *wcs; 2560 *nwcs = 0; 2561 for (int ialt = 0; ialt < 27; ialt++) { 2562 if (alts[ialt]) { 2563 wcsp->flag = -1; 2564 int npvmax = npv[ialt]; 2565 int npsmax = nps[ialt]; 2566 if ((status = wcsinit(1, alts[ialt], wcsp, npvmax, npsmax, -1))) { 2567 wcsvfree(nwcs, wcs); 2568 break; 2569 } 2570 2571 // Record the alternate version code. 2572 if (ialt) { 2573 wcsp->alt[0] = 'A' + ialt - 1; 2574 } 2575 2576 // Record in wcsname whether this is a default description. 2577 if (defaults) { 2578 strcpy(wcsp->wcsname, "DEFAULTS"); 2579 } 2580 2581 // Any additional auxiliary keywords present? 2582 if (naux) { 2583 if (wcsauxi(1, wcsp)) { 2584 return WCSHDRERR_MEMORY; 2585 } 2586 } 2587 2588 // Any distortions present? 2589 struct disprm *disp; 2590 if (dpq[ialt] & 1) { 2591 if ((disp = calloc(1, sizeof(struct disprm))) == 0x0) { 2592 return WCSHDRERR_MEMORY; 2593 } 2594 2595 // Attach it to linprm. Also inits it. 2596 ndis++; 2597 int ndpmax = ndp[ialt]; 2598 disp->flag = -1; 2599 lindist(1, &(wcsp->lin), disp, ndpmax); 2600 } 2601 2602 if (dpq[ialt] & 2) { 2603 if ((disp = calloc(1, sizeof(struct disprm))) == 0x0) { 2604 return WCSHDRERR_MEMORY; 2605 } 2606 2607 // Attach it to linprm. Also inits it. 2608 ndis++; 2609 int ndpmax = ndq[ialt]; 2610 disp->flag = -1; 2611 lindist(2, &(wcsp->lin), disp, ndpmax); 2612 } 2613 2614 // On the second pass alts[] indexes the array of wcsprm structs. 2615 alts[ialt] = (*nwcs)++; 2616 2617 wcsp++; 2618 2619 } else { 2620 // Signal that there is no wcsprm for this alt. 2621 alts[ialt] = -1; 2622 } 2623 } 2624 2625 2626 // Translated distortion? Neither SIP nor DSS have alternates, so the 2627 // presence of keywords for either (not both together), as flagged by 2628 // distran, necessarily refers to the primary representation. 2629 if (distran == SIP) { 2630 strcpy((*wcs)->lin.dispre->dtype[0], "SIP"); 2631 strcpy((*wcs)->lin.dispre->dtype[1], "SIP"); 2632 2633 // SIP doesn't have axis mapping. 2634 (*wcs)->lin.dispre->ndp = 6; 2635 dpfill((*wcs)->lin.dispre->dp, "DP1", "NAXES", 0, 0, 2, 0.0); 2636 dpfill((*wcs)->lin.dispre->dp+3, "DP2", "NAXES", 0, 0, 2, 0.0); 2637 2638 } else if (distran == DSS) { 2639 strcpy((*wcs)->lin.disseq->dtype[0], "DSS"); 2640 strcpy((*wcs)->lin.disseq->dtype[1], "DSS"); 2641 2642 // The Paper IV translation of DSS doesn't require an axis mapping. 2643 (*wcs)->lin.disseq->ndp = 2; 2644 dpfill((*wcs)->lin.disseq->dp, "DQ1", "NAXES", 0, 0, 2, 0.0); 2645 dpfill((*wcs)->lin.disseq->dp+1, "DQ2", "NAXES", 0, 0, 2, 0.0); 2646 } 2647 } 2648 2649 return status; 2650 } 2651 2652 2653 /*---------------------------------------------------------------------------- 2654 * Interpret the JDREF, JDREFI, and JDREFF keywords. 2655 *---------------------------------------------------------------------------*/ 2656 2657 int wcspih_jdref(double *mjdref, const double *jdref) 2658 2659 { 2660 // Set MJDREF from JDREF. 2661 if (undefined(mjdref[0] && undefined(mjdref[1]))) { 2662 mjdref[0] = jdref[0] - 2400000.0; 2663 mjdref[1] = jdref[1] - 0.5; 2664 2665 if (mjdref[1] < 0.0) { 2666 mjdref[0] -= 1.0; 2667 mjdref[1] += 1.0; 2668 } 2669 } 2670 2671 return 0; 2672 } 2673 2674 int wcspih_jdrefi(double *mjdref, const double *jdrefi) 2675 2676 { 2677 // Set the integer part of MJDREF from JDREFI. 2678 if (undefined(mjdref[0])) { 2679 mjdref[0] = *jdrefi - 2400000.5; 2680 } 2681 2682 return 0; 2683 } 2684 2685 2686 int wcspih_jdreff(double *mjdref, const double *jdreff) 2687 2688 { 2689 // Set the fractional part of MJDREF from JDREFF. 2690 if (undefined(mjdref[1])) { 2691 mjdref[1] = *jdreff; 2692 } 2693 2694 return 0; 2695 } 2696 2697 2698 /*---------------------------------------------------------------------------- 2699 * Interpret EPOCHa keywords. 2700 *---------------------------------------------------------------------------*/ 2701 2702 int wcspih_epoch(double *equinox, const double *epoch) 2703 2704 { 2705 // If EQUINOXa is currently undefined then set it from EPOCHa. 2706 if (undefined(*equinox)) { 2707 *equinox = *epoch; 2708 } 2709 2710 return 0; 2711 } 2712 2713 2714 /*---------------------------------------------------------------------------- 2715 * Interpret VSOURCEa keywords. 2716 *---------------------------------------------------------------------------*/ 2717 2718 int wcspih_vsource(double *zsource, const double *vsource) 2719 2720 { 2721 const double c = 299792458.0; 2722 2723 // If ZSOURCEa is currently undefined then set it from VSOURCEa. 2724 if (undefined(*zsource)) { 2725 // Convert relativistic Doppler velocity to redshift. 2726 double beta = *vsource/c; 2727 *zsource = (1.0 + beta)/sqrt(1.0 - beta*beta) - 1.0; 2728 } 2729 2730 return 0; 2731 } 2732 2733 2734 /*---------------------------------------------------------------------------- 2735 * Check validity of a TIMEPIXR keyvalue. 2736 *---------------------------------------------------------------------------*/ 2737 2738 int wcspih_timepixr(double timepixr) 2739 2740 { 2741 return (timepixr < 0.0 || 1.0 < timepixr); 2742 } 2743 2744 2745 /*---------------------------------------------------------------------------- 2746 * Interpret special keywords encountered for each coordinate representation. 2747 *---------------------------------------------------------------------------*/ 2748 2749 int wcspih_final( 2750 int ndp[], 2751 int ndq[], 2752 int distran, 2753 double dsstmp[], 2754 char *wat[], 2755 int *nwcs, 2756 struct wcsprm **wcs) 2757 2758 { 2759 for (int ialt = 0; ialt < *nwcs; ialt++) { 2760 // Interpret -TAB header keywords. 2761 int status; 2762 if ((status = wcstab(*wcs+ialt))) { 2763 wcsvfree(nwcs, wcs); 2764 return status; 2765 } 2766 2767 if (ndp[ialt] && ndq[ialt]) { 2768 // Prior and sequent distortions co-exist in this representation; 2769 // ensure the latter gets DVERRa. 2770 (*wcs+ialt)->lin.disseq->totdis = (*wcs+ialt)->lin.dispre->totdis; 2771 } 2772 } 2773 2774 // Translated distortion functions; apply only to the primary WCS. 2775 struct wcsprm *wcsp = *wcs; 2776 if (distran == SIP) { 2777 // SIP doesn't have alternates, nor axis mapping. 2778 struct disprm *disp = wcsp->lin.dispre; 2779 dpfill(disp->dp+1, "DP1", "OFFSET.1", 0, 1, 0, wcsp->crpix[0]); 2780 dpfill(disp->dp+2, "DP1", "OFFSET.2", 0, 1, 0, wcsp->crpix[1]); 2781 dpfill(disp->dp+4, "DP2", "OFFSET.1", 0, 1, 0, wcsp->crpix[0]); 2782 dpfill(disp->dp+5, "DP2", "OFFSET.2", 0, 1, 0, wcsp->crpix[1]); 2783 2784 } else if (distran == DSS) { 2785 // DSS doesn't have alternates, nor axis mapping. This translation 2786 // follows Paper IV, Sect. 5.2 using the same variable names. 2787 double CNPIX1 = dsstmp[0]; 2788 double CNPIX2 = dsstmp[1]; 2789 2790 double Xc = dsstmp[2]/1000.0; 2791 double Yc = dsstmp[3]/1000.0; 2792 double Rx = dsstmp[4]/1000.0; 2793 double Ry = dsstmp[5]/1000.0; 2794 2795 double A1 = dsstmp[14]; 2796 double A2 = dsstmp[15]; 2797 double A3 = dsstmp[16]; 2798 double B1 = dsstmp[17]; 2799 double B2 = dsstmp[18]; 2800 double B3 = dsstmp[19]; 2801 double S = sqrt(fabs(A1*B1 - A2*B2)); 2802 2803 double X0 = (A2*B3 - A3*B1) / (A1*B1 - A2*B2); 2804 double Y0 = (A3*B2 - A1*B3) / (A1*B1 - A2*B2); 2805 2806 wcsp->crpix[0] = (Xc - X0)/Rx - (CNPIX1 - 0.5); 2807 wcsp->crpix[1] = (Yc + Y0)/Ry - (CNPIX2 - 0.5); 2808 2809 wcsp->pc[0] = A1*Rx/S; 2810 wcsp->pc[1] = -A2*Ry/S; 2811 wcsp->pc[2] = -B2*Rx/S; 2812 wcsp->pc[3] = B1*Ry/S; 2813 wcsp->altlin = 1; 2814 2815 wcsp->cdelt[0] = -S/3600.0; 2816 wcsp->cdelt[1] = S/3600.0; 2817 2818 double *crval = wcsp->crval; 2819 crval[0] = (dsstmp[6] + (dsstmp[7] + dsstmp[8] /60.0)/60.0)*15.0; 2820 crval[1] = dsstmp[10] + (dsstmp[11] + dsstmp[12]/60.0)/60.0; 2821 if (dsstmp[9] == -1.0) crval[1] *= -1.0; 2822 2823 strcpy(wcsp->ctype[0], "RA---TAN"); 2824 strcpy(wcsp->ctype[1], "DEC--TAN"); 2825 2826 sprintf(wcsp->wcsname, "DSS PLATEID %.4s", (char *)(dsstmp+13)); 2827 2828 // Erase the approximate WCS provided in modern DSS headers. 2829 wcsp->cd[0] = 0.0; 2830 wcsp->cd[1] = 0.0; 2831 wcsp->cd[2] = 0.0; 2832 wcsp->cd[3] = 0.0; 2833 2834 } else if (distran == WAT) { 2835 // TNX and ZPX don't have alternates, nor axis mapping. 2836 char *wp; 2837 int omax, omin, wctrl[4]; 2838 double wval; 2839 struct disprm *disp = wcsp->lin.disseq; 2840 2841 // Disassemble the core dump stored in the WATi_m strings. 2842 int i, nterms = 0; 2843 for (i = 0; i < 2; i++) { 2844 char wtype[8]; 2845 sscanf(wat[i], "wtype=%s", wtype); 2846 2847 if (strcmp(wtype, "tnx") == 0) { 2848 strcpy(disp->dtype[i], "WAT-TNX"); 2849 } else if (strcmp(wtype, "zpx") == 0) { 2850 strcpy(disp->dtype[i], "WAT-ZPX"); 2851 } else { 2852 // Could contain "tan" or something else to be ignored. 2853 lindist(2, &(wcsp->lin), 0x0, 0); 2854 return 0; 2855 } 2856 2857 // The PROJPn parameters are duplicated on each ZPX axis. 2858 if (i == 1 && strcmp(wtype, "zpx") == 0) { 2859 // Take those on the second (latitude) axis ignoring the other. 2860 // First we have to count them and allocate space in wcsprm. 2861 wp = wat[i]; 2862 int npv; 2863 for (npv = 0; npv < 30; npv++) { 2864 if ((wp = strstr(wp, "projp")) == 0x0) break; 2865 wp += 5; 2866 } 2867 2868 // Allocate space. 2869 if (npv) { 2870 wcsp->npvmax += npv; 2871 wcsp->pv = realloc(wcsp->pv, wcsp->npvmax*sizeof(struct pvcard)); 2872 if (wcsp->pv == 0x0) { 2873 return WCSHDRERR_MEMORY; 2874 } 2875 2876 wcsp->m_pv = wcsp->pv; 2877 } 2878 2879 // Copy the values. 2880 wp = wat[i]; 2881 for (int ipv = wcsp->npv; ipv < wcsp->npvmax; ipv++) { 2882 if ((wp = strstr(wp, "projp")) == 0x0) break; 2883 2884 int m; 2885 sscanf(wp, "projp%d=%lf", &m, &wval); 2886 wcsp->pv[ipv].i = 2; 2887 wcsp->pv[ipv].m = m; 2888 wcsp->pv[ipv].value = wval; 2889 2890 wp += 5; 2891 } 2892 2893 wcsp->npv += npv; 2894 } 2895 2896 // Read the control parameters. 2897 if ((wp = strchr(wat[i], '"')) == 0x0) { 2898 return WCSHDRERR_PARSER; 2899 } 2900 wp++; 2901 2902 for (int m = 0; m < 4; m++) { 2903 sscanf(wp, "%d", wctrl+m); 2904 if ((wp = strchr(wp, ' ')) == 0x0) { 2905 return WCSHDRERR_PARSER; 2906 } 2907 wp++; 2908 } 2909 2910 // How many coefficients are we expecting? 2911 omin = (wctrl[1] < wctrl[2]) ? wctrl[1] : wctrl[2]; 2912 omax = (wctrl[1] < wctrl[2]) ? wctrl[2] : wctrl[1]; 2913 if (wctrl[3] == 0) { 2914 // No cross terms. 2915 nterms += omin + omax; 2916 2917 } else if (wctrl[3] == 1) { 2918 // Full cross terms. 2919 nterms += omin*omax; 2920 2921 } else if (wctrl[3] == 2) { 2922 // Half cross terms. 2923 nterms += omin*omax - omin*(omin-1)/2; 2924 } 2925 } 2926 2927 // Allocate memory for dpkeys. 2928 ndq[0] += 2*(1 + 1 + 4) + nterms; 2929 2930 disp->ndpmax += ndq[0]; 2931 disp->dp = realloc(disp->dp, disp->ndpmax*sizeof(struct dpkey)); 2932 if (disp->dp == 0x0) { 2933 return WCSHDRERR_MEMORY; 2934 } 2935 2936 disp->m_dp = disp->dp; 2937 2938 2939 // Populate dpkeys. 2940 int idp = disp->ndp; 2941 for (i = 0; i < 2; i++) { 2942 dpfill(disp->dp+(idp++), "DQ", "NAXES", i+1, 0, 2, 0.0); 2943 2944 // Read the control parameters. 2945 if ((wp = strchr(wat[i], '"')) == 0x0) { 2946 return WCSHDRERR_PARSER; 2947 } 2948 wp++; 2949 2950 for (int m = 0; m < 4; m++) { 2951 sscanf(wp, "%d", wctrl+m); 2952 if ((wp = strchr(wp, ' ')) == 0x0) { 2953 return WCSHDRERR_PARSER; 2954 } 2955 wp++; 2956 } 2957 2958 // Polynomial type. 2959 char wpoly[12]; 2960 dpfill(disp->dp+(idp++), "DQ", "WAT.POLY", i+1, 0, wctrl[0], 0.0); 2961 if (wctrl[0] == 1) { 2962 // Chebyshev polynomial. 2963 strcpy(wpoly, "CHBY"); 2964 } else if (wctrl[0] == 2) { 2965 // Legendre polynomial. 2966 strcpy(wpoly, "LEGR"); 2967 } else if (wctrl[0] == 3) { 2968 // Polynomial is the sum of monomials. 2969 strcpy(wpoly, "MONO"); 2970 } else { 2971 // Unknown code. 2972 strcpy(wpoly, "UNKN"); 2973 } 2974 2975 // Read the scaling parameters. 2976 char field[40]; 2977 for (int m = 0; m < 4; m++) { 2978 sscanf(wp, "%lf", &wval); 2979 sprintf(field, "WAT.%c%s", (m<2)?'X':'Y', (m%2)?"MAX":"MIN"); 2980 dpfill(disp->dp+(idp++), "DQ", field, i+1, 1, 0, wval); 2981 2982 if ((wp = strchr(wp, ' ')) == 0x0) { 2983 return WCSHDRERR_PARSER; 2984 } 2985 wp++; 2986 } 2987 2988 // Read the coefficients. 2989 for (int n = 0; n < wctrl[2]; n++) { 2990 for (int m = 0; m < wctrl[1]; m++) { 2991 if (wctrl[3] == 0) { 2992 if (m && n) continue; 2993 } else if (wctrl[3] == 2) { 2994 if (m+n > omax-1) continue; 2995 } 2996 2997 sscanf(wp, "%lf", &wval); 2998 if (wval == 0.0) continue; 2999 3000 sprintf(field, "WAT.%s.%d_%d", wpoly, m, n); 3001 dpfill(disp->dp+(idp++), "DQ", field, i+1, 1, 0, wval); 3002 3003 if ((wp = strchr(wp, ' ')) == 0x0) { 3004 return WCSHDRERR_PARSER; 3005 } 3006 wp++; 3007 } 3008 } 3009 } 3010 3011 disp->ndp = idp; 3012 } 3013 3014 return 0; 3015 } 3016