summaryrefslogtreecommitdiffstats
path: root/funtools/wcs
diff options
context:
space:
mode:
authorWilliam Joye <wjoye@cfa.harvard.edu>2016-10-25 20:57:49 (GMT)
committerWilliam Joye <wjoye@cfa.harvard.edu>2016-10-25 20:57:49 (GMT)
commitd1c4bf158203c4e8ec29fdeb83fd311e36320885 (patch)
tree15874534e282f67505ce4af5ba805a1ff70ec43e /funtools/wcs
parente19a18e035dc4d0e8e215f9b452bb9ef6f58b9d7 (diff)
parent339420dd5dd874c41f6bab5808291fb4036dd022 (diff)
downloadblt-d1c4bf158203c4e8ec29fdeb83fd311e36320885.zip
blt-d1c4bf158203c4e8ec29fdeb83fd311e36320885.tar.gz
blt-d1c4bf158203c4e8ec29fdeb83fd311e36320885.tar.bz2
Merge commit '339420dd5dd874c41f6bab5808291fb4036dd022' as 'funtools'
Diffstat (limited to 'funtools/wcs')
-rw-r--r--funtools/wcs/COPYING460
-rw-r--r--funtools/wcs/Files179
-rw-r--r--funtools/wcs/Makefile-orig36
-rw-r--r--funtools/wcs/Makefile.in206
-rw-r--r--funtools/wcs/NEWS473
-rw-r--r--funtools/wcs/Readme36
-rw-r--r--funtools/wcs/cel.c474
-rw-r--r--funtools/wcs/conf.h.in56
-rw-r--r--funtools/wcs/config.guess1435
-rw-r--r--funtools/wcs/config.sub1807
-rwxr-xr-xfuntools/wcs/configure-failsafe6222
-rw-r--r--funtools/wcs/configure.ac177
-rw-r--r--funtools/wcs/dateutil.c4554
-rw-r--r--funtools/wcs/distort.c407
-rw-r--r--funtools/wcs/dsspos.c318
-rw-r--r--funtools/wcs/fileutil.c818
-rw-r--r--funtools/wcs/fitsfile.c2308
-rw-r--r--funtools/wcs/fitsfile.h1286
-rw-r--r--funtools/wcs/fitshead.h438
-rw-r--r--funtools/wcs/hget.c1913
-rw-r--r--funtools/wcs/hput.c1316
-rw-r--r--funtools/wcs/iget.c531
-rw-r--r--funtools/wcs/imhfile.c1941
-rw-r--r--funtools/wcs/imio.c1543
-rw-r--r--funtools/wcs/imio.h64
-rwxr-xr-xfuntools/wcs/install-sh276
-rw-r--r--funtools/wcs/lin.c448
-rw-r--r--funtools/wcs/platepos.c391
-rw-r--r--funtools/wcs/poly.c914
-rw-r--r--funtools/wcs/proj.c4527
-rw-r--r--funtools/wcs/slasubs.c364
-rw-r--r--funtools/wcs/sph.c234
-rw-r--r--funtools/wcs/tnxpos.c1234
-rw-r--r--funtools/wcs/wcs.c2994
-rw-r--r--funtools/wcs/wcs.h963
-rw-r--r--funtools/wcs/wcscon.c2328
-rw-r--r--funtools/wcs/wcsinit.c1611
-rw-r--r--funtools/wcs/wcslib.c1334
-rw-r--r--funtools/wcs/wcslib.h476
-rw-r--r--funtools/wcs/wcstrig.c189
-rw-r--r--funtools/wcs/worldpos.c693
-rw-r--r--funtools/wcs/zpxpos.c735
42 files changed, 48709 insertions, 0 deletions
diff --git a/funtools/wcs/COPYING b/funtools/wcs/COPYING
new file mode 100644
index 0000000..6320024
--- /dev/null
+++ b/funtools/wcs/COPYING
@@ -0,0 +1,460 @@
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
diff --git a/funtools/wcs/Files b/funtools/wcs/Files
new file mode 100644
index 0000000..94d18da
--- /dev/null
+++ b/funtools/wcs/Files
@@ -0,0 +1,179 @@
+WCSTools libwcs Subroutines (3.9.0, March 11, 2011)
+
+actread.c
+ Return stars from the USNO ACT Reference Catalog
+binread.c
+ Return stars from catalog files in the TDC binary catalog format
+catread.c
+ Return stars from catalog files in the TDC ASCII catalog format
+catutil.c
+ Subroutines for catalog identification and number range decoding
+cel.c
+ WCSLIB spherical coordinate transformation drivers
+daoread.c
+ Read x, y, and magnitude from DAOFIND output file and return x, y, and
+ flux for use by IMSTAR or IMWCS.
+dateutil.c
+ Subroutines for conversions between various date and time formats
+distort.c
+ Subroutines for conversions between image pixel and focal plane coordinates
+dsspos.c
+ dsspos() uses the WCS structure to compute sky coordinates given
+ image pixel X and Y for images with Digitized Sky Survey plate solutions
+ in their headers. dsspix() uses the WCS structure to compute image
+ pixel X and Y given sky coordinates for DSS images. Algorithms from
+ StSCI CASB.
+fileutil.c
+ Subroutines for finding size and contents of ASCII files
+findstar.c
+ findStars() gets the location and brightest pixel of stars in the given
+ image. Included are subroutines to find and reject bright pixels and
+ compute a star centroid.
+fitsfile.c
+ FITS header and image reading and writing subroutines, including FITS
+ table support.
+fitswcs.c
+ GetWCSFITS() returns a WCS structure used by wcs.c subroutines from a FITS
+ or IRAF .imh image, reading only the header.
+ GetFITShead() returns a FITS header from a FITS or IRAF .imh image.
+ DelWCS() delete the WCS keywords in a FITS header.
+fortcat.c
+ Fortran wrapper subroutines for catalog reading subroutines ctgread() and ctgrnum()
+fortwcs.c
+ Fortran wrapper subroutines for all useful subroutines in wcs.c and wcsinit.c
+gscread.c
+ Return HST Guide Stars from standard CDROM format FITS table files for
+ a given RA, Dec, and magnitude range or list of star numbers.
+gsc2read.c
+ Return GSC II Stars using an HTTP query over the web for
+ a given RA, Dec, and magnitude range or list of star numbers.
+hget.c
+ Subroutines to extract values from FITS headers by keyword.
+ Subroutines for parsing RA and Dec strings are included.
+hput.c
+ Subroutines to implant values into FITS headers by keyword (and to
+ delete headers).
+iget.c
+ Subroutines to extract values from IRAF multi-keyword header parameters
+imhfile.c
+ IRAF header and image reading and writing subroutines. IRAF headers
+ are converted to FITS headers for use by other programs and can be
+ derived from FITS headers for writing.
+imio.c
+ Subroutines to get, put, and move pixels of various data types between images
+ im memory and a program.
+imrotate.c
+ RotFITS() rotates an image by 90, 180, or 270 degrees, with an optional
+ left-right reflection before the rotation.
+imgetwcs.c
+ GetWCSFITS() reads world coordinate system header information and returns
+ the image center coordinates and size as well as the wcs data structure.
+imsetwcs.c
+ SetWCSFITS() uses findStars to find the stars in an image, gscread to
+ find the Guide Stars in the nominal image region, and findRegisration or
+ findCoords to fit plate-tangent WCS to the image.
+lin.c
+ WCSLIB linear transformation subroutines
+matchstar.c
+ StarMatch() takes a list of reference star positions and a list
+ of object coordinates from an image and finds the image pixels
+ which correspond to each of the reference stars. It then uses these
+ matches to get an image center, plate scale, and rotation. The actual
+ fit is based on the amoeba subroutine in Numerical Recipes, and all
+ necessary subroutines are included.
+platepos.c
+ platepos() uses the WCS structure to compute sky coordinates given
+ image pixel X and Y for images with polynomial plate solutions
+ in their headers. platepix() uses the WCS structure to compute image
+ pixel X and Y given sky coordinates for such images. Algorithms are based
+ on those in dsspos.c, but go straight from pixels to angles without an
+ intermediate plate coordinate.
+poly.c
+ Polynomial evaluation for SCAMP distortion correction
+proj.c
+ WCSLIB spherical map projection subroutines
+sdssread.c
+ Return Sloan Digital Sky Survey Photometry Catalog sources using an
+ HTTP query over the web for a given RA, Dec, and magnitude range.
+sortstars.c
+ Subroutines to sort lists of stars by right ascension, magnitude, or flux
+sph.c
+ WCSLIB spherical coordinate transformation subroutines
+tabread.c
+ Return stars from a tab table format catalog file for a given RA, Dec,
+ and magnitude range or list of star numbers. Based on John Roll's
+ Starbase format.
+tmcread.c
+ Return 2MASS Point Source Catalog stars from the catalog as ungzipped from
+ the DVD into (or linked from) a common root directory for a given RA, Dec,
+ and magnitude range or list of star numbers. Both IDR2 and All-Sky release
+ formats are supported.
+tnxpos.c
+ tnxpos() uses the WCS keywords set up for IRAF's TNX projection to compute
+ sky coordinates given image pixel X and Y. tnxpix() uses the WCS structure
+ to compute image pixel X and Y given sky coordinates for such images. The
+ projection is a tangent plane with corrections between the rotation and
+ scaling and the actual projection.
+uacread.c
+ Return USNO A and SA Catalog stars from their standard CDROM format
+ files for a given RA, Dec, and magnitude range or list of star numbers.
+ubcread.c
+ Return USNO B Catalog stars from their standard format files for a
+ given RA, Dec, and magnitude range or list of star numbers.
+ucacread.c
+ Return USNO UCAC1, UCAC2, or UCAC3 Catalog stars from their standard format
+ files for a given RA, Dec, and magnitude range or list of star numbers.
+ujcread.c
+ Return USNO UJ Catalog stars from its standard CDROM format files for
+ a given RA, Dec, and magnitude range or list of star numbers.
+wcs.c
+ Subroutines for using FITS or IRAF header spatial world coordinate
+ system information.
+wcsinit.c
+ Subroutines to initialize WCS structure from a FITS header
+wcscon.c
+ Subroutines for converting between B1950, J2000, and galactic
+ coordinates, mostly based on Starlink SLA_LIB subroutines.
+webread.c
+ Open Starbase files across the Internet using HTTP queries
+worldpos.c
+ worldpos() uses the WCS structure to compute sky coordinates given
+ image pixel X and Y for images with header information for any of 8
+ standard world coordinate systems. worldpix() uses the WCS structure
+ to compute image pixel X and Y given sky coordinates for the same images.
+ Mostly from NRAO.
+zpxpos.c
+ zpxpos() uses the WCS keywords set up for IRAF's ZPX projection to
+ compute sky coordinates given image pixel X and Y. zpxpix() uses
+ the WCS structure to compute image pixel X and Y given sky coordinates
+ for such images. The projection is a tangent plane with corrections
+ between the rotation and scaling and the actual projection.
+
+fitshead.h
+ Declarations of FITS header access subroutines
+fitsfile.h
+ Declarations of image access subroutines and FITS table data structure.
+imio.h
+ Declarations of subroutines to convert binary formats of numbers
+lwcs.h
+ Constants used by star-finding and WCS-setting subroutines
+wcscat.h
+ Declarations for star catalog data structures
+wcs.h
+ Declaration of WCS data structure and useful conversions.
+wcslib.h
+ Declarations for WCSLIB high level driver subroutines, trig and inverse
+ trig functions, spherical map projection subroutines, spherical coordinate
+ transformation drivers, and linear transformation subroutines
+
+* Notes:
+ WCSLIB subroutines were written by Mark Calabretta of CSIRO and have
+ been modified in several ways:
+ 1) His distributed wcs.h has been changed to wcslib.h, and
+ 2) wcstrig.c subroutine names have been changed from <function>d()
+ to <function>deg() to avoid name conflicts on some operating
+ systems.
+ 3) ifndef's at start of headers files have been named to reflect
+ the names of the header files, i.e. wcslib_h_ in wcslib.h.
+ 4) All header files have been combined into wcslib.h
+ 5) Emmanuel Bertin's SCAMP distortion has been added to proj.c:1
diff --git a/funtools/wcs/Makefile-orig b/funtools/wcs/Makefile-orig
new file mode 100644
index 0000000..9caa507
--- /dev/null
+++ b/funtools/wcs/Makefile-orig
@@ -0,0 +1,36 @@
+OBJS = wcsinit.o wcs.o wcscon.o fitsfile.o imhfile.o \
+ hget.o hput.o iget.o imio.o worldpos.o platepos.o \
+ tnxpos.o zpxpos.o dsspos.o poly.o \
+ wcslib.o lin.o cel.o proj.o sph.o wcstrig.o dateutil.o distort.o
+
+libwcs.a: $(OBJS)
+ ar rv $@ $?
+ ranlib $@
+
+cel.o: wcslib.h
+distort.o: wcs.h fitshead.h wcslib.h
+fitsfile.o: fitsfile.h fitshead.h
+hget.o: fitshead.h
+hput.o: fitshead.h
+iget.o: fitshead.h
+imhfile.o: fitsfile.h fitshead.h
+imio.o: fitshead.h
+lin.o: wcslib.h
+platepos.o: wcs.h fitshead.h wcslib.h
+poly.o: wcslib.h
+proj.o: wcslib.h
+sph.o: wcslib.h
+tnxpos.o: wcs.h fitshead.h wcslib.h
+zpxpos.o: wcs.h fitshead.h wcslib.h
+wcs.o: wcs.h fitshead.h wcslib.h
+wcsinit.o: wcs.h fitshead.h wcslib.h
+wcscon.o: wcs.h fitshead.h wcslib.h
+wcslib.o: wcslib.h
+wcstrig.o: wcslib.h
+worldpos.o: wcs.h fitshead.h wcslib.h
+dateutil.o: fitsfile.h fitshead.h
+fileutil.o: fitsfile.h
+
+clean:
+ rm -f *.a *.o
+
diff --git a/funtools/wcs/Makefile.in b/funtools/wcs/Makefile.in
new file mode 100644
index 0000000..53ed80a
--- /dev/null
+++ b/funtools/wcs/Makefile.in
@@ -0,0 +1,206 @@
+#
+# This file is a Makefile for wcssubs. If it has the name "Makefile.in"
+# then it is a template for a Makefile; to generate the actual Makefile,
+# run "./configure", which is a configuration script generated by the
+# "autoconf" program (constructs like "@foo@" will get replaced in the
+# actual Makefile.
+#
+
+PACKAGE = @PACKAGE_NAME@
+VERSION = @PACKAGE_VERSION@
+
+DISTNAME = wcs-${VERSION}
+DISTDIR = ../export/${DISTNAME}
+FTPDIR = ../ftp
+
+#----------------------------------------------------------------
+# Things you can change to personalize the Makefile for your own
+# site (you can make these changes in either Makefile.in or
+# Makefile, but changes to Makefile will get lost if you re-run
+# the configuration script).
+#----------------------------------------------------------------
+
+# Default top-level directories in which to install architecture-
+# specific files (exec_prefix) and machine-independent files such
+# as scripts (prefix). The values specified here may be overridden
+# at configure-time with the --exec-prefix and --prefix options
+# to the "configure" script.
+
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+# The following definition can be set to non-null for special systems
+# like AFS with replication. It allows the pathnames used for installation
+# to be different than those used for actually reference files at
+# run-time. INSTALL_ROOT is prepended to $prefix and $exec_prefix
+# when installing files.
+INSTALL_ROOT =
+
+# Directory in which to install the .a or .so binary for the WCS library:
+LIB_INSTALL_DIR = $(INSTALL_ROOT)$(exec_prefix)/lib
+
+# Directory in which to install the program wish:
+BIN_INSTALL_DIR = $(INSTALL_ROOT)$(exec_prefix)/bin
+
+# Directory in which to install the include file wcs.h:
+INCLUDE_INSTALL_DIR = $(INSTALL_ROOT)$(prefix)/include
+
+# To change the compiler switches, for example to change from -O
+# to -g, change the following line:
+CFLAGS = @CFLAGS@
+
+# To add ld switches, change the following line:
+LDFLAGS = @LDFLAGS@
+
+# Some versions of make, like SGI's, use the following variable to
+# determine which shell to use for executing commands:
+SHELL = /bin/sh
+
+# extra modules added by configure.in to fix OS bugs
+EXTRA_OBJS = @EXTRA_OBJS@
+
+# There are just too many different versions of "install" around;
+# better to use the install-sh script that comes with the distribution,
+# which is slower but guaranteed to work.
+
+INSTALL = @srcdir@/install-sh -c
+INSTALL_PROGRAM = ${INSTALL}
+INSTALL_DATA = ${INSTALL} -m 644
+
+#----------------------------------------------------------------
+# The information below is modified by the configure script when
+# Makefile is generated from Makefile.in. You shouldn't normally
+# modify any of this stuff by hand.
+#----------------------------------------------------------------
+
+AC_FLAGS = @DEFS@
+RANLIB = @RANLIB@
+
+#----------------------------------------------------------------
+# The information below should be usable as is. The configure
+# script won't modify it and you shouldn't need to modify it
+# either.
+#----------------------------------------------------------------
+
+CC = @CC@
+
+CC_SWITCHES = -I. ${CFLAGS} -DWCS_VERSION="\"$(VERSION)\"" ${AC_FLAGS}
+
+DEPEND_SWITCHES = -I. ${CFLAGS} ${AC_FLAGS}
+
+SRCS = wcsinit.c wcs.c wcscon.c fitsfile.c imhfile.c fileutil.c \
+ hget.c hput.c iget.c imio.c worldpos.c tnxpos.c dsspos.c platepos.c \
+ wcslib.c lin.c cel.c proj.c sph.c wcstrig.c dateutil.c distort.c \
+ zpxpos.c
+
+OBJS = wcsinit.o wcs.o wcscon.o fitsfile.o imhfile.o \
+ hget.o hput.o iget.o imio.o worldpos.o platepos.o \
+ tnxpos.o zpxpos.o dsspos.o poly.o \
+ wcslib.o lin.o cel.o proj.o sph.o wcstrig.o dateutil.o distort.o
+
+# these are all the modules going into the "normal" wcs library
+LIBOBJS = ${OBJS}
+
+# whether to build library at all
+WHICHLIB = @WHICHLIB@
+EXTLIB = @EXTLIB@
+
+# the default library for this package
+DEFLIB = @DEFLIB@
+# the actual library we are building (if this is a subpackage)
+LIB = @LIB@
+
+PROGS =
+
+TESTPROGS =
+
+all: $(WHICHLIB) $(PROGS)
+
+testall: $(TESTPROGS)
+
+All: all testall
+
+install: install-binaries
+
+extlib:
+ @echo "No build needed -- using external WCS library: $(EXTLIB)"
+
+lib: $(LIBOBJS)
+ ar cruv $(LIB) $(LIBOBJS)
+ $(RANLIB) $(LIB)
+
+# Note: before running ranlib below, must cd to target directory because
+# some ranlibs write to current directory, and this might not always be
+# possible (e.g. if installing as root).
+
+install-binaries: $(LIB) $(PROGS)
+ @for i in $(LIB_INSTALL_DIR) $(INCLUDE_INSTALL_DIR) $(BIN_INSTALL_DIR) ; \
+ do \
+ if [ ! -d $$i ] ; then \
+ echo "Making directory $$i"; \
+ mkdir $$i; \
+ chmod 755 $$i; \
+ else true; \
+ fi; \
+ done;
+ @if [ "$(LIB)" = "$(DEFLIB)" ] ; then \
+ XLIB=`basename $(LIB)`; \
+ echo "Installing $$XLIB"; \
+ $(INSTALL_DATA) $$XLIB $(LIB_INSTALL_DIR)/$$XLIB; \
+ (cd $(LIB_INSTALL_DIR); $(RANLIB) $$XLIB); \
+ chmod 555 $(LIB_INSTALL_DIR)/$$XLIB; \
+ fi;
+ @echo "Installing fitshead.h"
+ @$(INSTALL_DATA) fitshead.h $(INCLUDE_INSTALL_DIR)/fitshead.h
+ @echo "Installing wcs.h"
+ @$(INSTALL_DATA) wcs.h $(INCLUDE_INSTALL_DIR)/wcs.h
+ @echo "Installing wcslib.h"
+ @$(INSTALL_DATA) wcslib.h $(INCLUDE_INSTALL_DIR)/wcslib.h
+
+Makefile: Makefile.in
+ $(SHELL) config.status
+
+RM = rm -f
+
+clean:
+ $(RM) *.a *.so *.o *.exe core errs *pure* .nfs* \
+ foo* *~ *.log \#* TAGS *.E a.out errors \
+ $(PROGS) $(TESTPROGS) \
+ gmon.out *.pg *.bak \
+ config.info config.log \
+ doc/*~
+ $(RM) -r autom4te.cache
+
+distclean: clean
+ $(RM) Makefile config.status config.cache config.log
+
+depend:
+ makedepend -- $(DEPEND_SWITCHES) -- $(SRCS)
+
+
+.c.o:
+ $(CC) -c $(CC_SWITCHES) $<
+
+cel.o: wcslib.h
+distort.o: wcs.h fitshead.h wcslib.h
+fitsfile.o: fitsfile.h fitshead.h
+hget.o: fitshead.h
+hput.o: fitshead.h
+iget.o: fitshead.h
+imhfile.o: fitsfile.h fitshead.h
+imio.o: fitshead.h
+lin.o: wcslib.h
+platepos.o: wcs.h fitshead.h wcslib.h
+proj.o: wcslib.h
+sph.o: wcslib.h
+tnxpos.o: wcs.h fitshead.h wcslib.h
+wcs.o: wcs.h fitshead.h wcslib.h
+wcsinit.o: wcs.h fitshead.h wcslib.h
+wcscon.o: wcs.h fitshead.h wcslib.h
+wcslib.o: wcslib.h
+wcstrig.o: wcslib.h
+worldpos.o: wcs.h fitshead.h wcslib.h
+dateutil.o: fitsfile.h fitshead.h
+fileutil.o: fitsfile.h
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/funtools/wcs/NEWS b/funtools/wcs/NEWS
new file mode 100644
index 0000000..73db1fe
--- /dev/null
+++ b/funtools/wcs/NEWS
@@ -0,0 +1,473 @@
+WCSTools WCS subroutine library release history
+
+Version 3.8.7 (October 19, 2012)
+dateutil.c: Unused l0 dropped from jd2lst(); ts2ss from jd2mst()
+imio.c: Fix errors with character images in minvec() and maxvec()
+wcs.c: Drop d1 and d2 from wcsdist(); diffi from wcsdist1()
+wcs.c: Drop depwcs; it's in main wcs structure
+wcsinit.c: Drop unused variable iszpx; fix bug in latmin assignment
+
+catutil.c: Skip trailing right bracket in aget*()
+
+Version 3.8.6 (August 10, 2012)
+All: Update author name
+imio.c: Fix 8-bit variables to be unsigned char
+
+Version 3.8.5 (April 12, 2012)
+imio.c: Change 8-bit pixel values from char to unsigned char
+fitsfile.c: Always check first 8 characters of FITS files for "SIMPLE"
+
+Version 3.8.4 (September 1, 2011)
+imgetwcs.c, wcsinit.c, wcs.c, wcs.h, worldpos.c: Add TPV WCS for TAN with PV terms
+
+Version 3.8.3 (May 20, 2011)
+hget.c: Free allocated memory in strnsrch() to eliminate memory leak (2011-05-19)
+imhfile.c: Free *newpixname* not pixname. (2011-05-20)
+wcsinit.c: Change error() calls to setwcserr()
+wcslib.h: Declare undeclared SCAMP subroutine raw-to-pv()
+wcs.c: Fix wcsfree() so it frees depended-on WCS structures (2011-05-09)
+
+March 18, 2011 - Release 3.8.2
+zpxpos.c, wcs.c, wcsinit.c: Add support for NOAO ZPX protection (Frank Valdes)
+imsetwcs.c: Allocate NMAXMAG instead of number of magnitudes, nmag
+wcsinit.c,wcs.c,proj.c: Support SCAMP TAN distortion correction (Ed Los)
+wcsinit.c: ARSEC and DEG constants used by SCAMP replaced by S2D and D2S
+proj.c: If no PV coefficients in ZPN projection, make it ARC
+wcs.c: Fix bug involving dependent WCS's (Ed Los)
+
+April 30, 2010 - Release 3.8.1
+scat,imcat: Set GSC2 magnitudes > 90 to 99.99
+gethead: Fix buffer reallocation bug which crashed reading very large
+ headers
+gethead: Fix trailing spaces on ASCII file quoted string values
+gethead: Fix problems with string value extraction changing ASCII files
+skycoor: Use number of decimal places from -n for -r difference if set
+wcscon.c: Fix bug in fk524() e-term computation; fix J<->B conversions
+fitsfile.c: In fitswhead(), always pad blocks to 2880 bytes with spaces
+ and fix bug dealing with large primary headers
+wcscon.c: Fix bug in computing the magnitude of the e-terms in fk524()
+ and drop ep1 assignment after line 178 in wcsconp()
+
+
+November 13, 2009 - Release 3.8.0
+dateutil.c: Fix possible bug in nutation subroutine
+fitsfile.c: Add subroutine moveb() and fix binary table calls to it
+ Fix lengths for ASCII numeric table entries in fitsrthead()
+fitsfile.h: Add moveb() which is used by binary FITS table code in fitsfile.c
+hget.c: In strfix(), if parentheses enclose a number, drop them
+
+November 21, 2008 - Release 3.7.6
+fitsfile.c: In fitswhead() do not print write error if nw = nbytes
+dateutil.c: Use IAU 2006 nutation for sidereal time computations
+dateutil.c: Add ang2hr(), ang2deg(), deg2ang(), and ang2hr() to
+ convert betweem decimal floating point degrees and
+ vigesimal hours or degrees
+tnxpos.c: Fix image to world coordinate system transformation and
+ WCS to image transformation
+
+July 1, 2008 - Release 3.7.5
+wcsinit.c: Initialize TNX projection when projection types first set and
+ check for IMAGEW and IMAGEH if NAXIS1 and NAXIS2 not present,
+fitsfile.c: Drop comma from name when reading file in isfits() and
+ do not append primary data header if it is the only header
+
+May 9, 2008 - Release 3.7.4
+fitsfile.c: In isfits(), allow extensions in FITS files without .fit or .fts
+wcsinit.c: Call tnxinit() before any projection calls are made
+
+March 20, 2008 - Release 3.7.3
+wcs.c: Compute angular separation in wcsdist() using arcos
+
+December 31, 2007 - Release 3.7.2
+wcscon.c: In wcsconp, make it clear that proper motion is in spherical coordinates
+fitsfile.c: Add support to BINTABLE in ftget*() and fitsrthead()
+fitsfile.c: Add data heap numerated by PCOUNT when skipping HDU in fitsrhead()
+fitsfile.c: Return NULL pointer if fitsrhead() cannot find requested HDU
+fitswcs.c: Print error message set by fitsrhead()
+
+November 9, 2007 - Release 3.7.1
+wcsinit.c: Fix bug which tested &mchar instead of mchar in if statement
+
+August 24, 2007 - Release 3.7.0
+hget.c: If a closing quote isn't found in a string value, make one up
+hput.c: Fix bug in comment insertion and deal correctly with missing quotes
+
+June 11, 2007 - Release 3.6.9
+imio.c: Add minvec() and speed up maxvec()
+
+April 3, 2007 - Release 3.6.8
+hget.c: Initial header length to zero in hlength() if lhead argument <= 0
+wcs.c: In wcstype(), set to WCS_PIX if CTYPEi starts with "DET"
+wcs.c: In wcspset(), use correct cdelts when converting PC matrix to CD matrix
+wcsinit.c: Fix bug so RA, DEC, SECPIX can be used to set a WCS
+tnxpos.c: Fix bug so it doesn't crash
+
+January 16, 2007 - Release 3.6.7
+wcs.h: Fix and add ANSI C prototypes
+imio.h: Drop as it has been included in fitsfile.h for several releases now
+fitsfile.h, fitshead.h: Add ANSI C prototypes
+wcsinitc(),wcsninitc(),hgeti4c(),hgetr8c(),hgetsc(): Change WCS letter argument
+ from char to char*
+hget.c: Declare header and keyword const char in most subroutines
+hput.c: Declare keyword and value const in most subroutines
+hput.c: Fix bug in ra2str() and dec2str() so ndec=0 works
+imio.c: Include fitsfile.h instead of imio.h
+wcslib.h: Drop semicolon at end of c++ ifdef
+wcslib.h: Drop second declaration of SZP subroutines
+
+November 2, 2006 - Release 3.6.6
+fitsfile.c: Use calloc() when reallocating header as it is read
+wcsinit.c: Limit naxes to 2 everywhere; RA and DEC should always be 1st
+wcsinit.c: If either CUNITi is "pixel" set projection to WCS_XY
+wcscon.c: In wcscsys, set system to WCS_XY if PIXEL projection
+wcscon.c: In wcscsys, set system to WCS_LINEAR if LINEAR coordinate system
+dateutil.c, fitshead.h: Add sidereal time to UT and vice versa
+
+June 30, 2006 - Release 3.6.5
+wcsinit.c: Deal with up to 9x9 PC matrix
+wcs.c: Limit WCSLIB dimensions to two (this will change in 4.0)
+hput.c: Fix comment placement and replacement
+hget.c: Add strfix(), a utility to clean up strings
+
+May 3, 2006 - Release 3.6.4
+fileutil.c: Add istiff(), isjpeg(), isgif() to check TIFF, JPEG, GIF files
+fitsfile.c: Add fitsrtail() to read appended FITS headers
+fitsfile.c: Add file name to header-reading error messages
+fitswcs.c: Add code to read FITS header appended to TIFF file
+imio.c: Fix bug of occasional double application of bscale in getvec()
+ Clean up arithmetic and increment in addpix() and multpix()
+imsetwcs.c: Allow number of decimal places in image coordinates to be set
+wcsinit.c: Get Epoch of observation from MJD-OBS or DATE-OBS/UT unless DSS
+wcsinit.c: Set wcs->naxes to actual number of image WCS axes, usually 2
+wcscon.c,dateutil.c,fitsfile.c: Drop declarations of unused variables
+wcs.c: Fix calls to avoid type conflicts in Linux
+
+
+January 5, 2006 - Release 3.6.3
+wcs.h: Add WCS_ICRS to list of coordinate systems
+wcsinit.c: Initialize sys to WCS_ICRS if appropriate
+wcscon.c: Avoid precesssing ICRS coordinates
+wcscon.c: Fix precession which broke in 3.6.1
+
+July 21, 2005 - Release 3.6.2
+wcs.c: Fix wcsrange() to return correct range around RA=0
+Clean up accumulated unused and misdeclared variables using lint
+
+April 13, 2005 - Release 3.6.1
+Remove all sla_lib subroutines and calls thereto from wcscon.c, replacing
+them with local code.
+
+March 17, 2005 - Release 3.6.0
+In wcs.c, fix bug in wcsrotset() so angles > 360 are set to angle - 360, not 360
+Use unbuffered read() in isfits() in fitsfile.c
+
+------------------------
+
+November 01, 2004 - Release 3.5.8
+In wcs.c, keep wcs->rot between 0 and 360 degrees (360.0 -> 0.0)
+
+September 21, 2004 - Release 3.5.7
+In pix2wcs(), if spherical coordinate output, keep 0 < long/RA < 360
+Fix bug in wcsfull() when wrapping around RA=0:00
+In hput.c, add fixnegzero() to avoid putting -0.000 in header
+
+September 3, 2004 - Release 3.5.6
+Modify FITS file reading software to get image size from file size if
+SIMPLE is F, so FITS headers with WCS can be used on arbitrary files.
+In hget.c, fix bug so comment is not pushed onto the next line if character
+value string lengthens (off by one bug).
+
+July 13, 2004 - Release 3.5.5
+Add headshrink to hput.c to optionally keep blank lines after
+keywords are deleted.
+Read D, d, E, and e as exponent delimiters in floating point values in hget.c
+
+
+May 6, 2004 - Release 3.5.4
+Add fitswexhead() to fitsfile.c to overwrite FITS extension headers
+
+April 16, 2004 - Release 3.5.3
+Use strncsrch() in hget.c to get differently-cased keywords.
+
+February 3, 2004 - Release 3.5.2
+In worldpix() in worldpos.c, allow ra/long. to exceed 180 if reference
+pixel is more than 180 degrees from image (1,1).
+
+December 12, 2003 - Release 3.5.1
+Change p[0,1,2] initializations to p[1,2,3] in wcsinit.c to match proj.c
+(This affects constants for AZP,SIN,COP,COE,COD,COO,SZP,CEA,CYP,AIR,BON)
+Add wcs->naxes back into wcs structure for backward compatibility; it
+should always be equal to wcs->naxis.
+Fix bug in numdec() to return 0 if no digits after decimal point
+Fix call to setwcserr() with format in it
+
+November 17, 2003 - Release 3.5.0
+Rename mgets() to mgetstr() in iget.c, wcsinit.c and fitshead.h
+Add numdec() to hget.c to return number of decimal places in numeric string
+Change wcs->naxes to wcs->naxis to prepare for WCSLIB 3.*
+In iraf2fits() and irafrimage(), use image, not physical, dimensions.
+In iraf2fits(), set NAXISi to image dimensions, NPAXISi to physical dimensions.
+Fix bugs in wcsfull() in wcs.c
+Move all distortion-related code to distort.c; include unistd.h
+Include stdlib.h instead of malloc.h in lin.c and drop malloc.h from matchstar.c
+
+------------------------
+
+August 22, 2003 - Release 3.4.2
+Add fitsrfull() subroutine to read FITS files with more than 2 dimensions
+Modify fitswimage() to write FITS files with more than 2 dimensions
+
+July 11, 2003 - Release 3.4.1
+Use strncmp to check for both stdin and stdout in fitsfile.c
+
+May 30, 2003 - Release 3.4.0
+Add partial support for ZPX projection
+Fix bug reading COE and other projections when PROJPn coefficients
+were accidently reinitialized
+
+------------------------
+
+May 8, 2003 - Release 3.3.4
+Add two missing semicolons in C++ declarations in wcs.h
+Read prj.p[0] from PROJP0 for ZPN projections, instead of ignoring it
+
+April 3, 2003 - Release 3.3.2
+Add distortion conversion for SIRTF images
+
+March 27, 2003 - Release 3.3.1
+Add conversions to and from Heliocentric Julian Dates to dateutil.c
+Open FITS and IMH files "rb" instead of "r" for Linux compatibility
+Add isimlistd() to fileutil.c to check for list of images in a specified directory
+Fix default center pixel computation in GetFITSWCS(); it was off by half a pixel
+
+January 30, 2003 - Release 3.3.0
+Fix bug in dateutil.c ts2gst() sidereal time conversion.
+
+------------------------
+
+January 3, 2003 - Release 3.2.1
+Fix bug in wcsinit() which failed to read PVi_0, and now initialize
+PVi_j in only once place.
+
+December 6, 2002 - Release 3.2.0
+Add ET/TDT/TT and sidereal time conversion to dateutil.c
+Fix subroutine calls for radvel and latpole and correctly compute pixel
+at center of image for default CRPIX in wcsinit.c
+Add fitsrsect() to fitsfile.c to read a section of an image
+
+------------------------
+
+August 30, 2002 - Release 3.1.3
+Fix bug in imio.c getvec() dealing with scaled images
+Add case-insensitive string search subroutines strcsrch() and strncsrch()
+Accept stdin as file in isfile()
+Add Ephemeris time conversions to dateutil()
+
+July 8, 2002 - Release 3.1.2
+Fix bug in date utilities which always rounded to integer seconds of UT
+Fix bugs in date utilities to handle BC (negative) dates to JD 0.
+
+June 26, 2002 - Release 3.1.1
+Fix bugs which caused TNX projection to fail
+Fix two bugs in wcsinit() which caused setting RADECSYS when
+ an EQUINOX keyword is present.
+Write FITS error messages to string accessible by fitserr()
+Put SAO-written software under Gnu Lesser Public License
+
+April 12, 2002 - Release 3.1.0
+Implement WCSLIB 2.9
+Support PV entry of constants and PCi_j rotation matrices in wcsinit.c
+Support inversion (WCS->pix) of multiple dependent WCSs
+Add hgetri4c(), hgetr8c(), and hgetsc() for multiple WCS handling
+Fix bug in TNX projection software which caused an infinite loop during
+coefficient parsing.
+
+------------------------
+
+February 13, 2002 - Release 3.0.7
+Fix bug in ecliptic coordinate conversion in wcscon.c
+Allow "stdin" to include extension and/or WCS selection in fitsfile.c
+Add a global switch to turn off scaling in imio.c
+Add ifdef to lin.c so it will compile under Mac OS/X
+
+December 4, 2001 - Release 3.0.6
+In movepix(), add char to char move
+Always include stdlib.h in lin.c
+
+September 25, 2001 - Release 3.0.5
+Implement WCSLIB version 2.7
+Fix Makefile to include header files appropriately
+Accept FITS dates as yyyy/mm/dd
+Fix bug in str2dec() which misinterpreting strings with leading spaces
+Fix bug in isnum() which caused bad answer if trailing spaces
+Add fileutil.c, which includes various file info utilities
+
+September 7, 2001 - Release 3.0.3
+Disallow files with = in their name in isfits() and isiraf()
+Set coordinate system from CTYPE if not equatorial
+
+July 12, 2001 - Release 3.0
+Read PROJPn projection constants in wcsinit()
+
+------------------------
+
+March 30, 2001 - Release 2.9.4
+Fix possible header length problem in hget.c
+
+March 22, 2001 - Release 2.9.3
+Fix minor bugs in wcs.h, wcs.c, and wcsinit.c, wcslib.c, fitsfile.c, and
+cel.c found by gcc on Linux and possible memory leak in wcs.c
+
+March 9, 2001 - Release 2.9.2
+In fitsfile.c, change multiple WCS separator in FITS file names from : to %
+and fix bug which failed to read multi-extension files if END was not preceded
+by a blank line in the extension's header.
+
+February 28, 2001 - Release 2.9.1
+Fix major bug in wcsinit() which always set CRPIX2 the same as CRPIX1
+
+February 23, 2001 - Release 2.9.0
+FITS reading subroutines are fixed to ignore WCS name or character specified
+as :name or :character at end of filename.
+wcsinit() has new APIs which specify either a WCSNAME, wcsinitn(), or
+a WCS character, wcsinitc(), to allow use of multiple WCS's in a single
+FITS header. The WCSDEPx keyword has been added to indicate dependence
+on another WCS, though this feature has not been thoroughly debugged.
+fitscimage() is fixed so it doesn't overwrite data when overwriting a file
+An off-by-one bug was fixed for some polynomial types in tnxpos().
+The WCSLIB subroutines were brought up to release 2.6 with very minor changes
+
+------------------------
+
+December 29, 2000 - Release 2.8.6
+Fix handling of embedded + or - in isnum() in hget.c
+Default to 2000 for EQUINOX and EPOCH and FK5 for RADECSYS, if keywords not present.
+In wcscon.c, fk425() and fk524() algorithms were updated to include parallax and rv,
+proper motion is added by wcscon*() after fk425() or fk524() from system epoch, and
+proper motion units in fk524p() and fk425p() were fixed.
+In wcsinit.c, a bug initializing CD matrix was fixed.
+In cel.c, include string.h for strcmp().
+
+September 29, 2000 - Release 2.8.5
+wcsinit will now use a CD matrix if ANY CD keywords are present in header
+In getvec() in imio.c, move scaling outside of loop and make it conditional.
+Read .pix files in same directory as .imh file, if not otherwise found.
+
+August 1, 2000 - Release 2.8.3
+Improve handling of 1-D WCS data. Fix numerous warning-generating bugs.
+Fix bug in ep2jd()/jd2ep() so both start year at 1/1 0:00
+
+June 13, 2000 - Release 2.8.2
+If imh pixel file has no directory, *always* use same as header file
+
+June 9, 2000 - Release 2.8.1
+Read keyword values in hget.c even if no equal sign is present.
+
+June 2, 2000 - Release 2.8.0
+Only a few minor changes due to running lint on everything
+
+------------------------
+
+May 10, 2000 - Release 2.7.4
+In wcstype(), default to WCS_LIN, not error (after Bill Joye)
+
+May 1, 2000 - Release 2.7.3
+Bug in hadd() fixed so new line is not overwritten.
+Pixel files whcih are in subdirectories of files where IRAF .imh header
+files reside are now dealt with correctly.
+All dates in the old FITS format (dd/mm/yy) where the year ranges from
+ 0 to 999 have 1900 added to them: 01/05/100 becomes 2000-05-01.
+
+March 27, 2000 - Release 2.7.2
+In hputs(), do not add quotes if writing COMMENT or HISTORY
+In fits2iraf(), in imhfile.c, minimize length of path in pixel file name
+Fix code to deal with .imh file paths longer than 67 characters.
+In platepix(), use inverse CD matrix to get better initial x,y value
+Change the maximum header string length in the hget header reading
+ subroutines from 57600 to 256000
+Replace oldsys with wcsproj in the WCS data structure so that more options
+ are available, such as forcing use of AIPS or WCSLIB projection subroutines
+Add setdatedec() to set the number of decimal places in FITS date strings
+ returned by dateutil subroutines
+Fix precession code to deal correctly with equinoxes other than J2000 and
+ B1950.
+Move all date operations to dateutil.c, including current time used in imhfile.c
+
+February 23, 2000 - Release 2.7.0
+Upgrade WCSLIB subroutines to WCSLIB 2.5 from 2.4
+Add MJD and Besselian and Julian epoch conversion to dateutil.c
+Use WCSLIB CAR, COE, NCP projections if oldsys is 1, else use worldpos()
+Set CD matrix when using DSS projection
+Change oldwcs in wcs.h from switch to multi-value flag wcsproj, default is same
+Fix minor bug in fitsfile.c fitscimage error returns.
+
+------------------------
+
+January 11, 2000 - Release 2.6.12
+Fix bug in dateutil() to get fractional year to date conversion right
+
+December 20, 1999 - Release 2.6.11
+Fix bug in hgetdate() to get ISO minutes and seconds right
+Upgrade dateutil() to do many date conversions
+
+December 10, 1999 - Release 2.6.10
+Fix bug which caused strings starting with d and e followed by numbers
+to be declared numeric even though they're not really numbers
+Fix bug in dateutil.c ts2jd() which does not affect SAOimage
+Fix bugs dealing with NOAO TNX projection
+
+November 17, 1999 - Release 2.6.9
+Fix bug which caused loss of NCP projection
+
+November 5, 1999 - Release 2.6.8
+Change release number to match WCSTools
+Clean up code in all subroutines using lint
+Add DATE-MOD to FITS header in iraf2fits()
+Added dateutil.c file for conversions between date formats (used by iraf2fits())
+Return error code from hput*() subroutines if header buffer length exceeded.
+
+------------------------
+
+May 5, 1999 - Release 1.26
+hget.c, iget.c Use POSIX-compliant limits.h instead of values.h
+
+April 7, 1999 - Release 1.26
+wcs.c Fix bug in dealing with EPOCHless non-equatorial coordinates
+wcsinit.c Add optional filename to printed error messages
+
+April 5, 1999 - Release 1.26
+hget.c Check all string lengths before copying; ignore ^M at 80th character
+
+February 22, 1999 - Release 1.26
+wcs.c Fix bug dealing with SPA and NPA coordinates
+ Use faaces 0-5, not 1-6 for quad cube projections
+wcsinit.c Fix computed rotation angle for DSS projection
+
+February 9, 1999 - Release 1.26
+fitsfile.c: Allow BITPIX=0 dataless images
+wcsinit.c: Fix bug initializing DSS image rotation
+wcs.c: Free lin.imgpix and lin.piximg in wcsfree()
+hput.c: Fix bug to avoid writing HISTORY or COMMENT lines past 80 chars
+
+------------------------
+
+December 8, 1998 - Release 1.25
+fitsfile.c: Fix bug in fitsrhead() reading FITS table files caused by fix below
+
+November 30, 1998 - Release 1.25
+fitsfile.c: Fix bug dealing with very large headers in fitsrhead()
+
+November 12, 1998 - Release 1.25
+dsspos.c: Fix possible divide by zero problems
+fitsfile.c: Add isfits() which checks filename or first line of header
+imhfile.c: Add isiraf() which checks filename for .imh
+hget.c: Assume 2-digit year in hyphen-separated date means FITS, not ISO
+tnxpos.c: Fix multiple bugs
+wcscon.c: Add wcscstr() to get coordinate system as a character string
+wcscon.c: Add subroutine wcsconp() to convert coordinates + proper motions
+wcs.c: Add North and South Polar Angle coordinate systems
+wcs.c: Build WCS command initialization by getenv() into wcs*init()
+wcs.c: Fix bug in wcssize(); fix bug with rotated mirrored images
+wcslib.h: Add cel.h, lin.h, proj.h, and wcstrig.h to wcslib.h
+worldpos.c: Fix bug in inverse (sky to pixel) COE projection
+cel.c, lin.c, proj.c, sph.c, wcstrig.c: Include only wcslib.h
diff --git a/funtools/wcs/Readme b/funtools/wcs/Readme
new file mode 100644
index 0000000..61107cf
--- /dev/null
+++ b/funtools/wcs/Readme
@@ -0,0 +1,36 @@
+WCSsubs Subroutines
+
+These subroutines, developed as part of the WCSTools software package,
+constitute a self-contained package for accessing the world coordinate
+systems of FITS or IRAF(.imh) images, with image header I/O contained
+in fitsfile.c and imhfile.c, and WCS initialization and use through the
+subroutines in wcs.c. WCS information for an image is kept in a single
+data structure defined in wcs.h. Pixel to WCS translations are done by
+calls to pix2wcst() or pix2wcs(). WCS to pixel translations are done
+by calls to wcs2pix() or wcsc2pix(). The contents of the files are
+briefly described in Files. Dependencies between these files are given
+in Makefile. Documentation, to some extent, is online at
+
+http://tdc-www.harvard.edu/software/wcstools/libwcs.wcs.html
+
+Documentation for the entire open-source WCSTools package is online at
+
+http://tdc-www.harvard.edu/software/wcstools/
+
+Projection code in wcspos.c is by Bill Cotton of NRAO and is
+protected by the Gnu Lesser General Public License, which is stated
+in the file COPYING. Projection code in wcslib.c,
+cel.c, lin.c, proj.c, wcstrig.c, and sph.c is by Mark Calabretta
+of CSIRO and is also protected by the Gnu Lesser General Public
+License. Code in slasubs.c is by Pat Wallace of the Starlink
+project at Cambridge University. Doug Mink is responsible for
+the rest of the code, unless otherwise noted in the source file.
+Unless otherwise noted, this code is Copyright 2003 by the
+Smithsonian Astrophysical Observatory and protected by the Gnu
+Lesser General Public License.
+
+-Jessica Mink (jmink@cfa.harvard.edu)
+ Telescope Data Center
+ Harvard-Smithsonian Center for Astrophysics
+ Cambridge, Massachusetts
+ http://tdc-www.harvard.edu/mink
diff --git a/funtools/wcs/cel.c b/funtools/wcs/cel.c
new file mode 100644
index 0000000..9109284
--- /dev/null
+++ b/funtools/wcs/cel.c
@@ -0,0 +1,474 @@
+/*=============================================================================
+*
+* WCSLIB - an implementation of the FITS WCS proposal.
+* Copyright (C) 1995-2002, Mark Calabretta
+*
+* This library 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 2 of the License, or (at your option) any later version.
+*
+* This library 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 this library; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*
+* Correspondence concerning WCSLIB may be directed to:
+* Internet email: mcalabre@atnf.csiro.au
+* Postal address: Dr. Mark Calabretta,
+* Australia Telescope National Facility,
+* P.O. Box 76,
+* Epping, NSW, 2121,
+* AUSTRALIA
+*
+*=============================================================================
+*
+* C routines which implement the FITS World Coordinate System (WCS)
+* convention.
+*
+* Summary of routines
+* -------------------
+* These routines are provided as drivers for the lower level spherical
+* coordinate transformation and projection routines. There are separate
+* driver routines for the forward, celfwd(), and reverse, celrev(),
+* transformations.
+*
+* An initialization routine, celset(), computes intermediate values from
+* the transformation parameters but need not be called explicitly - see the
+* explanation of cel.flag below.
+*
+*
+* Initialization routine; celset()
+* --------------------------------
+* Initializes members of a celprm data structure which hold intermediate
+* values. Note that this routine need not be called directly; it will be
+* invoked by celfwd() and celrev() if the "flag" structure member is
+* anything other than a predefined magic value.
+*
+* Given:
+* pcode[4] const char
+* WCS projection code (see below).
+*
+* Given and returned:
+* cel celprm* Spherical coordinate transformation parameters
+* (see below).
+* prj prjprm* Projection parameters (usage is described in the
+* prologue to "proj.c").
+*
+* Function return value:
+* int Error status
+* 0: Success.
+* 1: Invalid coordinate transformation parameters.
+* 2: Ill-conditioned coordinate transformation
+* parameters.
+*
+* Forward transformation; celfwd()
+* --------------------------------
+* Compute (x,y) coordinates in the plane of projection from celestial
+* coordinates (lng,lat).
+*
+* Given:
+* pcode[4] const char
+* WCS projection code (see below).
+* lng,lat const double
+* Celestial longitude and latitude of the projected
+* point, in degrees.
+*
+* Given and returned:
+* cel celprm* Spherical coordinate transformation parameters
+* (see below).
+*
+* Returned:
+* phi, double* Longitude and latitude in the native coordinate
+* theta system of the projection, in degrees.
+*
+* Given and returned:
+* prj prjprm* Projection parameters (usage is described in the
+* prologue to "proj.c").
+*
+* Returned:
+* x,y double* Projected coordinates, "degrees".
+*
+* Function return value:
+* int Error status
+* 0: Success.
+* 1: Invalid coordinate transformation parameters.
+* 2: Invalid projection parameters.
+* 3: Invalid value of (lng,lat).
+*
+* Reverse transformation; celrev()
+* --------------------------------
+* Compute the celestial coordinates (lng,lat) of the point with projected
+* coordinates (x,y).
+*
+* Given:
+* pcode[4] const char
+* WCS projection code (see below).
+* x,y const double
+* Projected coordinates, "degrees".
+*
+* Given and returned:
+* prj prjprm* Projection parameters (usage is described in the
+* prologue to "proj.c").
+*
+* Returned:
+* phi, double* Longitude and latitude in the native coordinate
+* theta system of the projection, in degrees.
+*
+* Given and returned:
+* cel celprm* Spherical coordinate transformation parameters
+* (see below).
+*
+* Returned:
+* lng,lat double* Celestial longitude and latitude of the projected
+* point, in degrees.
+*
+* Function return value:
+* int Error status
+* 0: Success.
+* 1: Invalid coordinate transformation parameters.
+* 2: Invalid projection parameters.
+* 3: Invalid value of (x,y).
+*
+* Coordinate transformation parameters
+* ------------------------------------
+* The celprm struct consists of the following:
+*
+* int flag
+* The celprm struct contains pointers to the forward and reverse
+* projection routines as well as intermediaries computed from the
+* reference coordinates (see below). Whenever the projection code
+* (pcode) or any of ref[4] are set or changed then this flag must be
+* set to zero to signal the initialization routine, celset(), to
+* redetermine the function pointers and recompute intermediaries.
+* Once this has been done pcode itself is ignored.
+*
+* double ref[4]
+* The first pair of values should be set to the celestial longitude
+* and latitude (usually right ascension and declination) of the
+* reference point of the projection. These are given by the CRVALn
+* keywords in FITS.
+*
+* The second pair of values are the native longitude of the celestial
+* pole and the celestial latitude of the native pole and correspond to
+* FITS keywords LONPOLE and LATPOLE.
+*
+* LONPOLE defaults to 0 degrees if the celestial latitude of the
+* reference point of the projection is greater than the native
+* latitude, otherwise 180 degrees. (This is the condition for the
+* celestial latitude to increase in the same direction as the native
+* latitude at the reference point.) ref[2] may be set to 999.0 to
+* indicate that the correct default should be substituted.
+*
+* In some circumstances the celestial latitude of the native pole may
+* be determined by the first three values only to within a sign and
+* LATPOLE is used to choose between the two solutions. LATPOLE is
+* set in ref[3] and the solution closest to this value is used to
+* reset ref[3]. It is therefore legitimate, for example, to set
+* ref[3] to 999.0 to choose the more northerly solution - the default
+* if the LATPOLE card is omitted from the FITS header. For the
+* special case where the reference point of the projection is at
+* native latitude zero, its celestial latitude is zero, and
+* LONPOLE = +/- 90 then the celestial latitude of the pole is not
+* determined by the first three reference values and LATPOLE
+* specifies it completely.
+*
+* The remaining members of the celprm struct are maintained by the
+* initialization routines and should not be modified. This is done for the
+* sake of efficiency and to allow an arbitrary number of contexts to be
+* maintained simultaneously.
+*
+* double euler[5]
+* Euler angles and associated intermediaries derived from the
+* coordinate reference values.
+*
+*
+* WCS projection codes
+* --------------------
+* Zenithals/azimuthals:
+* AZP: zenithal/azimuthal perspective
+* TAN: gnomonic
+* STG: stereographic
+* SIN: synthesis (generalized orthographic)
+* ARC: zenithal/azimuthal equidistant
+* ZPN: zenithal/azimuthal polynomial
+* ZEA: zenithal/azimuthal equal area
+* AIR: Airy
+*
+* Cylindricals:
+* CYP: cylindrical perspective
+* CEA: cylindrical equal area
+* CAR: Cartesian
+* MER: Mercator
+*
+* Pseudo-cylindricals:
+* SFL: Sanson-Flamsteed
+* PAR: parabolic
+* MOL: Mollweide
+*
+* Conventional:
+* AIT: Hammer-Aitoff
+*
+* Conics:
+* COP: conic perspective
+* COD: conic equidistant
+* COE: conic equal area
+* COO: conic orthomorphic
+*
+* Polyconics:
+* BON: Bonne
+* PCO: polyconic
+*
+* Quad-cubes:
+* TSC: tangential spherical cube
+* CSC: COBE quadrilateralized spherical cube
+* QSC: quadrilateralized spherical cube
+*
+* Author: Mark Calabretta, Australia Telescope National Facility
+* $Id: cel.c,v 2.14 2002/04/03 01:25:29 mcalabre Exp $
+*===========================================================================*/
+
+#include <math.h>
+#include <string.h>
+#include "wcslib.h"
+
+/* Map error number to error message for each function. */
+const char *celset_errmsg[] = {
+ 0,
+ "Invalid coordinate transformation parameters",
+ "Ill-conditioned coordinate transformation parameters"};
+
+const char *celfwd_errmsg[] = {
+ 0,
+ "Invalid coordinate transformation parameters",
+ "Invalid projection parameters",
+ "Invalid value of (lng,lat)"};
+
+const char *celrev_errmsg[] = {
+ 0,
+ "Invalid coordinate transformation parameters",
+ "Invalid projection parameters",
+ "Invalid value of (x,y)"};
+
+
+int
+celset(pcode, cel, prj)
+
+const char pcode[4];
+struct celprm *cel;
+struct prjprm *prj;
+
+{
+ int dophip;
+ const double tol = 1.0e-10;
+ double clat0, cphip, cthe0, slat0, sphip, sthe0;
+ double latp, latp1, latp2;
+ double u, v, x, y, z;
+
+ /* Initialize the projection driver routines. */
+ if (prjset(pcode, prj)) {
+ return 1;
+ }
+
+ /* Set default for native longitude of the celestial pole? */
+ dophip = (cel->ref[2] == 999.0);
+
+ /* Compute celestial coordinates of the native pole. */
+ if (prj->theta0 == 90.0) {
+ /* Reference point is at the native pole. */
+
+ if (dophip) {
+ /* Set default for longitude of the celestial pole. */
+ cel->ref[2] = 180.0;
+ }
+
+ latp = cel->ref[1];
+ cel->ref[3] = latp;
+
+ cel->euler[0] = cel->ref[0];
+ cel->euler[1] = 90.0 - latp;
+ } else {
+ /* Reference point away from the native pole. */
+
+ /* Set default for longitude of the celestial pole. */
+ if (dophip) {
+ cel->ref[2] = (cel->ref[1] < prj->theta0) ? 180.0 : 0.0;
+ }
+
+ clat0 = cosdeg (cel->ref[1]);
+ slat0 = sindeg (cel->ref[1]);
+ cphip = cosdeg (cel->ref[2]);
+ sphip = sindeg (cel->ref[2]);
+ cthe0 = cosdeg (prj->theta0);
+ sthe0 = sindeg (prj->theta0);
+
+ x = cthe0*cphip;
+ y = sthe0;
+ z = sqrt(x*x + y*y);
+ if (z == 0.0) {
+ if (slat0 != 0.0) {
+ return 1;
+ }
+
+ /* latp determined by LATPOLE in this case. */
+ latp = cel->ref[3];
+ } else {
+ if (fabs(slat0/z) > 1.0) {
+ return 1;
+ }
+
+ u = atan2deg (y,x);
+ v = acosdeg (slat0/z);
+
+ latp1 = u + v;
+ if (latp1 > 180.0) {
+ latp1 -= 360.0;
+ } else if (latp1 < -180.0) {
+ latp1 += 360.0;
+ }
+
+ latp2 = u - v;
+ if (latp2 > 180.0) {
+ latp2 -= 360.0;
+ } else if (latp2 < -180.0) {
+ latp2 += 360.0;
+ }
+
+ if (fabs(cel->ref[3]-latp1) < fabs(cel->ref[3]-latp2)) {
+ if (fabs(latp1) < 90.0+tol) {
+ latp = latp1;
+ } else {
+ latp = latp2;
+ }
+ } else {
+ if (fabs(latp2) < 90.0+tol) {
+ latp = latp2;
+ } else {
+ latp = latp1;
+ }
+ }
+
+ cel->ref[3] = latp;
+ }
+
+ cel->euler[1] = 90.0 - latp;
+
+ z = cosdeg (latp)*clat0;
+ if (fabs(z) < tol) {
+ if (fabs(clat0) < tol) {
+ /* Celestial pole at the reference point. */
+ cel->euler[0] = cel->ref[0];
+ cel->euler[1] = 90.0 - prj->theta0;
+ } else if (latp > 0.0) {
+ /* Celestial pole at the native north pole.*/
+ cel->euler[0] = cel->ref[0] + cel->ref[2] - 180.0;
+ cel->euler[1] = 0.0;
+ } else if (latp < 0.0) {
+ /* Celestial pole at the native south pole. */
+ cel->euler[0] = cel->ref[0] - cel->ref[2];
+ cel->euler[1] = 180.0;
+ }
+ } else {
+ x = (sthe0 - sindeg (latp)*slat0)/z;
+ y = sphip*cthe0/clat0;
+ if (x == 0.0 && y == 0.0) {
+ return 1;
+ }
+ cel->euler[0] = cel->ref[0] - atan2deg (y,x);
+ }
+
+ /* Make euler[0] the same sign as ref[0]. */
+ if (cel->ref[0] >= 0.0) {
+ if (cel->euler[0] < 0.0) cel->euler[0] += 360.0;
+ } else {
+ if (cel->euler[0] > 0.0) cel->euler[0] -= 360.0;
+ }
+ }
+
+ cel->euler[2] = cel->ref[2];
+ cel->euler[3] = cosdeg (cel->euler[1]);
+ cel->euler[4] = sindeg (cel->euler[1]);
+ cel->flag = CELSET;
+
+ /* Check for ill-conditioned parameters. */
+ if (fabs(latp) > 90.0+tol) {
+ return 2;
+ }
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int
+celfwd(pcode, lng, lat, cel, phi, theta, prj, x, y)
+
+const char pcode[4];
+const double lng, lat;
+struct celprm *cel;
+double *phi, *theta;
+struct prjprm *prj;
+double *x, *y;
+
+{
+ int err;
+
+ if (cel->flag != CELSET) {
+ if (celset(pcode, cel, prj)) return 1;
+ }
+
+ /* Compute native coordinates. */
+ sphfwd(lng, lat, cel->euler, phi, theta);
+
+ /* Apply forward projection. */
+ if ((err = prj->prjfwd(*phi, *theta, prj, x, y))) {
+ return err == 1 ? 2 : 3;
+ }
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int
+celrev(pcode, x, y, prj, phi, theta, cel, lng, lat)
+
+const char pcode[4];
+const double x, y;
+struct prjprm *prj;
+double *phi, *theta;
+struct celprm *cel;
+double *lng, *lat;
+
+{
+ int err;
+
+ if (cel->flag != CELSET) {
+ if(celset(pcode, cel, prj)) return 1;
+ }
+
+ /* Apply reverse projection. */
+ if ((err = prj->prjrev(x, y, prj, phi, theta))) {
+ return err == 1 ? 2 : 3;
+ }
+
+ /* Compute native coordinates. */
+ sphrev(*phi, *theta, cel->euler, lng, lat);
+
+ return 0;
+}
+
+/* Dec 20 1999 Doug Mink - Change cosd() and sind() to cosdeg() and sindeg()
+ * Dec 20 1999 Doug Mink - Include wcslib.h, which includes wcsmath.h and cel.h
+ *
+ * Dec 18 2000 Doug Mink - Include string.h for strcmp()
+ *
+ * Mar 20 2001 Doug Mink - Add () around err assignments in if statements
+ * Sep 19 2001 Doug Mink - Add above changes to WCSLIB-2.7 cel.c
+ *
+ * Mar 12 2002 Doug Mink - Add changes to WCSLIB-2.8.2 cel.c
+ */
diff --git a/funtools/wcs/conf.h.in b/funtools/wcs/conf.h.in
new file mode 100644
index 0000000..e60ee1d
--- /dev/null
+++ b/funtools/wcs/conf.h.in
@@ -0,0 +1,56 @@
+/* Define as 1 if you have string.h */
+#undef HAVE_STRING_H
+
+/* Define as 1 if you have stdlib.h */
+#undef HAVE_STDLIB_H
+
+/* Define as 1 if you have malloc.h */
+#undef HAVE_MALLOC_H
+
+/* Define as 1 if you have unistd.h */
+#undef HAVE_UNISTD_H
+
+/* Define as 1 if you have getopt.h */
+#undef HAVE_GETOPT_H
+
+/* Define as 1 if you have values.h */
+#undef HAVE_VALUES_H
+
+/* Define as 1 if you have dlfcn.h */
+#undef HAVE_DLFCN_H
+
+/* Define as 1 if you have sys/un.h */
+#undef HAVE_SYS_UN_H
+
+/* Define as 1 if you have sys/shm.h */
+#undef HAVE_SYS_SHM_H
+
+/* Define as 1 if you have sys/mman.h */
+#undef HAVE_SYS_MMAN_H
+
+/* Define as 1 if you have sys/ipc.h */
+#undef HAVE_SYS_IPC_H
+
+/* Define as 1 if you have socklen_t */
+#undef HAVE_SOCKLEN_T
+
+/* Define as 1 if you have strchr */
+#undef HAVE_STRCHR
+
+/* Define as 1 if you have memcpy */
+#undef HAVE_MEMCPY
+
+/* Define as 1 if you have snprintf */
+#undef HAVE_SNPRINTF
+
+/* Define as 1 if you have Tcl */
+#undef HAVE_TCL
+
+/* Define as 1 if you have Xt */
+#undef HAVE_XT
+
+/* Define as 1 if you are running Cygwin. */
+#undef HAVE_CYGWIN
+
+/* Define as 1 if you are running MinGW. */
+#undef HAVE_MINGW32
diff --git a/funtools/wcs/config.guess b/funtools/wcs/config.guess
new file mode 100644
index 0000000..44290b8
--- /dev/null
+++ b/funtools/wcs/config.guess
@@ -0,0 +1,1435 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+# Copyright 1992-2015 Free Software Foundation, Inc.
+
+timestamp='2015-02-23'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program 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
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that
+# program. This Exception is an additional permission under section 7
+# of the GNU General Public License, version 3 ("GPLv3").
+#
+# Originally written by Per Bothner; maintained since 2000 by Ben Elliston.
+#
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+#
+# Please send patches to <config-patches@gnu.org>.
+
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright 1992-2015 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit ;;
+ --version | -v )
+ echo "$version" ; exit ;;
+ --help | --h* | -h )
+ echo "$usage"; exit ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help" >&2
+ exit 1 ;;
+ * )
+ break ;;
+ esac
+done
+
+if test $# != 0; then
+ echo "$me: too many arguments$help" >&2
+ exit 1
+fi
+
+trap 'exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,) echo "int x;" > $dummy.c ;
+ for c in cc gcc c89 c99 ; do
+ if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+ CC_FOR_BUILD="$c"; break ;
+ fi ;
+ done ;
+ if test x"$CC_FOR_BUILD" = x ; then
+ CC_FOR_BUILD=no_compiler_found ;
+ fi
+ ;;
+ ,,*) CC_FOR_BUILD=$CC ;;
+ ,*,*) CC_FOR_BUILD=$HOST_CC ;;
+esac ; set_cc_for_build= ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+ PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+case "${UNAME_SYSTEM}" in
+Linux|GNU|GNU/*)
+ # If the system lacks a compiler, then just pick glibc.
+ # We could probably try harder.
+ LIBC=gnu
+
+ eval $set_cc_for_build
+ cat <<-EOF > $dummy.c
+ #include <features.h>
+ #if defined(__UCLIBC__)
+ LIBC=uclibc
+ #elif defined(__dietlibc__)
+ LIBC=dietlibc
+ #else
+ LIBC=gnu
+ #endif
+ EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`
+ ;;
+esac
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+ *:NetBSD:*:*)
+ # NetBSD (nbsd) targets should (where applicable) match one or
+ # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*,
+ # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently
+ # switched to ELF, *-*-netbsd* would select the old
+ # object file format. This provides both forward
+ # compatibility and a consistent mechanism for selecting the
+ # object file format.
+ #
+ # Note: NetBSD doesn't particularly care about the vendor
+ # portion of the name. We always set it to "unknown".
+ sysctl="sysctl -n hw.machine_arch"
+ UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \
+ /sbin/$sysctl 2>/dev/null || \
+ /usr/sbin/$sysctl 2>/dev/null || \
+ echo unknown)`
+ case "${UNAME_MACHINE_ARCH}" in
+ armeb) machine=armeb-unknown ;;
+ arm*) machine=arm-unknown ;;
+ sh3el) machine=shl-unknown ;;
+ sh3eb) machine=sh-unknown ;;
+ sh5el) machine=sh5le-unknown ;;
+ earmv*)
+ arch=`echo ${UNAME_MACHINE_ARCH} | sed -e 's,^e\(armv[0-9]\).*$,\1,'`
+ endian=`echo ${UNAME_MACHINE_ARCH} | sed -ne 's,^.*\(eb\)$,\1,p'`
+ machine=${arch}${endian}-unknown
+ ;;
+ *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+ esac
+ # The Operating System including object format, if it has switched
+ # to ELF recently, or will in the future.
+ case "${UNAME_MACHINE_ARCH}" in
+ arm*|earm*|i386|m68k|ns32k|sh3*|sparc|vax)
+ eval $set_cc_for_build
+ if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ELF__
+ then
+ # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+ # Return netbsd for either. FIX?
+ os=netbsd
+ else
+ os=netbsdelf
+ fi
+ ;;
+ *)
+ os=netbsd
+ ;;
+ esac
+ # Determine ABI tags.
+ case "${UNAME_MACHINE_ARCH}" in
+ earm*)
+ expr='s/^earmv[0-9]/-eabi/;s/eb$//'
+ abi=`echo ${UNAME_MACHINE_ARCH} | sed -e "$expr"`
+ ;;
+ esac
+ # The OS release
+ # Debian GNU/NetBSD machines have a different userland, and
+ # thus, need a distinct triplet. However, they do not need
+ # kernel version information, so it can be replaced with a
+ # suitable tag, in the style of linux-gnu.
+ case "${UNAME_VERSION}" in
+ Debian*)
+ release='-gnu'
+ ;;
+ *)
+ release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ ;;
+ esac
+ # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+ # contains redundant information, the shorter form:
+ # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+ echo "${machine}-${os}${release}${abi}"
+ exit ;;
+ *:Bitrig:*:*)
+ UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`
+ echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE}
+ exit ;;
+ *:OpenBSD:*:*)
+ UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+ echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
+ exit ;;
+ *:ekkoBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
+ exit ;;
+ *:SolidBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}
+ exit ;;
+ macppc:MirBSD:*:*)
+ echo powerpc-unknown-mirbsd${UNAME_RELEASE}
+ exit ;;
+ *:MirBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
+ exit ;;
+ alpha:OSF1:*:*)
+ case $UNAME_RELEASE in
+ *4.0)
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+ ;;
+ *5.*)
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+ ;;
+ esac
+ # According to Compaq, /usr/sbin/psrinfo has been available on
+ # OSF/1 and Tru64 systems produced since 1995. I hope that
+ # covers most systems running today. This code pipes the CPU
+ # types through head -n 1, so we only detect the type of CPU 0.
+ ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+ case "$ALPHA_CPU_TYPE" in
+ "EV4 (21064)")
+ UNAME_MACHINE="alpha" ;;
+ "EV4.5 (21064)")
+ UNAME_MACHINE="alpha" ;;
+ "LCA4 (21066/21068)")
+ UNAME_MACHINE="alpha" ;;
+ "EV5 (21164)")
+ UNAME_MACHINE="alphaev5" ;;
+ "EV5.6 (21164A)")
+ UNAME_MACHINE="alphaev56" ;;
+ "EV5.6 (21164PC)")
+ UNAME_MACHINE="alphapca56" ;;
+ "EV5.7 (21164PC)")
+ UNAME_MACHINE="alphapca57" ;;
+ "EV6 (21264)")
+ UNAME_MACHINE="alphaev6" ;;
+ "EV6.7 (21264A)")
+ UNAME_MACHINE="alphaev67" ;;
+ "EV6.8CB (21264C)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.8AL (21264B)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.8CX (21264D)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.9A (21264/EV69A)")
+ UNAME_MACHINE="alphaev69" ;;
+ "EV7 (21364)")
+ UNAME_MACHINE="alphaev7" ;;
+ "EV7.9 (21364A)")
+ UNAME_MACHINE="alphaev79" ;;
+ esac
+ # A Pn.n version is a patched version.
+ # A Vn.n version is a released version.
+ # A Tn.n version is a released field test version.
+ # A Xn.n version is an unreleased experimental baselevel.
+ # 1.2 uses "1.2" for uname -r.
+ echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ # Reset EXIT trap before exiting to avoid spurious non-zero exit code.
+ exitcode=$?
+ trap '' 0
+ exit $exitcode ;;
+ Alpha\ *:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # Should we change UNAME_MACHINE based on the output of uname instead
+ # of the specific Alpha model?
+ echo alpha-pc-interix
+ exit ;;
+ 21064:Windows_NT:50:3)
+ echo alpha-dec-winnt3.5
+ exit ;;
+ Amiga*:UNIX_System_V:4.0:*)
+ echo m68k-unknown-sysv4
+ exit ;;
+ *:[Aa]miga[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-amigaos
+ exit ;;
+ *:[Mm]orph[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-morphos
+ exit ;;
+ *:OS/390:*:*)
+ echo i370-ibm-openedition
+ exit ;;
+ *:z/VM:*:*)
+ echo s390-ibm-zvmoe
+ exit ;;
+ *:OS400:*:*)
+ echo powerpc-ibm-os400
+ exit ;;
+ arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+ echo arm-acorn-riscix${UNAME_RELEASE}
+ exit ;;
+ arm*:riscos:*:*|arm*:RISCOS:*:*)
+ echo arm-unknown-riscos
+ exit ;;
+ SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+ echo hppa1.1-hitachi-hiuxmpp
+ exit ;;
+ Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+ # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+ if test "`(/bin/universe) 2>/dev/null`" = att ; then
+ echo pyramid-pyramid-sysv3
+ else
+ echo pyramid-pyramid-bsd
+ fi
+ exit ;;
+ NILE*:*:*:dcosx)
+ echo pyramid-pyramid-svr4
+ exit ;;
+ DRS?6000:unix:4.0:6*)
+ echo sparc-icl-nx6
+ exit ;;
+ DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
+ case `/usr/bin/uname -p` in
+ sparc) echo sparc-icl-nx7; exit ;;
+ esac ;;
+ s390x:SunOS:*:*)
+ echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4H:SunOS:5.*:*)
+ echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+ echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
+ echo i386-pc-auroraux${UNAME_RELEASE}
+ exit ;;
+ i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
+ eval $set_cc_for_build
+ SUN_ARCH="i386"
+ # If there is a compiler, see if it is configured for 64-bit objects.
+ # Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
+ # This test works for both compilers.
+ if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+ if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
+ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_64BIT_ARCH >/dev/null
+ then
+ SUN_ARCH="x86_64"
+ fi
+ fi
+ echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:6*:*)
+ # According to config.sub, this is the proper way to canonicalize
+ # SunOS6. Hard to guess exactly what SunOS6 will be like, but
+ # it's likely to be more like Solaris than SunOS4.
+ echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:*:*)
+ case "`/usr/bin/arch -k`" in
+ Series*|S4*)
+ UNAME_RELEASE=`uname -v`
+ ;;
+ esac
+ # Japanese Language versions have a version number like `4.1.3-JL'.
+ echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+ exit ;;
+ sun3*:SunOS:*:*)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ exit ;;
+ sun*:*:4.2BSD:*)
+ UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+ test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+ case "`/bin/arch`" in
+ sun3)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ ;;
+ sun4)
+ echo sparc-sun-sunos${UNAME_RELEASE}
+ ;;
+ esac
+ exit ;;
+ aushp:SunOS:*:*)
+ echo sparc-auspex-sunos${UNAME_RELEASE}
+ exit ;;
+ # The situation for MiNT is a little confusing. The machine name
+ # can be virtually everything (everything which is not
+ # "atarist" or "atariste" at least should have a processor
+ # > m68000). The system name ranges from "MiNT" over "FreeMiNT"
+ # to the lowercase version "mint" (or "freemint"). Finally
+ # the system name "TOS" denotes a system which is actually not
+ # MiNT. But MiNT is downward compatible to TOS, so this should
+ # be no problem.
+ atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+ echo m68k-milan-mint${UNAME_RELEASE}
+ exit ;;
+ hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+ echo m68k-hades-mint${UNAME_RELEASE}
+ exit ;;
+ *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+ echo m68k-unknown-mint${UNAME_RELEASE}
+ exit ;;
+ m68k:machten:*:*)
+ echo m68k-apple-machten${UNAME_RELEASE}
+ exit ;;
+ powerpc:machten:*:*)
+ echo powerpc-apple-machten${UNAME_RELEASE}
+ exit ;;
+ RISC*:Mach:*:*)
+ echo mips-dec-mach_bsd4.3
+ exit ;;
+ RISC*:ULTRIX:*:*)
+ echo mips-dec-ultrix${UNAME_RELEASE}
+ exit ;;
+ VAX*:ULTRIX*:*:*)
+ echo vax-dec-ultrix${UNAME_RELEASE}
+ exit ;;
+ 2020:CLIX:*:* | 2430:CLIX:*:*)
+ echo clipper-intergraph-clix${UNAME_RELEASE}
+ exit ;;
+ mips:*:*:UMIPS | mips:*:*:RISCos)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h> /* for printf() prototype */
+ int main (int argc, char *argv[]) {
+#else
+ int main (argc, argv) int argc; char *argv[]; {
+#endif
+ #if defined (host_mips) && defined (MIPSEB)
+ #if defined (SYSTYPE_SYSV)
+ printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_SVR4)
+ printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+ printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+ #endif
+ #endif
+ exit (-1);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c &&
+ dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
+ SYSTEM_NAME=`$dummy $dummyarg` &&
+ { echo "$SYSTEM_NAME"; exit; }
+ echo mips-mips-riscos${UNAME_RELEASE}
+ exit ;;
+ Motorola:PowerMAX_OS:*:*)
+ echo powerpc-motorola-powermax
+ exit ;;
+ Motorola:*:4.3:PL8-*)
+ echo powerpc-harris-powermax
+ exit ;;
+ Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+ echo powerpc-harris-powermax
+ exit ;;
+ Night_Hawk:Power_UNIX:*:*)
+ echo powerpc-harris-powerunix
+ exit ;;
+ m88k:CX/UX:7*:*)
+ echo m88k-harris-cxux7
+ exit ;;
+ m88k:*:4*:R4*)
+ echo m88k-motorola-sysv4
+ exit ;;
+ m88k:*:3*:R3*)
+ echo m88k-motorola-sysv3
+ exit ;;
+ AViiON:dgux:*:*)
+ # DG/UX returns AViiON for all architectures
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
+ if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+ then
+ if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+ [ ${TARGET_BINARY_INTERFACE}x = x ]
+ then
+ echo m88k-dg-dgux${UNAME_RELEASE}
+ else
+ echo m88k-dg-dguxbcs${UNAME_RELEASE}
+ fi
+ else
+ echo i586-dg-dgux${UNAME_RELEASE}
+ fi
+ exit ;;
+ M88*:DolphinOS:*:*) # DolphinOS (SVR3)
+ echo m88k-dolphin-sysv3
+ exit ;;
+ M88*:*:R3*:*)
+ # Delta 88k system running SVR3
+ echo m88k-motorola-sysv3
+ exit ;;
+ XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+ echo m88k-tektronix-sysv3
+ exit ;;
+ Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+ echo m68k-tektronix-bsd
+ exit ;;
+ *:IRIX*:*:*)
+ echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+ exit ;;
+ ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+ echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
+ exit ;; # Note that: echo "'`uname -s`'" gives 'AIX '
+ i*86:AIX:*:*)
+ echo i386-ibm-aix
+ exit ;;
+ ia64:AIX:*:*)
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+ exit ;;
+ *:AIX:2:3)
+ if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <sys/systemcfg.h>
+
+ main()
+ {
+ if (!__power_pc())
+ exit(1);
+ puts("powerpc-ibm-aix3.2.5");
+ exit(0);
+ }
+EOF
+ if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
+ then
+ echo "$SYSTEM_NAME"
+ else
+ echo rs6000-ibm-aix3.2.5
+ fi
+ elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+ echo rs6000-ibm-aix3.2.4
+ else
+ echo rs6000-ibm-aix3.2
+ fi
+ exit ;;
+ *:AIX:*:[4567])
+ IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+ if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+ IBM_ARCH=rs6000
+ else
+ IBM_ARCH=powerpc
+ fi
+ if [ -x /usr/bin/lslpp ] ; then
+ IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc |
+ awk -F: '{ print $3 }' | sed s/[0-9]*$/0/`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+ exit ;;
+ *:AIX:*:*)
+ echo rs6000-ibm-aix
+ exit ;;
+ ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+ echo romp-ibm-bsd4.4
+ exit ;;
+ ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and
+ echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to
+ exit ;; # report: romp-ibm BSD 4.3
+ *:BOSX:*:*)
+ echo rs6000-bull-bosx
+ exit ;;
+ DPX/2?00:B.O.S.:*:*)
+ echo m68k-bull-sysv3
+ exit ;;
+ 9000/[34]??:4.3bsd:1.*:*)
+ echo m68k-hp-bsd
+ exit ;;
+ hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+ echo m68k-hp-bsd4.4
+ exit ;;
+ 9000/[34678]??:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ case "${UNAME_MACHINE}" in
+ 9000/31? ) HP_ARCH=m68000 ;;
+ 9000/[34]?? ) HP_ARCH=m68k ;;
+ 9000/[678][0-9][0-9])
+ if [ -x /usr/bin/getconf ]; then
+ sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+ sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+ case "${sc_cpu_version}" in
+ 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+ 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+ 532) # CPU_PA_RISC2_0
+ case "${sc_kernel_bits}" in
+ 32) HP_ARCH="hppa2.0n" ;;
+ 64) HP_ARCH="hppa2.0w" ;;
+ '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20
+ esac ;;
+ esac
+ fi
+ if [ "${HP_ARCH}" = "" ]; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+
+ #define _HPUX_SOURCE
+ #include <stdlib.h>
+ #include <unistd.h>
+
+ int main ()
+ {
+ #if defined(_SC_KERNEL_BITS)
+ long bits = sysconf(_SC_KERNEL_BITS);
+ #endif
+ long cpu = sysconf (_SC_CPU_VERSION);
+
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+ case CPU_PA_RISC2_0:
+ #if defined(_SC_KERNEL_BITS)
+ switch (bits)
+ {
+ case 64: puts ("hppa2.0w"); break;
+ case 32: puts ("hppa2.0n"); break;
+ default: puts ("hppa2.0"); break;
+ } break;
+ #else /* !defined(_SC_KERNEL_BITS) */
+ puts ("hppa2.0"); break;
+ #endif
+ default: puts ("hppa1.0"); break;
+ }
+ exit (0);
+ }
+EOF
+ (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+ test -z "$HP_ARCH" && HP_ARCH=hppa
+ fi ;;
+ esac
+ if [ ${HP_ARCH} = "hppa2.0w" ]
+ then
+ eval $set_cc_for_build
+
+ # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
+ # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler
+ # generating 64-bit code. GNU and HP use different nomenclature:
+ #
+ # $ CC_FOR_BUILD=cc ./config.guess
+ # => hppa2.0w-hp-hpux11.23
+ # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
+ # => hppa64-hp-hpux11.23
+
+ if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
+ grep -q __LP64__
+ then
+ HP_ARCH="hppa2.0w"
+ else
+ HP_ARCH="hppa64"
+ fi
+ fi
+ echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+ exit ;;
+ ia64:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ echo ia64-hp-hpux${HPUX_REV}
+ exit ;;
+ 3050*:HI-UX:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <unistd.h>
+ int
+ main ()
+ {
+ long cpu = sysconf (_SC_CPU_VERSION);
+ /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+ true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
+ results, however. */
+ if (CPU_IS_PA_RISC (cpu))
+ {
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+ default: puts ("hppa-hitachi-hiuxwe2"); break;
+ }
+ }
+ else if (CPU_IS_HP_MC68K (cpu))
+ puts ("m68k-hitachi-hiuxwe2");
+ else puts ("unknown-hitachi-hiuxwe2");
+ exit (0);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
+ { echo "$SYSTEM_NAME"; exit; }
+ echo unknown-hitachi-hiuxwe2
+ exit ;;
+ 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+ echo hppa1.1-hp-bsd
+ exit ;;
+ 9000/8??:4.3bsd:*:*)
+ echo hppa1.0-hp-bsd
+ exit ;;
+ *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+ echo hppa1.0-hp-mpeix
+ exit ;;
+ hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+ echo hppa1.1-hp-osf
+ exit ;;
+ hp8??:OSF1:*:*)
+ echo hppa1.0-hp-osf
+ exit ;;
+ i*86:OSF1:*:*)
+ if [ -x /usr/sbin/sysversion ] ; then
+ echo ${UNAME_MACHINE}-unknown-osf1mk
+ else
+ echo ${UNAME_MACHINE}-unknown-osf1
+ fi
+ exit ;;
+ parisc*:Lites*:*:*)
+ echo hppa1.1-hp-lites
+ exit ;;
+ C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+ echo c1-convex-bsd
+ exit ;;
+ C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit ;;
+ C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+ echo c34-convex-bsd
+ exit ;;
+ C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+ echo c38-convex-bsd
+ exit ;;
+ C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+ echo c4-convex-bsd
+ exit ;;
+ CRAY*Y-MP:*:*:*)
+ echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*[A-Z]90:*:*:*)
+ echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+ -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*TS:*:*:*)
+ echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*T3E:*:*:*)
+ echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*SV1:*:*:*)
+ echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ *:UNICOS/mp:*:*)
+ echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+ FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+ echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
+ 5000:UNIX_System_V:4.*:*)
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
+ echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
+ i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+ echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+ exit ;;
+ sparc*:BSD/OS:*:*)
+ echo sparc-unknown-bsdi${UNAME_RELEASE}
+ exit ;;
+ *:BSD/OS:*:*)
+ echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+ exit ;;
+ *:FreeBSD:*:*)
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
+ case ${UNAME_PROCESSOR} in
+ amd64)
+ echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+ *)
+ echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+ esac
+ exit ;;
+ i*:CYGWIN*:*)
+ echo ${UNAME_MACHINE}-pc-cygwin
+ exit ;;
+ *:MINGW64*:*)
+ echo ${UNAME_MACHINE}-pc-mingw64
+ exit ;;
+ *:MINGW*:*)
+ echo ${UNAME_MACHINE}-pc-mingw32
+ exit ;;
+ *:MSYS*:*)
+ echo ${UNAME_MACHINE}-pc-msys
+ exit ;;
+ i*:windows32*:*)
+ # uname -m includes "-pc" on this system.
+ echo ${UNAME_MACHINE}-mingw32
+ exit ;;
+ i*:PW*:*)
+ echo ${UNAME_MACHINE}-pc-pw32
+ exit ;;
+ *:Interix*:*)
+ case ${UNAME_MACHINE} in
+ x86)
+ echo i586-pc-interix${UNAME_RELEASE}
+ exit ;;
+ authenticamd | genuineintel | EM64T)
+ echo x86_64-unknown-interix${UNAME_RELEASE}
+ exit ;;
+ IA64)
+ echo ia64-unknown-interix${UNAME_RELEASE}
+ exit ;;
+ esac ;;
+ [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+ echo i${UNAME_MACHINE}-pc-mks
+ exit ;;
+ 8664:Windows_NT:*)
+ echo x86_64-pc-mks
+ exit ;;
+ i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+ # UNAME_MACHINE based on the output of uname instead of i386?
+ echo i586-pc-interix
+ exit ;;
+ i*:UWIN*:*)
+ echo ${UNAME_MACHINE}-pc-uwin
+ exit ;;
+ amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
+ echo x86_64-unknown-cygwin
+ exit ;;
+ p*:CYGWIN*:*)
+ echo powerpcle-unknown-cygwin
+ exit ;;
+ prep*:SunOS:5.*:*)
+ echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ *:GNU:*:*)
+ # the GNU system
+ echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+ exit ;;
+ *:GNU/*:*:*)
+ # other systems with GNU libc and userland
+ echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC}
+ exit ;;
+ i*86:Minix:*:*)
+ echo ${UNAME_MACHINE}-pc-minix
+ exit ;;
+ aarch64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ aarch64_be:Linux:*:*)
+ UNAME_MACHINE=aarch64_be
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ alpha:Linux:*:*)
+ case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+ EV5) UNAME_MACHINE=alphaev5 ;;
+ EV56) UNAME_MACHINE=alphaev56 ;;
+ PCA56) UNAME_MACHINE=alphapca56 ;;
+ PCA57) UNAME_MACHINE=alphapca56 ;;
+ EV6) UNAME_MACHINE=alphaev6 ;;
+ EV67) UNAME_MACHINE=alphaev67 ;;
+ EV68*) UNAME_MACHINE=alphaev68 ;;
+ esac
+ objdump --private-headers /bin/sh | grep -q ld.so.1
+ if test "$?" = 0 ; then LIBC="gnulibc1" ; fi
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ arc:Linux:*:* | arceb:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ arm*:Linux:*:*)
+ eval $set_cc_for_build
+ if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ARM_EABI__
+ then
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ else
+ if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ARM_PCS_VFP
+ then
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi
+ else
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf
+ fi
+ fi
+ exit ;;
+ avr32*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ cris:Linux:*:*)
+ echo ${UNAME_MACHINE}-axis-linux-${LIBC}
+ exit ;;
+ crisv32:Linux:*:*)
+ echo ${UNAME_MACHINE}-axis-linux-${LIBC}
+ exit ;;
+ frv:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ hexagon:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ i*86:Linux:*:*)
+ echo ${UNAME_MACHINE}-pc-linux-${LIBC}
+ exit ;;
+ ia64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ m32r*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ m68*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ mips:Linux:*:* | mips64:Linux:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #undef CPU
+ #undef ${UNAME_MACHINE}
+ #undef ${UNAME_MACHINE}el
+ #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+ CPU=${UNAME_MACHINE}el
+ #else
+ #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+ CPU=${UNAME_MACHINE}
+ #else
+ CPU=
+ #endif
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
+ test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; }
+ ;;
+ openrisc*:Linux:*:*)
+ echo or1k-unknown-linux-${LIBC}
+ exit ;;
+ or32:Linux:*:* | or1k*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ padre:Linux:*:*)
+ echo sparc-unknown-linux-${LIBC}
+ exit ;;
+ parisc64:Linux:*:* | hppa64:Linux:*:*)
+ echo hppa64-unknown-linux-${LIBC}
+ exit ;;
+ parisc:Linux:*:* | hppa:Linux:*:*)
+ # Look for CPU level
+ case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+ PA7*) echo hppa1.1-unknown-linux-${LIBC} ;;
+ PA8*) echo hppa2.0-unknown-linux-${LIBC} ;;
+ *) echo hppa-unknown-linux-${LIBC} ;;
+ esac
+ exit ;;
+ ppc64:Linux:*:*)
+ echo powerpc64-unknown-linux-${LIBC}
+ exit ;;
+ ppc:Linux:*:*)
+ echo powerpc-unknown-linux-${LIBC}
+ exit ;;
+ ppc64le:Linux:*:*)
+ echo powerpc64le-unknown-linux-${LIBC}
+ exit ;;
+ ppcle:Linux:*:*)
+ echo powerpcle-unknown-linux-${LIBC}
+ exit ;;
+ s390:Linux:*:* | s390x:Linux:*:*)
+ echo ${UNAME_MACHINE}-ibm-linux-${LIBC}
+ exit ;;
+ sh64*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ sh*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ sparc:Linux:*:* | sparc64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ tile*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ vax:Linux:*:*)
+ echo ${UNAME_MACHINE}-dec-linux-${LIBC}
+ exit ;;
+ x86_64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ xtensa*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ i*86:DYNIX/ptx:4*:*)
+ # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+ # earlier versions are messed up and put the nodename in both
+ # sysname and nodename.
+ echo i386-sequent-sysv4
+ exit ;;
+ i*86:UNIX_SV:4.2MP:2.*)
+ # Unixware is an offshoot of SVR4, but it has its own version
+ # number series starting with 2...
+ # I am not positive that other SVR4 systems won't match this,
+ # I just have to hope. -- rms.
+ # Use sysv4.2uw... so that sysv4* matches it.
+ echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+ exit ;;
+ i*86:OS/2:*:*)
+ # If we were able to find `uname', then EMX Unix compatibility
+ # is probably installed.
+ echo ${UNAME_MACHINE}-pc-os2-emx
+ exit ;;
+ i*86:XTS-300:*:STOP)
+ echo ${UNAME_MACHINE}-unknown-stop
+ exit ;;
+ i*86:atheos:*:*)
+ echo ${UNAME_MACHINE}-unknown-atheos
+ exit ;;
+ i*86:syllable:*:*)
+ echo ${UNAME_MACHINE}-pc-syllable
+ exit ;;
+ i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
+ echo i386-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ i*86:*DOS:*:*)
+ echo ${UNAME_MACHINE}-pc-msdosdjgpp
+ exit ;;
+ i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+ UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+ if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+ echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+ else
+ echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+ fi
+ exit ;;
+ i*86:*:5:[678]*)
+ # UnixWare 7.x, OpenUNIX and OpenServer 6.
+ case `/bin/uname -X | grep "^Machine"` in
+ *486*) UNAME_MACHINE=i486 ;;
+ *Pentium) UNAME_MACHINE=i586 ;;
+ *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+ esac
+ echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+ exit ;;
+ i*86:*:3.2:*)
+ if test -f /usr/options/cb.name; then
+ UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+ echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+ elif /bin/uname -X 2>/dev/null >/dev/null ; then
+ UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+ (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+ (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+ && UNAME_MACHINE=i586
+ (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+ && UNAME_MACHINE=i686
+ (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+ && UNAME_MACHINE=i686
+ echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+ else
+ echo ${UNAME_MACHINE}-pc-sysv32
+ fi
+ exit ;;
+ pc:*:*:*)
+ # Left here for compatibility:
+ # uname -m prints for DJGPP always 'pc', but it prints nothing about
+ # the processor, so we play safe by assuming i586.
+ # Note: whatever this is, it MUST be the same as what config.sub
+ # prints for the "djgpp" host, or else GDB configury will decide that
+ # this is a cross-build.
+ echo i586-pc-msdosdjgpp
+ exit ;;
+ Intel:Mach:3*:*)
+ echo i386-pc-mach3
+ exit ;;
+ paragon:*:*:*)
+ echo i860-intel-osf1
+ exit ;;
+ i860:*:4.*:*) # i860-SVR4
+ if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+ echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+ else # Add other i860-SVR4 vendors below as they are discovered.
+ echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4
+ fi
+ exit ;;
+ mini*:CTIX:SYS*5:*)
+ # "miniframe"
+ echo m68010-convergent-sysv
+ exit ;;
+ mc68k:UNIX:SYSTEM5:3.51m)
+ echo m68k-convergent-sysv
+ exit ;;
+ M680?0:D-NIX:5.3:*)
+ echo m68k-diab-dnix
+ exit ;;
+ M68*:*:R3V[5678]*:*)
+ test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
+ 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
+ OS_REL=''
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+ 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4; exit; } ;;
+ NCR*:*:4.2:* | MPRAS*:*:4.2:*)
+ OS_REL='.3'
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+ m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+ echo m68k-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ mc68030:UNIX_System_V:4.*:*)
+ echo m68k-atari-sysv4
+ exit ;;
+ TSUNAMI:LynxOS:2.*:*)
+ echo sparc-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ rs6000:LynxOS:2.*:*)
+ echo rs6000-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
+ echo powerpc-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ SM[BE]S:UNIX_SV:*:*)
+ echo mips-dde-sysv${UNAME_RELEASE}
+ exit ;;
+ RM*:ReliantUNIX-*:*:*)
+ echo mips-sni-sysv4
+ exit ;;
+ RM*:SINIX-*:*:*)
+ echo mips-sni-sysv4
+ exit ;;
+ *:SINIX-*:*:*)
+ if uname -p 2>/dev/null >/dev/null ; then
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ echo ${UNAME_MACHINE}-sni-sysv4
+ else
+ echo ns32k-sni-sysv
+ fi
+ exit ;;
+ PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+ # says <Richard.M.Bartel@ccMail.Census.GOV>
+ echo i586-unisys-sysv4
+ exit ;;
+ *:UNIX_System_V:4*:FTX*)
+ # From Gerald Hewes <hewes@openmarket.com>.
+ # How about differentiating between stratus architectures? -djm
+ echo hppa1.1-stratus-sysv4
+ exit ;;
+ *:*:*:FTX*)
+ # From seanf@swdc.stratus.com.
+ echo i860-stratus-sysv4
+ exit ;;
+ i*86:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo ${UNAME_MACHINE}-stratus-vos
+ exit ;;
+ *:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo hppa1.1-stratus-vos
+ exit ;;
+ mc68*:A/UX:*:*)
+ echo m68k-apple-aux${UNAME_RELEASE}
+ exit ;;
+ news*:NEWS-OS:6*:*)
+ echo mips-sony-newsos6
+ exit ;;
+ R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+ if [ -d /usr/nec ]; then
+ echo mips-nec-sysv${UNAME_RELEASE}
+ else
+ echo mips-unknown-sysv${UNAME_RELEASE}
+ fi
+ exit ;;
+ BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
+ echo powerpc-be-beos
+ exit ;;
+ BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only.
+ echo powerpc-apple-beos
+ exit ;;
+ BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
+ echo i586-pc-beos
+ exit ;;
+ BePC:Haiku:*:*) # Haiku running on Intel PC compatible.
+ echo i586-pc-haiku
+ exit ;;
+ x86_64:Haiku:*:*)
+ echo x86_64-unknown-haiku
+ exit ;;
+ SX-4:SUPER-UX:*:*)
+ echo sx4-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-5:SUPER-UX:*:*)
+ echo sx5-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-6:SUPER-UX:*:*)
+ echo sx6-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-7:SUPER-UX:*:*)
+ echo sx7-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-8:SUPER-UX:*:*)
+ echo sx8-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-8R:SUPER-UX:*:*)
+ echo sx8r-nec-superux${UNAME_RELEASE}
+ exit ;;
+ Power*:Rhapsody:*:*)
+ echo powerpc-apple-rhapsody${UNAME_RELEASE}
+ exit ;;
+ *:Rhapsody:*:*)
+ echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+ exit ;;
+ *:Darwin:*:*)
+ UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
+ eval $set_cc_for_build
+ if test "$UNAME_PROCESSOR" = unknown ; then
+ UNAME_PROCESSOR=powerpc
+ fi
+ if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then
+ if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+ if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
+ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_64BIT_ARCH >/dev/null
+ then
+ case $UNAME_PROCESSOR in
+ i386) UNAME_PROCESSOR=x86_64 ;;
+ powerpc) UNAME_PROCESSOR=powerpc64 ;;
+ esac
+ fi
+ fi
+ elif test "$UNAME_PROCESSOR" = i386 ; then
+ # Avoid executing cc on OS X 10.9, as it ships with a stub
+ # that puts up a graphical alert prompting to install
+ # developer tools. Any system running Mac OS X 10.7 or
+ # later (Darwin 11 and later) is required to have a 64-bit
+ # processor. This is not true of the ARM version of Darwin
+ # that Apple uses in portable devices.
+ UNAME_PROCESSOR=x86_64
+ fi
+ echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+ exit ;;
+ *:procnto*:*:* | *:QNX:[0123456789]*:*)
+ UNAME_PROCESSOR=`uname -p`
+ if test "$UNAME_PROCESSOR" = "x86"; then
+ UNAME_PROCESSOR=i386
+ UNAME_MACHINE=pc
+ fi
+ echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+ exit ;;
+ *:QNX:*:4*)
+ echo i386-pc-qnx
+ exit ;;
+ NEO-?:NONSTOP_KERNEL:*:*)
+ echo neo-tandem-nsk${UNAME_RELEASE}
+ exit ;;
+ NSE-*:NONSTOP_KERNEL:*:*)
+ echo nse-tandem-nsk${UNAME_RELEASE}
+ exit ;;
+ NSR-?:NONSTOP_KERNEL:*:*)
+ echo nsr-tandem-nsk${UNAME_RELEASE}
+ exit ;;
+ *:NonStop-UX:*:*)
+ echo mips-compaq-nonstopux
+ exit ;;
+ BS2000:POSIX*:*:*)
+ echo bs2000-siemens-sysv
+ exit ;;
+ DS/*:UNIX_System_V:*:*)
+ echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+ exit ;;
+ *:Plan9:*:*)
+ # "uname -m" is not consistent, so use $cputype instead. 386
+ # is converted to i386 for consistency with other x86
+ # operating systems.
+ if test "$cputype" = "386"; then
+ UNAME_MACHINE=i386
+ else
+ UNAME_MACHINE="$cputype"
+ fi
+ echo ${UNAME_MACHINE}-unknown-plan9
+ exit ;;
+ *:TOPS-10:*:*)
+ echo pdp10-unknown-tops10
+ exit ;;
+ *:TENEX:*:*)
+ echo pdp10-unknown-tenex
+ exit ;;
+ KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+ echo pdp10-dec-tops20
+ exit ;;
+ XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+ echo pdp10-xkl-tops20
+ exit ;;
+ *:TOPS-20:*:*)
+ echo pdp10-unknown-tops20
+ exit ;;
+ *:ITS:*:*)
+ echo pdp10-unknown-its
+ exit ;;
+ SEI:*:*:SEIUX)
+ echo mips-sei-seiux${UNAME_RELEASE}
+ exit ;;
+ *:DragonFly:*:*)
+ echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+ exit ;;
+ *:*VMS:*:*)
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ case "${UNAME_MACHINE}" in
+ A*) echo alpha-dec-vms ; exit ;;
+ I*) echo ia64-dec-vms ; exit ;;
+ V*) echo vax-dec-vms ; exit ;;
+ esac ;;
+ *:XENIX:*:SysV)
+ echo i386-pc-xenix
+ exit ;;
+ i*86:skyos:*:*)
+ echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
+ exit ;;
+ i*86:rdos:*:*)
+ echo ${UNAME_MACHINE}-pc-rdos
+ exit ;;
+ i*86:AROS:*:*)
+ echo ${UNAME_MACHINE}-pc-aros
+ exit ;;
+ x86_64:VMkernel:*:*)
+ echo ${UNAME_MACHINE}-unknown-esx
+ exit ;;
+esac
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+ http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+and
+ http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches@gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo = `(hostinfo) 2>/dev/null`
+/bin/universe = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/funtools/wcs/config.sub b/funtools/wcs/config.sub
new file mode 100644
index 0000000..bc855a2
--- /dev/null
+++ b/funtools/wcs/config.sub
@@ -0,0 +1,1807 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+# Copyright 1992-2015 Free Software Foundation, Inc.
+
+timestamp='2015-02-22'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program 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
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that
+# program. This Exception is an additional permission under section 7
+# of the GNU General Public License, version 3 ("GPLv3").
+
+
+# Please send patches to <config-patches@gnu.org>.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support. The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+ $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright 1992-2015 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit ;;
+ --version | -v )
+ echo "$version" ; exit ;;
+ --help | --h* | -h )
+ echo "$usage"; exit ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help"
+ exit 1 ;;
+
+ *local*)
+ # First pass through any local machine types.
+ echo $1
+ exit ;;
+
+ * )
+ break ;;
+ esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+ exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+ exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+ nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
+ linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
+ knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \
+ kopensolaris*-gnu* | \
+ storm-chaos* | os2-emx* | rtmk-nova*)
+ os=-$maybe_os
+ basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+ ;;
+ android-linux)
+ os=-linux-android
+ basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown
+ ;;
+ *)
+ basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+ if [ $basic_machine != $1 ]
+ then os=`echo $1 | sed 's/.*-/-/'`
+ else os=; fi
+ ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work. We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+ -sun*os*)
+ # Prevent following clause from handling this invalid input.
+ ;;
+ -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+ -apple | -axis | -knuth | -cray | -microblaze*)
+ os=
+ basic_machine=$1
+ ;;
+ -bluegene*)
+ os=-cnk
+ ;;
+ -sim | -cisco | -oki | -wec | -winbond)
+ os=
+ basic_machine=$1
+ ;;
+ -scout)
+ ;;
+ -wrs)
+ os=-vxworks
+ basic_machine=$1
+ ;;
+ -chorusos*)
+ os=-chorusos
+ basic_machine=$1
+ ;;
+ -chorusrdb)
+ os=-chorusrdb
+ basic_machine=$1
+ ;;
+ -hiux*)
+ os=-hiuxwe2
+ ;;
+ -sco6)
+ os=-sco5v6
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco5)
+ os=-sco3.2v5
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco4)
+ os=-sco3.2v4
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2.[4-9]*)
+ os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2v[4-9]*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco5v6*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco*)
+ os=-sco3.2v2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -udk*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -isc)
+ os=-isc2.2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -clix*)
+ basic_machine=clipper-intergraph
+ ;;
+ -isc*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -lynx*178)
+ os=-lynxos178
+ ;;
+ -lynx*5)
+ os=-lynxos5
+ ;;
+ -lynx*)
+ os=-lynxos
+ ;;
+ -ptx*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+ ;;
+ -windowsnt*)
+ os=`echo $os | sed -e 's/windowsnt/winnt/'`
+ ;;
+ -psos*)
+ os=-psos
+ ;;
+ -mint | -mint[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+ # Recognize the basic CPU types without company name.
+ # Some are omitted here because they have special meanings below.
+ 1750a | 580 \
+ | a29k \
+ | aarch64 | aarch64_be \
+ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+ | am33_2.0 \
+ | arc | arceb \
+ | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \
+ | avr | avr32 \
+ | be32 | be64 \
+ | bfin \
+ | c4x | c8051 | clipper \
+ | d10v | d30v | dlx | dsp16xx \
+ | epiphany \
+ | fido | fr30 | frv | ft32 \
+ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+ | hexagon \
+ | i370 | i860 | i960 | ia64 \
+ | ip2k | iq2000 \
+ | k1om \
+ | le32 | le64 \
+ | lm32 \
+ | m32c | m32r | m32rle | m68000 | m68k | m88k \
+ | maxq | mb | microblaze | microblazeel | mcore | mep | metag \
+ | mips | mipsbe | mipseb | mipsel | mipsle \
+ | mips16 \
+ | mips64 | mips64el \
+ | mips64octeon | mips64octeonel \
+ | mips64orion | mips64orionel \
+ | mips64r5900 | mips64r5900el \
+ | mips64vr | mips64vrel \
+ | mips64vr4100 | mips64vr4100el \
+ | mips64vr4300 | mips64vr4300el \
+ | mips64vr5000 | mips64vr5000el \
+ | mips64vr5900 | mips64vr5900el \
+ | mipsisa32 | mipsisa32el \
+ | mipsisa32r2 | mipsisa32r2el \
+ | mipsisa32r6 | mipsisa32r6el \
+ | mipsisa64 | mipsisa64el \
+ | mipsisa64r2 | mipsisa64r2el \
+ | mipsisa64r6 | mipsisa64r6el \
+ | mipsisa64sb1 | mipsisa64sb1el \
+ | mipsisa64sr71k | mipsisa64sr71kel \
+ | mipsr5900 | mipsr5900el \
+ | mipstx39 | mipstx39el \
+ | mn10200 | mn10300 \
+ | moxie \
+ | mt \
+ | msp430 \
+ | nds32 | nds32le | nds32be \
+ | nios | nios2 | nios2eb | nios2el \
+ | ns16k | ns32k \
+ | open8 | or1k | or1knd | or32 \
+ | pdp10 | pdp11 | pj | pjl \
+ | powerpc | powerpc64 | powerpc64le | powerpcle \
+ | pyramid \
+ | riscv32 | riscv64 \
+ | rl78 | rx \
+ | score \
+ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
+ | sh64 | sh64le \
+ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
+ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \
+ | spu \
+ | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \
+ | ubicom32 \
+ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \
+ | visium \
+ | we32k \
+ | x86 | xc16x | xstormy16 | xtensa \
+ | z8k | z80)
+ basic_machine=$basic_machine-unknown
+ ;;
+ c54x)
+ basic_machine=tic54x-unknown
+ ;;
+ c55x)
+ basic_machine=tic55x-unknown
+ ;;
+ c6x)
+ basic_machine=tic6x-unknown
+ ;;
+ leon|leon[3-9])
+ basic_machine=sparc-$basic_machine
+ ;;
+ m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip)
+ basic_machine=$basic_machine-unknown
+ os=-none
+ ;;
+ m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+ ;;
+ ms1)
+ basic_machine=mt-unknown
+ ;;
+
+ strongarm | thumb | xscale)
+ basic_machine=arm-unknown
+ ;;
+ xgate)
+ basic_machine=$basic_machine-unknown
+ os=-none
+ ;;
+ xscaleeb)
+ basic_machine=armeb-unknown
+ ;;
+
+ xscaleel)
+ basic_machine=armel-unknown
+ ;;
+
+ # We use `pc' rather than `unknown'
+ # because (1) that's what they normally are, and
+ # (2) the word "unknown" tends to confuse beginning users.
+ i*86 | x86_64)
+ basic_machine=$basic_machine-pc
+ ;;
+ # Object if more than one company name word.
+ *-*-*)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+ # Recognize the basic CPU types with company name.
+ 580-* \
+ | a29k-* \
+ | aarch64-* | aarch64_be-* \
+ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \
+ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \
+ | avr-* | avr32-* \
+ | be32-* | be64-* \
+ | bfin-* | bs2000-* \
+ | c[123]* | c30-* | [cjt]90-* | c4x-* \
+ | c8051-* | clipper-* | craynv-* | cydra-* \
+ | d10v-* | d30v-* | dlx-* \
+ | elxsi-* \
+ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
+ | h8300-* | h8500-* \
+ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+ | hexagon-* \
+ | i*86-* | i860-* | i960-* | ia64-* \
+ | ip2k-* | iq2000-* \
+ | k1om-* \
+ | le32-* | le64-* \
+ | lm32-* \
+ | m32c-* | m32r-* | m32rle-* \
+ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \
+ | microblaze-* | microblazeel-* \
+ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+ | mips16-* \
+ | mips64-* | mips64el-* \
+ | mips64octeon-* | mips64octeonel-* \
+ | mips64orion-* | mips64orionel-* \
+ | mips64r5900-* | mips64r5900el-* \
+ | mips64vr-* | mips64vrel-* \
+ | mips64vr4100-* | mips64vr4100el-* \
+ | mips64vr4300-* | mips64vr4300el-* \
+ | mips64vr5000-* | mips64vr5000el-* \
+ | mips64vr5900-* | mips64vr5900el-* \
+ | mipsisa32-* | mipsisa32el-* \
+ | mipsisa32r2-* | mipsisa32r2el-* \
+ | mipsisa32r6-* | mipsisa32r6el-* \
+ | mipsisa64-* | mipsisa64el-* \
+ | mipsisa64r2-* | mipsisa64r2el-* \
+ | mipsisa64r6-* | mipsisa64r6el-* \
+ | mipsisa64sb1-* | mipsisa64sb1el-* \
+ | mipsisa64sr71k-* | mipsisa64sr71kel-* \
+ | mipsr5900-* | mipsr5900el-* \
+ | mipstx39-* | mipstx39el-* \
+ | mmix-* \
+ | mt-* \
+ | msp430-* \
+ | nds32-* | nds32le-* | nds32be-* \
+ | nios-* | nios2-* | nios2eb-* | nios2el-* \
+ | none-* | np1-* | ns16k-* | ns32k-* \
+ | open8-* \
+ | or1k*-* \
+ | orion-* \
+ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
+ | pyramid-* \
+ | rl78-* | romp-* | rs6000-* | rx-* \
+ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
+ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
+ | sparclite-* \
+ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \
+ | tahoe-* \
+ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
+ | tile*-* \
+ | tron-* \
+ | ubicom32-* \
+ | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \
+ | vax-* \
+ | visium-* \
+ | we32k-* \
+ | x86-* | x86_64-* | xc16x-* | xps100-* \
+ | xstormy16-* | xtensa*-* \
+ | ymp-* \
+ | z8k-* | z80-*)
+ ;;
+ # Recognize the basic CPU types without company name, with glob match.
+ xtensa*)
+ basic_machine=$basic_machine-unknown
+ ;;
+ # Recognize the various machine names and aliases which stand
+ # for a CPU type and a company and sometimes even an OS.
+ 386bsd)
+ basic_machine=i386-unknown
+ os=-bsd
+ ;;
+ 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+ basic_machine=m68000-att
+ ;;
+ 3b*)
+ basic_machine=we32k-att
+ ;;
+ a29khif)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ abacus)
+ basic_machine=abacus-unknown
+ ;;
+ adobe68k)
+ basic_machine=m68010-adobe
+ os=-scout
+ ;;
+ alliant | fx80)
+ basic_machine=fx80-alliant
+ ;;
+ altos | altos3068)
+ basic_machine=m68k-altos
+ ;;
+ am29k)
+ basic_machine=a29k-none
+ os=-bsd
+ ;;
+ amd64)
+ basic_machine=x86_64-pc
+ ;;
+ amd64-*)
+ basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ amdahl)
+ basic_machine=580-amdahl
+ os=-sysv
+ ;;
+ amiga | amiga-*)
+ basic_machine=m68k-unknown
+ ;;
+ amigaos | amigados)
+ basic_machine=m68k-unknown
+ os=-amigaos
+ ;;
+ amigaunix | amix)
+ basic_machine=m68k-unknown
+ os=-sysv4
+ ;;
+ apollo68)
+ basic_machine=m68k-apollo
+ os=-sysv
+ ;;
+ apollo68bsd)
+ basic_machine=m68k-apollo
+ os=-bsd
+ ;;
+ aros)
+ basic_machine=i386-pc
+ os=-aros
+ ;;
+ aux)
+ basic_machine=m68k-apple
+ os=-aux
+ ;;
+ balance)
+ basic_machine=ns32k-sequent
+ os=-dynix
+ ;;
+ blackfin)
+ basic_machine=bfin-unknown
+ os=-linux
+ ;;
+ blackfin-*)
+ basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
+ os=-linux
+ ;;
+ bluegene*)
+ basic_machine=powerpc-ibm
+ os=-cnk
+ ;;
+ c54x-*)
+ basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ c55x-*)
+ basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ c6x-*)
+ basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ c90)
+ basic_machine=c90-cray
+ os=-unicos
+ ;;
+ cegcc)
+ basic_machine=arm-unknown
+ os=-cegcc
+ ;;
+ convex-c1)
+ basic_machine=c1-convex
+ os=-bsd
+ ;;
+ convex-c2)
+ basic_machine=c2-convex
+ os=-bsd
+ ;;
+ convex-c32)
+ basic_machine=c32-convex
+ os=-bsd
+ ;;
+ convex-c34)
+ basic_machine=c34-convex
+ os=-bsd
+ ;;
+ convex-c38)
+ basic_machine=c38-convex
+ os=-bsd
+ ;;
+ cray | j90)
+ basic_machine=j90-cray
+ os=-unicos
+ ;;
+ craynv)
+ basic_machine=craynv-cray
+ os=-unicosmp
+ ;;
+ cr16 | cr16-*)
+ basic_machine=cr16-unknown
+ os=-elf
+ ;;
+ crds | unos)
+ basic_machine=m68k-crds
+ ;;
+ crisv32 | crisv32-* | etraxfs*)
+ basic_machine=crisv32-axis
+ ;;
+ cris | cris-* | etrax*)
+ basic_machine=cris-axis
+ ;;
+ crx)
+ basic_machine=crx-unknown
+ os=-elf
+ ;;
+ da30 | da30-*)
+ basic_machine=m68k-da30
+ ;;
+ decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+ basic_machine=mips-dec
+ ;;
+ decsystem10* | dec10*)
+ basic_machine=pdp10-dec
+ os=-tops10
+ ;;
+ decsystem20* | dec20*)
+ basic_machine=pdp10-dec
+ os=-tops20
+ ;;
+ delta | 3300 | motorola-3300 | motorola-delta \
+ | 3300-motorola | delta-motorola)
+ basic_machine=m68k-motorola
+ ;;
+ delta88)
+ basic_machine=m88k-motorola
+ os=-sysv3
+ ;;
+ dicos)
+ basic_machine=i686-pc
+ os=-dicos
+ ;;
+ djgpp)
+ basic_machine=i586-pc
+ os=-msdosdjgpp
+ ;;
+ dpx20 | dpx20-*)
+ basic_machine=rs6000-bull
+ os=-bosx
+ ;;
+ dpx2* | dpx2*-bull)
+ basic_machine=m68k-bull
+ os=-sysv3
+ ;;
+ ebmon29k)
+ basic_machine=a29k-amd
+ os=-ebmon
+ ;;
+ elxsi)
+ basic_machine=elxsi-elxsi
+ os=-bsd
+ ;;
+ encore | umax | mmax)
+ basic_machine=ns32k-encore
+ ;;
+ es1800 | OSE68k | ose68k | ose | OSE)
+ basic_machine=m68k-ericsson
+ os=-ose
+ ;;
+ fx2800)
+ basic_machine=i860-alliant
+ ;;
+ genix)
+ basic_machine=ns32k-ns
+ ;;
+ gmicro)
+ basic_machine=tron-gmicro
+ os=-sysv
+ ;;
+ go32)
+ basic_machine=i386-pc
+ os=-go32
+ ;;
+ h3050r* | hiux*)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ h8300hms)
+ basic_machine=h8300-hitachi
+ os=-hms
+ ;;
+ h8300xray)
+ basic_machine=h8300-hitachi
+ os=-xray
+ ;;
+ h8500hms)
+ basic_machine=h8500-hitachi
+ os=-hms
+ ;;
+ harris)
+ basic_machine=m88k-harris
+ os=-sysv3
+ ;;
+ hp300-*)
+ basic_machine=m68k-hp
+ ;;
+ hp300bsd)
+ basic_machine=m68k-hp
+ os=-bsd
+ ;;
+ hp300hpux)
+ basic_machine=m68k-hp
+ os=-hpux
+ ;;
+ hp3k9[0-9][0-9] | hp9[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k2[0-9][0-9] | hp9k31[0-9])
+ basic_machine=m68000-hp
+ ;;
+ hp9k3[2-9][0-9])
+ basic_machine=m68k-hp
+ ;;
+ hp9k6[0-9][0-9] | hp6[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k7[0-79][0-9] | hp7[0-79][0-9])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k78[0-9] | hp78[0-9])
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][13679] | hp8[0-9][13679])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][0-9] | hp8[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hppa-next)
+ os=-nextstep3
+ ;;
+ hppaosf)
+ basic_machine=hppa1.1-hp
+ os=-osf
+ ;;
+ hppro)
+ basic_machine=hppa1.1-hp
+ os=-proelf
+ ;;
+ i370-ibm* | ibm*)
+ basic_machine=i370-ibm
+ ;;
+ i*86v32)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv32
+ ;;
+ i*86v4*)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv4
+ ;;
+ i*86v)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv
+ ;;
+ i*86sol2)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-solaris2
+ ;;
+ i386mach)
+ basic_machine=i386-mach
+ os=-mach
+ ;;
+ i386-vsta | vsta)
+ basic_machine=i386-unknown
+ os=-vsta
+ ;;
+ iris | iris4d)
+ basic_machine=mips-sgi
+ case $os in
+ -irix*)
+ ;;
+ *)
+ os=-irix4
+ ;;
+ esac
+ ;;
+ isi68 | isi)
+ basic_machine=m68k-isi
+ os=-sysv
+ ;;
+ leon-*|leon[3-9]-*)
+ basic_machine=sparc-`echo $basic_machine | sed 's/-.*//'`
+ ;;
+ m68knommu)
+ basic_machine=m68k-unknown
+ os=-linux
+ ;;
+ m68knommu-*)
+ basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'`
+ os=-linux
+ ;;
+ m88k-omron*)
+ basic_machine=m88k-omron
+ ;;
+ magnum | m3230)
+ basic_machine=mips-mips
+ os=-sysv
+ ;;
+ merlin)
+ basic_machine=ns32k-utek
+ os=-sysv
+ ;;
+ microblaze*)
+ basic_machine=microblaze-xilinx
+ ;;
+ mingw64)
+ basic_machine=x86_64-pc
+ os=-mingw64
+ ;;
+ mingw32)
+ basic_machine=i686-pc
+ os=-mingw32
+ ;;
+ mingw32ce)
+ basic_machine=arm-unknown
+ os=-mingw32ce
+ ;;
+ miniframe)
+ basic_machine=m68000-convergent
+ ;;
+ *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+ mips3*-*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+ ;;
+ mips3*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+ ;;
+ monitor)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ morphos)
+ basic_machine=powerpc-unknown
+ os=-morphos
+ ;;
+ moxiebox)
+ basic_machine=moxie-unknown
+ os=-moxiebox
+ ;;
+ msdos)
+ basic_machine=i386-pc
+ os=-msdos
+ ;;
+ ms1-*)
+ basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
+ ;;
+ msys)
+ basic_machine=i686-pc
+ os=-msys
+ ;;
+ mvs)
+ basic_machine=i370-ibm
+ os=-mvs
+ ;;
+ nacl)
+ basic_machine=le32-unknown
+ os=-nacl
+ ;;
+ ncr3000)
+ basic_machine=i486-ncr
+ os=-sysv4
+ ;;
+ netbsd386)
+ basic_machine=i386-unknown
+ os=-netbsd
+ ;;
+ netwinder)
+ basic_machine=armv4l-rebel
+ os=-linux
+ ;;
+ news | news700 | news800 | news900)
+ basic_machine=m68k-sony
+ os=-newsos
+ ;;
+ news1000)
+ basic_machine=m68030-sony
+ os=-newsos
+ ;;
+ news-3600 | risc-news)
+ basic_machine=mips-sony
+ os=-newsos
+ ;;
+ necv70)
+ basic_machine=v70-nec
+ os=-sysv
+ ;;
+ next | m*-next )
+ basic_machine=m68k-next
+ case $os in
+ -nextstep* )
+ ;;
+ -ns2*)
+ os=-nextstep2
+ ;;
+ *)
+ os=-nextstep3
+ ;;
+ esac
+ ;;
+ nh3000)
+ basic_machine=m68k-harris
+ os=-cxux
+ ;;
+ nh[45]000)
+ basic_machine=m88k-harris
+ os=-cxux
+ ;;
+ nindy960)
+ basic_machine=i960-intel
+ os=-nindy
+ ;;
+ mon960)
+ basic_machine=i960-intel
+ os=-mon960
+ ;;
+ nonstopux)
+ basic_machine=mips-compaq
+ os=-nonstopux
+ ;;
+ np1)
+ basic_machine=np1-gould
+ ;;
+ neo-tandem)
+ basic_machine=neo-tandem
+ ;;
+ nse-tandem)
+ basic_machine=nse-tandem
+ ;;
+ nsr-tandem)
+ basic_machine=nsr-tandem
+ ;;
+ op50n-* | op60c-*)
+ basic_machine=hppa1.1-oki
+ os=-proelf
+ ;;
+ openrisc | openrisc-*)
+ basic_machine=or32-unknown
+ ;;
+ os400)
+ basic_machine=powerpc-ibm
+ os=-os400
+ ;;
+ OSE68000 | ose68000)
+ basic_machine=m68000-ericsson
+ os=-ose
+ ;;
+ os68k)
+ basic_machine=m68k-none
+ os=-os68k
+ ;;
+ pa-hitachi)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ paragon)
+ basic_machine=i860-intel
+ os=-osf
+ ;;
+ parisc)
+ basic_machine=hppa-unknown
+ os=-linux
+ ;;
+ parisc-*)
+ basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'`
+ os=-linux
+ ;;
+ pbd)
+ basic_machine=sparc-tti
+ ;;
+ pbb)
+ basic_machine=m68k-tti
+ ;;
+ pc532 | pc532-*)
+ basic_machine=ns32k-pc532
+ ;;
+ pc98)
+ basic_machine=i386-pc
+ ;;
+ pc98-*)
+ basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentium | p5 | k5 | k6 | nexgen | viac3)
+ basic_machine=i586-pc
+ ;;
+ pentiumpro | p6 | 6x86 | athlon | athlon_*)
+ basic_machine=i686-pc
+ ;;
+ pentiumii | pentium2 | pentiumiii | pentium3)
+ basic_machine=i686-pc
+ ;;
+ pentium4)
+ basic_machine=i786-pc
+ ;;
+ pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+ basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumpro-* | p6-* | 6x86-* | athlon-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentium4-*)
+ basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pn)
+ basic_machine=pn-gould
+ ;;
+ power) basic_machine=power-ibm
+ ;;
+ ppc | ppcbe) basic_machine=powerpc-unknown
+ ;;
+ ppc-* | ppcbe-*)
+ basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppcle | powerpclittle | ppc-le | powerpc-little)
+ basic_machine=powerpcle-unknown
+ ;;
+ ppcle-* | powerpclittle-*)
+ basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64) basic_machine=powerpc64-unknown
+ ;;
+ ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+ basic_machine=powerpc64le-unknown
+ ;;
+ ppc64le-* | powerpc64little-*)
+ basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ps2)
+ basic_machine=i386-ibm
+ ;;
+ pw32)
+ basic_machine=i586-unknown
+ os=-pw32
+ ;;
+ rdos | rdos64)
+ basic_machine=x86_64-pc
+ os=-rdos
+ ;;
+ rdos32)
+ basic_machine=i386-pc
+ os=-rdos
+ ;;
+ rom68k)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ rm[46]00)
+ basic_machine=mips-siemens
+ ;;
+ rtpc | rtpc-*)
+ basic_machine=romp-ibm
+ ;;
+ s390 | s390-*)
+ basic_machine=s390-ibm
+ ;;
+ s390x | s390x-*)
+ basic_machine=s390x-ibm
+ ;;
+ sa29200)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ sb1)
+ basic_machine=mipsisa64sb1-unknown
+ ;;
+ sb1el)
+ basic_machine=mipsisa64sb1el-unknown
+ ;;
+ sde)
+ basic_machine=mipsisa32-sde
+ os=-elf
+ ;;
+ sei)
+ basic_machine=mips-sei
+ os=-seiux
+ ;;
+ sequent)
+ basic_machine=i386-sequent
+ ;;
+ sh)
+ basic_machine=sh-hitachi
+ os=-hms
+ ;;
+ sh5el)
+ basic_machine=sh5le-unknown
+ ;;
+ sh64)
+ basic_machine=sh64-unknown
+ ;;
+ sparclite-wrs | simso-wrs)
+ basic_machine=sparclite-wrs
+ os=-vxworks
+ ;;
+ sps7)
+ basic_machine=m68k-bull
+ os=-sysv2
+ ;;
+ spur)
+ basic_machine=spur-unknown
+ ;;
+ st2000)
+ basic_machine=m68k-tandem
+ ;;
+ stratus)
+ basic_machine=i860-stratus
+ os=-sysv4
+ ;;
+ strongarm-* | thumb-*)
+ basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ sun2)
+ basic_machine=m68000-sun
+ ;;
+ sun2os3)
+ basic_machine=m68000-sun
+ os=-sunos3
+ ;;
+ sun2os4)
+ basic_machine=m68000-sun
+ os=-sunos4
+ ;;
+ sun3os3)
+ basic_machine=m68k-sun
+ os=-sunos3
+ ;;
+ sun3os4)
+ basic_machine=m68k-sun
+ os=-sunos4
+ ;;
+ sun4os3)
+ basic_machine=sparc-sun
+ os=-sunos3
+ ;;
+ sun4os4)
+ basic_machine=sparc-sun
+ os=-sunos4
+ ;;
+ sun4sol2)
+ basic_machine=sparc-sun
+ os=-solaris2
+ ;;
+ sun3 | sun3-*)
+ basic_machine=m68k-sun
+ ;;
+ sun4)
+ basic_machine=sparc-sun
+ ;;
+ sun386 | sun386i | roadrunner)
+ basic_machine=i386-sun
+ ;;
+ sv1)
+ basic_machine=sv1-cray
+ os=-unicos
+ ;;
+ symmetry)
+ basic_machine=i386-sequent
+ os=-dynix
+ ;;
+ t3e)
+ basic_machine=alphaev5-cray
+ os=-unicos
+ ;;
+ t90)
+ basic_machine=t90-cray
+ os=-unicos
+ ;;
+ tile*)
+ basic_machine=$basic_machine-unknown
+ os=-linux-gnu
+ ;;
+ tx39)
+ basic_machine=mipstx39-unknown
+ ;;
+ tx39el)
+ basic_machine=mipstx39el-unknown
+ ;;
+ toad1)
+ basic_machine=pdp10-xkl
+ os=-tops20
+ ;;
+ tower | tower-32)
+ basic_machine=m68k-ncr
+ ;;
+ tpf)
+ basic_machine=s390x-ibm
+ os=-tpf
+ ;;
+ udi29k)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ ultra3)
+ basic_machine=a29k-nyu
+ os=-sym1
+ ;;
+ v810 | necv810)
+ basic_machine=v810-nec
+ os=-none
+ ;;
+ vaxv)
+ basic_machine=vax-dec
+ os=-sysv
+ ;;
+ vms)
+ basic_machine=vax-dec
+ os=-vms
+ ;;
+ vpp*|vx|vx-*)
+ basic_machine=f301-fujitsu
+ ;;
+ vxworks960)
+ basic_machine=i960-wrs
+ os=-vxworks
+ ;;
+ vxworks68)
+ basic_machine=m68k-wrs
+ os=-vxworks
+ ;;
+ vxworks29k)
+ basic_machine=a29k-wrs
+ os=-vxworks
+ ;;
+ w65*)
+ basic_machine=w65-wdc
+ os=-none
+ ;;
+ w89k-*)
+ basic_machine=hppa1.1-winbond
+ os=-proelf
+ ;;
+ xbox)
+ basic_machine=i686-pc
+ os=-mingw32
+ ;;
+ xps | xps100)
+ basic_machine=xps100-honeywell
+ ;;
+ xscale-* | xscalee[bl]-*)
+ basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'`
+ ;;
+ ymp)
+ basic_machine=ymp-cray
+ os=-unicos
+ ;;
+ z8k-*-coff)
+ basic_machine=z8k-unknown
+ os=-sim
+ ;;
+ z80-*-coff)
+ basic_machine=z80-unknown
+ os=-sim
+ ;;
+ none)
+ basic_machine=none-none
+ os=-none
+ ;;
+
+# Here we handle the default manufacturer of certain CPU types. It is in
+# some cases the only manufacturer, in others, it is the most popular.
+ w89k)
+ basic_machine=hppa1.1-winbond
+ ;;
+ op50n)
+ basic_machine=hppa1.1-oki
+ ;;
+ op60c)
+ basic_machine=hppa1.1-oki
+ ;;
+ romp)
+ basic_machine=romp-ibm
+ ;;
+ mmix)
+ basic_machine=mmix-knuth
+ ;;
+ rs6000)
+ basic_machine=rs6000-ibm
+ ;;
+ vax)
+ basic_machine=vax-dec
+ ;;
+ pdp10)
+ # there are many clones, so DEC is not a safe bet
+ basic_machine=pdp10-unknown
+ ;;
+ pdp11)
+ basic_machine=pdp11-dec
+ ;;
+ we32k)
+ basic_machine=we32k-att
+ ;;
+ sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
+ basic_machine=sh-unknown
+ ;;
+ sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
+ basic_machine=sparc-sun
+ ;;
+ cydra)
+ basic_machine=cydra-cydrome
+ ;;
+ orion)
+ basic_machine=orion-highlevel
+ ;;
+ orion105)
+ basic_machine=clipper-highlevel
+ ;;
+ mac | mpw | mac-mpw)
+ basic_machine=m68k-apple
+ ;;
+ pmac | pmac-mpw)
+ basic_machine=powerpc-apple
+ ;;
+ *-unknown)
+ # Make sure to match an already-canonicalized machine name.
+ ;;
+ *)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+ *-digital*)
+ basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+ ;;
+ *-commodore*)
+ basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+ ;;
+ *)
+ ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+ # First match some system type aliases
+ # that might get confused with valid system types.
+ # -solaris* is a basic system type, with this one exception.
+ -auroraux)
+ os=-auroraux
+ ;;
+ -solaris1 | -solaris1.*)
+ os=`echo $os | sed -e 's|solaris1|sunos4|'`
+ ;;
+ -solaris)
+ os=-solaris2
+ ;;
+ -svr4*)
+ os=-sysv4
+ ;;
+ -unixware*)
+ os=-sysv4.2uw
+ ;;
+ -gnu/linux*)
+ os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+ ;;
+ # First accept the basic system types.
+ # The portable systems comes first.
+ # Each alternative MUST END IN A *, to match a version number.
+ # -sysv* is not here because it comes later, after sysvr4.
+ -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
+ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
+ | -sym* | -kopensolaris* | -plan9* \
+ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+ | -aos* | -aros* \
+ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
+ | -bitrig* | -openbsd* | -solidbsd* \
+ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
+ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+ | -chorusos* | -chorusrdb* | -cegcc* \
+ | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+ | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \
+ | -linux-newlib* | -linux-musl* | -linux-uclibc* \
+ | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \
+ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
+ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* | -tirtos*)
+ # Remember, each alternative MUST END IN *, to match a version number.
+ ;;
+ -qnx*)
+ case $basic_machine in
+ x86-* | i*86-*)
+ ;;
+ *)
+ os=-nto$os
+ ;;
+ esac
+ ;;
+ -nto-qnx*)
+ ;;
+ -nto*)
+ os=`echo $os | sed -e 's|nto|nto-qnx|'`
+ ;;
+ -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
+ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+ ;;
+ -mac*)
+ os=`echo $os | sed -e 's|mac|macos|'`
+ ;;
+ -linux-dietlibc)
+ os=-linux-dietlibc
+ ;;
+ -linux*)
+ os=`echo $os | sed -e 's|linux|linux-gnu|'`
+ ;;
+ -sunos5*)
+ os=`echo $os | sed -e 's|sunos5|solaris2|'`
+ ;;
+ -sunos6*)
+ os=`echo $os | sed -e 's|sunos6|solaris3|'`
+ ;;
+ -opened*)
+ os=-openedition
+ ;;
+ -os400*)
+ os=-os400
+ ;;
+ -wince*)
+ os=-wince
+ ;;
+ -osfrose*)
+ os=-osfrose
+ ;;
+ -osf*)
+ os=-osf
+ ;;
+ -utek*)
+ os=-bsd
+ ;;
+ -dynix*)
+ os=-bsd
+ ;;
+ -acis*)
+ os=-aos
+ ;;
+ -atheos*)
+ os=-atheos
+ ;;
+ -syllable*)
+ os=-syllable
+ ;;
+ -386bsd)
+ os=-bsd
+ ;;
+ -ctix* | -uts*)
+ os=-sysv
+ ;;
+ -nova*)
+ os=-rtmk-nova
+ ;;
+ -ns2 )
+ os=-nextstep2
+ ;;
+ -nsk*)
+ os=-nsk
+ ;;
+ # Preserve the version number of sinix5.
+ -sinix5.*)
+ os=`echo $os | sed -e 's|sinix|sysv|'`
+ ;;
+ -sinix*)
+ os=-sysv4
+ ;;
+ -tpf*)
+ os=-tpf
+ ;;
+ -triton*)
+ os=-sysv3
+ ;;
+ -oss*)
+ os=-sysv3
+ ;;
+ -svr4)
+ os=-sysv4
+ ;;
+ -svr3)
+ os=-sysv3
+ ;;
+ -sysvr4)
+ os=-sysv4
+ ;;
+ # This must come after -sysvr4.
+ -sysv*)
+ ;;
+ -ose*)
+ os=-ose
+ ;;
+ -es1800*)
+ os=-ose
+ ;;
+ -xenix)
+ os=-xenix
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ os=-mint
+ ;;
+ -aros*)
+ os=-aros
+ ;;
+ -zvmoe)
+ os=-zvmoe
+ ;;
+ -dicos*)
+ os=-dicos
+ ;;
+ -nacl*)
+ ;;
+ -none)
+ ;;
+ *)
+ # Get rid of the `-' at the beginning of $os.
+ os=`echo $os | sed 's/[^-]*-//'`
+ echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system. Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+ score-*)
+ os=-elf
+ ;;
+ spu-*)
+ os=-elf
+ ;;
+ *-acorn)
+ os=-riscix1.2
+ ;;
+ arm*-rebel)
+ os=-linux
+ ;;
+ arm*-semi)
+ os=-aout
+ ;;
+ c4x-* | tic4x-*)
+ os=-coff
+ ;;
+ c8051-*)
+ os=-elf
+ ;;
+ hexagon-*)
+ os=-elf
+ ;;
+ tic54x-*)
+ os=-coff
+ ;;
+ tic55x-*)
+ os=-coff
+ ;;
+ tic6x-*)
+ os=-coff
+ ;;
+ # This must come before the *-dec entry.
+ pdp10-*)
+ os=-tops20
+ ;;
+ pdp11-*)
+ os=-none
+ ;;
+ *-dec | vax-*)
+ os=-ultrix4.2
+ ;;
+ m68*-apollo)
+ os=-domain
+ ;;
+ i386-sun)
+ os=-sunos4.0.2
+ ;;
+ m68000-sun)
+ os=-sunos3
+ ;;
+ m68*-cisco)
+ os=-aout
+ ;;
+ mep-*)
+ os=-elf
+ ;;
+ mips*-cisco)
+ os=-elf
+ ;;
+ mips*-*)
+ os=-elf
+ ;;
+ or32-*)
+ os=-coff
+ ;;
+ *-tti) # must be before sparc entry or we get the wrong os.
+ os=-sysv3
+ ;;
+ sparc-* | *-sun)
+ os=-sunos4.1.1
+ ;;
+ *-be)
+ os=-beos
+ ;;
+ *-haiku)
+ os=-haiku
+ ;;
+ *-ibm)
+ os=-aix
+ ;;
+ *-knuth)
+ os=-mmixware
+ ;;
+ *-wec)
+ os=-proelf
+ ;;
+ *-winbond)
+ os=-proelf
+ ;;
+ *-oki)
+ os=-proelf
+ ;;
+ *-hp)
+ os=-hpux
+ ;;
+ *-hitachi)
+ os=-hiux
+ ;;
+ i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+ os=-sysv
+ ;;
+ *-cbm)
+ os=-amigaos
+ ;;
+ *-dg)
+ os=-dgux
+ ;;
+ *-dolphin)
+ os=-sysv3
+ ;;
+ m68k-ccur)
+ os=-rtu
+ ;;
+ m88k-omron*)
+ os=-luna
+ ;;
+ *-next )
+ os=-nextstep
+ ;;
+ *-sequent)
+ os=-ptx
+ ;;
+ *-crds)
+ os=-unos
+ ;;
+ *-ns)
+ os=-genix
+ ;;
+ i370-*)
+ os=-mvs
+ ;;
+ *-next)
+ os=-nextstep3
+ ;;
+ *-gould)
+ os=-sysv
+ ;;
+ *-highlevel)
+ os=-bsd
+ ;;
+ *-encore)
+ os=-bsd
+ ;;
+ *-sgi)
+ os=-irix
+ ;;
+ *-siemens)
+ os=-sysv4
+ ;;
+ *-masscomp)
+ os=-rtu
+ ;;
+ f30[01]-fujitsu | f700-fujitsu)
+ os=-uxpv
+ ;;
+ *-rom68k)
+ os=-coff
+ ;;
+ *-*bug)
+ os=-coff
+ ;;
+ *-apple)
+ os=-macos
+ ;;
+ *-atari*)
+ os=-mint
+ ;;
+ *)
+ os=-none
+ ;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer. We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+ *-unknown)
+ case $os in
+ -riscix*)
+ vendor=acorn
+ ;;
+ -sunos*)
+ vendor=sun
+ ;;
+ -cnk*|-aix*)
+ vendor=ibm
+ ;;
+ -beos*)
+ vendor=be
+ ;;
+ -hpux*)
+ vendor=hp
+ ;;
+ -mpeix*)
+ vendor=hp
+ ;;
+ -hiux*)
+ vendor=hitachi
+ ;;
+ -unos*)
+ vendor=crds
+ ;;
+ -dgux*)
+ vendor=dg
+ ;;
+ -luna*)
+ vendor=omron
+ ;;
+ -genix*)
+ vendor=ns
+ ;;
+ -mvs* | -opened*)
+ vendor=ibm
+ ;;
+ -os400*)
+ vendor=ibm
+ ;;
+ -ptx*)
+ vendor=sequent
+ ;;
+ -tpf*)
+ vendor=ibm
+ ;;
+ -vxsim* | -vxworks* | -windiss*)
+ vendor=wrs
+ ;;
+ -aux*)
+ vendor=apple
+ ;;
+ -hms*)
+ vendor=hitachi
+ ;;
+ -mpw* | -macos*)
+ vendor=apple
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ vendor=atari
+ ;;
+ -vos*)
+ vendor=stratus
+ ;;
+ esac
+ basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+ ;;
+esac
+
+echo $basic_machine$os
+exit
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/funtools/wcs/configure-failsafe b/funtools/wcs/configure-failsafe
new file mode 100755
index 0000000..4de89e2
--- /dev/null
+++ b/funtools/wcs/configure-failsafe
@@ -0,0 +1,6222 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.59 for wcs 3.8.7.
+#
+# Report bugs to <dmink@cfa.harvard.edu>.
+#
+# Copyright (C) 2003 Free Software Foundation, Inc.
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## --------------------- ##
+## M4sh Initialization. ##
+## --------------------- ##
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
+ set -o posix
+fi
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# Support unset when possible.
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+ as_unset=unset
+else
+ as_unset=false
+fi
+
+
+# Work around bugs in pre-3.0 UWIN ksh.
+$as_unset ENV MAIL MAILPATH
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+for as_var in \
+ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
+ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
+ LC_TELEPHONE LC_TIME
+do
+ if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then
+ eval $as_var=C; export $as_var
+ else
+ $as_unset $as_var
+ fi
+done
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+
+# Name of the executable.
+as_me=`$as_basename "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)$' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; }
+ /^X\/\(\/\/\)$/{ s//\1/; q; }
+ /^X\/\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+
+
+# PATH needs CR, and LINENO needs CR and PATH.
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ echo "#! /bin/sh" >conf$$.sh
+ echo "exit 0" >>conf$$.sh
+ chmod +x conf$$.sh
+ if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+ PATH_SEPARATOR=';'
+ else
+ PATH_SEPARATOR=:
+ fi
+ rm -f conf$$.sh
+fi
+
+
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x$as_lineno_3" = "x$as_lineno_2" || {
+ # Find who we are. Look in the path if we contain no path at all
+ # relative or not.
+ case $0 in
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+done
+
+ ;;
+ esac
+ # We did not find ourselves, most probably we were run as `sh COMMAND'
+ # in which case we are not to be found in the path.
+ if test "x$as_myself" = x; then
+ as_myself=$0
+ fi
+ if test ! -f "$as_myself"; then
+ { echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2
+ { (exit 1); exit 1; }; }
+ fi
+ case $CONFIG_SHELL in
+ '')
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for as_base in sh bash ksh sh5; do
+ case $as_dir in
+ /*)
+ if ("$as_dir/$as_base" -c '
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then
+ $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; }
+ $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; }
+ CONFIG_SHELL=$as_dir/$as_base
+ export CONFIG_SHELL
+ exec "$CONFIG_SHELL" "$0" ${1+"$@"}
+ fi;;
+ esac
+ done
+done
+;;
+ esac
+
+ # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+ # uniformly replaced by the line number. The first 'sed' inserts a
+ # line-number line before each line; the second 'sed' does the real
+ # work. The second script uses 'N' to pair each line-number line
+ # with the numbered line, and appends trailing '-' during
+ # substitution so that $LINENO is not a special case at line end.
+ # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+ # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-)
+ sed '=' <$as_myself |
+ sed '
+ N
+ s,$,-,
+ : loop
+ s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3,
+ t loop
+ s,-$,,
+ s,^['$as_cr_digits']*\n,,
+ ' >$as_me.lineno &&
+ chmod +x $as_me.lineno ||
+ { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2
+ { (exit 1); exit 1; }; }
+
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensible to this).
+ . ./$as_me.lineno
+ # Exit status is that of the last command.
+ exit
+}
+
+
+case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in
+ *c*,-n*) ECHO_N= ECHO_C='
+' ECHO_T=' ' ;;
+ *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;;
+ *) ECHO_N= ECHO_C='\c' ECHO_T= ;;
+esac
+
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+ # We could just check for DJGPP; but this test a) works b) is more generic
+ # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04).
+ if test -f conf$$.exe; then
+ # Don't use ln at all; we don't have any links
+ as_ln_s='cp -p'
+ else
+ as_ln_s='ln -s'
+ fi
+elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+else
+ as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.file
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p=:
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+as_executable_p="test -f"
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.
+as_nl='
+'
+IFS=" $as_nl"
+
+# CDPATH.
+$as_unset CDPATH
+
+
+# Name of the host.
+# hostname on some systems (SVR3.2, Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+exec 6>&1
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_config_libobj_dir=.
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+# Maximum number of lines to put in a shell here document.
+# This variable seems obsolete. It should probably be removed, and
+# only ac_max_sed_lines should be used.
+: ${ac_max_here_lines=38}
+
+# Identity of this package.
+PACKAGE_NAME='wcs'
+PACKAGE_TARNAME='wcs'
+PACKAGE_VERSION='3.8.7'
+PACKAGE_STRING='wcs 3.8.7'
+PACKAGE_BUGREPORT='dmink@cfa.harvard.edu'
+
+ac_unique_file="./wcs.h"
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#if HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# if HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#if HAVE_STRING_H
+# if !STDC_HEADERS && HAVE_MEMORY_H
+# include <memory.h>
+# endif
+# include <string.h>
+#endif
+#if HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#else
+# if HAVE_STDINT_H
+# include <stdint.h>
+# endif
+#endif
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT RANLIB ac_ct_RANLIB CPP EGREP WHICHLIB EXTLIB LIB DEFLIB DOSHARED LLIB USE_DL EXTRA_LIBS EXTRA_OBJS LIBOBJS LTLIBOBJS'
+ac_subst_files=''
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+ac_prev=
+for ac_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval "$ac_prev=\$ac_option"
+ ac_prev=
+ continue
+ fi
+
+ ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'`
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_option in
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+ | --da=*)
+ datadir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+ { (exit 1); exit 1; }; }
+ ac_feature=`echo $ac_feature | sed 's/-/_/g'`
+ eval "enable_$ac_feature=no" ;;
+
+ -enable-* | --enable-*)
+ ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+ { (exit 1); exit 1; }; }
+ ac_feature=`echo $ac_feature | sed 's/-/_/g'`
+ case $ac_option in
+ *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "enable_$ac_feature='$ac_optarg'" ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst \
+ | --locals | --local | --loca | --loc | --lo)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid package name: $ac_package" >&2
+ { (exit 1); exit 1; }; }
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ case $ac_option in
+ *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "with_$ac_package='$ac_optarg'" ;;
+
+ -without-* | --without-*)
+ ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid package name: $ac_package" >&2
+ { (exit 1); exit 1; }; }
+ ac_package=`echo $ac_package | sed 's/-/_/g'`
+ eval "with_$ac_package=no" ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) { echo "$as_me: error: unrecognized option: $ac_option
+Try \`$0 --help' for more information." >&2
+ { (exit 1); exit 1; }; }
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid variable name: $ac_envvar" >&2
+ { (exit 1); exit 1; }; }
+ ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`
+ eval "$ac_envvar='$ac_optarg'"
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ { echo "$as_me: error: missing argument to $ac_option" >&2
+ { (exit 1); exit 1; }; }
+fi
+
+# Be sure to have absolute paths.
+for ac_var in exec_prefix prefix
+do
+ eval ac_val=$`echo $ac_var`
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* | NONE | '' ) ;;
+ *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
+ { (exit 1); exit 1; }; };;
+ esac
+done
+
+# Be sure to have absolute paths.
+for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \
+ localstatedir libdir includedir oldincludedir infodir mandir
+do
+ eval ac_val=$`echo $ac_var`
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) ;;
+ *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
+ { (exit 1); exit 1; }; };;
+ esac
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host.
+ If a cross compiler is detected then cross compile mode will be used." >&2
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then its parent.
+ ac_confdir=`(dirname "$0") 2>/dev/null ||
+$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$0" : 'X\(//\)[^/]' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$0" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ srcdir=$ac_confdir
+ if test ! -r $srcdir/$ac_unique_file; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+ if test "$ac_srcdir_defaulted" = yes; then
+ { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2
+ { (exit 1); exit 1; }; }
+ else
+ { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2
+ { (exit 1); exit 1; }; }
+ fi
+fi
+(cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null ||
+ { echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2
+ { (exit 1); exit 1; }; }
+srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'`
+ac_env_build_alias_set=${build_alias+set}
+ac_env_build_alias_value=$build_alias
+ac_cv_env_build_alias_set=${build_alias+set}
+ac_cv_env_build_alias_value=$build_alias
+ac_env_host_alias_set=${host_alias+set}
+ac_env_host_alias_value=$host_alias
+ac_cv_env_host_alias_set=${host_alias+set}
+ac_cv_env_host_alias_value=$host_alias
+ac_env_target_alias_set=${target_alias+set}
+ac_env_target_alias_value=$target_alias
+ac_cv_env_target_alias_set=${target_alias+set}
+ac_cv_env_target_alias_value=$target_alias
+ac_env_CC_set=${CC+set}
+ac_env_CC_value=$CC
+ac_cv_env_CC_set=${CC+set}
+ac_cv_env_CC_value=$CC
+ac_env_CFLAGS_set=${CFLAGS+set}
+ac_env_CFLAGS_value=$CFLAGS
+ac_cv_env_CFLAGS_set=${CFLAGS+set}
+ac_cv_env_CFLAGS_value=$CFLAGS
+ac_env_LDFLAGS_set=${LDFLAGS+set}
+ac_env_LDFLAGS_value=$LDFLAGS
+ac_cv_env_LDFLAGS_set=${LDFLAGS+set}
+ac_cv_env_LDFLAGS_value=$LDFLAGS
+ac_env_CPPFLAGS_set=${CPPFLAGS+set}
+ac_env_CPPFLAGS_value=$CPPFLAGS
+ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set}
+ac_cv_env_CPPFLAGS_value=$CPPFLAGS
+ac_env_CPP_set=${CPP+set}
+ac_env_CPP_value=$CPP
+ac_cv_env_CPP_set=${CPP+set}
+ac_cv_env_CPP_value=$CPP
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures wcs 3.8.7 to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+_ACEOF
+
+ cat <<_ACEOF
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --datadir=DIR read-only architecture-independent data [PREFIX/share]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --infodir=DIR info documentation [PREFIX/info]
+ --mandir=DIR man documentation [PREFIX/man]
+_ACEOF
+
+ cat <<\_ACEOF
+
+System types:
+ --build=BUILD configure for building on BUILD [guessed]
+ --host=HOST cross-compile to build programs to run on HOST [BUILD]
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+ case $ac_init_help in
+ short | recursive ) echo "Configuration of wcs 3.8.7:";;
+ esac
+ cat <<\_ACEOF
+
+Optional Features:
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --enable-shared build shared libraries
+ --enable-dl allow use of dynamic loading if available
+
+Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --with-wcslib=LIB library name
+ --with-altlib=LIB library name
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ CPPFLAGS C/C++ preprocessor flags, e.g. -I<include dir> if you have
+ headers in a nonstandard directory <include dir>
+ CPP C preprocessor
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to <dmink@cfa.harvard.edu>.
+_ACEOF
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ ac_popdir=`pwd`
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d $ac_dir || continue
+ ac_builddir=.
+
+if test "$ac_dir" != .; then
+ ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'`
+else
+ ac_dir_suffix= ac_top_builddir=
+fi
+
+case $srcdir in
+ .) # No --srcdir option. We are building in place.
+ ac_srcdir=.
+ if test -z "$ac_top_builddir"; then
+ ac_top_srcdir=.
+ else
+ ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'`
+ fi ;;
+ [\\/]* | ?:[\\/]* ) # Absolute path.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir ;;
+ *) # Relative path.
+ ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_builddir$srcdir ;;
+esac
+
+# Do not use `cd foo && pwd` to compute absolute paths, because
+# the directories may not exist.
+case `pwd` in
+.) ac_abs_builddir="$ac_dir";;
+*)
+ case "$ac_dir" in
+ .) ac_abs_builddir=`pwd`;;
+ [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";;
+ *) ac_abs_builddir=`pwd`/"$ac_dir";;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_builddir=${ac_top_builddir}.;;
+*)
+ case ${ac_top_builddir}. in
+ .) ac_abs_top_builddir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;;
+ *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_srcdir=$ac_srcdir;;
+*)
+ case $ac_srcdir in
+ .) ac_abs_srcdir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;;
+ *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_srcdir=$ac_top_srcdir;;
+*)
+ case $ac_top_srcdir in
+ .) ac_abs_top_srcdir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;;
+ *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;;
+ esac;;
+esac
+
+ cd $ac_dir
+ # Check for guested configure; otherwise get Cygnus style configure.
+ if test -f $ac_srcdir/configure.gnu; then
+ echo
+ $SHELL $ac_srcdir/configure.gnu --help=recursive
+ elif test -f $ac_srcdir/configure; then
+ echo
+ $SHELL $ac_srcdir/configure --help=recursive
+ elif test -f $ac_srcdir/configure.ac ||
+ test -f $ac_srcdir/configure.in; then
+ echo
+ $ac_configure --help
+ else
+ echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi
+ cd $ac_popdir
+ done
+fi
+
+test -n "$ac_init_help" && exit 0
+if $ac_init_version; then
+ cat <<\_ACEOF
+wcs configure 3.8.7
+generated by GNU Autoconf 2.59
+
+Copyright (C) 2003 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit 0
+fi
+exec 5>config.log
+cat >&5 <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by wcs $as_me 3.8.7, which was
+generated by GNU Autoconf 2.59. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+hostinfo = `(hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ echo "PATH: $as_dir"
+done
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_sep=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*)
+ ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;;
+ 2)
+ ac_configure_args1="$ac_configure_args1 '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'"
+ # Get rid of the leading space.
+ ac_sep=" "
+ ;;
+ esac
+ done
+done
+$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; }
+$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; }
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Be sure not to use single quotes in there, as some shells,
+# such as our DU 5.0 friend, will then `close' the trap.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ cat <<\_ASBOX
+## ---------------- ##
+## Cache variables. ##
+## ---------------- ##
+_ASBOX
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+{
+ (set) 2>&1 |
+ case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in
+ *ac_space=\ *)
+ sed -n \
+ "s/'"'"'/'"'"'\\\\'"'"''"'"'/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p"
+ ;;
+ *)
+ sed -n \
+ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p"
+ ;;
+ esac;
+}
+ echo
+
+ cat <<\_ASBOX
+## ----------------- ##
+## Output variables. ##
+## ----------------- ##
+_ASBOX
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=$`echo $ac_var`
+ echo "$ac_var='"'"'$ac_val'"'"'"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ cat <<\_ASBOX
+## ------------- ##
+## Output files. ##
+## ------------- ##
+_ASBOX
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=$`echo $ac_var`
+ echo "$ac_var='"'"'$ac_val'"'"'"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ cat <<\_ASBOX
+## ----------- ##
+## confdefs.h. ##
+## ----------- ##
+_ASBOX
+ echo
+ sed "/^$/d" confdefs.h | sort
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ echo "$as_me: caught signal $ac_signal"
+ echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core &&
+ rm -rf conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+ ' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo >confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+ if test "x$prefix" != xNONE; then
+ CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+ else
+ CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+ fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+ if test -r "$ac_site_file"; then
+ { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5
+echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file"
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special
+ # files actually), so we avoid doing that.
+ if test -f "$cache_file"; then
+ { echo "$as_me:$LINENO: loading cache $cache_file" >&5
+echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . $cache_file;;
+ *) . ./$cache_file;;
+ esac
+ fi
+else
+ { echo "$as_me:$LINENO: creating cache $cache_file" >&5
+echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in `(set) 2>&1 |
+ sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val="\$ac_cv_env_${ac_var}_value"
+ eval ac_new_val="\$ac_env_${ac_var}_value"
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5
+echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ { echo "$as_me:$LINENO: former value: $ac_old_val" >&5
+echo "$as_me: former value: $ac_old_val" >&2;}
+ { echo "$as_me:$LINENO: current value: $ac_new_val" >&5
+echo "$as_me: current value: $ac_new_val" >&2;}
+ ac_cache_corrupted=:
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*)
+ ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5
+echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5
+echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ac_config_headers="$ac_config_headers conf.h"
+
+
+ac_aux_dir=
+for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+ if test -f $ac_dir/install-sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install-sh -c"
+ break
+ elif test -f $ac_dir/install.sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install.sh -c"
+ break
+ elif test -f $ac_dir/shtool; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/shtool install -c"
+ break
+ fi
+done
+if test -z "$ac_aux_dir"; then
+ { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&5
+echo "$as_me: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+ac_config_guess="$SHELL $ac_aux_dir/config.guess"
+ac_config_sub="$SHELL $ac_aux_dir/config.sub"
+ac_configure="$SHELL $ac_aux_dir/configure" # This should be Cygnus configure.
+
+# Make sure we can run config.sub.
+$ac_config_sub sun4 >/dev/null 2>&1 ||
+ { { echo "$as_me:$LINENO: error: cannot run $ac_config_sub" >&5
+echo "$as_me: error: cannot run $ac_config_sub" >&2;}
+ { (exit 1); exit 1; }; }
+
+echo "$as_me:$LINENO: checking build system type" >&5
+echo $ECHO_N "checking build system type... $ECHO_C" >&6
+if test "${ac_cv_build+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_build_alias=$build_alias
+test -z "$ac_cv_build_alias" &&
+ ac_cv_build_alias=`$ac_config_guess`
+test -z "$ac_cv_build_alias" &&
+ { { echo "$as_me:$LINENO: error: cannot guess build type; you must specify one" >&5
+echo "$as_me: error: cannot guess build type; you must specify one" >&2;}
+ { (exit 1); exit 1; }; }
+ac_cv_build=`$ac_config_sub $ac_cv_build_alias` ||
+ { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_build_alias failed" >&5
+echo "$as_me: error: $ac_config_sub $ac_cv_build_alias failed" >&2;}
+ { (exit 1); exit 1; }; }
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_build" >&5
+echo "${ECHO_T}$ac_cv_build" >&6
+build=$ac_cv_build
+build_cpu=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+build_vendor=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+build_os=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+
+
+echo "$as_me:$LINENO: checking host system type" >&5
+echo $ECHO_N "checking host system type... $ECHO_C" >&6
+if test "${ac_cv_host+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_host_alias=$host_alias
+test -z "$ac_cv_host_alias" &&
+ ac_cv_host_alias=$ac_cv_build_alias
+ac_cv_host=`$ac_config_sub $ac_cv_host_alias` ||
+ { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_host_alias failed" >&5
+echo "$as_me: error: $ac_config_sub $ac_cv_host_alias failed" >&2;}
+ { (exit 1); exit 1; }; }
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_host" >&5
+echo "${ECHO_T}$ac_cv_host" >&6
+host=$ac_cv_host
+host_cpu=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+host_vendor=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+host_os=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+
+
+
+#
+# checks that we use in most projects
+#
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}gcc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="gcc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ CC=$ac_ct_CC
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}cc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="cc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ CC=$ac_ct_CC
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+fi
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# != 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+ fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in cl
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$CC" && break
+ done
+fi
+if test -z "$CC"; then
+ ac_ct_CC=$CC
+ for ac_prog in cl
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$ac_ct_CC" && break
+done
+
+ CC=$ac_ct_CC
+fi
+
+fi
+
+
+test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&5
+echo "$as_me: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+
+# Provide some information about the compiler.
+echo "$as_me:$LINENO:" \
+ "checking for C compiler version" >&5
+ac_compiler=`set X $ac_compile; echo $2`
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version </dev/null >&5\"") >&5
+ (eval $ac_compiler --version </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v </dev/null >&5\"") >&5
+ (eval $ac_compiler -v </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V </dev/null >&5\"") >&5
+ (eval $ac_compiler -V </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+echo "$as_me:$LINENO: checking for C compiler default output file name" >&5
+echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6
+ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+if { (eval echo "$as_me:$LINENO: \"$ac_link_default\"") >&5
+ (eval $ac_link_default) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ # Find the output, starting from the most likely. This scheme is
+# not robust to junk in `.', hence go to wildcards (a.*) only as a last
+# resort.
+
+# Be careful to initialize this variable, since it used to be cached.
+# Otherwise an old cache value of `no' led to `EXEEXT = no' in a Makefile.
+ac_cv_exeext=
+# b.out is created by i960 compilers.
+for ac_file in a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out
+do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj )
+ ;;
+ conftest.$ac_ext )
+ # This is the source file.
+ ;;
+ [ab].out )
+ # We found the default executable, but exeext='' is most
+ # certainly right.
+ break;;
+ *.* )
+ ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ # FIXME: I believe we export ac_cv_exeext for Libtool,
+ # but it would be cool to find out if it's true. Does anybody
+ # maintain Libtool? --akim.
+ export ac_cv_exeext
+ break;;
+ * )
+ break;;
+ esac
+done
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { echo "$as_me:$LINENO: error: C compiler cannot create executables
+See \`config.log' for more details." >&5
+echo "$as_me: error: C compiler cannot create executables
+See \`config.log' for more details." >&2;}
+ { (exit 77); exit 77; }; }
+fi
+
+ac_exeext=$ac_cv_exeext
+echo "$as_me:$LINENO: result: $ac_file" >&5
+echo "${ECHO_T}$ac_file" >&6
+
+# Check the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+echo "$as_me:$LINENO: checking whether the C compiler works" >&5
+echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6
+# FIXME: These cross compiler hacks should be removed for Autoconf 3.0
+# If not cross compiling, check that we can run a simple program.
+if test "$cross_compiling" != yes; then
+ if { ac_try='./$ac_file'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ cross_compiling=no
+ else
+ if test "$cross_compiling" = maybe; then
+ cross_compiling=yes
+ else
+ { { echo "$as_me:$LINENO: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+ fi
+fi
+echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+
+rm -f a.out a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+# Check the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+echo "$as_me:$LINENO: checking whether we are cross compiling" >&5
+echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6
+echo "$as_me:$LINENO: result: $cross_compiling" >&5
+echo "${ECHO_T}$cross_compiling" >&6
+
+echo "$as_me:$LINENO: checking for suffix of executables" >&5
+echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) ;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ export ac_cv_exeext
+ break;;
+ * ) break;;
+ esac
+done
+else
+ { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+rm -f conftest$ac_cv_exeext
+echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5
+echo "${ECHO_T}$ac_cv_exeext" >&6
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+echo "$as_me:$LINENO: checking for suffix of object files" >&5
+echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6
+if test "${ac_cv_objext+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg ) ;;
+ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+ break;;
+ esac
+done
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_objext" >&5
+echo "${ECHO_T}$ac_cv_objext" >&6
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5
+echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6
+if test "${ac_cv_c_compiler_gnu+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_compiler_gnu=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_compiler_gnu=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5
+echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6
+GCC=`test $ac_compiler_gnu = yes && echo yes`
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+CFLAGS="-g"
+echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5
+echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6
+if test "${ac_cv_prog_cc_g+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_prog_cc_g=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_prog_cc_g=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_g" >&6
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+echo "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5
+echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6
+if test "${ac_cv_prog_cc_stdc+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_prog_cc_stdc=no
+ac_save_CC=$CC
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
+ function prototypes and stuff, but not '\xHH' hex character constants.
+ These don't provoke an error unfortunately, instead are silently treated
+ as 'x'. The following induces an error, until -std1 is added to get
+ proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
+ array size at least. It's necessary to write '\x00'==0 to get something
+ that's true only with -std1. */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+ ;
+ return 0;
+}
+_ACEOF
+# Don't try gcc -ansi; that turns off useful extensions and
+# breaks some systems' header files.
+# AIX -qlanglvl=ansi
+# Ultrix and OSF/1 -std1
+# HP-UX 10.20 and later -Ae
+# HP-UX older versions -Aa -D_HPUX_SOURCE
+# SVR4 -Xc -D__EXTENSIONS__
+for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_prog_cc_stdc=$ac_arg
+break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext
+done
+rm -f conftest.$ac_ext conftest.$ac_objext
+CC=$ac_save_CC
+
+fi
+
+case "x$ac_cv_prog_cc_stdc" in
+ x|xno)
+ echo "$as_me:$LINENO: result: none needed" >&5
+echo "${ECHO_T}none needed" >&6 ;;
+ *)
+ echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6
+ CC="$CC $ac_cv_prog_cc_stdc" ;;
+esac
+
+# Some people use a C++ compiler to compile C. Since we use `exit',
+# in C++ we need to declare it. In case someone uses the same compiler
+# for both compiling C and C++ we need to have the C++ compiler decide
+# the declaration of exit, since it's the most demanding environment.
+cat >conftest.$ac_ext <<_ACEOF
+#ifndef __cplusplus
+ choke me
+#endif
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ for ac_declaration in \
+ '' \
+ 'extern "C" void std::exit (int) throw (); using std::exit;' \
+ 'extern "C" void std::exit (int); using std::exit;' \
+ 'extern "C" void exit (int) throw ();' \
+ 'extern "C" void exit (int);' \
+ 'void exit (int);'
+do
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_declaration
+#include <stdlib.h>
+int
+main ()
+{
+exit (42);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+continue
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_declaration
+int
+main ()
+{
+exit (42);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+rm -f conftest*
+if test -n "$ac_declaration"; then
+ echo '#ifdef __cplusplus' >>confdefs.h
+ echo $ac_declaration >>confdefs.h
+ echo '#endif' >>confdefs.h
+fi
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+if test x"${EXEEXT}" = "xno"; then
+ EXEEXT=""
+fi
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ranlib; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_RANLIB+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$RANLIB"; then
+ ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+RANLIB=$ac_cv_prog_RANLIB
+if test -n "$RANLIB"; then
+ echo "$as_me:$LINENO: result: $RANLIB" >&5
+echo "${ECHO_T}$RANLIB" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_RANLIB"; then
+ ac_ct_RANLIB=$RANLIB
+ # Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_RANLIB"; then
+ ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_RANLIB="ranlib"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+ test -z "$ac_cv_prog_ac_ct_RANLIB" && ac_cv_prog_ac_ct_RANLIB=":"
+fi
+fi
+ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
+if test -n "$ac_ct_RANLIB"; then
+ echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5
+echo "${ECHO_T}$ac_ct_RANLIB" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ RANLIB=$ac_ct_RANLIB
+else
+ RANLIB="$ac_cv_prog_RANLIB"
+fi
+
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5
+echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+ if test "${ac_cv_prog_CPP+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ # Double quotes because CPP needs to be expanded
+ for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+ do
+ ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether non-existent headers
+ # can be detected and how.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ # Broken: success on invalid input.
+continue
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+ break
+fi
+
+ done
+ ac_cv_prog_CPP=$CPP
+
+fi
+ CPP=$ac_cv_prog_CPP
+else
+ ac_cv_prog_CPP=$CPP
+fi
+echo "$as_me:$LINENO: result: $CPP" >&5
+echo "${ECHO_T}$CPP" >&6
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether non-existent headers
+ # can be detected and how.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ # Broken: success on invalid input.
+continue
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+ :
+else
+ { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&5
+echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+echo "$as_me:$LINENO: checking for egrep" >&5
+echo $ECHO_N "checking for egrep... $ECHO_C" >&6
+if test "${ac_cv_prog_egrep+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if echo a | (grep -E '(a|b)') >/dev/null 2>&1
+ then ac_cv_prog_egrep='grep -E'
+ else ac_cv_prog_egrep='egrep'
+ fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_prog_egrep" >&5
+echo "${ECHO_T}$ac_cv_prog_egrep" >&6
+ EGREP=$ac_cv_prog_egrep
+
+
+echo "$as_me:$LINENO: checking for ANSI C header files" >&5
+echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6
+if test "${ac_cv_header_stdc+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_header_stdc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_header_stdc=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "memchr" >/dev/null 2>&1; then
+ :
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "free" >/dev/null 2>&1; then
+ :
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+ if test "$cross_compiling" = yes; then
+ :
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <ctype.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+ (('a' <= (c) && (c) <= 'i') \
+ || ('j' <= (c) && (c) <= 'r') \
+ || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+ int i;
+ for (i = 0; i < 256; i++)
+ if (XOR (islower (i), ISLOWER (i))
+ || toupper (i) != TOUPPER (i))
+ exit(2);
+ exit (0);
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ :
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_header_stdc=no
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5
+echo "${ECHO_T}$ac_cv_header_stdc" >&6
+if test $ac_cv_header_stdc = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define STDC_HEADERS 1
+_ACEOF
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+
+
+
+
+
+
+
+
+
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+ inttypes.h stdint.h unistd.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_Header=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_Header=no"
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+for ac_header in malloc.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to dmink@cfa.harvard.edu ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_header in getopt.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to dmink@cfa.harvard.edu ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_header in values.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to dmink@cfa.harvard.edu ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_header in dlfcn.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to dmink@cfa.harvard.edu ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_header in sys/un.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to dmink@cfa.harvard.edu ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_header in sys/mman.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to dmink@cfa.harvard.edu ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_header in sys/ipc.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to dmink@cfa.harvard.edu ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+case $host_os in
+ *cygwin*|*Cygwin* )
+ ;;
+ * )
+
+for ac_header in sys/shm.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to dmink@cfa.harvard.edu ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+ ;;
+esac
+
+echo "$as_me:$LINENO: checking for socklen_t" >&5
+echo $ECHO_N "checking for socklen_t... $ECHO_C" >&6
+if test "${ac_cv_type_socklen_t+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/socket.h>
+
+int
+main ()
+{
+if ((socklen_t *) 0)
+ return 0;
+if (sizeof (socklen_t))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_type_socklen_t=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_socklen_t=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_socklen_t" >&5
+echo "${ECHO_T}$ac_cv_type_socklen_t" >&6
+if test $ac_cv_type_socklen_t = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_SOCKLEN_T 1
+_ACEOF
+
+
+fi
+
+
+echo "$as_me:$LINENO: checking for an ANSI C-conforming const" >&5
+echo $ECHO_N "checking for an ANSI C-conforming const... $ECHO_C" >&6
+if test "${ac_cv_c_const+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+/* FIXME: Include the comments suggested by Paul. */
+#ifndef __cplusplus
+ /* Ultrix mips cc rejects this. */
+ typedef int charset[2];
+ const charset x;
+ /* SunOS 4.1.1 cc rejects this. */
+ char const *const *ccp;
+ char **p;
+ /* NEC SVR4.0.2 mips cc rejects this. */
+ struct point {int x, y;};
+ static struct point const zero = {0,0};
+ /* AIX XL C 1.02.0.0 rejects this.
+ It does not let you subtract one const X* pointer from another in
+ an arm of an if-expression whose if-part is not a constant
+ expression */
+ const char *g = "string";
+ ccp = &g + (g ? g-g : 0);
+ /* HPUX 7.0 cc rejects these. */
+ ++ccp;
+ p = (char**) ccp;
+ ccp = (char const *const *) p;
+ { /* SCO 3.2v4 cc rejects this. */
+ char *t;
+ char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+ *t++ = 0;
+ }
+ { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */
+ int x[] = {25, 17};
+ const int *foo = &x[0];
+ ++foo;
+ }
+ { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+ typedef const int *iptr;
+ iptr p = 0;
+ ++p;
+ }
+ { /* AIX XL C 1.02.0.0 rejects this saying
+ "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+ struct s { int j; const int *ap[3]; };
+ struct s *b; b->j = 5;
+ }
+ { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+ const int foo = 10;
+ }
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_c_const=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_c_const=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_const" >&5
+echo "${ECHO_T}$ac_cv_c_const" >&6
+if test $ac_cv_c_const = no; then
+
+cat >>confdefs.h <<\_ACEOF
+#define const
+_ACEOF
+
+fi
+
+
+
+
+
+for ac_func in strchr memcpy snprintf
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+echo "$as_me:$LINENO: checking for connect" >&5
+echo $ECHO_N "checking for connect... $ECHO_C" >&6
+if test "${ac_cv_func_connect+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define connect to an innocuous variant, in case <limits.h> declares connect.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define connect innocuous_connect
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char connect (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef connect
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char connect ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_connect) || defined (__stub___connect)
+choke me
+#else
+char (*f) () = connect;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != connect;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_connect=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_connect=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_connect" >&5
+echo "${ECHO_T}$ac_cv_func_connect" >&6
+
+if test $ac_cv_func_connect = no; then
+ echo "$as_me:$LINENO: checking for connect in -lsocket" >&5
+echo $ECHO_N "checking for connect in -lsocket... $ECHO_C" >&6
+if test "${ac_cv_lib_socket_connect+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsocket $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char connect ();
+int
+main ()
+{
+connect ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_socket_connect=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_socket_connect=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_socket_connect" >&5
+echo "${ECHO_T}$ac_cv_lib_socket_connect" >&6
+if test $ac_cv_lib_socket_connect = yes; then
+ EXTRA_LIBS="$EXTRA_LIBS -lsocket"
+fi
+
+fi
+echo "$as_me:$LINENO: checking for gethostbyname" >&5
+echo $ECHO_N "checking for gethostbyname... $ECHO_C" >&6
+if test "${ac_cv_func_gethostbyname+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define gethostbyname to an innocuous variant, in case <limits.h> declares gethostbyname.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define gethostbyname innocuous_gethostbyname
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char gethostbyname (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef gethostbyname
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char gethostbyname ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_gethostbyname) || defined (__stub___gethostbyname)
+choke me
+#else
+char (*f) () = gethostbyname;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != gethostbyname;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_gethostbyname=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_gethostbyname=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_gethostbyname" >&5
+echo "${ECHO_T}$ac_cv_func_gethostbyname" >&6
+
+if test $ac_cv_func_gethostbyname = no; then
+ echo "$as_me:$LINENO: checking for gethostbyname in -lnsl" >&5
+echo $ECHO_N "checking for gethostbyname in -lnsl... $ECHO_C" >&6
+if test "${ac_cv_lib_nsl_gethostbyname+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lnsl $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char gethostbyname ();
+int
+main ()
+{
+gethostbyname ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_nsl_gethostbyname=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_nsl_gethostbyname=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_nsl_gethostbyname" >&5
+echo "${ECHO_T}$ac_cv_lib_nsl_gethostbyname" >&6
+if test $ac_cv_lib_nsl_gethostbyname = yes; then
+ EXTRA_LIBS="$EXTRA_LIBS -lnsl"
+fi
+
+fi
+# AC_CHECK_LIB(db, snprintf, EXTRA_LIBS="$EXTRA_LIBS -ldb")
+
+#
+# checks specific to this project
+#
+
+echo "$as_me:$LINENO: checking for external wcslib" >&5
+echo $ECHO_N "checking for external wcslib... $ECHO_C" >&6
+
+# Check whether --with-wcslib or --without-wcslib was given.
+if test "${with_wcslib+set}" = set; then
+ withval="$with_wcslib"
+ wcslib=yes WHICHLIB="extlib" EXTLIB=$withval
+else
+ wcslib=no WHICHLIB="lib" EXTLIB=""
+fi;
+echo "$as_me:$LINENO: result: $wcslib" >&5
+echo "${ECHO_T}$wcslib" >&6
+
+
+
+DEFLIB="libwcs.a"
+echo "$as_me:$LINENO: checking for alternate target library" >&5
+echo $ECHO_N "checking for alternate target library... $ECHO_C" >&6
+
+# Check whether --with-altlib or --without-altlib was given.
+if test "${with_altlib+set}" = set; then
+ withval="$with_altlib"
+ alt_lib=yes LIB=$withval
+else
+ alt_lib=no LIB=$DEFLIB
+fi;
+echo "$as_me:$LINENO: result: $alt_lib ($LIB)" >&5
+echo "${ECHO_T}$alt_lib ($LIB)" >&6
+
+
+
+echo "$as_me:$LINENO: checking for shared library build" >&5
+echo $ECHO_N "checking for shared library build... $ECHO_C" >&6
+# Check whether --enable-shared or --disable-shared was given.
+if test "${enable_shared+set}" = set; then
+ enableval="$enable_shared"
+ fun_ok=$enableval
+else
+ fun_ok=no
+fi;
+if test "$fun_ok" != "no"; then
+ fpic="yes"
+ DOSHARED=shlib
+
+ if test "$fun_ok" = "link"; then
+ LLIB="-L. -l$PACKAGE_NAME"
+ else
+ LLIB='$(LIB)'
+ fi
+else
+ LLIB='$(LIB)'
+fi
+
+echo "$as_me:$LINENO: result: $fun_ok" >&5
+echo "${ECHO_T}$fun_ok" >&6
+
+# Check whether --enable-dl or --disable-dl was given.
+if test "${enable_dl+set}" = set; then
+ enableval="$enable_dl"
+ fun_ok=$enableval
+else
+ fun_ok=no
+fi;
+if test "$fun_ok" = "yes"; then
+echo "$as_me:$LINENO: checking for dynamic loading (with gcc) " >&5
+echo $ECHO_N "checking for dynamic loading (with gcc) ... $ECHO_C" >&6
+if test "$CC" = "gcc" -o `$CC -v 2>&1 | grep -c gcc` != "0" ; then
+ using_dl="yes"
+ echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5
+echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6
+if test "${ac_cv_lib_dl_dlopen+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char dlopen ();
+int
+main ()
+{
+dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_dl_dlopen=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_dl_dlopen=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5
+echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6
+if test $ac_cv_lib_dl_dlopen = yes; then
+ have_dl=yes
+else
+ have_dl=no
+fi
+
+ if test "$have_dl" = yes; then
+ USE_DL="-DUSE_DL=1"
+ fpic="yes"
+ EXTRA_LIBS="$EXTRA_LIBS -ldl"
+ if test `$CC -v -rdynamic 2>&1 | grep -c unrecognized` = "0" ; then
+ LDFLAGS="$LDFLAGS -rdynamic"
+ fi
+ else
+ echo "$as_me:$LINENO: checking for dlopen in -lc" >&5
+echo $ECHO_N "checking for dlopen in -lc... $ECHO_C" >&6
+if test "${ac_cv_lib_c_dlopen+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lc $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char dlopen ();
+int
+main ()
+{
+dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_c_dlopen=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_c_dlopen=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_c_dlopen" >&5
+echo "${ECHO_T}$ac_cv_lib_c_dlopen" >&6
+if test $ac_cv_lib_c_dlopen = yes; then
+ have_dl=yes
+else
+ have_dl=no
+fi
+
+ if test "$have_dl" = yes; then
+ USE_DL="-DUSE_DL=1"
+ fpic="yes"
+ if test `$CC -v -rdynamic 2>&1 | grep -c unrecognized` = "0" ; then
+ LDFLAGS="$LDFLAGS -rdynamic"
+ fi
+ else
+ using_dl="no"
+ fi
+ fi
+else
+ using_dl="no"
+fi
+echo "$as_me:$LINENO: result: $using_dl ($CC)" >&5
+echo "${ECHO_T}$using_dl ($CC)" >&6
+fi
+
+echo "$as_me:$LINENO: checking $host_os configuration" >&5
+echo $ECHO_N "checking $host_os configuration... $ECHO_C" >&6
+PRE=""
+POST="|\& cat"
+case $host_os in
+ *cygwin*|*Cygwin* )
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_CYGWIN
+_ACEOF
+
+ echo "$as_me:$LINENO: result: flagging Cygwin" >&5
+echo "${ECHO_T}flagging Cygwin" >&6
+ PRE="sh -c {"
+ POST="}"
+ ;;
+ *mingw32*|*Mingw32*)
+ CFLAGS="$CFLAGS -mconsole -D_WSTRING_DEFINED=1"
+ EXTRA_LIBS="$EXTRA_LIBS -lwsock32"
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_MINGW32
+_ACEOF
+
+ echo "$as_me:$LINENO: result: flagging MinGW" >&5
+echo "${ECHO_T}flagging MinGW" >&6
+ ;;
+ *osf*|*Osf*)
+ echo "$as_me:$LINENO: checking for snprintf in -ldb" >&5
+echo $ECHO_N "checking for snprintf in -ldb... $ECHO_C" >&6
+if test "${ac_cv_lib_db_snprintf+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldb $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char snprintf ();
+int
+main ()
+{
+snprintf ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_db_snprintf=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_db_snprintf=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_db_snprintf" >&5
+echo "${ECHO_T}$ac_cv_lib_db_snprintf" >&6
+if test $ac_cv_lib_db_snprintf = yes; then
+ EXTRA_LIBS="$EXTRA_LIBS -ldb"
+fi
+
+ ;;
+ *darwin*|*Darwin*)
+ LDFLAGS="$LDFLAGS $CFLAGS"
+ G=`$CC -v 2>&1 | grep version | awk '{print $3}' | awk -F. '{print $1$2}'`
+ if test x"$G" != x -a "$G" -lt 42; then
+ CFLAGS="$CFLAGS -no-cpp-precomp"
+ fi
+ CFLAGS="$CFLAGS -fno-common"
+ if test x"$fpic" = x"yes" ; then
+ CFLAGS="$CFLAGS -fPIC"
+ echo "$as_me:$LINENO: result: adding -fno-common, -fPIC to CFLAGS" >&5
+echo "${ECHO_T}adding -fno-common, -fPIC to CFLAGS" >&6
+ else
+ echo "$as_me:$LINENO: result: adding -fno-common to CFLAGS" >&5
+echo "${ECHO_T}adding -fno-common to CFLAGS" >&6
+ fi
+ ;;
+ * )
+ if test x"$fpic" = x"yes" ; then
+ if test "$CC" = "gcc" -o `$CC -v 2>&1 | grep -c gcc` != "0" ; then
+ CFLAGS="$CFLAGS -fPIC"
+ echo "$as_me:$LINENO: result: adding -fPIC to gcc" >&5
+echo "${ECHO_T}adding -fPIC to gcc" >&6
+ else
+ echo "$as_me:$LINENO: result: none" >&5
+echo "${ECHO_T}none" >&6
+ fi
+ else
+ echo "$as_me:$LINENO: result: none" >&5
+echo "${ECHO_T}none" >&6
+ fi
+ ;;
+esac
+
+
+
+
+
+
+ ac_config_files="$ac_config_files Makefile"
+
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+{
+ (set) 2>&1 |
+ case `(ac_space=' '; set | grep ac_space) 2>&1` in
+ *ac_space=\ *)
+ # `set' does not quote correctly, so add quotes (double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \).
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;;
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n \
+ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p"
+ ;;
+ esac;
+} |
+ sed '
+ t clear
+ : clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ : end' >>confcache
+if diff $cache_file confcache >/dev/null 2>&1; then :; else
+ if test -w $cache_file; then
+ test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file"
+ cat confcache >$cache_file
+ else
+ echo "not updating unwritable cache $cache_file"
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# VPATH may cause trouble with some makes, so we remove $(srcdir),
+# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=/{
+s/:*\$(srcdir):*/:/;
+s/:*\${srcdir}:*/:/;
+s/:*@srcdir@:*/:/;
+s/^\([^=]*=[ ]*\):*/\1/;
+s/:*$//;
+s/^[^=]*=[ ]*$//;
+}'
+fi
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_i=`echo "$ac_i" |
+ sed 's/\$U\././;s/\.o$//;s/\.obj$//'`
+ # 2. Add them.
+ ac_libobjs="$ac_libobjs $ac_i\$U.$ac_objext"
+ ac_ltlibobjs="$ac_ltlibobjs $ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: ${CONFIG_STATUS=./config.status}
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5
+echo "$as_me: creating $CONFIG_STATUS" >&6;}
+cat >$CONFIG_STATUS <<_ACEOF
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+SHELL=\${CONFIG_SHELL-$SHELL}
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+## --------------------- ##
+## M4sh Initialization. ##
+## --------------------- ##
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
+ set -o posix
+fi
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# Support unset when possible.
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+ as_unset=unset
+else
+ as_unset=false
+fi
+
+
+# Work around bugs in pre-3.0 UWIN ksh.
+$as_unset ENV MAIL MAILPATH
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+for as_var in \
+ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
+ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
+ LC_TELEPHONE LC_TIME
+do
+ if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then
+ eval $as_var=C; export $as_var
+ else
+ $as_unset $as_var
+ fi
+done
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+
+# Name of the executable.
+as_me=`$as_basename "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)$' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; }
+ /^X\/\(\/\/\)$/{ s//\1/; q; }
+ /^X\/\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+
+
+# PATH needs CR, and LINENO needs CR and PATH.
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ echo "#! /bin/sh" >conf$$.sh
+ echo "exit 0" >>conf$$.sh
+ chmod +x conf$$.sh
+ if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+ PATH_SEPARATOR=';'
+ else
+ PATH_SEPARATOR=:
+ fi
+ rm -f conf$$.sh
+fi
+
+
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x$as_lineno_3" = "x$as_lineno_2" || {
+ # Find who we are. Look in the path if we contain no path at all
+ # relative or not.
+ case $0 in
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+done
+
+ ;;
+ esac
+ # We did not find ourselves, most probably we were run as `sh COMMAND'
+ # in which case we are not to be found in the path.
+ if test "x$as_myself" = x; then
+ as_myself=$0
+ fi
+ if test ! -f "$as_myself"; then
+ { { echo "$as_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5
+echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+ case $CONFIG_SHELL in
+ '')
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for as_base in sh bash ksh sh5; do
+ case $as_dir in
+ /*)
+ if ("$as_dir/$as_base" -c '
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then
+ $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; }
+ $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; }
+ CONFIG_SHELL=$as_dir/$as_base
+ export CONFIG_SHELL
+ exec "$CONFIG_SHELL" "$0" ${1+"$@"}
+ fi;;
+ esac
+ done
+done
+;;
+ esac
+
+ # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+ # uniformly replaced by the line number. The first 'sed' inserts a
+ # line-number line before each line; the second 'sed' does the real
+ # work. The second script uses 'N' to pair each line-number line
+ # with the numbered line, and appends trailing '-' during
+ # substitution so that $LINENO is not a special case at line end.
+ # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+ # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-)
+ sed '=' <$as_myself |
+ sed '
+ N
+ s,$,-,
+ : loop
+ s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3,
+ t loop
+ s,-$,,
+ s,^['$as_cr_digits']*\n,,
+ ' >$as_me.lineno &&
+ chmod +x $as_me.lineno ||
+ { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5
+echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;}
+ { (exit 1); exit 1; }; }
+
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensible to this).
+ . ./$as_me.lineno
+ # Exit status is that of the last command.
+ exit
+}
+
+
+case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in
+ *c*,-n*) ECHO_N= ECHO_C='
+' ECHO_T=' ' ;;
+ *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;;
+ *) ECHO_N= ECHO_C='\c' ECHO_T= ;;
+esac
+
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+ # We could just check for DJGPP; but this test a) works b) is more generic
+ # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04).
+ if test -f conf$$.exe; then
+ # Don't use ln at all; we don't have any links
+ as_ln_s='cp -p'
+ else
+ as_ln_s='ln -s'
+ fi
+elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+else
+ as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.file
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p=:
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+as_executable_p="test -f"
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.
+as_nl='
+'
+IFS=" $as_nl"
+
+# CDPATH.
+$as_unset CDPATH
+
+exec 6>&1
+
+# Open the log real soon, to keep \$[0] and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling. Logging --version etc. is OK.
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+} >&5
+cat >&5 <<_CSEOF
+
+This file was extended by wcs $as_me 3.8.7, which was
+generated by GNU Autoconf 2.59. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+_CSEOF
+echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5
+echo >&5
+_ACEOF
+
+# Files that config.status was made for.
+if test -n "$ac_config_files"; then
+ echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_headers"; then
+ echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_links"; then
+ echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_commands"; then
+ echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+ac_cs_usage="\
+\`$as_me' instantiates files from templates according to the
+current configuration.
+
+Usage: $0 [OPTIONS] [FILE]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number, then exit
+ -q, --quiet do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+ --header=FILE[:TEMPLATE]
+ instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Report bugs to <bug-autoconf@gnu.org>."
+_ACEOF
+
+cat >>$CONFIG_STATUS <<_ACEOF
+ac_cs_version="\\
+wcs config.status 3.8.7
+configured by $0, generated by GNU Autoconf 2.59,
+ with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"
+
+Copyright (C) 2003 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+srcdir=$srcdir
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+# If no file are specified by the user, then we need to provide default
+# value. By we need to know if files were specified by the user.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=*)
+ ac_option=`expr "x$1" : 'x\([^=]*\)='`
+ ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ -*)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ *) # This is not an option, so the user has probably given explicit
+ # arguments.
+ ac_option=$1
+ ac_need_defaults=false;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --vers* | -V )
+ echo "$ac_cs_version"; exit 0 ;;
+ --he | --h)
+ # Conflict between --help and --header
+ { { echo "$as_me:$LINENO: error: ambiguous option: $1
+Try \`$0 --help' for more information." >&5
+echo "$as_me: error: ambiguous option: $1
+Try \`$0 --help' for more information." >&2;}
+ { (exit 1); exit 1; }; };;
+ --help | --hel | -h )
+ echo "$ac_cs_usage"; exit 0 ;;
+ --debug | --d* | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ CONFIG_FILES="$CONFIG_FILES $ac_optarg"
+ ac_need_defaults=false;;
+ --header | --heade | --head | --hea )
+ $ac_shift
+ CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg"
+ ac_need_defaults=false;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1
+Try \`$0 --help' for more information." >&5
+echo "$as_me: error: unrecognized option: $1
+Try \`$0 --help' for more information." >&2;}
+ { (exit 1); exit 1; }; } ;;
+
+ *) ac_config_targets="$ac_config_targets $1" ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+if \$ac_cs_recheck; then
+ echo "running $SHELL $0 " $ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6
+ exec $SHELL $0 $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+fi
+
+_ACEOF
+
+
+
+
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+for ac_config_target in $ac_config_targets
+do
+ case "$ac_config_target" in
+ # Handling of arguments.
+ "Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+ "conf.h" ) CONFIG_HEADERS="$CONFIG_HEADERS conf.h" ;;
+ *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5
+echo "$as_me: error: invalid argument: $ac_config_target" >&2;}
+ { (exit 1); exit 1; }; };;
+ esac
+done
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+ test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason to put it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Create a temporary directory, and hook for its removal unless debugging.
+$debug ||
+{
+ trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0
+ trap '{ (exit 1); exit 1; }' 1 2 13 15
+}
+
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d -q "./confstatXXXXXX") 2>/dev/null` &&
+ test -n "$tmp" && test -d "$tmp"
+} ||
+{
+ tmp=./confstat$$-$RANDOM
+ (umask 077 && mkdir $tmp)
+} ||
+{
+ echo "$me: cannot create a temporary directory in ." >&2
+ { (exit 1); exit 1; }
+}
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<_ACEOF
+
+#
+# CONFIG_FILES section.
+#
+
+# No need to generate the scripts if there are no CONFIG_FILES.
+# This happens for instance when ./config.status config.h
+if test -n "\$CONFIG_FILES"; then
+ # Protect against being on the right side of a sed subst in config.status.
+ sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g;
+ s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF
+s,@SHELL@,$SHELL,;t t
+s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t
+s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t
+s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t
+s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t
+s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t
+s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t
+s,@exec_prefix@,$exec_prefix,;t t
+s,@prefix@,$prefix,;t t
+s,@program_transform_name@,$program_transform_name,;t t
+s,@bindir@,$bindir,;t t
+s,@sbindir@,$sbindir,;t t
+s,@libexecdir@,$libexecdir,;t t
+s,@datadir@,$datadir,;t t
+s,@sysconfdir@,$sysconfdir,;t t
+s,@sharedstatedir@,$sharedstatedir,;t t
+s,@localstatedir@,$localstatedir,;t t
+s,@libdir@,$libdir,;t t
+s,@includedir@,$includedir,;t t
+s,@oldincludedir@,$oldincludedir,;t t
+s,@infodir@,$infodir,;t t
+s,@mandir@,$mandir,;t t
+s,@build_alias@,$build_alias,;t t
+s,@host_alias@,$host_alias,;t t
+s,@target_alias@,$target_alias,;t t
+s,@DEFS@,$DEFS,;t t
+s,@ECHO_C@,$ECHO_C,;t t
+s,@ECHO_N@,$ECHO_N,;t t
+s,@ECHO_T@,$ECHO_T,;t t
+s,@LIBS@,$LIBS,;t t
+s,@build@,$build,;t t
+s,@build_cpu@,$build_cpu,;t t
+s,@build_vendor@,$build_vendor,;t t
+s,@build_os@,$build_os,;t t
+s,@host@,$host,;t t
+s,@host_cpu@,$host_cpu,;t t
+s,@host_vendor@,$host_vendor,;t t
+s,@host_os@,$host_os,;t t
+s,@CC@,$CC,;t t
+s,@CFLAGS@,$CFLAGS,;t t
+s,@LDFLAGS@,$LDFLAGS,;t t
+s,@CPPFLAGS@,$CPPFLAGS,;t t
+s,@ac_ct_CC@,$ac_ct_CC,;t t
+s,@EXEEXT@,$EXEEXT,;t t
+s,@OBJEXT@,$OBJEXT,;t t
+s,@RANLIB@,$RANLIB,;t t
+s,@ac_ct_RANLIB@,$ac_ct_RANLIB,;t t
+s,@CPP@,$CPP,;t t
+s,@EGREP@,$EGREP,;t t
+s,@WHICHLIB@,$WHICHLIB,;t t
+s,@EXTLIB@,$EXTLIB,;t t
+s,@LIB@,$LIB,;t t
+s,@DEFLIB@,$DEFLIB,;t t
+s,@DOSHARED@,$DOSHARED,;t t
+s,@LLIB@,$LLIB,;t t
+s,@USE_DL@,$USE_DL,;t t
+s,@EXTRA_LIBS@,$EXTRA_LIBS,;t t
+s,@EXTRA_OBJS@,$EXTRA_OBJS,;t t
+s,@LIBOBJS@,$LIBOBJS,;t t
+s,@LTLIBOBJS@,$LTLIBOBJS,;t t
+CEOF
+
+_ACEOF
+
+ cat >>$CONFIG_STATUS <<\_ACEOF
+ # Split the substitutions into bite-sized pieces for seds with
+ # small command number limits, like on Digital OSF/1 and HP-UX.
+ ac_max_sed_lines=48
+ ac_sed_frag=1 # Number of current file.
+ ac_beg=1 # First line for current file.
+ ac_end=$ac_max_sed_lines # Line after last line for current file.
+ ac_more_lines=:
+ ac_sed_cmds=
+ while $ac_more_lines; do
+ if test $ac_beg -gt 1; then
+ sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag
+ else
+ sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag
+ fi
+ if test ! -s $tmp/subs.frag; then
+ ac_more_lines=false
+ else
+ # The purpose of the label and of the branching condition is to
+ # speed up the sed processing (if there are no `@' at all, there
+ # is no need to browse any of the substitutions).
+ # These are the two extra sed commands mentioned above.
+ (echo ':t
+ /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed"
+ else
+ ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed"
+ fi
+ ac_sed_frag=`expr $ac_sed_frag + 1`
+ ac_beg=$ac_end
+ ac_end=`expr $ac_end + $ac_max_sed_lines`
+ fi
+ done
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds=cat
+ fi
+fi # test -n "$CONFIG_FILES"
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case $ac_file in
+ - | *:- | *:-:* ) # input from stdin
+ cat >$tmp/stdin
+ ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+ *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+ * ) ac_file_in=$ac_file.in ;;
+ esac
+
+ # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories.
+ ac_dir=`(dirname "$ac_file") 2>/dev/null ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ { if $as_mkdir_p; then
+ mkdir -p "$ac_dir"
+ else
+ as_dir="$ac_dir"
+ as_dirs=
+ while test ! -d "$as_dir"; do
+ as_dirs="$as_dir $as_dirs"
+ as_dir=`(dirname "$as_dir") 2>/dev/null ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ done
+ test ! -n "$as_dirs" || mkdir $as_dirs
+ fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5
+echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;}
+ { (exit 1); exit 1; }; }; }
+
+ ac_builddir=.
+
+if test "$ac_dir" != .; then
+ ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'`
+else
+ ac_dir_suffix= ac_top_builddir=
+fi
+
+case $srcdir in
+ .) # No --srcdir option. We are building in place.
+ ac_srcdir=.
+ if test -z "$ac_top_builddir"; then
+ ac_top_srcdir=.
+ else
+ ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'`
+ fi ;;
+ [\\/]* | ?:[\\/]* ) # Absolute path.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir ;;
+ *) # Relative path.
+ ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_builddir$srcdir ;;
+esac
+
+# Do not use `cd foo && pwd` to compute absolute paths, because
+# the directories may not exist.
+case `pwd` in
+.) ac_abs_builddir="$ac_dir";;
+*)
+ case "$ac_dir" in
+ .) ac_abs_builddir=`pwd`;;
+ [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";;
+ *) ac_abs_builddir=`pwd`/"$ac_dir";;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_builddir=${ac_top_builddir}.;;
+*)
+ case ${ac_top_builddir}. in
+ .) ac_abs_top_builddir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;;
+ *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_srcdir=$ac_srcdir;;
+*)
+ case $ac_srcdir in
+ .) ac_abs_srcdir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;;
+ *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_srcdir=$ac_top_srcdir;;
+*)
+ case $ac_top_srcdir in
+ .) ac_abs_top_srcdir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;;
+ *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;;
+ esac;;
+esac
+
+
+
+ if test x"$ac_file" != x-; then
+ { echo "$as_me:$LINENO: creating $ac_file" >&5
+echo "$as_me: creating $ac_file" >&6;}
+ rm -f "$ac_file"
+ fi
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ if test x"$ac_file" = x-; then
+ configure_input=
+ else
+ configure_input="$ac_file. "
+ fi
+ configure_input=$configure_input"Generated from `echo $ac_file_in |
+ sed 's,.*/,,'` by configure."
+
+ # First look for the input files in the build tree, otherwise in the
+ # src tree.
+ ac_file_inputs=`IFS=:
+ for f in $ac_file_in; do
+ case $f in
+ -) echo $tmp/stdin ;;
+ [\\/$]*)
+ # Absolute (can't be DOS-style, as IFS=:)
+ test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+ { (exit 1); exit 1; }; }
+ echo "$f";;
+ *) # Relative
+ if test -f "$f"; then
+ # Build tree
+ echo "$f"
+ elif test -f "$srcdir/$f"; then
+ # Source tree
+ echo "$srcdir/$f"
+ else
+ # /dev/null tree
+ { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+ { (exit 1); exit 1; }; }
+ fi;;
+ esac
+ done` || { (exit 1); exit 1; }
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+ sed "$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s,@configure_input@,$configure_input,;t t
+s,@srcdir@,$ac_srcdir,;t t
+s,@abs_srcdir@,$ac_abs_srcdir,;t t
+s,@top_srcdir@,$ac_top_srcdir,;t t
+s,@abs_top_srcdir@,$ac_abs_top_srcdir,;t t
+s,@builddir@,$ac_builddir,;t t
+s,@abs_builddir@,$ac_abs_builddir,;t t
+s,@top_builddir@,$ac_top_builddir,;t t
+s,@abs_top_builddir@,$ac_abs_top_builddir,;t t
+" $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out
+ rm -f $tmp/stdin
+ if test x"$ac_file" != x-; then
+ mv $tmp/out $ac_file
+ else
+ cat $tmp/out
+ rm -f $tmp/out
+ fi
+
+done
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+#
+# CONFIG_HEADER section.
+#
+
+# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
+# NAME is the cpp macro being defined and VALUE is the value it is being given.
+#
+# ac_d sets the value in "#define NAME VALUE" lines.
+ac_dA='s,^\([ ]*\)#\([ ]*define[ ][ ]*\)'
+ac_dB='[ ].*$,\1#\2'
+ac_dC=' '
+ac_dD=',;t'
+# ac_u turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
+ac_uA='s,^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_uB='$,\1#\2define\3'
+ac_uC=' '
+ac_uD=',;t'
+
+for ac_file in : $CONFIG_HEADERS; do test "x$ac_file" = x: && continue
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case $ac_file in
+ - | *:- | *:-:* ) # input from stdin
+ cat >$tmp/stdin
+ ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+ *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+ * ) ac_file_in=$ac_file.in ;;
+ esac
+
+ test x"$ac_file" != x- && { echo "$as_me:$LINENO: creating $ac_file" >&5
+echo "$as_me: creating $ac_file" >&6;}
+
+ # First look for the input files in the build tree, otherwise in the
+ # src tree.
+ ac_file_inputs=`IFS=:
+ for f in $ac_file_in; do
+ case $f in
+ -) echo $tmp/stdin ;;
+ [\\/$]*)
+ # Absolute (can't be DOS-style, as IFS=:)
+ test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+ { (exit 1); exit 1; }; }
+ # Do quote $f, to prevent DOS paths from being IFS'd.
+ echo "$f";;
+ *) # Relative
+ if test -f "$f"; then
+ # Build tree
+ echo "$f"
+ elif test -f "$srcdir/$f"; then
+ # Source tree
+ echo "$srcdir/$f"
+ else
+ # /dev/null tree
+ { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+ { (exit 1); exit 1; }; }
+ fi;;
+ esac
+ done` || { (exit 1); exit 1; }
+ # Remove the trailing spaces.
+ sed 's/[ ]*$//' $ac_file_inputs >$tmp/in
+
+_ACEOF
+
+# Transform confdefs.h into two sed scripts, `conftest.defines' and
+# `conftest.undefs', that substitutes the proper values into
+# config.h.in to produce config.h. The first handles `#define'
+# templates, and the second `#undef' templates.
+# And first: Protect against being on the right side of a sed subst in
+# config.status. Protect against being in an unquoted here document
+# in config.status.
+rm -f conftest.defines conftest.undefs
+# Using a here document instead of a string reduces the quoting nightmare.
+# Putting comments in sed scripts is not portable.
+#
+# `end' is used to avoid that the second main sed command (meant for
+# 0-ary CPP macros) applies to n-ary macro definitions.
+# See the Autoconf documentation for `clear'.
+cat >confdef2sed.sed <<\_ACEOF
+s/[\\&,]/\\&/g
+s,[\\$`],\\&,g
+t clear
+: clear
+s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*\)\(([^)]*)\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1\2${ac_dC}\3${ac_dD},gp
+t end
+s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD},gp
+: end
+_ACEOF
+# If some macros were called several times there might be several times
+# the same #defines, which is useless. Nevertheless, we may not want to
+# sort them, since we want the *last* AC-DEFINE to be honored.
+uniq confdefs.h | sed -n -f confdef2sed.sed >conftest.defines
+sed 's/ac_d/ac_u/g' conftest.defines >conftest.undefs
+rm -f confdef2sed.sed
+
+# This sed command replaces #undef with comments. This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it.
+cat >>conftest.undefs <<\_ACEOF
+s,^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*,/* & */,
+_ACEOF
+
+# Break up conftest.defines because some shells have a limit on the size
+# of here documents, and old seds have small limits too (100 cmds).
+echo ' # Handle all the #define templates only if necessary.' >>$CONFIG_STATUS
+echo ' if grep "^[ ]*#[ ]*define" $tmp/in >/dev/null; then' >>$CONFIG_STATUS
+echo ' # If there are no defines, we may have an empty if/fi' >>$CONFIG_STATUS
+echo ' :' >>$CONFIG_STATUS
+rm -f conftest.tail
+while grep . conftest.defines >/dev/null
+do
+ # Write a limited-size here document to $tmp/defines.sed.
+ echo ' cat >$tmp/defines.sed <<CEOF' >>$CONFIG_STATUS
+ # Speed up: don't consider the non `#define' lines.
+ echo '/^[ ]*#[ ]*define/!b' >>$CONFIG_STATUS
+ # Work around the forget-to-reset-the-flag bug.
+ echo 't clr' >>$CONFIG_STATUS
+ echo ': clr' >>$CONFIG_STATUS
+ sed ${ac_max_here_lines}q conftest.defines >>$CONFIG_STATUS
+ echo 'CEOF
+ sed -f $tmp/defines.sed $tmp/in >$tmp/out
+ rm -f $tmp/in
+ mv $tmp/out $tmp/in
+' >>$CONFIG_STATUS
+ sed 1,${ac_max_here_lines}d conftest.defines >conftest.tail
+ rm -f conftest.defines
+ mv conftest.tail conftest.defines
+done
+rm -f conftest.defines
+echo ' fi # grep' >>$CONFIG_STATUS
+echo >>$CONFIG_STATUS
+
+# Break up conftest.undefs because some shells have a limit on the size
+# of here documents, and old seds have small limits too (100 cmds).
+echo ' # Handle all the #undef templates' >>$CONFIG_STATUS
+rm -f conftest.tail
+while grep . conftest.undefs >/dev/null
+do
+ # Write a limited-size here document to $tmp/undefs.sed.
+ echo ' cat >$tmp/undefs.sed <<CEOF' >>$CONFIG_STATUS
+ # Speed up: don't consider the non `#undef'
+ echo '/^[ ]*#[ ]*undef/!b' >>$CONFIG_STATUS
+ # Work around the forget-to-reset-the-flag bug.
+ echo 't clr' >>$CONFIG_STATUS
+ echo ': clr' >>$CONFIG_STATUS
+ sed ${ac_max_here_lines}q conftest.undefs >>$CONFIG_STATUS
+ echo 'CEOF
+ sed -f $tmp/undefs.sed $tmp/in >$tmp/out
+ rm -f $tmp/in
+ mv $tmp/out $tmp/in
+' >>$CONFIG_STATUS
+ sed 1,${ac_max_here_lines}d conftest.undefs >conftest.tail
+ rm -f conftest.undefs
+ mv conftest.tail conftest.undefs
+done
+rm -f conftest.undefs
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ if test x"$ac_file" = x-; then
+ echo "/* Generated by configure. */" >$tmp/config.h
+ else
+ echo "/* $ac_file. Generated by configure. */" >$tmp/config.h
+ fi
+ cat $tmp/in >>$tmp/config.h
+ rm -f $tmp/in
+ if test x"$ac_file" != x-; then
+ if diff $ac_file $tmp/config.h >/dev/null 2>&1; then
+ { echo "$as_me:$LINENO: $ac_file is unchanged" >&5
+echo "$as_me: $ac_file is unchanged" >&6;}
+ else
+ ac_dir=`(dirname "$ac_file") 2>/dev/null ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ { if $as_mkdir_p; then
+ mkdir -p "$ac_dir"
+ else
+ as_dir="$ac_dir"
+ as_dirs=
+ while test ! -d "$as_dir"; do
+ as_dirs="$as_dir $as_dirs"
+ as_dir=`(dirname "$as_dir") 2>/dev/null ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ done
+ test ! -n "$as_dirs" || mkdir $as_dirs
+ fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5
+echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;}
+ { (exit 1); exit 1; }; }; }
+
+ rm -f $ac_file
+ mv $tmp/config.h $ac_file
+ fi
+ else
+ cat $tmp/config.h
+ rm -f $tmp/config.h
+ fi
+done
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+{ (exit 0); exit 0; }
+_ACEOF
+chmod +x $CONFIG_STATUS
+ac_clean_files=$ac_clean_files_save
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || { (exit 1); exit 1; }
+fi
+
diff --git a/funtools/wcs/configure.ac b/funtools/wcs/configure.ac
new file mode 100644
index 0000000..f8449c3
--- /dev/null
+++ b/funtools/wcs/configure.ac
@@ -0,0 +1,177 @@
+# This file is an input file used by the GNU "autoconf" program to
+# generate the file "configure", which is run during XPA installation
+# to configure the system for the local environment.
+AC_INIT(wcs, 3.8.7, dmink@cfa.harvard.edu, wcs)
+
+AC_CONFIG_HEADERS([conf.h])
+AC_CONFIG_SRCDIR(./wcs.h)
+AC_CANONICAL_HOST
+
+#
+# checks that we use in most projects
+#
+AC_PROG_CC
+
+AC_EXEEXT
+if test x"${EXEEXT}" = "xno"; then
+ EXEEXT=""
+fi
+
+AC_PROG_RANLIB
+
+AC_HEADER_STDC
+AC_CHECK_HEADERS(malloc.h)
+AC_CHECK_HEADERS(getopt.h)
+AC_CHECK_HEADERS(values.h)
+AC_CHECK_HEADERS(dlfcn.h)
+AC_CHECK_HEADERS(sys/un.h)
+AC_CHECK_HEADERS(sys/mman.h)
+AC_CHECK_HEADERS(sys/ipc.h)
+case $host_os in
+ *cygwin*|*Cygwin* )
+ ;;
+ * )
+ AC_CHECK_HEADERS(sys/shm.h)
+ ;;
+esac
+
+AC_CHECK_TYPES([socklen_t], [], [], [#include <sys/socket.h>])
+
+AC_C_CONST
+
+AC_CHECK_FUNCS(strchr memcpy snprintf)
+
+AC_CHECK_FUNC(connect)
+if test $ac_cv_func_connect = no; then
+ AC_CHECK_LIB(socket, connect, EXTRA_LIBS="$EXTRA_LIBS -lsocket")
+fi
+AC_CHECK_FUNC(gethostbyname)
+if test $ac_cv_func_gethostbyname = no; then
+ AC_CHECK_LIB(nsl, gethostbyname, EXTRA_LIBS="$EXTRA_LIBS -lnsl")
+fi
+# AC_CHECK_LIB(db, snprintf, EXTRA_LIBS="$EXTRA_LIBS -ldb")
+
+#
+# checks specific to this project
+#
+
+AC_MSG_CHECKING(for external wcslib)
+AC_ARG_WITH(wcslib, [ --with-wcslib=LIB library name],
+ wcslib=yes WHICHLIB="extlib" EXTLIB=$withval, wcslib=no WHICHLIB="lib" EXTLIB="")
+AC_MSG_RESULT($wcslib)
+AC_SUBST(WHICHLIB)
+AC_SUBST(EXTLIB)
+
+DEFLIB="libwcs.a"
+AC_MSG_CHECKING(for alternate target library)
+AC_ARG_WITH(altlib, [ --with-altlib=LIB library name],
+ alt_lib=yes LIB=$withval, alt_lib=no LIB=$DEFLIB)
+AC_MSG_RESULT($alt_lib ($LIB))
+AC_SUBST(LIB)
+AC_SUBST(DEFLIB)
+
+AC_MSG_CHECKING(for shared library build)
+AC_ARG_ENABLE(shared, [ --enable-shared build shared libraries],
+ [fun_ok=$enableval], [fun_ok=no])
+if test "$fun_ok" != "no"; then
+ fpic="yes"
+ DOSHARED=shlib
+ AC_SUBST(DOSHARED)
+ if test "$fun_ok" = "link"; then
+ LLIB="-L. -l$PACKAGE_NAME"
+ else
+ LLIB='$(LIB)'
+ fi
+else
+ LLIB='$(LIB)'
+fi
+AC_SUBST(LLIB)
+AC_MSG_RESULT($fun_ok)
+
+AC_ARG_ENABLE(dl, [ --enable-dl allow use of dynamic loading if available],
+ [fun_ok=$enableval], [fun_ok=no])
+if test "$fun_ok" = "yes"; then
+AC_MSG_CHECKING([for dynamic loading (with gcc) ])
+if test "$CC" = "gcc" -o `$CC -v 2>&1 | grep -c gcc` != "0" ; then
+ using_dl="yes"
+ AC_CHECK_LIB(dl, dlopen, have_dl=yes, have_dl=no)
+ if test "$have_dl" = yes; then
+ USE_DL="-DUSE_DL=1"
+ fpic="yes"
+ EXTRA_LIBS="$EXTRA_LIBS -ldl"
+ if test `$CC -v -rdynamic 2>&1 | grep -c unrecognized` = "0" ; then
+ LDFLAGS="$LDFLAGS -rdynamic"
+ fi
+ else
+ AC_CHECK_LIB(c, dlopen, have_dl=yes, have_dl=no)
+ if test "$have_dl" = yes; then
+ USE_DL="-DUSE_DL=1"
+ fpic="yes"
+ if test `$CC -v -rdynamic 2>&1 | grep -c unrecognized` = "0" ; then
+ LDFLAGS="$LDFLAGS -rdynamic"
+ fi
+ else
+ using_dl="no"
+ fi
+ fi
+else
+ using_dl="no"
+fi
+AC_MSG_RESULT([$using_dl ($CC)])
+fi
+
+AC_MSG_CHECKING([$host_os configuration])
+PRE=""
+POST="|\& cat"
+case $host_os in
+ *cygwin*|*Cygwin* )
+ AC_DEFINE([HAVE_CYGWIN])
+ AC_MSG_RESULT(flagging Cygwin)
+ PRE="sh -c {"
+ POST="}"
+ ;;
+ *mingw32*|*Mingw32*)
+ CFLAGS="$CFLAGS -mconsole -D_WSTRING_DEFINED=1"
+ EXTRA_LIBS="$EXTRA_LIBS -lwsock32"
+ AC_DEFINE([HAVE_MINGW32])
+ AC_MSG_RESULT(flagging MinGW)
+ ;;
+ *osf*|*Osf*)
+ AC_CHECK_LIB(db, snprintf, EXTRA_LIBS="$EXTRA_LIBS -ldb")
+ ;;
+ *darwin*|*Darwin*)
+ LDFLAGS="$LDFLAGS $CFLAGS"
+ G=`$CC -v 2>&1 | grep version | awk '{print $3}' | awk -F. '{print $1$2}'`
+ if test x"$G" != x -a "$G" -lt 42; then
+ CFLAGS="$CFLAGS -no-cpp-precomp"
+ fi
+ CFLAGS="$CFLAGS -fno-common"
+ if test x"$fpic" = x"yes" ; then
+ CFLAGS="$CFLAGS -fPIC"
+ AC_MSG_RESULT([adding -fno-common, -fPIC to CFLAGS])
+ else
+ AC_MSG_RESULT([adding -fno-common to CFLAGS])
+ fi
+ ;;
+ * )
+ if test x"$fpic" = x"yes" ; then
+ if test "$CC" = "gcc" -o `$CC -v 2>&1 | grep -c gcc` != "0" ; then
+ CFLAGS="$CFLAGS -fPIC"
+ AC_MSG_RESULT(adding -fPIC to gcc)
+ else
+ AC_MSG_RESULT(none)
+ fi
+ else
+ AC_MSG_RESULT(none)
+ fi
+ ;;
+esac
+
+AC_SUBST(USE_DL)
+
+AC_SUBST(EXTRA_LIBS)
+AC_SUBST(EXTRA_OBJS)
+
+AC_CONFIG_FILES(Makefile)
+
+AC_OUTPUT
diff --git a/funtools/wcs/dateutil.c b/funtools/wcs/dateutil.c
new file mode 100644
index 0000000..ada0c95
--- /dev/null
+++ b/funtools/wcs/dateutil.c
@@ -0,0 +1,4554 @@
+/*** File libwcs/dateutil.c
+ *** October 19, 2012
+ *** By Jessica Mink, jmink@cfa.harvard.edu
+ *** Harvard-Smithsonian Center for Astrophysics
+ *** Copyright (C) 1999-2012
+ *** Smithsonian Astrophysical Observatory, Cambridge, MA, USA
+
+ This library 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 2 of the License, or (at your option) any later version.
+
+ This library 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 this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Correspondence concerning WCSTools should be addressed as follows:
+ Internet email: jmink@cfa.harvard.edu
+ Postal address: Jessica Mink
+ Smithsonian Astrophysical Observatory
+ 60 Garden St.
+ Cambridge, MA 02138 USA
+ */
+
+/* Date and time conversion routines using the following conventions:
+ ang = Angle in fractional degrees
+ deg = Angle in degrees as dd:mm:ss.ss
+ doy = 2 floating point numbers: year and day, including fraction, of year
+ *** First day of year is 1, not zero.
+ dt = 2 floating point numbers: yyyy.mmdd, hh.mmssssss
+ ep = fractional year, often epoch of a position including proper motion
+ epb = Besselian epoch = 365.242198781-day years based on 1900.0
+ epj = Julian epoch = 365.25-day years based on 2000.0
+ fd = FITS date string which may be any of the following:
+ yyyy.ffff (fractional year)
+ dd/mm/yy (FITS standard before 2000)
+ dd-mm-yy (nonstandard FITS use before 2000)
+ yyyy-mm-dd (FITS standard after 1999)
+ yyyy-mm-ddThh:mm:ss.ss (FITS standard after 1999)
+ hr = Sexigesimal hours as hh:mm:dd.ss
+ jd = Julian Date
+ lt = Local time
+ mjd = modified Julian Date = JD - 2400000.5
+ ofd = FITS date string (dd/mm/yy before 2000, else no return)
+ time = use fd2* with no date to convert time as hh:mm:ss.ss to sec, day, year
+ ts = UT seconds since 1950-01-01T00:00 (used for ephemeris computations)
+ tsi = local seconds since 1980-01-01T00:00 (used by IRAF as a time tag)
+ tsu = UT seconds since 1970-01-01T00:00 (used as Unix system time)
+ tsd = UT seconds of current day
+ ut = Universal Time (UTC)
+ et = Ephemeris Time (or TDB or TT) = TAI + 32.184 seconds
+ tai = International Atomic Time (Temps Atomique International) = ET - 32.184 seconds
+ gps = GPS time = TAI - 19 seconds
+ mst = Mean Greenwich Sidereal Time
+ gst = Greenwich Sidereal Time (includes nutation)
+ lst = Local Sidereal Time (includes nutation) (longitude must be set)
+ hjd = Heliocentric Julian Date
+ mhjd = modified Heliocentric Julian Date = HJD - 2400000.5
+
+ * ang2hr (angle)
+ * Convert angle in decimal floating point degrees to hours as hh:mm:ss.ss
+ * ang2deg (angle)
+ * Convert angle in decimal floating point degrees to degrees as dd:mm:ss.ss
+ * deg2ang (angle as dd:mm:ss.ss)
+ * Convert angle in degrees as dd:mm:ss.ss to decimal floating point degrees
+ * ang2hr (angle)
+ * Convert angle in hours as hh:mm:ss.ss to decimal floating point degrees
+ *
+ * doy2dt (year, doy, date, time)
+ * Convert year and day of year to date as yyyy.ddmm and time as hh.mmsss
+ * doy2ep, doy2epb, doy2epj (date, time)
+ * Convert year and day of year to fractional year
+ * doy2fd (year, doy)
+ * Convert year and day of year to FITS date string
+ * doy2mjd (year, doy)
+ * Convert year and day of year to modified Julian date
+ *
+ * dt2doy (date, time, year, doy)
+ * Convert date as yyyy.ddmm and time as hh.mmsss to year and day of year
+ * dt2ep, dt2epb, dt2epj (date, time)
+ * Convert date as yyyy.ddmm and time as hh.mmsss to fractional year
+ * dt2fd (date, time)
+ * Convert date as yyyy.ddmm and time as hh.mmsss to FITS date string
+ * dt2i (date,time,iyr,imon,iday,ihr,imn,sec, ndsec)
+ * Convert yyyy.mmdd hh.mmssss to year month day hours minutes seconds
+ * dt2jd (date,time)
+ * Convert date as yyyy.ddmm and time as hh.mmsss to Julian date
+ * dt2mjd (date,time)
+ * Convert date as yyyy.ddmm and time as hh.mmsss to modified Julian date
+ * dt2ts (date,time)
+ * Convert date (yyyy.ddmm) and time (hh.mmsss) to seconds since 1950-01-01
+ * dt2tsi (date,time)
+ * Convert date (yyyy.ddmm) and time (hh.mmsss) to seconds since 1980-01-01
+ * dt2tsu (date,time)
+ * Convert date (yyyy.ddmm) and time (hh.mmsss) to seconds since 1970-01-01
+ *
+ * ep2dt, epb2dt, epj2dt (epoch,date, time)
+ * Convert fractional year to date as yyyy.ddmm and time as hh.mmsss
+ * ep2fd, epb2fd, epj2fd (epoch)
+ * Convert epoch to FITS ISO date string
+ * ep2i, epb2i, epj2i (epoch,iyr,imon,iday,ihr,imn,sec, ndsec)
+ * Convert fractional year to year month day hours minutes seconds
+ * ep2jd, epb2jd, epj2jd (epoch)
+ * Convert fractional year as used in epoch to Julian date
+ * ep2mjd, epb2mjd, epj2mjd (epoch)
+ * Convert fractional year as used in epoch to modified Julian date
+ * ep2ts, epb2ts, epj2ts (epoch)
+ * Convert fractional year to seconds since 1950.0
+ *
+ * et2fd (string)
+ * Convert from ET (or TDT or TT) in FITS format to UT in FITS format
+ * fd2et (string)
+ * Convert from UT in FITS format to ET (or TDT or TT) in FITS format
+ * jd2jed (dj)
+ * Convert from Julian Date to Julian Ephemeris Date
+ * jed2jd (dj)
+ * Convert from Julian Ephemeris Date to Julian Date
+ * dt2et (date, time)
+ * Convert date (yyyy.ddmm) and time (hh.mmsss) to ephemeris time
+ * edt2dt (date, time)
+ * Convert ephemeris date (yyyy.ddmm) and time (hh.mmsss) to UT
+ * dt2tai (date, time)
+ * Convert date (yyyy.ddmm) and time (hh.mmsss) to TAI date and time
+ * tai2dt (date, time)
+ * Convert TAI date (yyyy.ddmm) and time (hh.mmsss) to UT
+ * ts2ets (tsec)
+ * Convert from UT in seconds since 1950-01-01 to ET in same format
+ * ets2ts (tsec)
+ * Convert from ET in seconds since 1950-01-01 to UT in same format
+ *
+ * fd2ep, fd2epb, fd2epj (string)
+ * Convert FITS date string to fractional year
+ * Convert time alone to fraction of Besselian year
+ * fd2doy (string, year, doy)
+ * Convert FITS standard date string to year and day of year
+ * fd2dt (string, date, time)
+ * Convert FITS date string to date as yyyy.ddmm and time as hh.mmsss
+ * Convert time alone to hh.mmssss with date set to 0.0
+ * fd2i (string,iyr,imon,iday,ihr,imn,sec, ndsec)
+ * Convert FITS standard date string to year month day hours min sec
+ * Convert time alone to hours min sec, year month day are zero
+ * fd2jd (string)
+ * Convert FITS standard date string to Julian date
+ * Convert time alone to fraction of day
+ * fd2mjd (string)
+ * Convert FITS standard date string to modified Julian date
+ * fd2ts (string)
+ * Convert FITS standard date string to seconds since 1950.0
+ * Convert time alone to seconds of day
+ * fd2fd (string)
+ * Convert FITS standard date string to ISO FITS date string
+ * fd2of (string)
+ * Convert FITS standard date string to old-format FITS date and time
+ * fd2ofd (string)
+ * Convert FITS standard date string to old-format FITS date string
+ * fd2oft (string)
+ * Convert time part of FITS standard date string to FITS date string
+ *
+ * jd2doy (dj, year, doy)
+ * Convert Julian date to year and day of year
+ * jd2dt (dj,date,time)
+ * Convert Julian date to date as yyyy.mmdd and time as hh.mmssss
+ * jd2ep, jd2epb, jd2epj (dj)
+ * Convert Julian date to fractional year as used in epoch
+ * jd2fd (dj)
+ * Convert Julian date to FITS ISO date string
+ * jd2i (dj,iyr,imon,iday,ihr,imn,sec, ndsec)
+ * Convert Julian date to year month day hours min sec
+ * jd2mjd (dj)
+ * Convert Julian date to modified Julian date
+ * jd2ts (dj)
+ * Convert Julian day to seconds since 1950.0
+ *
+ * lt2dt()
+ * Return local time as yyyy.mmdd and time as hh.mmssss
+ * lt2fd()
+ * Return local time as FITS ISO date string
+ * lt2tsi()
+ * Return local time as IRAF seconds since 1980-01-01 00:00
+ * lt2tsu()
+ * Return local time as Unix seconds since 1970-01-01 00:00
+ * lt2ts()
+ * Return local time as Unix seconds since 1950-01-01 00:00
+ *
+ * mjd2doy (dj,year,doy)
+ * Convert modified Julian date to date as year and day of year
+ * mjd2dt (dj,date,time)
+ * Convert modified Julian date to date as yyyy.mmdd and time as hh.mmssss
+ * mjd2ep, mjd2epb, mjd2epj (dj)
+ * Convert modified Julian date to fractional year as used in epoch
+ * mjd2fd (dj)
+ * Convert modified Julian date to FITS ISO date string
+ * mjd2i (dj,iyr,imon,iday,ihr,imn,sec, ndsec)
+ * Convert modified Julian date to year month day hours min sec
+ * mjd2jd (dj)
+ * Convert modified Julian date to Julian date
+ * mjd2ts (dj)
+ * Convert modified Julian day to seconds since 1950.0
+ *
+ * ts2dt (tsec,date,time)
+ * Convert seconds since 1950.0 to date as yyyy.ddmm and time as hh.mmsss
+ * ts2ep, ts2epb, ts2epj (tsec)
+ * Convert seconds since 1950.0 to fractional year
+ * ts2fd (tsec)
+ * Convert seconds since 1950.0 to FITS standard date string
+ * ts2i (tsec,iyr,imon,iday,ihr,imn,sec, ndsec)
+ * Convert sec since 1950.0 to year month day hours minutes seconds
+ * ts2jd (tsec)
+ * Convert seconds since 1950.0 to Julian date
+ * ts2mjd (tsec)
+ * Convert seconds since 1950.0 to modified Julian date
+ * tsi2fd (tsec)
+ * Convert seconds since 1980-01-01 to FITS standard date string
+ * tsi2dt (tsec,date,time)
+ * Convert seconds since 1980-01-01 to date as yyyy.ddmm, time as hh.mmsss
+ * tsu2fd (tsec)
+ * Convert seconds since 1970-01-01 to FITS standard date string
+ * tsu2tsi (tsec)
+ * Convert UT seconds since 1970-01-01 to local seconds since 1980-01-01
+ * tsu2dt (tsec,date,time)
+ * Convert seconds since 1970-01-01 to date as yyyy.ddmm, time as hh.mmsss
+ *
+ * tsd2fd (tsec)
+ * Convert seconds since start of day to FITS time, hh:mm:ss.ss
+ * tsd2dt (tsec)
+ * Convert seconds since start of day to hh.mmssss
+ *
+ * fd2gst (string)
+ * convert from FITS date Greenwich Sidereal Time
+ * dt2gst (date, time)
+ * convert from UT as yyyy.mmdd hh.mmssss to Greenwich Sidereal Time
+ * ts2gst (tsec)
+ * Calculate Greenwich Sidereal Time given Universal Time
+ * in seconds since 1951-01-01T0:00:00
+ * fd2mst (string)
+ * convert from FITS UT date to Mean Sidereal Time
+ * dt2gmt (date, time)
+ * convert from UT as yyyy.mmdd hh.mmssss to Mean Sidereal Time
+ * ts2mst (tsec)
+ * Calculate Mean Sidereal Time given Universal Time
+ * in seconds since 1951-01-01T0:00:00
+ * jd2mst (string)
+ * convert from Julian Date to Mean Sidereal Time
+ * mst2fd (string)
+ * convert to current UT in FITS format given Greenwich Mean Sidereal Time
+ * mst2jd (dj)
+ * convert to current UT as Julian Date given Greenwich Mean Sidereal Time
+ * jd2lst (dj)
+ * Calculate Local Sidereal Time from Julian Date
+ * ts2lst (tsec)
+ * Calculate Local Sidereal Time given UT in seconds since 1951-01-01T0:00
+ * fd2lst (string)
+ * Calculate Local Sidereal Time given Universal Time as FITS ISO date
+ * lst2jd (dj, lst)
+ * Calculate Julian Date given current Julian date and Local Sidereal Time
+ * lst2fd (string, lst)
+ * Calculate Julian Date given current UT date and Local Sidereal Time
+ * gst2fd (string)
+ * Calculate current UT given UT date and Greenwich Sidereal Time
+ * gst2jd (dj)
+ * Calculate current UT given UT date and Greenwich Sidereal Time as JD
+ *
+ * compnut (dj, dpsi, deps, eps0)
+ * Compute the longitude and obliquity components of nutation and
+ * mean obliquity from the IAU 1980 theory
+ *
+ * utdt (dj)
+ * Compute difference between UT and dynamical time (ET-UT)
+ * ut2dt (year, doy)
+ * Current Universal Time to year and day of year
+ * ut2dt (date, time)
+ * Current Universal Time to date (yyyy.mmdd) and time (hh.mmsss)
+ * ut2ep(), ut2epb(), ut2epj()
+ * Current Universal Time to fractional year, Besselian, Julian epoch
+ * ut2fd()
+ * Current Universal Time to FITS ISO date string
+ * ut2jd()
+ * Current Universal Time to Julian Date
+ * ut2mjd()
+ * Current Universal Time to Modified Julian Date
+ * ut2tsi()
+ * Current Universal Time to IRAF seconds since 1980-01-01T00:00
+ * ut2tsu()
+ * Current Universal Time to Unix seconds since 1970-01-01T00:00
+ * ut2ts()
+ * Current Universal Time to seconds since 1950-01-01T00:00
+ * isdate (string)
+ * Return 1 if string is a FITS date (old or ISO)
+ *
+ * Internally-used subroutines
+ *
+ * fixdate (iyr, imon, iday, ihr, imn, sec, ndsec)
+ * Round seconds and make sure date and time numbers are within limits
+ * caldays (year, month)
+ * Calculate days in month 1-12 given year (Gregorian calendar only
+ * dint (dnum)
+ * Return integer part of floating point number
+ * dmod (dnum)
+ * Return Mod of floating point number
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <time.h>
+#include <sys/time.h>
+#include "wcs.h"
+#include "fitsfile.h"
+
+static double suntl();
+static void fixdate();
+static int caldays();
+static double dint();
+static double dmod();
+
+static double longitude = 0.0; /* longitude of observatory in degrees (+=west) */
+void
+setlongitude (longitude0)
+double longitude0;
+{ longitude = longitude0; return; }
+
+static int ndec = 3;
+void
+setdatedec (nd)
+int nd;
+{ ndec = nd; return; }
+
+/* ANG2HR -- Convert angle in fraction degrees to hours as hh:mm:ss.ss */
+
+void
+ang2hr (angle, lstr, string)
+
+double angle; /* Angle in fractional degrees */
+int lstr; /* Maximum number of characters in string */
+char *string; /* Character string (hh:mm:ss.ss returned) */
+
+{
+ angle = angle / 15.0;
+ dec2str (string, lstr, angle, ndec);
+ return;
+}
+
+
+/* ANG2DEG -- Convert angle in fraction degrees to degrees as dd:mm:ss.ss */
+
+void
+ang2deg (angle, lstr, string)
+
+double angle; /* Angle in fractional degrees */
+int lstr; /* Maximum number of characters in string */
+char *string; /* Character string (dd:mm:ss.ss returned) */
+{
+ dec2str (string, lstr, angle, ndec);
+ return;
+}
+
+
+/* DEG2ANG -- Convert angle in degrees as dd:mm:ss.ss to fractional degrees */
+
+double
+deg2ang (angle)
+
+char *angle; /* Angle as dd:mm:ss.ss */
+{
+ double deg;
+
+ deg = str2dec (angle);
+ return (deg);
+}
+
+/* HR2ANG -- Convert angle in hours as hh:mm:ss.ss to fractional degrees */
+
+double
+hr2ang (angle)
+
+char *angle; /* Angle in sexigesimal hours (hh:mm:ss.sss) */
+
+{
+ double deg;
+
+ deg = str2dec (angle);
+ deg = deg * 15.0;
+ return (deg);
+}
+
+
+/* DT2FD-- convert vigesimal date and time to FITS date, yyyy-mm-ddThh:mm:ss.ss */
+
+char *
+dt2fd (date, time)
+
+double date; /* Date as yyyy.mmdd
+ yyyy = calendar year (e.g. 1973)
+ mm = calendar month (e.g. 04 = april)
+ dd = calendar day (e.g. 15) */
+double time; /* Time as hh.mmssxxxx
+ *if time<0, it is time as -(fraction of a day)
+ hh = hour of day (0 .le. hh .le. 23)
+ nn = minutes (0 .le. nn .le. 59)
+ ss = seconds (0 .le. ss .le. 59)
+ xxxx = tenths of milliseconds (0 .le. xxxx .le. 9999) */
+{
+ int iyr,imon,iday,ihr,imn;
+ double sec;
+ int nf;
+ char *string;
+ char tstring[32], dstring[32];
+ char outform[64];
+
+ dt2i (date, time, &iyr,&imon,&iday,&ihr,&imn,&sec, ndec);
+
+ /* Convert to ISO date format */
+ string = (char *) calloc (32, sizeof (char));
+
+ /* Make time string */
+ if (time != 0.0 || ndec > 0) {
+ if (ndec == 0)
+ nf = 2;
+ else
+ nf = 3 + ndec;
+ if (ndec > 0) {
+ sprintf (outform, "%%02d:%%02d:%%0%d.%df", nf, ndec);
+ sprintf (tstring, outform, ihr, imn, sec);
+ }
+ else {
+ sprintf (outform, "%%02d:%%02d:%%0%dd", nf);
+ sprintf (tstring, outform, ihr, imn, (int)(sec+0.5));
+ }
+ }
+
+ /* Make date string */
+ if (date != 0.0)
+ sprintf (dstring, "%4d-%02d-%02d", iyr, imon, iday);
+
+ /* Make FITS (ISO) date string */
+ if (date == 0.0)
+ strcpy (string, tstring);
+ else if (time == 0.0 && ndec < 1)
+ strcpy (string, dstring);
+ else
+ sprintf (string, "%sT%s", dstring, tstring);
+
+ return (string);
+}
+
+
+/* DT2JD-- convert from date as yyyy.mmdd and time as hh.mmsss to Julian Date
+ * Return fractional days if date is zero */
+
+double
+dt2jd (date,time)
+
+double date; /* Date as yyyy.mmdd
+ yyyy = calendar year (e.g. 1973)
+ mm = calendar month (e.g. 04 = april)
+ dd = calendar day (e.g. 15) */
+double time; /* Time as hh.mmssxxxx
+ *if time<0, it is time as -(fraction of a day)
+ hh = hour of day (0 .le. hh .le. 23)
+ nn = minutes (0 .le. nn .le. 59)
+ ss = seconds (0 .le. ss .le. 59)
+ xxxx = tenths of milliseconds (0 .le. xxxx .le. 9999) */
+{
+ double dj; /* Julian date (returned) */
+ double tsec; /* seconds since 1950.0 */
+
+ tsec = dt2ts (date, time);
+ if (date == 0.0)
+ dj = tsec / 86400.0;
+ else
+ dj = ts2jd (tsec);
+
+ return (dj);
+}
+
+
+/* DT2MJD-- convert from date yyyy.mmdd time hh.mmsss to modified Julian Date
+ * Return fractional days if date is zero */
+
+double
+dt2mjd (date,time)
+
+double date; /* Date as yyyy.mmdd
+ yyyy = calendar year (e.g. 1973)
+ mm = calendar month (e.g. 04 = april)
+ dd = calendar day (e.g. 15) */
+double time; /* Time as hh.mmssxxxx
+ *if time<0, it is time as -(fraction of a day)
+ hh = hour of day (0 .le. hh .le. 23)
+ nn = minutes (0 .le. nn .le. 59)
+ ss = seconds (0 .le. ss .le. 59)
+ xxxx = tenths of milliseconds (0 .le. xxxx .le. 9999) */
+{
+ double dj; /* Modified Julian date (returned) */
+ double tsec; /* seconds since 1950.0 */
+
+ tsec = dt2ts (date, time);
+ if (date == 0.0)
+ dj = tsec / 86400.0;
+ else
+ dj = ts2jd (tsec);
+
+ return (dj - 2400000.5);
+}
+
+
+/* HJD2JD-- convert Heliocentric Julian Date to (geocentric) Julian date */
+
+double
+hjd2jd (dj, ra, dec, sys)
+
+double dj; /* Heliocentric Julian date */
+double ra; /* Right ascension (degrees) */
+double dec; /* Declination (degrees) */
+int sys; /* J2000, B1950, GALACTIC, ECLIPTIC */
+{
+ double lt; /* Light travel difference to the Sun (days) */
+
+ lt = suntl (dj, ra, dec, sys);
+
+ /* Return Heliocentric Julian Date */
+ return (dj - lt);
+}
+
+
+/* JD2HJD-- convert (geocentric) Julian date to Heliocentric Julian Date */
+
+double
+jd2hjd (dj, ra, dec, sys)
+
+double dj; /* Julian date (geocentric) */
+double ra; /* Right ascension (degrees) */
+double dec; /* Declination (degrees) */
+int sys; /* J2000, B1950, GALACTIC, ECLIPTIC */
+{
+ double lt; /* Light travel difference to the Sun (days) */
+
+ lt = suntl (dj, ra, dec, sys);
+
+ /* Return Heliocentric Julian Date */
+ return (dj + lt);
+}
+
+
+/* MHJD2MJD-- convert modified Heliocentric Julian Date to
+ modified geocentric Julian date */
+
+double
+mhjd2mjd (mhjd, ra, dec, sys)
+
+double mhjd; /* Modified Heliocentric Julian date */
+double ra; /* Right ascension (degrees) */
+double dec; /* Declination (degrees) */
+int sys; /* J2000, B1950, GALACTIC, ECLIPTIC */
+{
+ double lt; /* Light travel difference to the Sun (days) */
+ double hjd; /* Heliocentric Julian date */
+
+ hjd = mjd2jd (mhjd);
+
+ lt = suntl (hjd, ra, dec, sys);
+
+ /* Return Heliocentric Julian Date */
+ return (jd2mjd (hjd - lt));
+}
+
+
+/* MJD2MHJD-- convert modified geocentric Julian date tp
+ modified Heliocentric Julian Date */
+
+double
+mjd2mhjd (mjd, ra, dec, sys)
+
+double mjd; /* Julian date (geocentric) */
+double ra; /* Right ascension (degrees) */
+double dec; /* Declination (degrees) */
+int sys; /* J2000, B1950, GALACTIC, ECLIPTIC */
+{
+ double lt; /* Light travel difference to the Sun (days) */
+ double dj; /* Julian date (geocentric) */
+
+ dj = mjd2jd (mjd);
+
+ lt = suntl (dj, ra, dec, sys);
+
+ /* Return Heliocentric Julian Date */
+ return (jd2mjd (dj + lt));
+}
+
+
+/* SUNTL-- compute light travel time to heliocentric correction in days */
+/* Translated into C from IRAF SPP noao.astutils.asttools.asthjd.x */
+
+static double
+suntl (dj, ra, dec, sys)
+
+double dj; /* Julian date (geocentric) */
+double ra; /* Right ascension (degrees) */
+double dec; /* Declination (degrees) */
+int sys; /* J2000, B1950, GALACTIC, ECLIPTIC */
+{
+ double t; /* Number of Julian centuries since J1900 */
+ double manom; /* Mean anomaly of the Earth's orbit (degrees) */
+ double lperi; /* Mean longitude of perihelion (degrees) */
+ double oblq; /* Mean obliquity of the ecliptic (degrees) */
+ double eccen; /* Eccentricity of the Earth's orbit (dimensionless) */
+ double eccen2, eccen3;
+ double tanom; /* True anomaly (approximate formula) (radians) */
+ double slong; /* True longitude of the Sun from the Earth (radians) */
+ double rs; /* Distance to the sun (AU) */
+ double lt; /* Light travel difference to the Sun (days) */
+ double l; /* Longitude of star in orbital plane of Earth (radians) */
+ double b; /* Latitude of star in orbital plane of Earth (radians) */
+ double epoch; /* Epoch of obervation */
+ double rs1,rs2;
+
+ t = (dj - 2415020.0) / 36525.0;
+
+ /* Compute earth orbital parameters */
+ manom = 358.47583 + (t * (35999.04975 - t * (0.000150 + t * 0.000003)));
+ lperi = 101.22083 + (t * (1.7191733 + t * (0.000453 + t * 0.000003)));
+ oblq = 23.452294 - (t * (0.0130125 + t * (0.00000164 - t * 0.000000503)));
+ eccen = 0.01675104 - (t * (0.00004180 + t * 0.000000126));
+ eccen2 = eccen * eccen;
+ eccen3 = eccen * eccen2;
+
+ /* Convert to principle angles */
+ manom = manom - (360.0 * (dint) (manom / 360.0));
+ lperi = lperi - (360.0 * (dint) (lperi / 360.0));
+
+ /* Convert to radians */
+ manom = degrad (manom);
+ lperi = degrad (lperi);
+ oblq = degrad (oblq);
+
+ /* True anomaly */
+ tanom = manom + (2 * eccen - 0.25 * eccen3) * sin (manom) +
+ 1.25 * eccen2 * sin (2 * manom) +
+ 13./12. * eccen3 * sin (3 * manom);
+
+ /* Distance to the Sun */
+ rs1 = 1.0 - eccen2;
+ rs2 = 1.0 + (eccen * cos (tanom));
+ rs = rs1 / rs2;
+
+ /* True longitude of the Sun seen from the Earth */
+ slong = lperi + tanom + PI;
+
+ /* Longitude and latitude of star in orbital plane of the Earth */
+ epoch = jd2ep (dj);
+ wcscon (sys, WCS_ECLIPTIC, 0.0, 0.0, &ra, &dec, epoch);
+ l = degrad (ra);
+ b = degrad (dec);
+
+ /* Light travel difference to the Sun */
+ lt = -0.005770 * rs * cos (b) * cos (l - slong);
+
+ /* Return light travel difference */
+ return (lt);
+}
+
+
+/* JD2DT-- convert Julian date to date as yyyy.mmdd and time as hh.mmssss */
+
+void
+jd2dt (dj,date,time)
+
+double dj; /* Julian date */
+double *date; /* Date as yyyy.mmdd (returned) */
+double *time; /* Time as hh.mmssxxxx (returned) */
+{
+ int iyr,imon,iday,ihr,imn;
+ double sec;
+
+ /* Convert Julian Date to date and time */
+ jd2i (dj, &iyr, &imon, &iday, &ihr, &imn, &sec, 4);
+
+ /* Convert date to yyyy.mmdd */
+ if (iyr < 0) {
+ *date = (double) (-iyr) + 0.01 * (double) imon + 0.0001 * (double) iday;
+ *date = -(*date);
+ }
+ else
+ *date = (double) iyr + 0.01 * (double) imon + 0.0001 * (double) iday;
+
+ /* Convert time to hh.mmssssss */
+ *time = (double) ihr + 0.01 * (double) imn + 0.0001 * sec;
+
+ return;
+}
+
+
+/* JD2I-- convert Julian date to date as year, month, and day, and time hours,
+ minutes, and seconds */
+/* after Fliegel and Van Flander, CACM 11, 657 (1968) */
+
+
+void
+jd2i (dj, iyr, imon, iday, ihr, imn, sec, ndsec)
+
+double dj; /* Julian date */
+int *iyr; /* year (returned) */
+int *imon; /* month (returned) */
+int *iday; /* day (returned) */
+int *ihr; /* hours (returned) */
+int *imn; /* minutes (returned) */
+double *sec; /* seconds (returned) */
+int ndsec; /* Number of decimal places in seconds (0=int) */
+
+{
+ double tsec;
+ double frac, dts, ts, sday;
+ int jd, l, n, i, j;
+
+ tsec = jd2ts (dj);
+ /* ts2i (tsec, iyr, imon, iday, ihr, imn, sec, ndsec); */
+
+ /* Round seconds to 0 - 4 decimal places */
+ if (tsec < 0.0)
+ dts = -0.5;
+ else
+ dts = 0.5;
+ if (ndsec < 1)
+ ts = dint (tsec + dts);
+ else if (ndsec < 2)
+ ts = dint (tsec * 10.0 + dts) / 10.0;
+ else if (ndsec < 3)
+ ts = dint (tsec * 100.0 + dts) / 100.0;
+ else if (ndsec < 4)
+ ts = dint (tsec * 1000.0 + dts) / 1000.0;
+ else
+ ts = dint (tsec * 10000.0 + dts) / 10000.0;
+
+ /* Convert back to Julian Date */
+ dj = ts2jd (ts);
+
+ /* Compute time from fraction of a day */
+ frac = dmod (dj, 1.0);
+ if (frac < 0.5) {
+ jd = (int) (dj - frac);
+ sday = (frac + 0.5) * 86400.0;
+ }
+ else {
+ jd = (int) (dj - frac) + 1;
+ sday = (frac - 0.5) * 86400.0;
+ }
+
+ *ihr = (int) (sday / 3600.0);
+ sday = sday - (double) (*ihr * 3600);
+ *imn = (int) (sday / 60.0);
+ *sec = sday - (double) (*imn * 60);
+
+ /* Compute day, month, year */
+ l = jd + 68569;
+ n = (4 * l) / 146097;
+ l = l - (146097 * n + 3) / 4;
+ i = (4000 * (l + 1)) / 1461001;
+ l = l - (1461 * i) / 4 + 31;
+ j = (80 * l) / 2447;
+ *iday = l - (2447 * j) / 80;
+ l = j / 11;
+ *imon = j + 2 - (12 * l);
+ *iyr = 100 * (n - 49) + i + l;
+
+ return;
+}
+
+
+/* JD2MJD-- convert Julian Date to Modified Julian Date */
+
+double
+jd2mjd (dj)
+
+double dj; /* Julian Date */
+
+{
+ return (dj - 2400000.5);
+}
+
+
+/* JD2EP-- convert Julian date to fractional year as used in epoch */
+
+double
+jd2ep (dj)
+
+double dj; /* Julian date */
+
+{
+ double date, time;
+ jd2dt (dj, &date, &time);
+ return (dt2ep (date, time));
+}
+
+
+/* JD2EPB-- convert Julian date to Besselian epoch */
+
+double
+jd2epb (dj)
+
+double dj; /* Julian date */
+
+{
+ return (1900.0 + (dj - 2415020.31352) / 365.242198781);
+}
+
+
+/* JD2EPJ-- convert Julian date to Julian epoch */
+
+double
+jd2epj (dj)
+
+double dj; /* Julian date */
+
+{
+ return (2000.0 + (dj - 2451545.0) / 365.25);
+}
+
+
+/* LT2DT-- Return local time as yyyy.mmdd and time as hh.mmssss */
+
+void
+lt2dt(date, time)
+
+double *date; /* Date as yyyy.mmdd (returned) */
+double *time; /* Time as hh.mmssxxxx (returned) */
+
+{
+ time_t tsec;
+ struct timeval tp;
+ struct timezone tzp;
+ struct tm *ts;
+
+ gettimeofday (&tp,&tzp);
+
+ tsec = tp.tv_sec;
+ ts = localtime (&tsec);
+
+ if (ts->tm_year < 1000)
+ *date = (double) (ts->tm_year + 1900);
+ else
+ *date = (double) ts->tm_year;
+ *date = *date + (0.01 * (double) (ts->tm_mon + 1));
+ *date = *date + (0.0001 * (double) ts->tm_mday);
+ *time = (double) ts->tm_hour;
+ *time = *time + (0.01 * (double) ts->tm_min);
+ *time = *time + (0.0001 * (double) ts->tm_sec);
+
+ return;
+}
+
+
+/* LT2FD-- Return current local time as FITS ISO date string */
+
+char *
+lt2fd()
+{
+ time_t tsec;
+ struct tm *ts;
+ struct timeval tp;
+ struct timezone tzp;
+ int month, day, year, hour, minute, second;
+ char *isotime;
+
+ gettimeofday (&tp,&tzp);
+ tsec = tp.tv_sec;
+
+ ts = localtime (&tsec);
+
+ year = ts->tm_year;
+ if (year < 1000)
+ year = year + 1900;
+ month = ts->tm_mon + 1;
+ day = ts->tm_mday;
+ hour = ts->tm_hour;
+ minute = ts->tm_min;
+ second = ts->tm_sec;
+
+ isotime = (char *) calloc (32, sizeof (char));
+ sprintf (isotime, "%04d-%02d-%02dT%02d:%02d:%02d",
+ year, month, day, hour, minute, second);
+ return (isotime);
+}
+
+
+/* LT2TSI-- Return local time as IRAF seconds since 1980-01-01 00:00 */
+
+int
+lt2tsi()
+{
+ return ((int)(lt2ts() - 946684800.0));
+}
+
+
+/* LT2TSU-- Return local time as Unix seconds since 1970-01-01 00:00 */
+
+time_t
+lt2tsu()
+{
+ return ((time_t)(lt2ts() - 631152000.0));
+}
+
+/* LT2TS-- Return local time as Unix seconds since 1950-01-01 00:00 */
+
+double
+lt2ts()
+{
+ double tsec;
+ char *datestring;
+ datestring = lt2fd();
+ tsec = fd2ts (datestring);
+ free (datestring);
+ return (tsec);
+}
+
+
+/* MJD2DT-- convert Modified Julian Date to date (yyyy.mmdd) time (hh.mmssss) */
+
+void
+mjd2dt (dj,date,time)
+
+double dj; /* Modified Julian Date */
+double *date; /* Date as yyyy.mmdd (returned)
+ yyyy = calendar year (e.g. 1973)
+ mm = calendar month (e.g. 04 = april)
+ dd = calendar day (e.g. 15) */
+double *time; /* Time as hh.mmssxxxx (returned)
+ *if time<0, it is time as -(fraction of a day)
+ hh = hour of day (0 .le. hh .le. 23)
+ nn = minutes (0 .le. nn .le. 59)
+ ss = seconds (0 .le. ss .le. 59)
+ xxxx = tenths of milliseconds (0 .le. xxxx .le. 9999) */
+{
+ double tsec;
+
+ tsec = jd2ts (dj + 2400000.5);
+ ts2dt (tsec, date, time);
+
+ return;
+}
+
+
+/* MJD2I-- convert Modified Julian Date to date as year, month, day and
+ time as hours, minutes, seconds */
+
+void
+mjd2i (dj, iyr, imon, iday, ihr, imn, sec, ndsec)
+
+double dj; /* Modified Julian Date */
+int *iyr; /* year (returned) */
+int *imon; /* month (returned) */
+int *iday; /* day (returned) */
+int *ihr; /* hours (returned) */
+int *imn; /* minutes (returned) */
+double *sec; /* seconds (returned) */
+int ndsec; /* Number of decimal places in seconds (0=int) */
+
+{
+ double tsec;
+
+ tsec = jd2ts (dj + 2400000.5);
+ ts2i (tsec, iyr, imon, iday, ihr, imn, sec, ndsec);
+ return;
+}
+
+
+/* MJD2DOY-- convert Modified Julian Date to Year,Day-of-Year */
+
+void
+mjd2doy (dj, year, doy)
+
+double dj; /* Modified Julian Date */
+int *year; /* Year (returned) */
+double *doy; /* Day of year with fraction (returned) */
+
+{
+ jd2doy (dj + 2400000.5, year, doy);
+ return;
+}
+
+
+/* MJD2JD-- convert Modified Julian Date to Julian Date */
+
+double
+mjd2jd (dj)
+
+double dj; /* Modified Julian Date */
+
+{
+ return (dj + 2400000.5);
+}
+
+
+/* MJD2EP-- convert Modified Julian Date to fractional year */
+
+double
+mjd2ep (dj)
+
+double dj; /* Modified Julian Date */
+
+{
+ double date, time;
+ jd2dt (dj + 2400000.5, &date, &time);
+ return (dt2ep (date, time));
+}
+
+
+/* MJD2EPB-- convert Modified Julian Date to Besselian epoch */
+
+double
+mjd2epb (dj)
+
+double dj; /* Modified Julian Date */
+
+{
+ return (1900.0 + (dj - 15019.81352) / 365.242198781);
+}
+
+
+/* MJD2EPJ-- convert Modified Julian Date to Julian epoch */
+
+double
+mjd2epj (dj)
+
+double dj; /* Modified Julian Date */
+
+{
+ return (2000.0 + (dj - 51544.5) / 365.25);
+}
+
+
+/* MJD2FD-- convert modified Julian date to FITS date, yyyy-mm-ddThh:mm:ss.ss */
+
+char *
+mjd2fd (dj)
+
+double dj; /* Modified Julian date */
+{
+ return (jd2fd (dj + 2400000.5));
+}
+
+
+/* MJD2TS-- convert modified Julian date to seconds since 1950.0 */
+
+double
+mjd2ts (dj)
+
+double dj; /* Modified Julian date */
+{
+ return ((dj - 33282.0) * 86400.0);
+}
+
+
+/* EP2FD-- convert fractional year to FITS date, yyyy-mm-ddThh:mm:ss.ss */
+
+char *
+ep2fd (epoch)
+
+double epoch; /* Date as fractional year */
+{
+ double tsec; /* seconds since 1950.0 (returned) */
+ tsec = ep2ts (epoch);
+ return (ts2fd (tsec));
+}
+
+
+/* EPB2FD-- convert Besselian epoch to FITS date, yyyy-mm-ddThh:mm:ss.ss */
+
+char *
+epb2fd (epoch)
+
+double epoch; /* Besselian epoch (fractional 365.242198781-day years) */
+{
+ double dj; /* Julian Date */
+ dj = epb2jd (epoch);
+ return (jd2fd (dj));
+}
+
+
+/* EPJ2FD-- convert Julian epoch to FITS date, yyyy-mm-ddThh:mm:ss.ss */
+
+char *
+epj2fd (epoch)
+
+double epoch; /* Julian epoch (fractional 365.25-day years) */
+{
+ double dj; /* Julian Date */
+ dj = epj2jd (epoch);
+ return (jd2fd (dj));
+}
+
+
+/* EP2TS-- convert fractional year to seconds since 1950.0 */
+
+double
+ep2ts (epoch)
+
+double epoch; /* Date as fractional year */
+{
+ double dj;
+ dj = ep2jd (epoch);
+ return ((dj - 2433282.5) * 86400.0);
+}
+
+
+/* EPB2TS-- convert Besselian epoch to seconds since 1950.0 */
+
+double
+epb2ts (epoch)
+
+double epoch; /* Besselian epoch (fractional 365.242198781-day years) */
+{
+ double dj;
+ dj = epb2jd (epoch);
+ return ((dj - 2433282.5) * 86400.0);
+}
+
+
+/* EPJ2TS-- convert Julian epoch to seconds since 1950.0 */
+
+double
+epj2ts (epoch)
+
+double epoch; /* Julian epoch (fractional 365.25-day years) */
+{
+ double dj;
+ dj = epj2jd (epoch);
+ return ((dj - 2433282.5) * 86400.0);
+}
+
+
+/* EPB2EP-- convert Besselian epoch to fractional years */
+
+double
+epb2ep (epoch)
+
+double epoch; /* Besselian epoch (fractional 365.242198781-day years) */
+{
+ double dj;
+ dj = epb2jd (epoch);
+ return (jd2ep (dj));
+}
+
+
+/* EP2EPB-- convert fractional year to Besselian epoch */
+
+double
+ep2epb (epoch)
+
+double epoch; /* Fractional year */
+{
+ double dj;
+ dj = ep2jd (epoch);
+ return (jd2epb (dj));
+}
+
+
+/* EPJ2EP-- convert Julian epoch to fractional year */
+
+double
+epj2ep (epoch)
+
+double epoch; /* Julian epoch (fractional 365.25-day years) */
+{
+ double dj;
+ dj = epj2jd (epoch);
+ return (jd2ep (dj));
+}
+
+
+/* EP2EPJ-- convert fractional year to Julian epoch */
+
+double
+ep2epj (epoch)
+
+double epoch; /* Fractional year */
+{
+ double dj;
+ dj = ep2jd (epoch);
+ return (jd2epj (dj));
+}
+
+
+/* EP2I-- convert fractional year to year month day hours min sec */
+
+void
+ep2i (epoch, iyr, imon, iday, ihr, imn, sec, ndsec)
+
+double epoch; /* Date as fractional year */
+int *iyr; /* year (returned) */
+int *imon; /* month (returned) */
+int *iday; /* day (returned) */
+int *ihr; /* hours (returned) */
+int *imn; /* minutes (returned) */
+double *sec; /* seconds (returned) */
+int ndsec; /* Number of decimal places in seconds (0=int) */
+{
+ double date, time;
+
+ ep2dt (epoch, &date, &time);
+ dt2i (date, time, iyr,imon,iday,ihr,imn,sec, ndsec);
+ return;
+}
+
+
+/* EPB2I-- convert Besselian epoch to year month day hours min sec */
+
+void
+epb2i (epoch, iyr, imon, iday, ihr, imn, sec, ndsec)
+
+double epoch; /* Besselian epoch (fractional 365.242198781-day years) */
+int *iyr; /* year (returned) */
+int *imon; /* month (returned) */
+int *iday; /* day (returned) */
+int *ihr; /* hours (returned) */
+int *imn; /* minutes (returned) */
+double *sec; /* seconds (returned) */
+int ndsec; /* Number of decimal places in seconds (0=int) */
+{
+ double date, time;
+
+ epb2dt (epoch, &date, &time);
+ dt2i (date, time, iyr,imon,iday,ihr,imn,sec, ndsec);
+ return;
+}
+
+
+/* EPJ2I-- convert Julian epoch to year month day hours min sec */
+
+void
+epj2i (epoch, iyr, imon, iday, ihr, imn, sec, ndsec)
+
+double epoch; /* Julian epoch (fractional 365.25-day years) */
+int *iyr; /* year (returned) */
+int *imon; /* month (returned) */
+int *iday; /* day (returned) */
+int *ihr; /* hours (returned) */
+int *imn; /* minutes (returned) */
+double *sec; /* seconds (returned) */
+int ndsec; /* Number of decimal places in seconds (0=int) */
+{
+ double date, time;
+
+ epj2dt (epoch, &date, &time);
+ dt2i (date, time, iyr,imon,iday,ihr,imn,sec, ndsec);
+ return;
+}
+
+
+/* EP2JD-- convert fractional year as used in epoch to Julian date */
+
+double
+ep2jd (epoch)
+
+double epoch; /* Date as fractional year */
+
+{
+ double dj; /* Julian date (returned)*/
+ double date, time;
+
+ ep2dt (epoch, &date, &time);
+ dj = dt2jd (date, time);
+ return (dj);
+}
+
+
+/* EPB2JD-- convert Besselian epoch to Julian Date */
+
+double
+epb2jd (epoch)
+
+double epoch; /* Besselian epoch (fractional 365.242198781-day years) */
+
+{
+ return (2415020.31352 + ((epoch - 1900.0) * 365.242198781));
+}
+
+
+/* EPJ2JD-- convert Julian epoch to Julian Date */
+
+double
+epj2jd (epoch)
+
+double epoch; /* Julian epoch (fractional 365.25-day years) */
+
+{
+ return (2451545.0 + ((epoch - 2000.0) * 365.25));
+}
+
+
+/* EP2MJD-- convert fractional year as used in epoch to modified Julian date */
+
+double
+ep2mjd (epoch)
+
+double epoch; /* Date as fractional year */
+
+{
+ double dj; /* Julian date (returned)*/
+ double date, time;
+
+ ep2dt (epoch, &date, &time);
+ dj = dt2jd (date, time);
+ return (dj - 2400000.5);
+}
+
+
+/* EPB2MJD-- convert Besselian epoch to modified Julian Date */
+
+double
+epb2mjd (epoch)
+
+double epoch; /* Besselian epoch (fractional 365.242198781-day years) */
+
+{
+ return (15019.81352 + ((epoch - 1900.0) * 365.242198781));
+}
+
+
+/* EPJ2MJD-- convert Julian epoch to modified Julian Date */
+
+double
+epj2mjd (epoch)
+
+double epoch; /* Julian epoch (fractional 365.25-day years) */
+
+{
+ return (51544.5 + ((epoch - 2000.0) * 365.25));
+}
+
+
+
+/* EPB2EPJ-- convert Besselian epoch to Julian epoch */
+
+double
+epb2epj (epoch)
+
+double epoch; /* Besselian epoch (fractional 365.242198781-day years) */
+{
+ double dj; /* Julian date */
+ dj = epb2jd (epoch);
+ return (jd2epj (dj));
+}
+
+
+/* EPJ2EPB-- convert Julian epoch to Besselian epoch */
+
+double
+epj2epb (epoch)
+
+double epoch; /* Julian epoch (fractional 365.25-day years) */
+{
+ double dj; /* Julian date */
+ dj = epj2jd (epoch);
+ return (jd2epb (dj));
+}
+
+
+/* JD2FD-- convert Julian date to FITS date, yyyy-mm-ddThh:mm:ss.ss */
+
+char *
+jd2fd (dj)
+
+double dj; /* Julian date */
+{
+ double tsec; /* seconds since 1950.0 (returned) */
+ tsec = (dj - 2433282.5) * 86400.0;
+ return (ts2fd (tsec));
+}
+
+
+/* JD2TS-- convert Julian date to seconds since 1950.0 */
+
+double
+jd2ts (dj)
+
+double dj; /* Julian date */
+{
+ return ((dj - 2433282.5) * 86400.0);
+}
+
+
+/* JD2TSI-- convert Julian date to IRAF seconds since 1980-01-01T0:00 */
+
+int
+jd2tsi (dj)
+
+double dj; /* Julian date */
+{
+ double ts;
+ ts = (dj - 2444239.5) * 86400.0;
+ return ((int) ts);
+}
+
+
+/* JD2TSU-- convert Julian date to Unix seconds since 1970-01-01T0:00 */
+
+time_t
+jd2tsu (dj)
+
+double dj; /* Julian date */
+{
+ return ((time_t)((dj - 2440587.5) * 86400.0));
+}
+
+
+/* DT2DOY-- convert yyyy.mmdd hh.mmss to year and day of year */
+
+void
+dt2doy (date, time, year, doy)
+
+double date; /* Date as yyyy.mmdd */
+double time; /* Time as hh.mmssxxxx */
+int *year; /* Year (returned) */
+double *doy; /* Day of year with fraction (returned) */
+{
+ double dj; /* Julian date */
+ double dj0; /* Julian date on January 1 0:00 */
+ double date0; /* January first of date's year */
+ double dyear;
+
+ dyear = floor (date);
+ date0 = dyear + 0.0101;
+ dj0 = dt2jd (date0, 0.0);
+ dj = dt2jd (date, time);
+ *year = (int) (dyear + 0.00000001);
+ *doy = dj - dj0 + 1.0;
+ return;
+}
+
+
+/* DOY2DT-- convert year and day of year to yyyy.mmdd hh.mmss */
+
+void
+doy2dt (year, doy, date, time)
+
+int year; /* Year */
+double doy; /* Day of year with fraction */
+double *date; /* Date as yyyy.mmdd (returned) */
+double *time; /* Time as hh.mmssxxxx (returned) */
+{
+ double dj; /* Julian date */
+ double dj0; /* Julian date on January 1 0:00 */
+ double date0; /* January first of date's year */
+
+ date0 = year + 0.0101;
+ dj0 = dt2jd (date0, 0.0);
+ dj = dj0 + doy - 1.0;
+ jd2dt (dj, date, time);
+ return;
+}
+
+
+/* DOY2EP-- convert year and day of year to fractional year as used in epoch */
+
+double
+doy2ep (year, doy)
+
+int year; /* Year */
+double doy; /* Day of year with fraction */
+{
+ double date, time;
+ doy2dt (year, doy, &date, &time);
+ return (dt2ep (date, time));
+}
+
+
+
+/* DOY2EPB-- convert year and day of year to Besellian epoch */
+
+double
+doy2epb (year, doy)
+
+int year; /* Year */
+double doy; /* Day of year with fraction */
+{
+ double dj;
+ dj = doy2jd (year, doy);
+ return (jd2epb (dj));
+}
+
+
+/* DOY2EPJ-- convert year and day of year to Julian epoch */
+
+double
+doy2epj (year, doy)
+
+int year; /* Year */
+double doy; /* Day of year with fraction */
+{
+ double dj;
+ dj = doy2jd (year, doy);
+ return (jd2epj (dj));
+}
+
+
+/* DOY2FD-- convert year and day of year to FITS date */
+
+char *
+doy2fd (year, doy)
+
+int year; /* Year */
+double doy; /* Day of year with fraction */
+{
+ double dj; /* Julian date */
+
+ dj = doy2jd (year, doy);
+ return (jd2fd (dj));
+}
+
+
+/* DOY2JD-- convert year and day of year to Julian date */
+
+double
+doy2jd (year, doy)
+
+int year; /* Year */
+double doy; /* Day of year with fraction */
+{
+ double dj0; /* Julian date */
+ double date; /* Date as yyyy.mmdd (returned) */
+ double time; /* Time as hh.mmssxxxx (returned) */
+
+ date = (double) year + 0.0101;
+ time = 0.0;
+ dj0 = dt2jd (date, time);
+ return (dj0 + doy - 1.0);
+}
+
+
+/* DOY2MJD-- convert year and day of year to Julian date */
+
+double
+doy2mjd (year, doy)
+
+int year; /* Year */
+double doy; /* Day of year with fraction */
+{
+ double dj0; /* Julian date */
+ double date; /* Date as yyyy.mmdd (returned) */
+ double time; /* Time as hh.mmssxxxx (returned) */
+
+ date = (double) year + 0.0101;
+ time = 0.0;
+ dj0 = dt2jd (date, time);
+ return (dj0 + doy - 1.0 - 2400000.5);
+}
+
+
+/* DOY2TSU-- convert from FITS date to Unix seconds since 1970-01-01T0:00 */
+
+time_t
+doy2tsu (year, doy)
+
+int year; /* Year */
+double doy; /* Day of year with fraction */
+{
+ double dj;
+ dj = doy2jd (year, doy);
+ return ((time_t)jd2ts (dj));
+}
+
+
+/* DOY2TSI-- convert from FITS date to IRAF seconds since 1980-01-01T0:00 */
+
+int
+doy2tsi (year, doy)
+
+int year; /* Year */
+double doy; /* Day of year with fraction */
+{
+ double dj;
+ dj = doy2jd (year, doy);
+ return ((int)jd2tsi (dj));
+}
+
+
+/* DOY2TS-- convert year, day of year to seconds since 1950 */
+
+double
+doy2ts (year, doy)
+
+int year; /* Year */
+double doy; /* Day of year with fraction */
+{
+ double dj;
+ dj = doy2jd (year, doy);
+ return (jd2ts (dj));
+}
+
+
+/* FD2DOY-- convert FITS date to year and day of year */
+
+void
+fd2doy (string, year, doy)
+
+char *string; /* FITS date string, which may be:
+ fractional year
+ dd/mm/yy (FITS standard before 2000)
+ dd-mm-yy (nonstandard use before 2000)
+ yyyy-mm-dd (FITS standard after 1999)
+ yyyy-mm-ddThh:mm:ss.ss (FITS standard after 1999) */
+int *year; /* Year (returned) */
+double *doy; /* Day of year with fraction (returned) */
+{
+ double dj; /* Julian date */
+
+ dj = fd2jd (string);
+ jd2doy (dj, year, doy);
+ return;
+}
+
+
+/* JD2DOY-- convert Julian date to year and day of year */
+
+void
+jd2doy (dj, year, doy)
+
+double dj; /* Julian date */
+int *year; /* Year (returned) */
+double *doy; /* Day of year with fraction (returned) */
+{
+ double date; /* Date as yyyy.mmdd (returned) */
+ double time; /* Time as hh.mmssxxxx (returned) */
+ double dj0; /* Julian date at 0:00 on 1/1 */
+ double dyear;
+
+ jd2dt (dj, &date, &time);
+ *year = (int) date;
+ dyear = (double) *year;
+ dj0 = dt2jd (dyear+0.0101, 0.0);
+ *doy = dj - dj0 + 1.0;
+ return;
+}
+
+
+/* TS2JD-- convert seconds since 1950.0 to Julian date */
+
+double
+ts2jd (tsec)
+
+double tsec; /* seconds since 1950.0 */
+{
+ return (2433282.5 + (tsec / 86400.0));
+}
+
+
+/* TS2MJD-- convert seconds since 1950.0 to modified Julian date */
+
+double
+ts2mjd (tsec)
+
+double tsec; /* seconds since 1950.0 */
+{
+ return (33282.0 + (tsec / 86400.0));
+}
+
+
+/* TS2EP-- convert seconds since 1950.0 to fractional year as used in epoch */
+
+double
+ts2ep (tsec)
+
+double tsec; /* Seconds since 1950.0 */
+
+{
+ double date, time;
+ ts2dt (tsec, &date, &time);
+ return (dt2ep (date, time));
+}
+
+
+/* TS2EPB-- convert seconds since 1950.0 to Besselian epoch */
+
+double
+ts2epb (tsec)
+
+double tsec; /* Seconds since 1950.0 */
+
+{
+ double dj; /* Julian Date */
+ dj = ts2jd (tsec);
+ return (jd2epb (dj));
+}
+
+
+/* TS2EPB-- convert seconds since 1950.0 to Julian epoch */
+
+double
+ts2epj (tsec)
+
+double tsec; /* Seconds since 1950.0 */
+
+{
+ double dj; /* Julian Date */
+ dj = ts2jd (tsec);
+ return (jd2epj (dj));
+}
+
+
+/* DT2EP-- convert from date, time as yyyy.mmdd hh.mmsss to fractional year */
+
+double
+dt2ep (date, time)
+
+double date; /* Date as yyyy.mmdd
+ yyyy = calendar year (e.g. 1973)
+ mm = calendar month (e.g. 04 = april)
+ dd = calendar day (e.g. 15) */
+double time; /* Time as hh.mmssxxxx
+ *if time<0, it is time as -(fraction of a day)
+ hh = hour of day (0 .le. hh .le. 23)
+ nn = minutes (0 .le. nn .le. 59)
+ ss = seconds (0 .le. ss .le. 59)
+ xxxx = tenths of milliseconds (0 .le. xxxx .le. 9999) */
+{
+ double epoch; /* Date as fractional year (returned) */
+ double dj, dj0, dj1, date0, time0, date1;
+
+ dj = dt2jd (date, time);
+ if (date == 0.0)
+ epoch = dj / 365.2422;
+ else {
+ time0 = 0.0;
+ date0 = dint (date) + 0.0101;
+ date1 = dint (date) + 1.0101;
+ dj0 = dt2jd (date0, time0);
+ dj1 = dt2jd (date1, time0);
+ epoch = dint (date) + ((dj - dj0) / (dj1 - dj0));
+ }
+ return (epoch);
+}
+
+
+/* DT2EPB-- convert from date, time as yyyy.mmdd hh.mmsss to Besselian epoch */
+
+double
+dt2epb (date, time)
+
+double date; /* Date as yyyy.mmdd
+ yyyy = calendar year (e.g. 1973)
+ mm = calendar month (e.g. 04 = april)
+ dd = calendar day (e.g. 15) */
+double time; /* Time as hh.mmssxxxx
+ *if time<0, it is time as -(fraction of a day)
+ hh = hour of day (0 .le. hh .le. 23)
+ nn = minutes (0 .le. nn .le. 59)
+ ss = seconds (0 .le. ss .le. 59)
+ xxxx = tenths of milliseconds (0 .le. xxxx .le. 9999) */
+{
+ double dj; /* Julian date */
+ double epoch; /* Date as fractional year (returned) */
+ dj = dt2jd (date, time);
+ if (date == 0.0)
+ epoch = dj / 365.242198781;
+ else
+ epoch = jd2epb (dj);
+ return (epoch);
+}
+
+
+/* DT2EPJ-- convert from date, time as yyyy.mmdd hh.mmsss to Julian epoch */
+
+double
+dt2epj (date, time)
+
+double date; /* Date as yyyy.mmdd
+ yyyy = calendar year (e.g. 1973)
+ mm = calendar month (e.g. 04 = april)
+ dd = calendar day (e.g. 15) */
+double time; /* Time as hh.mmssxxxx
+ *if time<0, it is time as -(fraction of a day)
+ hh = hour of day (0 .le. hh .le. 23)
+ nn = minutes (0 .le. nn .le. 59)
+ ss = seconds (0 .le. ss .le. 59)
+ xxxx = tenths of milliseconds (0 .le. xxxx .le. 9999) */
+{
+ double dj; /* Julian date */
+ double epoch; /* Date as fractional year (returned) */
+ dj = dt2jd (date, time);
+ if (date == 0.0)
+ epoch = dj / 365.25;
+ else
+ epoch = jd2epj (dj);
+ return (epoch);
+}
+
+
+/* EP2DT-- convert from fractional year to date, time as yyyy.mmdd hh.mmsss */
+
+void
+ep2dt (epoch, date, time)
+
+double epoch; /* Date as fractional year */
+double *date; /* Date as yyyy.mmdd (returned)
+ yyyy = calendar year (e.g. 1973)
+ mm = calendar month (e.g. 04 = april)
+ dd = calendar day (e.g. 15) */
+double *time; /* Time as hh.mmssxxxx (returned)
+ *if time<0, it is time as -(fraction of a day)
+ hh = hour of day (0 .le. hh .le. 23)
+ nn = minutes (0 .le. nn .le. 59)
+ ss = seconds (0 .le. ss .le. 59)
+ xxxx = tenths of milliseconds (0 .le. xxxx .le. 9999) */
+{
+ double dj, dj0, dj1, date0, time0, date1, epochi, epochf;
+
+ time0 = 0.0;
+ epochi = dint (epoch);
+ epochf = epoch - epochi;
+ date0 = epochi + 0.0101;
+ date1 = epochi + 1.0101;
+ dj0 = dt2jd (date0, time0);
+ dj1 = dt2jd (date1, time0);
+ dj = dj0 + epochf * (dj1 - dj0);
+ jd2dt (dj, date, time);
+ return;
+}
+
+
+/* EPB2DT-- convert from Besselian epoch to date, time as yyyy.mmdd hh.mmsss */
+
+void
+epb2dt (epoch, date, time)
+
+double epoch; /* Besselian epoch (fractional 365.242198781-day years) */
+double *date; /* Date as yyyy.mmdd (returned)
+ yyyy = calendar year (e.g. 1973)
+ mm = calendar month (e.g. 04 = april)
+ dd = calendar day (e.g. 15) */
+double *time; /* Time as hh.mmssxxxx (returned)
+ *if time<0, it is time as -(fraction of a day)
+ hh = hour of day (0 .le. hh .le. 23)
+ nn = minutes (0 .le. nn .le. 59)
+ ss = seconds (0 .le. ss .le. 59)
+ xxxx = tenths of milliseconds (0 .le. xxxx .le. 9999) */
+{
+ double dj; /* Julian date */
+ dj = epb2jd (epoch);
+ jd2dt (dj, date, time);
+}
+
+
+/* EPJ2DT-- convert from Julian epoch to date, time as yyyy.mmdd hh.mmsss */
+
+void
+epj2dt (epoch, date, time)
+
+double epoch; /* Julian epoch (fractional 365.25-day years) */
+double *date; /* Date as yyyy.mmdd (returned)
+ yyyy = calendar year (e.g. 1973)
+ mm = calendar month (e.g. 04 = april)
+ dd = calendar day (e.g. 15) */
+double *time; /* Time as hh.mmssxxxx (returned)
+ *if time<0, it is time as -(fraction of a day)
+ hh = hour of day (0 .le. hh .le. 23)
+ nn = minutes (0 .le. nn .le. 59)
+ ss = seconds (0 .le. ss .le. 59)
+ xxxx = tenths of milliseconds (0 .le. xxxx .le. 9999) */
+{
+ double dj; /* Julian date */
+ dj = epj2jd (epoch);
+ jd2dt (dj, date, time);
+}
+
+
+/* FD2JD-- convert FITS standard date to Julian date */
+
+double
+fd2jd (string)
+
+char *string; /* FITS date string, which may be:
+ fractional year
+ dd/mm/yy (FITS standard before 2000)
+ dd-mm-yy (nonstandard use before 2000)
+ yyyy-mm-dd (FITS standard after 1999)
+ yyyy-mm-ddThh:mm:ss.ss (FITS standard after 1999) */
+{
+ double date, time;
+
+ fd2dt (string, &date, &time);
+ return (dt2jd (date, time));
+}
+
+
+/* FD2MJD-- convert FITS standard date to modified Julian date */
+
+double
+fd2mjd (string)
+
+char *string; /* FITS date string, which may be:
+ fractional year
+ dd/mm/yy (FITS standard before 2000)
+ dd-mm-yy (nonstandard use before 2000)
+ yyyy-mm-dd (FITS standard after 1999)
+ yyyy-mm-ddThh:mm:ss.ss (FITS standard after 1999) */
+{
+ return (fd2jd (string) - 2400000.5);
+}
+
+
+/* FD2TSU-- convert from FITS date to Unix seconds since 1970-01-01T0:00 */
+
+time_t
+fd2tsu (string)
+
+char *string; /* FITS date string, which may be:
+ fractional year
+ dd/mm/yy (FITS standard before 2000)
+ dd-mm-yy (nonstandard use before 2000)
+ yyyy-mm-dd (FITS standard after 1999)
+ yyyy-mm-ddThh:mm:ss.ss (FITS standard after 1999) */
+{
+ double date, time;
+ fd2dt (string, &date, &time);
+ return (dt2tsu (date, time));
+}
+
+
+/* FD2TSI-- convert from FITS date to IRAF seconds since 1980-01-01T0:00 */
+
+int
+fd2tsi (string)
+
+char *string; /* FITS date string, which may be:
+ fractional year
+ dd/mm/yy (FITS standard before 2000)
+ dd-mm-yy (nonstandard use before 2000)
+ yyyy-mm-dd (FITS standard after 1999)
+ yyyy-mm-ddThh:mm:ss.ss (FITS standard after 1999) */
+{
+ double date, time;
+ fd2dt (string, &date, &time);
+ return (dt2tsi (date, time));
+}
+
+
+/* FD2TS-- convert FITS standard date to seconds since 1950 */
+
+double
+fd2ts (string)
+
+char *string; /* FITS date string, which may be:
+ fractional year
+ dd/mm/yy (FITS standard before 2000)
+ dd-mm-yy (nonstandard use before 2000)
+ yyyy-mm-dd (FITS standard after 1999)
+ yyyy-mm-ddThh:mm:ss.ss (FITS standard after 1999) */
+{
+ double date, time;
+ fd2dt (string, &date, &time);
+ return (dt2ts (date, time));
+}
+
+
+/* FD2FD-- convert any FITS standard date to ISO FITS standard date */
+
+char *
+fd2fd (string)
+
+char *string; /* FITS date string, which may be:
+ fractional year
+ dd/mm/yy (FITS standard before 2000)
+ dd-mm-yy (nonstandard use before 2000)
+ yyyy-mm-dd (FITS standard after 1999)
+ yyyy-mm-ddThh:mm:ss.ss (FITS standard after 1999) */
+{
+ double date, time;
+ fd2dt (string, &date, &time);
+ return (dt2fd (date, time));
+}
+
+
+/* FD2OF-- convert any FITS standard date to old FITS standard date time */
+
+char *
+fd2of (string)
+
+char *string; /* FITS date string, which may be:
+ fractional year
+ dd/mm/yy (FITS standard before 2000)
+ dd-mm-yy (nonstandard use before 2000)
+ yyyy-mm-dd (FITS standard after 1999)
+ yyyy-mm-ddThh:mm:ss.ss (FITS standard after 1999) */
+{
+ int iyr,imon,iday,ihr,imn;
+ double sec;
+
+ fd2i (string,&iyr,&imon,&iday,&ihr,&imn,&sec, 3);
+
+ /* Convert to old FITS date format */
+ string = (char *) calloc (32, sizeof (char));
+ if (iyr < 1900)
+ sprintf (string, "*** date out of range ***");
+ else if (iyr < 2000)
+ sprintf (string, "%02d/%02d/%02d %02d:%02d:%06.3f",
+ iday, imon, iyr-1900, ihr, imn, sec);
+ else if (iyr < 2900.0)
+ sprintf (string, "%02d/%02d/%3d %02d:%02d:%6.3f",
+ iday, imon, iyr-1900, ihr, imn, sec);
+ else
+ sprintf (string, "*** date out of range ***");
+ return (string);
+}
+
+
+/* TAI-UTC from the U.S. Naval Observatory */
+/* ftp://maia.usno.navy.mil/ser7/tai-utc.dat */
+static double taijd[26]={2441317.5, 2441499.5, 2441683.5, 2442048.5, 2442413.5,
+ 2442778.5, 2443144.5, 2443509.5, 2443874.5, 2444239.5, 2444786.5,
+ 2445151.5, 2445516.5, 2446247.5, 2447161.5, 2447892.5, 2448257.5,
+ 2448804.5, 2449169.5, 2449534.5, 2450083.5, 2450630.5, 2451179.5,
+ 2453736.5, 2454832.5, 2456293.5};
+static double taidt[26]={10.0,11.0,12.0,13.0,14.0,15.0,16.0,17.0,18.0,19.0,
+ 20.0,21.0,22.0,23.0,24.0,25.0,26.0,27.0,28.0,29.0,30.0,31.0,32.0,
+ 33.0,34.0,35.0};
+static double dttab[173]={13.7,13.4,13.1,12.9,12.7,12.6,12.5,12.5,12.5,12.5,
+ 12.5,12.5,12.5,12.5,12.5,12.5,12.5,12.4,12.3,12.2,12.0,11.7,11.4,
+ 11.1,10.6,10.2, 9.6, 9.1, 8.6, 8.0, 7.5, 7.0, 6.6, 6.3, 6.0, 5.8,
+ 5.7, 5.6, 5.6, 5.6, 5.7, 5.8, 5.9, 6.1, 6.2, 6.3, 6.5, 6.6, 6.8,
+ 6.9, 7.1, 7.2, 7.3, 7.4, 7.5, 7.6, 7.7, 7.7, 7.8, 7.8,7.88,7.82,
+ 7.54, 6.97, 6.40, 6.02, 5.41, 4.10, 2.92, 1.82, 1.61, 0.10,-1.02,
+ -1.28,-2.69,-3.24,-3.64,-4.54,-4.71,-5.11,-5.40,-5.42,-5.20,-5.46,
+ -5.46,-5.79,-5.63,-5.64,-5.80,-5.66,-5.87,-6.01,-6.19,-6.64,-6.44,
+ -6.47,-6.09,-5.76,-4.66,-3.74,-2.72,-1.54,-0.02, 1.24, 2.64, 3.86,
+ 5.37, 6.14, 7.75, 9.13,10.46,11.53,13.36,14.65,16.01,17.20,18.24,
+ 19.06,20.25,20.95,21.16,22.25,22.41,23.03,23.49,23.62,23.86,24.49,
+ 24.34,24.08,24.02,24.00,23.87,23.95,23.86,23.93,23.73,23.92,23.96,
+ 24.02,24.33,24.83,25.30,25.70,26.24,26.77,27.28,27.78,28.25,28.71,
+ 29.15,29.57,29.97,30.36,30.72,31.07,31.35,31.68,32.18,32.68,33.15,
+ 33.59,34.00,34.47,35.03,35.73,36.54,37.43,38.29,39.20,40.18,41.17,
+ 42.23};
+
+
+/* TAI2FD-- convert from TAI in FITS format to UT in FITS format */
+
+char *
+tai2fd (string)
+
+char *string; /* FITS date string, which may be:
+ fractional year
+ dd/mm/yy (FITS standard before 2000)
+ dd-mm-yy (nonstandard use before 2000)
+ yyyy-mm-dd (FITS standard after 1999)
+ yyyy-mm-ddThh:mm:ss.ss (FITS standard after 1999) */
+{
+ double dj0, dj, tsec, dt;
+
+ dj0 = fd2jd (string);
+ dt = utdt (dj0);
+ dj = dj0 - (dt / 86400.0);
+ dt = utdt (dj);
+ tsec = fd2ts (string);
+ tsec = tsec - dt + 32.184;
+ return (ts2fd (tsec));
+}
+
+
+/* FD2TAI-- convert from UT in FITS format to TAI in FITS format */
+
+char *
+fd2tai (string)
+
+char *string; /* FITS date string, which may be:
+ fractional year
+ dd/mm/yy (FITS standard before 2000)
+ dd-mm-yy (nonstandard use before 2000)
+ yyyy-mm-dd (FITS standard after 1999)
+ yyyy-mm-ddThh:mm:ss.ss (FITS standard after 1999) */
+{
+ double dj, tsec, dt;
+
+ dj = fd2jd (string);
+ dt = utdt (dj);
+ tsec = fd2ts (string);
+ tsec = tsec + dt - 32.184;
+ return (ts2fd (tsec));
+}
+
+
+/* DT2TAI-- convert from UT as yyyy.mmdd hh.mmssss to TAI in same format */
+
+void
+dt2tai (date, time)
+double *date; /* Date as yyyy.mmdd */
+double *time; /* Time as hh.mmssxxxx
+ *if time<0, it is time as -(fraction of a day) */
+{
+ double dj, dt, tsec;
+
+ dj = dt2jd (*date, *time);
+ dt = utdt (dj);
+ tsec = dt2ts (*date, *time);
+ tsec = tsec + dt - 32.184;
+ ts2dt (tsec, date, time);
+ return;
+}
+
+
+/* TAI2DT-- convert from TAI as yyyy.mmdd hh.mmssss to UT in same format */
+
+void
+tai2dt (date, time)
+double *date; /* Date as yyyy.mmdd */
+double *time; /* Time as hh.mmssxxxx
+ *if time<0, it is time as -(fraction of a day) */
+{
+ double dj, dt, tsec, tsec0;
+
+ dj = dt2jd (*date, *time);
+ dt = utdt (dj);
+ tsec0 = dt2ts (*date, *time);
+ tsec = tsec0 + dt;
+ dj = ts2jd (tsec);
+ dt = utdt (dj);
+ tsec = tsec0 + dt + 32.184;
+ ts2dt (tsec, date, time);
+ return;
+}
+
+
+/* ET2FD-- convert from ET (or TDT or TT) in FITS format to UT in FITS format */
+
+char *
+et2fd (string)
+
+char *string; /* FITS date string, which may be:
+ fractional year
+ dd/mm/yy (FITS standard before 2000)
+ dd-mm-yy (nonstandard use before 2000)
+ yyyy-mm-dd (FITS standard after 1999)
+ yyyy-mm-ddThh:mm:ss.ss (FITS standard after 1999) */
+{
+ double dj0, dj, tsec, dt;
+
+ dj0 = fd2jd (string);
+ dt = utdt (dj0);
+ dj = dj0 - (dt / 86400.0);
+ dt = utdt (dj);
+ tsec = fd2ts (string);
+ tsec = tsec - dt;
+ return (ts2fd (tsec));
+}
+
+
+/* FD2ET-- convert from UT in FITS format to ET (or TDT or TT) in FITS format */
+
+char *
+fd2et (string)
+
+char *string; /* FITS date string, which may be:
+ fractional year
+ dd/mm/yy (FITS standard before 2000)
+ dd-mm-yy (nonstandard use before 2000)
+ yyyy-mm-dd (FITS standard after 1999)
+ yyyy-mm-ddThh:mm:ss.ss (FITS standard after 1999) */
+{
+ double dj, tsec, dt;
+
+ dj = fd2jd (string);
+ dt = utdt (dj);
+ tsec = fd2ts (string);
+ tsec = tsec + dt;
+ return (ts2fd (tsec));
+}
+
+
+/* DT2ET-- convert from UT as yyyy.mmdd hh.mmssss to ET in same format */
+
+void
+dt2et (date, time)
+double *date; /* Date as yyyy.mmdd */
+double *time; /* Time as hh.mmssxxxx
+ *if time<0, it is time as -(fraction of a day) */
+{
+ double dj, dt, tsec;
+
+ dj = dt2jd (*date, *time);
+ dt = utdt (dj);
+ tsec = dt2ts (*date, *time);
+ tsec = tsec + dt;
+ ts2dt (tsec, date, time);
+ return;
+}
+
+
+/* EDT2DT-- convert from ET as yyyy.mmdd hh.mmssss to UT in same format */
+
+void
+edt2dt (date, time)
+double *date; /* Date as yyyy.mmdd */
+double *time; /* Time as hh.mmssxxxx
+ *if time<0, it is time as -(fraction of a day) */
+{
+ double dj, dt, tsec, tsec0;
+
+ dj = dt2jd (*date, *time);
+ dt = utdt (dj);
+ tsec0 = dt2ts (*date, *time);
+ tsec = tsec0 + dt;
+ dj = ts2jd (tsec);
+ dt = utdt (dj);
+ tsec = tsec0 + dt;
+ ts2dt (tsec, date, time);
+ return;
+}
+
+
+/* JD2JED-- convert from Julian Date to Julian Ephemeris Date */
+
+double
+jd2jed (dj)
+
+double dj; /* Julian Date */
+{
+ double dt;
+
+ dt = utdt (dj);
+ return (dj + (dt / 86400.0));
+}
+
+
+/* JED2JD-- convert from Julian Ephemeris Date to Julian Date */
+
+double
+jed2jd (dj)
+
+double dj; /* Julian Ephemeris Date */
+{
+ double dj0, dt;
+
+ dj0 = dj;
+ dt = utdt (dj);
+ dj = dj0 - (dt / 86400.0);
+ dt = utdt (dj);
+ return (dj - (dt / 86400.0));
+}
+
+
+/* TS2ETS-- convert from UT in seconds since 1950-01-01 to ET in same format */
+
+double
+ts2ets (tsec)
+
+double tsec;
+{
+ double dj, dt;
+
+ dj = ts2jd (tsec);
+ dt = utdt (dj);
+ return (tsec + dt);
+}
+
+
+/* ETS2TS-- convert from ET in seconds since 1950-01-01 to UT in same format */
+
+double
+ets2ts (tsec)
+
+double tsec;
+{
+ double dj, dj0, dt;
+
+ dj0 = ts2jd (tsec);
+ dt = utdt (dj0);
+ dj = dj0 - (dt / 86400.0);
+ dt = utdt (dj);
+ return (tsec - dt);
+}
+
+
+/* UTDT-- Compute difference between UT and dynamical time (ET-UT) */
+
+double
+utdt (dj)
+
+double dj; /* Julian Date (UT) */
+{
+ double dt, date, time, ts, ts1, ts0, date0, yfrac, diff, cj;
+ int i, iyr, iyear;
+
+ /* If after 1972-01-01, use tabulated TAI-UT */
+ if (dj >= 2441317.5) {
+ dt = 0.0;
+ for (i = 22; i > 0; i--) {
+ if (dj >= taijd[i])
+ dt = taidt[i];
+ }
+ dt = dt + 32.184;
+ }
+
+ /* For 1800-01-01 to 1972-01-01, use table of ET-UT from AE */
+ else if (dj >= 2378496.5) {
+ jd2dt (dj, &date, &time);
+ ts = jd2ts (dj);
+ iyear = (int) date;
+ iyr = iyear - 1800;
+ date0 = (double) iyear + 0.0101;
+ ts0 = dt2ts (date0, 0.0);
+ date0 = (double) (iyear + 1) + 0.0101;
+ ts1 = dt2ts (date0, 0.0);
+ yfrac = (ts - ts0) / (ts1 - ts0);
+ diff = dttab[iyr+1] - dttab[iyr];
+ dt = dttab[iyr] + (diff * yfrac);
+ }
+
+ /* Compute back to 1600 using formula from McCarthy and Babcock (1986) */
+ else if (dj >= 2305447.5) {
+ cj = (dj - 2378496.5) / 36525.0;
+ dt = 5.156 + 13.3066 * (cj - 0.19) * (cj - 0.19);
+ }
+
+ /* Compute back to 948 using formula from Stephenson and Morrison (1984) */
+ else if (dj >= 2067309.5) {
+ cj = (dj - 2378496.5) / 36525.0;
+ dt = 25.5 * cj * cj;
+ }
+
+ /*Compute back to 390 BC using formula from Stephenson and Morrison (1984)*/
+ else if (dj >= 0.0) {
+ cj = (dj = 2378496.5) / 36525.0;
+ dt = 1360.0 + (320.0 * cj) + (44.3 * cj * cj);
+ }
+
+ else
+ dt = 0.0;
+ return (dt);
+}
+
+
+/* FD2OFD-- convert any FITS standard date to old FITS standard date */
+
+char *
+fd2ofd (string)
+
+char *string; /* FITS date string, which may be:
+ fractional year
+ dd/mm/yy (FITS standard before 2000)
+ dd-mm-yy (nonstandard use before 2000)
+ yyyy-mm-dd (FITS standard after 1999)
+ yyyy-mm-ddThh:mm:ss.ss (FITS standard after 1999) */
+{
+ int iyr,imon,iday,ihr,imn;
+ double sec;
+
+ fd2i (string,&iyr,&imon,&iday,&ihr,&imn,&sec, 3);
+
+ /* Convert to old FITS date format */
+ string = (char *) calloc (32, sizeof (char));
+ if (iyr < 1900)
+ sprintf (string, "*** date out of range ***");
+ else if (iyr < 2000)
+ sprintf (string, "%02d/%02d/%02d", iday, imon, iyr-1900);
+ else if (iyr < 2900.0)
+ sprintf (string, "%02d/%02d/%3d", iday, imon, iyr-1900);
+ else
+ sprintf (string, "*** date out of range ***");
+ return (string);
+}
+
+
+/* FD2OFT-- convert any FITS standard date to old FITS standard time */
+
+char *
+fd2oft (string)
+
+char *string; /* FITS date string, which may be:
+ fractional year
+ dd/mm/yy (FITS standard before 2000)
+ dd-mm-yy (nonstandard use before 2000)
+ yyyy-mm-dd (FITS standard after 1999)
+ yyyy-mm-ddThh:mm:ss.ss (FITS standard after 1999) */
+{
+ int iyr,imon,iday,ihr,imn;
+ double sec;
+
+ fd2i (string,&iyr,&imon,&iday,&ihr,&imn,&sec, 3);
+
+ /* Convert to old FITS date format */
+ string = (char *) calloc (32, sizeof (char));
+ sprintf (string, "%02d:%02d:%06.3f", ihr, imn, sec);
+ return (string);
+}
+
+
+/* FD2DT-- convert FITS standard date to date, time as yyyy.mmdd hh.mmsss */
+
+void
+fd2dt (string, date, time)
+
+char *string; /* FITS date string, which may be:
+ fractional year
+ dd/mm/yy (FITS standard before 2000)
+ dd-mm-yy (nonstandard use before 2000)
+ yyyy-mm-dd (FITS standard after 1999)
+ yyyy-mm-ddThh:mm:ss.ss (FITS standard after 1999) */
+double *date; /* Date as yyyy.mmdd (returned)
+ yyyy = calendar year (e.g. 1973)
+ mm = calendar month (e.g. 04 = april)
+ dd = calendar day (e.g. 15) */
+double *time; /* Time as hh.mmssxxxx (returned)
+ *if time<0, it is time as -(fraction of a day)
+ hh = hour of day (0 .le. hh .le. 23)
+ nn = minutes (0 .le. nn .le. 59)
+ ss = seconds (0 .le. ss .le. 59)
+ xxxx = tenths of milliseconds (0 .le. xxxx .le. 9999) */
+{
+ int iyr,imon,iday,ihr,imn;
+ double sec;
+
+ fd2i (string,&iyr,&imon,&iday,&ihr,&imn,&sec, 4);
+
+ /* Convert date to yyyy.mmdd */
+ if (iyr < 0) {
+ *date = (double) (-iyr) + 0.01 * (double) imon + 0.0001 * (double) iday;
+ *date = -(*date);
+ }
+ else
+ *date = (double) iyr + 0.01 * (double) imon + 0.0001 * (double) iday;
+
+ /* Convert time to hh.mmssssss */
+ *time = (double) ihr + 0.01 * (double) imn + 0.0001 * sec;
+
+ return;
+}
+
+
+/* FD2EP-- convert from FITS standard date to fractional year */
+
+double
+fd2ep (string)
+
+char *string; /* FITS date string, which may be:
+ yyyy.ffff (fractional year)
+ dd/mm/yy (FITS standard before 2000)
+ dd-mm-yy (nonstandard FITS use before 2000)
+ yyyy-mm-dd (FITS standard after 1999)
+ yyyy-mm-ddThh:mm:ss.ss (FITS standard after 1999) */
+
+{
+ double dj; /* Julian date */
+ dj = fd2jd (string);
+ if (dj < 1.0)
+ return (dj / 365.2422);
+ else
+ return (jd2ep (dj));
+}
+
+
+/* FD2EPB-- convert from FITS standard date to Besselian epoch */
+
+double
+fd2epb (string)
+
+char *string; /* FITS date string, which may be:
+ yyyy.ffff (fractional year)
+ dd/mm/yy (FITS standard before 2000)
+ dd-mm-yy (nonstandard FITS use before 2000)
+ yyyy-mm-dd (FITS standard after 1999)
+ yyyy-mm-ddThh:mm:ss.ss (FITS standard after 1999) */
+
+{
+ double dj; /* Julian date */
+ dj = fd2jd (string);
+ if (dj < 1.0)
+ return (dj / 365.242198781);
+ else
+ return (jd2epb (dj));
+}
+
+
+/* FD2EPJ-- convert from FITS standard date to Julian epoch */
+
+double
+fd2epj (string)
+
+char *string; /* FITS date string, which may be:
+ yyyy.ffff (fractional year)
+ dd/mm/yy (FITS standard before 2000)
+ dd-mm-yy (nonstandard FITS use before 2000)
+ yyyy-mm-dd (FITS standard after 1999)
+ yyyy-mm-ddThh:mm:ss.ss (FITS standard after 1999) */
+
+{
+ double dj; /* Julian date */
+ dj = fd2jd (string);
+ if (dj < 1.0)
+ return (dj / 365.25);
+ else
+ return (jd2epj (dj));
+}
+
+
+/* DT2TSU-- convert from date and time to Unix seconds since 1970-01-01T0:00 */
+
+time_t
+dt2tsu (date,time)
+
+double date; /* Date as yyyy.mmdd */
+double time; /* Time as hh.mmssxxxx
+ *if time<0, it is time as -(fraction of a day) */
+{
+ return ((time_t)(dt2ts (date, time) - 631152000.0));
+}
+
+
+/* DT2TSI-- convert from date and time to IRAF seconds since 1980-01-01T0:00 */
+
+int
+dt2tsi (date,time)
+
+double date; /* Date as yyyy.mmdd */
+double time; /* Time as hh.mmssxxxx
+ *if time<0, it is time as -(fraction of a day) */
+{
+ return ((int)(dt2ts (date, time) - 946684800.0));
+}
+
+
+
+/* DT2TS-- convert from date, time as yyyy.mmdd hh.mmsss to sec since 1950.0 */
+
+double
+dt2ts (date,time)
+
+double date; /* Date as yyyy.mmdd
+ yyyy = calendar year (e.g. 1973)
+ mm = calendar month (e.g. 04 = april)
+ dd = calendar day (e.g. 15) */
+double time; /* Time as hh.mmssxxxx
+ *if time<0, it is time as -(fraction of a day)
+ hh = hour of day (0 .le. hh .le. 23)
+ nn = minutes (0 .le. nn .le. 59)
+ ss = seconds (0 .le. ss .le. 59)
+ xxxx = tenths of milliseconds (0 .le. xxxx .le. 9999) */
+{
+ double tsec; /* Seconds past 1950.0 (returned) */
+
+ double dh,dm,dd;
+ int iy,im,id;
+
+/* Calculate the number of full years, months, and days already
+ * elapsed since 0h, March 1, -1 (up to most recent midnight). */
+
+ /* convert time of day to elapsed seconds */
+
+ /* If time is < 0, it is assumed to be a fractional day */
+ if (time < 0.0)
+ tsec = time * -86400.0;
+ else {
+ dh = (int) (time + 0.0000000001);
+ dm = (int) (((time - dh) * 100.0) + 0.0000000001);
+ tsec = (time * 10000.0) - (dh * 10000.0) - (dm * 100.0);
+ tsec = (int) (tsec * 100000.0 + 0.0001) / 100000.0;
+ tsec = tsec + (dm * 60.0) + (dh * 3600.0);
+ }
+
+
+ /* Calculate the number of full months elapsed since
+ * the current or most recent March */
+ if (date >= 0.0301) {
+ iy = (int) (date + 0.0000000001);
+ im = (int) (((date - (double) (iy)) * 10000.0) + 0.00000001);
+ id = im % 100;
+ im = (im / 100) + 9;
+ if (im < 12) iy = iy - 1;
+ im = im % 12;
+ id = id - 1;
+
+ /* starting with March as month 0 and ending with the following
+ * February as month 11, the calculation of the number of days
+ * per month reduces to a simple formula. the following statement
+ * determines the number of whole days elapsed since 3/1/-1 and then
+ * subtracts the 712163 days between then and 1/1/1950. it converts
+ * the result to seconds and adds the accumulated seconds above. */
+ id = id + ((im+1+im/6+im/11)/2 * 31) + ((im-im/6-im/11)/2 * 30) +
+ (iy / 4) - (iy / 100) + (iy / 400);
+ dd = (double) id + (365.0 * (double) iy) - 712163.0;
+ tsec = tsec + (dd * 86400.0);
+ }
+
+ return (tsec);
+}
+
+
+/* TS2DT-- convert seconds since 1950.0 to date, time as yyyy.mmdd hh.mmssss */
+
+void
+ts2dt (tsec,date,time)
+
+double tsec; /* Seconds past 1950.0 */
+double *date; /* Date as yyyy.mmdd (returned)
+ yyyy = calendar year (e.g. 1973)
+ mm = calendar month (e.g. 04 = april)
+ dd = calendar day (e.g. 15) */
+double *time; /* Time as hh.mmssxxxx (returned)
+ *if time<0, it is time as -(fraction of a day)
+ hh = hour of day (0 .le. hh .le. 23)
+ nn = minutes (0 .le. nn .le. 59)
+ ss = seconds (0 .le. ss .le. 59)
+ xxxx = tenths of milliseconds (0 .le. xxxx .le. 9999) */
+{
+ int iyr,imon,iday,ihr,imn;
+ double sec;
+
+ ts2i (tsec,&iyr,&imon,&iday,&ihr,&imn,&sec, 4);
+
+ /* Convert date to yyyy.mmdd */
+ if (iyr < 0) {
+ *date = (double) (-iyr) + 0.01 * (double) imon + 0.0001 * (double) iday;
+ *date = -(*date);
+ }
+ else
+ *date = (double) iyr + 0.01 * (double) imon + 0.0001 * (double) iday;
+
+ /* Convert time to hh.mmssssss */
+ *time = (double) ihr + 0.01 * (double) imn + 0.0001 * sec;
+
+ return;
+}
+
+
+/* TSI2DT-- Convert seconds since 1980-01-01 to date yyyy.ddmm, time hh.mmsss */
+
+void
+tsi2dt (isec,date,time)
+
+int isec; /* Seconds past 1980-01-01 */
+double *date; /* Date as yyyy.mmdd (returned) */
+double *time; /* Time as hh.mmssxxxx (returned) */
+{
+ ts2dt (tsi2ts (isec), date, time);
+}
+
+
+/* TSI2FD-- Convert seconds since 1980-01-01 to FITS standard date string */
+
+char *
+tsi2fd (isec)
+
+int isec; /* Seconds past 1980-01-01 */
+{
+ return (ts2fd (tsi2ts (isec)));
+}
+
+
+/* TSI2TS-- Convert seconds since 1980-01-01 to seconds since 1950-01-01 */
+
+double
+tsi2ts (isec)
+int isec; /* Seconds past 1980-01-01 */
+{
+ return ((double) isec + 946684800.0);
+}
+
+
+/* TSU2FD-- Convert seconds since 1970-01-01 to FITS standard date string */
+
+char *
+tsu2fd (isec)
+time_t isec; /* Seconds past 1970-01-01 */
+{
+ return (ts2fd (tsu2ts (isec)));
+}
+
+
+/* TSU2DT-- Convert seconds since 1970-01-01 to date yyyy.ddmm, time hh.mmsss */
+
+void
+tsu2dt (isec,date,time)
+time_t isec; /* Seconds past 1970-01-01 */
+double *date; /* Date as yyyy.mmdd (returned) */
+double *time; /* Time as hh.mmssxxxx (returned) */
+{
+ ts2dt (tsu2ts (isec), date, time);
+}
+
+
+/* TSU2TS-- Convert seconds since 1970-01-01 to seconds since 1950-01-01 */
+
+double
+tsu2ts (isec)
+time_t isec; /* Seconds past 1970-01-01 */
+{
+ return ((double) isec + 631152000.0);
+}
+
+/* TSU2TSI-- UT seconds since 1970-01-01 to local seconds since 1980-01-01 */
+
+int
+tsu2tsi (isec)
+time_t isec; /* Seconds past 1970-01-01 */
+{
+ double date, time;
+ struct tm *ts;
+
+ /* Get local time from UT seconds */
+ ts = localtime (&isec);
+ if (ts->tm_year < 1000)
+ date = (double) (ts->tm_year + 1900);
+ else
+ date = (double) ts->tm_year;
+ date = date + (0.01 * (double) (ts->tm_mon + 1));
+ date = date + (0.0001 * (double) ts->tm_mday);
+ time = (double) ts->tm_hour;
+ time = time + (0.01 * (double) ts->tm_min);
+ time = time + (0.0001 * (double) ts->tm_sec);
+ return ((int)(dt2ts (date, time) - 631152000.0));
+}
+
+
+/* TS2FD-- convert seconds since 1950.0 to FITS date, yyyy-mm-ddThh:mm:ss.ss */
+
+char *
+ts2fd (tsec)
+
+double tsec; /* Seconds past 1950.0 */
+{
+ double date, time;
+
+ ts2dt (tsec, &date, &time);
+ return (dt2fd (date, time));
+}
+
+
+/* TSD2FD-- convert seconds since start of day to FITS time, hh:mm:ss.ss */
+
+char *
+tsd2fd (tsec)
+
+double tsec; /* Seconds since start of day */
+{
+ double date, time;
+ char *thms, *fdate;
+ int lfd, nbc;
+
+ ts2dt (tsec, &date, &time);
+ fdate = dt2fd (date, time);
+ thms = (char *) calloc (16, 1);
+ lfd = strlen (fdate);
+ nbc = lfd - 11;
+ strncpy (thms, fdate+11, nbc);
+ return (thms);
+}
+
+
+/* TSD2DT-- convert seconds since start of day to hh.mmssss */
+
+double
+tsd2dt (tsec)
+
+double tsec; /* Seconds since start of day */
+{
+ double date, time;
+
+ ts2dt (tsec, &date, &time);
+ return (time);
+}
+
+
+
+/* DT2I-- convert vigesimal date and time to year month day hours min sec */
+
+void
+dt2i (date, time, iyr, imon, iday, ihr, imn, sec, ndsec)
+
+double date; /* Date as yyyy.mmdd (returned)
+ yyyy = calendar year (e.g. 1973)
+ mm = calendar month (e.g. 04 = april)
+ dd = calendar day (e.g. 15) */
+double time; /* Time as hh.mmssxxxx (returned)
+ *if time<0, it is time as -(fraction of a day)
+ hh = hour of day (0 .le. hh .le. 23)
+ nn = minutes (0 .le. nn .le. 59)
+ ss = seconds (0 .le. ss .le. 59)
+ xxxx = tenths of milliseconds (0 .le. xxxx .le. 9999) */
+int *iyr; /* year (returned) */
+int *imon; /* month (returned) */
+int *iday; /* day (returned) */
+int *ihr; /* hours (returned) */
+int *imn; /* minutes (returned) */
+double *sec; /* seconds (returned) */
+int ndsec; /* Number of decimal places in seconds (0=int) */
+
+{
+ double t,d;
+
+ t = time;
+ if (date < 0.0)
+ d = -date;
+ else
+ d = date;
+
+ /* Extract components of time */
+ *ihr = dint (t + 0.000000001);
+ t = 100.0 * (t - (double) *ihr);
+ *imn = dint (t + 0.0000001);
+ *sec = 100.0 * (t - (double) *imn);
+
+ /* Extract components of date */
+ *iyr = dint (d + 0.00001);
+ d = 100.0 * (d - (double) *iyr);
+ if (date < 0.0)
+ *iyr = - *iyr;
+ *imon = dint (d + 0.001);
+ d = 100.0 * (d - (double) *imon);
+ *iday = dint (d + 0.1);
+
+ /* Make sure date and time are legal */
+ fixdate (iyr, imon, iday, ihr, imn, sec, ndsec);
+
+ return;
+}
+
+
+/* FD2I-- convert from FITS standard date to year, mon, day, hours, min, sec */
+
+void
+fd2i (string, iyr, imon, iday, ihr, imn, sec, ndsec)
+
+char *string; /* FITS date string, which may be:
+ yyyy.ffff (fractional year)
+ dd/mm/yy (FITS standard before 2000)
+ dd-mm-yy (nonstandard FITS use before 2000)
+ yyyy-mm-dd (FITS standard after 1999)
+ yyyy-mm-ddThh:mm:ss.ss (FITS standard after 1999) */
+int *iyr; /* year (returned) */
+int *imon; /* month (returned) */
+int *iday; /* day (returned) */
+int *ihr; /* hours (returned) */
+int *imn; /* minutes (returned) */
+double *sec; /* seconds (returned) */
+int ndsec; /* Number of decimal places in seconds (0=int) */
+
+{
+ double tsec, fday, hr, mn;
+ int i;
+ char *sstr, *dstr, *tstr, *cstr, *nval, *fstr;
+
+ /* Initialize all returned data to zero */
+ *iyr = 0;
+ *imon = 0;
+ *iday = 0;
+ *ihr = 0;
+ *imn = 0;
+ *sec = 0.0;
+
+ /* Return if no input string */
+ if (string == NULL)
+ return;
+
+ /* Check for various non-numeric characters */
+ sstr = strchr (string,'/');
+ dstr = strchr (string,'-');
+ if (dstr == string)
+ dstr = strchr (string+1, '-');
+ fstr = strchr (string, '.');
+ tstr = strchr (string,'T');
+ if (tstr == NULL)
+ tstr = strchr (string, 'Z');
+ if (tstr == NULL)
+ tstr = strchr (string, 'S');
+ if (fstr != NULL && tstr != NULL && fstr > tstr)
+ fstr = NULL;
+ cstr = strchr (string,':');
+
+ /* Original FITS date format: dd/mm/yy */
+ if (sstr > string) {
+ *sstr = '\0';
+ *iday = (int) atof (string);
+ if (*iday > 31) {
+ *iyr = *iday;
+ if (*iyr >= 0 && *iyr <= 49)
+ *iyr = *iyr + 2000;
+ else if (*iyr < 1000)
+ *iyr = *iyr + 1900;
+ *sstr = '/';
+ nval = sstr + 1;
+ sstr = strchr (nval,'/');
+ if (sstr > string) {
+ *sstr = '\0';
+ *imon = (int) atof (nval);
+ *sstr = '/';
+ nval = sstr + 1;
+ *iday = (int) atof (nval);
+ }
+ }
+ else {
+ *sstr = '/';
+ nval = sstr + 1;
+ sstr = strchr (nval,'/');
+ if (sstr == NULL)
+ sstr = strchr (nval,'-');
+ if (sstr > string) {
+ *sstr = '\0';
+ *imon = (int) atof (nval);
+ *sstr = '/';
+ nval = sstr + 1;
+ *iyr = (int) atof (nval);
+ if (*iyr >= 0 && *iyr <= 49)
+ *iyr = *iyr + 2000;
+ else if (*iyr < 1000)
+ *iyr = *iyr + 1900;
+ }
+ }
+ tstr = strchr (string,'_');
+ if (tstr == NULL)
+ return;
+ }
+
+ /* New FITS date format: yyyy-mm-ddThh:mm:ss[.sss] */
+ else if (dstr > string) {
+ *dstr = '\0';
+ *iyr = (int) atof (string);
+ *dstr = '-';
+ nval = dstr + 1;
+ dstr = strchr (nval,'-');
+ *imon = 1;
+ *iday = 1;
+
+ /* Decode year, month, and day */
+ if (dstr > string) {
+ *dstr = '\0';
+ *imon = (int) atof (nval);
+ *dstr = '-';
+ nval = dstr + 1;
+ if (tstr > string)
+ *tstr = '\0';
+ *iday = (int) atof (nval);
+
+ /* If fraction of a day is present, turn it into a time */
+ if (fstr != NULL) {
+ fday = atof (fstr);
+ hr = fday * 24.0;
+ *ihr = (int) hr;
+ mn = 60.0 * (hr - (double) *ihr);
+ *imn = (int) mn;
+ *sec = 60.0 * (mn - (double) *imn);
+ }
+
+ if (tstr > string)
+ *tstr = 'T';
+ }
+
+ /* If date is > 31, it is really year in old format */
+ if (*iday > 31) {
+ i = *iyr;
+ if (*iday < 100)
+ *iyr = *iday + 1900;
+ else
+ *iyr = *iday;
+ *iday = i;
+ }
+ }
+
+ /* In rare cases, a FITS time is entered as an epoch */
+ else if (tstr == NULL && cstr == NULL && isnum (string)) {
+ tsec = ep2ts (atof (string));
+ ts2i (tsec,iyr,imon,iday,ihr,imn,sec, ndsec);
+ return;
+ }
+
+ /* Extract time, if it is present */
+ if (tstr > string || cstr > string) {
+ if (tstr > string)
+ nval = tstr + 1;
+ else
+ nval = string;
+ cstr = strchr (nval,':');
+ if (cstr > string) {
+ *cstr = '\0';
+ *ihr = (int) atof (nval);
+ *cstr = ':';
+ nval = cstr + 1;
+ cstr = strchr (nval,':');
+ if (cstr > string) {
+ *cstr = '\0';
+ *imn = (int) atof (nval);
+ *cstr = ':';
+ nval = cstr + 1;
+ *sec = atof (nval);
+ }
+ else
+ *imn = (int) atof (nval);
+ }
+ else
+ *ihr = (int) atof (nval);
+ }
+ else
+ ndsec = -1;
+
+ /* Make sure date and time are legal */
+ fixdate (iyr, imon, iday, ihr, imn, sec, ndsec);
+
+ return;
+}
+
+
+/* TS2I-- convert sec since 1950.0 to year month day hours minutes seconds */
+
+void
+ts2i (tsec,iyr,imon,iday,ihr,imn,sec, ndsec)
+
+double tsec; /* seconds since 1/1/1950 0:00 */
+int *iyr; /* year (returned) */
+int *imon; /* month (returned) */
+int *iday; /* day (returned) */
+int *ihr; /* hours (returned) */
+int *imn; /* minutes (returned) */
+double *sec; /* seconds (returned) */
+int ndsec; /* Number of decimal places in seconds (0=int) */
+
+{
+ double t,days, ts, dts;
+ int nc,nc4,nly,ny,m,im;
+
+ /* Round seconds to 0 - 4 decimal places */
+ ts = tsec + 61530883200.0;
+ if (ts < 0.0)
+ dts = -0.5;
+ else
+ dts = 0.5;
+ if (ndsec < 1)
+ t = dint (ts + dts) * 10000.0;
+ else if (ndsec < 2)
+ t = dint (ts * 10.0 + dts) * 1000.0;
+ else if (ndsec < 3)
+ t = dint (ts * 100.0 + dts) * 100.0;
+ else if (ndsec < 4)
+ t = dint (ts * 1000.0 + dts) * 10.0;
+ else
+ t = dint (ts * 10000.0 + dts);
+ ts = t / 10000.0;
+
+ /* Time of day (hours, minutes, seconds */
+ *ihr = (int) (dmod (ts/3600.0, 24.0));
+ *imn = (int) (dmod (ts/60.0, 60.0));
+ *sec = dmod (ts, 60.0);
+
+ /* Number of days since 0 hr 0/0/0000 */
+ days = dint ((t / 864000000.0) + 0.000001);
+
+ /* Number of leap centuries (400 years) */
+ nc4 = (int) ((days / 146097.0) + 0.00001);
+
+ /* Number of centuries since last /400 */
+ days = days - (146097.0 * (double) (nc4));
+ nc = (int) ((days / 36524.0) + 0.000001);
+ if (nc > 3) nc = 3;
+
+ /* Number of leap years since last century */
+ days = days - (36524.0 * nc);
+ nly = (int) ((days / 1461.0) + 0.0000000001);
+
+ /* Number of years since last leap year */
+ days = days - (1461.0 * (double) nly);
+ ny = (int) ((days / 365.0) + 0.00000001);
+ if (ny > 3) ny = 3;
+
+ /* Day of month */
+ days = days - (365.0 * (double) ny);
+ if (days < 0) {
+ m = 0;
+ *iday = 29;
+ }
+ else {
+ *iday = (int) (days + 0.00000001) + 1;
+ for (m = 1; m <= 12; m++) {
+ im = (m + ((m - 1) / 5)) % 2;
+ /* fprintf (stderr,"%d %d %d %d\n", m, im, *iday, nc); */
+ if (*iday-1 < im+30) break;
+ *iday = *iday - im - 30;
+ }
+ }
+
+ /* Month */
+ *imon = ((m+1) % 12) + 1;
+
+ /* Year */
+ *iyr = nc4*400 + nc*100 + nly*4 + ny + m/11;
+
+ /* Make sure date and time are legal */
+ fixdate (iyr, imon, iday, ihr, imn, sec, ndsec);
+
+ return;
+}
+
+
+/* UT2DOY-- Current Universal Time as year, day of year */
+
+void
+ut2doy (year, doy)
+
+int *year; /* Year (returned) */
+double *doy; /* Day of year (returned) */
+{
+ double date, time;
+ ut2dt (&date, &time);
+ dt2doy (date, time, year, doy);
+ return;
+}
+
+
+/* UT2DT-- Current Universal Time as date (yyyy.mmdd) and time (hh.mmsss) */
+
+void
+ut2dt(date, time)
+
+double *date; /* Date as yyyy.mmdd (returned) */
+double *time; /* Time as hh.mmssxxxx (returned) */
+{
+ time_t tsec;
+ struct timeval tp;
+ struct timezone tzp;
+ struct tm *ts;
+
+ gettimeofday (&tp,&tzp);
+
+ tsec = tp.tv_sec;
+ ts = gmtime (&tsec);
+
+ if (ts->tm_year < 1000)
+ *date = (double) (ts->tm_year + 1900);
+ else
+ *date = (double) ts->tm_year;
+ *date = *date + (0.01 * (double) (ts->tm_mon + 1));
+ *date = *date + (0.0001 * (double) ts->tm_mday);
+ *time = (double) ts->tm_hour;
+ *time = *time + (0.01 * (double) ts->tm_min);
+ *time = *time + (0.0001 * (double) ts->tm_sec);
+
+ return;
+}
+
+
+/* UT2EP-- Return current Universal Time as fractional year */
+
+double
+ut2ep()
+{
+ return (jd2ep (ut2jd()));
+}
+
+
+/* UT2EPB-- Return current Universal Time as Besselian epoch */
+
+double
+ut2epb()
+{
+ return (jd2epb (ut2jd()));
+}
+
+
+/* UT2EPJ-- Return current Universal Time as Julian epoch */
+
+double
+ut2epj()
+{
+ return (jd2epj (ut2jd()));
+}
+
+
+/* UT2FD-- Return current Universal Time as FITS ISO date string */
+
+char *
+ut2fd()
+{
+ int year, month, day, hour, minute, second;
+ time_t tsec;
+ struct timeval tp;
+ struct timezone tzp;
+ struct tm *ts;
+ char *isotime;
+
+ gettimeofday (&tp,&tzp);
+ tsec = tp.tv_sec;
+ ts = gmtime (&tsec);
+
+ year = ts->tm_year;
+ if (year < 1000)
+ year = year + 1900;
+ month = ts->tm_mon + 1;
+ day = ts->tm_mday;
+ hour = ts->tm_hour;
+ minute = ts->tm_min;
+ second = ts->tm_sec;
+
+ isotime = (char *) calloc (32, sizeof (char));
+ sprintf (isotime, "%04d-%02d-%02dT%02d:%02d:%02d",
+ year, month, day, hour, minute, second);
+ return (isotime);
+}
+
+
+/* UT2JD-- Return current Universal Time as Julian Date */
+
+double
+ut2jd()
+{
+ return (fd2jd (ut2fd()));
+}
+
+
+/* UT2MJD-- convert current UT to Modified Julian Date */
+
+double
+ut2mjd ()
+
+{
+ return (ut2jd() - 2400000.5);
+}
+
+/* UT2TS-- current Universal Time as IRAF seconds since 1950-01-01T00:00 */
+
+double
+ut2ts()
+{
+ double tsec;
+ char *datestring;
+ datestring = ut2fd();
+ tsec = fd2ts (datestring);
+ free (datestring);
+ return (tsec);
+}
+
+
+/* UT2TSI-- current Universal Time as IRAF seconds since 1980-01-01T00:00 */
+
+int
+ut2tsi()
+{
+ return ((int)(ut2ts() - 946684800.0));
+}
+
+
+/* UT2TSU-- current Universal Time as IRAF seconds since 1970-01-01T00:00 */
+
+time_t
+ut2tsu()
+{
+ return ((time_t)(ut2ts () - 631152000.0));
+}
+
+
+/* FD2GST-- convert from FITS date to Greenwich Sidereal Time */
+
+char *
+fd2gst (string)
+
+char *string; /* FITS date string, which may be:
+ fractional year
+ dd/mm/yy (FITS standard before 2000)
+ dd-mm-yy (nonstandard use before 2000)
+ yyyy-mm-dd (FITS standard after 1999)
+ yyyy-mm-ddThh:mm:ss.ss (FITS standard after 1999) */
+{
+ double dj, gsec, date, time;
+
+ dj = fd2jd (string);
+ gsec = jd2gst (dj);
+ ts2dt (gsec, &date, &time);
+ date = 0.0;
+ return (dt2fd (date, time));
+}
+
+
+/* DT2GST-- convert from UT as yyyy.mmdd hh.mmssss to Greenwich Sidereal Time*/
+
+void
+dt2gst (date, time)
+double *date; /* Date as yyyy.mmdd */
+double *time; /* Time as hh.mmssxxxx
+ *if time<0, it is time as -(fraction of a day) */
+{
+ double dj, gsec;
+
+ dj = dt2ts (*date, *time);
+ gsec = jd2gst (dj);
+ ts2dt (gsec, date, time);
+ *date = 0.0;
+ return;
+}
+
+
+/* JD2LST - Local Sidereal Time in seconds from Julian Date */
+
+double
+jd2lst (dj)
+
+double dj; /* Julian Date */
+{
+ double gst, lst;
+
+ /* Compute Greenwich Sidereal Time at this epoch */
+ gst = jd2gst (dj);
+
+ /* Subtract longitude (degrees to seconds of time) */
+ lst = gst - (240.0 * longitude);
+ if (lst < 0.0)
+ lst = lst + 86400.0;
+ else if (lst > 86400.0)
+ lst = lst - 86400.0;
+ return (lst);
+}
+
+
+/* FD2LST - Local Sidereal Time as hh:mm:ss.ss
+ from Universal Time as FITS ISO date */
+
+char *
+fd2lst (string)
+
+char *string; /* FITS date string, which may be:
+ fractional year
+ dd/mm/yy (FITS standard before 2000)
+ dd-mm-yy (nonstandard use before 2000)
+ yyyy-mm-dd (FITS standard after 1999) */
+{
+ double dj, date, time, lst;
+
+ dj = fd2jd (string);
+ lst = jd2lst (dj);
+ ts2dt (lst, &date, &time);
+ date = 0.0;
+ return (dt2fd (date, time));
+}
+
+
+/* DT2LST - Local Sidereal Time as hh.mmssss
+ from Universal Time as yyyy.mmdd hh.mmssss */
+
+void
+dt2lst (date, time)
+
+double *date; /* Date as yyyy.mmdd */
+double *time; /* Time as hh.mmssxxxx
+ *if time<0, it is time as -(fraction of a day) */
+{
+ double dj, lst, date0;
+
+ dj = dt2jd (*date, *time);
+ lst = jd2lst (dj);
+ date0 = 0.0;
+ ts2dt (lst, &date0, time);
+ return;
+}
+
+
+/* TS2LST - Local Sidereal Time in seconds of day
+ * from Universal Time in seconds since 1951-01-01T0:00:00
+ */
+
+double
+ts2lst (tsec)
+
+double tsec; /* time since 1950.0 in UT seconds */
+{
+ double gst; /* Greenwich Sidereal Time in seconds since 0:00 */
+ double lst; /* Local Sidereal Time in seconds since 0:00 */
+ double gsec, date;
+
+ /* Greenwich Sidereal Time */
+ gsec = ts2gst (tsec);
+ date = 0.0;
+ ts2dt (gsec, &date, &gst);
+
+ lst = gst - (longitude / 15.0);
+ if (lst < 0.0)
+ lst = lst + 86400.0;
+ else if (lst > 86400.0)
+ lst = lst - 86400.0;
+ return (lst);
+}
+
+
+/* LST2FD - calculate current UT given Local Sidereal Time
+ * plus date in FITS ISO format (yyyy-mm-dd)
+ * Return UT date and time in FITS ISO format
+ */
+
+char *
+lst2fd (string)
+
+char *string; /* UT Date, LST as yyyy-mm-ddShh:mm:ss.ss */
+{
+ double sdj, dj;
+
+ sdj = fd2jd (string);
+
+ dj = lst2jd (sdj);
+
+ return (jd2fd (dj));
+}
+
+
+/* LST2JD - calculate current Julian Date given Local Sidereal Time
+ * plus current Julian Date (0.5 at 0:00 UT)
+ * Return UT date and time as Julian Date
+ */
+
+double
+lst2jd (sdj)
+
+double sdj; /* Julian Date of desired day at 0:00 UT + sidereal time */
+{
+ double gst; /* Greenwich Sidereal Time in seconds since 0:00 */
+ double lsd; /* Local Sidereal Time in seconds since 0:00 */
+ double gst0, tsd, dj1, dj0, eqnx;
+ int idj;
+
+ /* Julian date at 0:00 UT */
+ idj = (int) sdj;
+ dj0 = (double) idj + 0.5;
+ if (dj0 > sdj) dj0 = dj0 - 1.0;
+
+ /* Greenwich Sidereal Time at 0:00 UT in seconds */
+ gst0 = jd2gst (dj0);
+
+ /* Sidereal seconds since 0:00 */
+ lsd = (sdj - dj0) * 86400.0;
+
+ /* Remove longitude for current Greenwich Sidereal Time in seconds */
+ /* (convert longitude from degrees to seconds of time) */
+ gst = lsd + (longitude * 240.0);
+
+ /* Time since 0:00 UT */
+ tsd = (gst - gst0) / 1.0027379093;
+
+ /* Julian Date (UT) */
+ dj1 = dj0 + (tsd / 86400.0);
+
+ /* Equation of the equinoxes converted to UT seconds */
+ eqnx = eqeqnx (dj1) / 1.002739093;
+
+ /* Remove equation of equinoxes */
+ dj1 = dj1 - (eqnx / 86400.0);
+ if (dj1 < dj0)
+ dj1 = dj1 + 1.0;
+
+ return (dj1);
+}
+
+
+/* MST2FD - calculate current UT given Greenwich Mean Sidereal Time
+ * plus date in FITS ISO format (yyyy-mm-ddShh:mm:ss.ss)
+ * Return UT date and time in FITS ISO format
+ */
+
+char *
+mst2fd (string)
+
+char *string; /* UT Date, MST as yyyy-mm-ddShh:mm:ss.ss */
+{
+ double sdj, dj;
+
+ sdj = fd2jd (string);
+
+ dj = mst2jd (sdj);
+
+ return (jd2fd (dj));
+}
+
+
+/* MST2JD - calculate current UT given Greenwich Mean Sidereal Time
+ * plus date in Julian Date (0:00 UT + Mean Sidereal Time)
+ * Return UT date and time as Julian Date
+ */
+
+double
+mst2jd (sdj)
+
+double sdj; /* UT Date, MST as Julian Date */
+{
+ double tsd, djd, st0, dj0, dj;
+
+ dj0 = (double) ((int) sdj) + 0.5;
+
+ /* Greenwich Mean Sidereal Time at 0:00 UT in seconds */
+ st0 = jd2mst (dj0);
+
+ /* Mean Sidereal Time in seconds */
+ tsd = (sdj - dj0) * 86400.0;
+ if (tsd < 0.0)
+ tsd = tsd + 86400.0;
+
+ /* Convert to fraction of a day since 0:00 UT */
+ djd = ((tsd - st0) / 1.0027379093) / 86400.0;
+
+ /* Julian Date */
+ dj = dj0 + djd;
+ if (dj < dj0)
+ dj = dj + (1.0 / 1.0027379093);
+
+ return (dj);
+}
+
+
+
+/* GST2FD - calculate current UT given Greenwich Sidereal Time
+ * plus date in FITS ISO format (yyyy-mm-ddShh:mm:ss.ss)
+ * Return UT date and time in FITS ISO format
+ */
+
+char *
+gst2fd (string)
+
+char *string; /* UT Date, GST as yyyy-mm-ddShh:mm:ss.ss */
+{
+ double sdj, dj;
+
+ sdj = fd2jd (string);
+
+ dj = gst2jd (sdj);
+
+ return (jd2fd (dj));
+}
+
+
+/* GST2JD - calculate current UT given Greenwich Sidereal Time
+ * plus date as Julian Date (JD at 0:00 UT + sidereal time)
+ * Return UT date and time as Julian Date
+ */
+
+double
+gst2jd (sdj)
+
+double sdj; /* UT Date, GST as Julian Date */
+{
+ double dj, tsd, djd, st0, dj0, eqnx;
+
+ dj0 = (double) ((int) sdj) + 0.5;
+
+ /* Greenwich Mean Sidereal Time at 0:00 UT in seconds */
+ st0 = jd2mst (dj0);
+
+ /* Mean Sidereal Time in seconds */
+ tsd = (sdj - dj0) * 86400.0;
+ if (tsd < 0.0)
+ tsd = tsd + 86400.0;
+
+ /* Convert to fraction of a day since 0:00 UT */
+ djd = ((tsd - st0) / 1.0027379093) / 86400.0;
+
+ /* Julian Date */
+ dj = dj0 + djd;
+
+ /* Equation of the equinoxes (converted to UT seconds) */
+ eqnx = eqeqnx (dj) / 1.002737909;
+
+ dj = dj - eqnx / 86400.0;
+ if (dj < dj0)
+ dj = dj + 1.0;
+
+ return (dj);
+}
+
+
+/* LST2DT - calculate current UT given Local Sidereal Time as hh.mmsss
+ * plus date as yyyy.mmdd
+ * Return UT time as hh.mmssss
+ */
+
+double
+lst2dt (date0, time0)
+
+double date0; /* UT date as yyyy.mmdd */
+double time0; /* LST as hh.mmssss */
+{
+ double gst; /* Greenwich Sidereal Time in seconds since 0:00 */
+ double lst; /* Local Sidereal Time in seconds since 0:00 */
+ double date1; /* UT date as yyyy.mmdd */
+ double time1; /* UT as hh.mmssss */
+ double tsec0, gst0, tsd, tsec;
+
+ /* Greenwich Sidereal Time at 0:00 UT */
+ tsec0 = dt2ts (date0, 0.0);
+ gst0 = ts2gst (tsec0);
+
+ /* Current Greenwich Sidereal Time in seconds */
+ /* (convert longitude from degrees to seconds of time) */
+ lst = dt2ts (0.0, time0);
+ gst = lst + (longitude * 240.0);
+
+ /* Time since 0:00 UT */
+ tsd = (gst - gst0) / 1.0027379093;
+
+ /* UT date and time */
+ tsec = tsec0 + tsd;
+ ts2dt (tsec, &date1, &time1);
+
+ return (time1);
+}
+
+
+/* TS2GST - calculate Greenwich Sidereal Time given Universal Time
+ * in seconds since 1951-01-01T0:00:00
+ * Return sidereal time of day in seconds
+ */
+
+double
+ts2gst (tsec)
+
+double tsec; /* time since 1950.0 in UT seconds */
+{
+ double gst; /* Greenwich Sidereal Time in seconds since 0:00 */
+ double tsd, eqnx, dj;
+ int its;
+
+ /* Elapsed time as of 0:00 UT */
+ if (tsec >= 0.0) {
+ its = (int) (tsec + 0.5);
+ tsd = (double) (its % 86400);
+ }
+ else {
+ its = (int) (-tsec + 0.5);
+ tsd = (double) (86400 - (its % 86400));
+ }
+
+ /* Mean sidereal time */
+ gst = ts2mst (tsec);
+
+ /* Equation of the equinoxes */
+ dj = ts2jd (tsec);
+ eqnx = eqeqnx (dj);
+
+ /* Apparent sidereal time at 0:00 ut */
+ gst = gst + eqnx;
+
+ /* Current sidereal time */
+ gst = gst + (tsd * 1.0027379093);
+ gst = dmod (gst,86400.0);
+
+ return (gst);
+}
+
+
+/* FD2MST-- convert from FITS date Mean Sidereal Time */
+
+char *
+fd2mst (string)
+
+char *string; /* FITS date string, which may be:
+ fractional year
+ dd/mm/yy (FITS standard before 2000)
+ dd-mm-yy (nonstandard use before 2000)
+ yyyy-mm-dd (FITS standard after 1999)
+ yyyy-mm-ddThh:mm:ss.ss (FITS standard after 1999) */
+{
+ double gsec, date, time, dj;
+
+ dj = fd2jd (string);
+ gsec = jd2mst (dj);
+ ts2dt (gsec, &date, &time);
+ date = 0.0;
+ return (dt2fd (date, time));
+}
+
+
+/* DT2MST-- convert from UT as yyyy.mmdd hh.mmssss to Mean Sidereal Time
+ in the same format */
+
+void
+dt2mst (date, time)
+double *date; /* Date as yyyy.mmdd */
+double *time; /* Time as hh.mmssxxxx
+ *if time<0, it is time as -(fraction of a day) */
+{
+ double date0, gsec, dj;
+ date0 = *date;
+ dj = dt2jd (*date, *time);
+ gsec = jd2mst (dj);
+ ts2dt (gsec, date, time);
+ *date = date0;
+ return;
+}
+
+
+/* TS2MST - calculate Greenwich Mean Sidereal Time given Universal Time
+ * in seconds since 1951-01-01T0:00:00
+ */
+
+double
+ts2mst (tsec)
+
+double tsec; /* time since 1950.0 in UT seconds */
+{
+ double dj;
+
+ dj = ts2jd (tsec);
+ return (jd2mst (dj));
+}
+
+
+/* JD2MST - Julian Date to Greenwich Mean Sidereal Time using IAU 2000
+ * Return sideral time in seconds of time
+ * (from USNO NOVAS package
+ * http://aa.usno.navy.mil/software/novas/novas_info.html
+ */
+
+double
+jd2mst2 (dj)
+
+double dj; /* Julian Date */
+{
+ double dt, t, t2, t3, mst, st;
+
+ dt = dj - 2451545.0;
+ t = dt / 36525.0;
+ t2 = t * t;
+ t3 = t2 * t;
+
+ /* Compute Greenwich Mean Sidereal Time in seconds */
+ st = (8640184.812866 * t) + (3155760000.0 * t) - (0.0000062 * t3)
+ + (0.093104 * t2) + 67310.54841;
+
+ mst = dmod (st, 86400.0);
+ if (mst < 0.0)
+ mst = mst + 86400.0;
+ return (mst);
+}
+
+
+/* MJD2MST - Modified Julian Date to Greenwich Mean Sidereal Time using IAU 2000
+ * Return sideral time in seconds of time
+ * (from USNO NOVAS package
+ * http://aa.usno.navy.mil/software/novas/novas_info.html
+ */
+
+double
+mjd2mst (dj)
+
+double dj; /* Modified Julian Date */
+{
+ double dt, t, t2, t3, mst, st;
+
+ dt = dj - 51544.5;
+ t = dt / 36525.0;
+ t2 = t * t;
+ t3 = t2 * t;
+
+ /* Compute Greenwich Mean Sidereal Time in seconds */
+ st = (8640184.812866 * t) + (3155760000.0 * t) - (0.0000062 * t3)
+ + (0.093104 * t2) + 67310.54841;
+
+ mst = dmod (st, 86400.0);
+ if (mst < 0.0)
+ mst = mst + 86400.0;
+ return (mst);
+}
+
+
+/* JD2GST - Julian Date to Greenwich Sideral Time
+ * Return sideral time in seconds of time
+ * (Jean Meeus, Astronomical Algorithms, Willmann-Bell, 1991, pp 83-84)
+ */
+
+double
+jd2gst (dj)
+
+double dj; /* Julian Date */
+{
+ double dj0, gmt, gst, tsd, eqnx, ssd, l0;
+ double ts2ss = 1.00273790935;
+ int ijd;
+
+ /* Julian date at 0:00 UT */
+ ijd = (int) dj;
+ dj0 = (double) ijd + 0.5;
+ if (dj0 > dj) dj0 = dj0 - 1.0;
+
+ /* Greenwich mean sidereal time at 0:00 UT in seconds */
+ l0 = longitude;
+ longitude = 0.0;
+ gmt = jd2mst (dj0);
+ longitude = l0;
+
+ /* Equation of the equinoxes */
+ eqnx = eqeqnx (dj);
+
+ /* Apparent sidereal time at 0:00 ut */
+ gst = gmt + eqnx;
+
+ /* UT seconds since 0:00 */
+ tsd = (dj - dj0) * 86400.0;
+ ssd = tsd * ts2ss;
+
+ /* Current sidereal time */
+ gst = gst + ssd;
+ gst = dmod (gst, 86400.0);
+
+ return (gst);
+}
+
+
+/* EQEQNX - Compute equation of the equinoxes for apparent sidereal time */
+
+double
+eqeqnx (dj)
+
+double dj; /* Julian Date */
+
+{
+ double dt, edj, dpsi, deps, obl, eqnx;
+ double rad2tsec = 13750.98708;
+
+ /* Convert UT to Ephemeris Time (TDB or TT)*/
+ dt = utdt (dj);
+ edj = dj + dt / 86400.0;
+
+ /* Nutation and obliquity */
+ compnut (edj, &dpsi, &deps, &obl);
+
+ /* Correct obliquity for nutation */
+ obl = obl + deps;
+
+ /* Equation of the equinoxes in seconds */
+ eqnx = (dpsi * cos (obl)) * rad2tsec;
+
+ return (eqnx);
+}
+
+
+
+/* JD2MST - Julian Date to Mean Sideral Time
+ * Return sideral time in seconds of time
+ * (Jean Meeus, Astronomical Algorithms, Willmann-Bell, 1991, pp 83-84)
+ */
+
+double
+jd2mst (dj)
+
+double dj; /* Julian Date */
+{
+ double dt, t, mst;
+
+ dt = dj - 2451545.0;
+ t = dt / 36525.0;
+
+ /* Compute Greenwich mean sidereal time in degrees (Meeus, page 84) */
+ mst = 280.46061837 + (360.98564736629 * dt) + (0.000387933 * t * t) -
+ (t * t * t / 38710000.0);
+
+ /* Keep degrees between 0 and 360 */
+ while (mst > 360.0)
+ mst = mst - 360.0;
+ while (mst < 0.0)
+ mst = mst + 360.0;
+
+ /* Convert to time in seconds (3600 / 15) */
+ mst = mst * 240.0;
+
+ /* Subtract longitude (degrees to seconds of time) */
+ mst = mst - (240.0 * longitude);
+ if (mst < 0.0)
+ mst = mst + 86400.0;
+ else if (mst > 86400.0)
+ mst = mst - 86400.0;
+
+ return (mst);
+}
+
+
+/* COMPNUT - Compute nutation using the IAU 2000b model */
+/* Translated from Pat Wallace's Fortran subroutine iau_nut00b (June 26 2007)
+ into C by Jessica Mink on September 5, 2008 */
+
+#define NLS 77 /* number of terms in the luni-solar nutation model */
+
+void
+compnut (dj, dpsi, deps, eps0)
+
+double dj; /* Julian Date */
+double *dpsi; /* Nutation in longitude in radians (returned) */
+double *deps; /* Nutation in obliquity in radians (returned) */
+double *eps0; /* Mean obliquity in radians (returned) */
+
+/* This routine is translated from the International Astronomical Union's
+ * Fortran SOFA (Standards Of Fundamental Astronomy) software collection.
+ *
+ * notes:
+ *
+ * 1) the nutation components in longitude and obliquity are in radians
+ * and with respect to the equinox and ecliptic of date. the
+ * obliquity at j2000 is assumed to be the lieske et al. (1977) value
+ * of 84381.448 arcsec. (the errors that result from using this
+ * routine with the iau 2006 value of 84381.406 arcsec can be
+ * neglected.)
+ *
+ * the nutation model consists only of luni-solar terms, but includes
+ * also a fixed offset which compensates for certain long-period
+ * planetary terms (note 7).
+ *
+ * 2) this routine is an implementation of the iau 2000b abridged
+ * nutation model formally adopted by the iau general assembly in
+ * 2000. the routine computes the mhb_2000_short luni-solar nutation
+ * series (luzum 2001), but without the associated corrections for
+ * the precession rate adjustments and the offset between the gcrs
+ * and j2000 mean poles.
+ *
+ * 3) the full IAU 2000a (mhb2000) nutation model contains nearly 1400
+ * terms. the IAU 2000b model (mccarthy & luzum 2003) contains only
+ * 77 terms, plus additional simplifications, yet still delivers
+ * results of 1 mas accuracy at present epochs. this combination of
+ * accuracy and size makes the IAU 2000b abridged nutation model
+ * suitable for most practical applications.
+ *
+ * the routine delivers a pole accurate to 1 mas from 1900 to 2100
+ * (usually better than 1 mas, very occasionally just outside 1 mas).
+ * the full IAU 2000a model, which is implemented in the routine
+ * iau_nut00a (q.v.), delivers considerably greater accuracy at
+ * current epochs; however, to realize this improved accuracy,
+ * corrections for the essentially unpredictable free-core-nutation
+ * (fcn) must also be included.
+ *
+ * 4) the present routine provides classical nutation. the
+ * mhb_2000_short algorithm, from which it is adapted, deals also
+ * with (i) the offsets between the gcrs and mean poles and (ii) the
+ * adjustments in longitude and obliquity due to the changed
+ * precession rates. these additional functions, namely frame bias
+ * and precession adjustments, are supported by the sofa routines
+ * iau_bi00 and iau_pr00.
+ *
+ * 6) the mhb_2000_short algorithm also provides "total" nutations,
+ * comprising the arithmetic sum of the frame bias, precession
+ * adjustments, and nutation (luni-solar + planetary). these total
+ * nutations can be used in combination with an existing IAU 1976
+ * precession implementation, such as iau_pmat76, to deliver gcrs-to-
+ * true predictions of mas accuracy at current epochs. however, for
+ * symmetry with the iau_nut00a routine (q.v. for the reasons), the
+ * sofa routines do not generate the "total nutations" directly.
+ * should they be required, they could of course easily be generated
+ * by calling iau_bi00, iau_pr00 and the present routine and adding
+ * the results.
+ *
+ * 7) the IAU 2000b model includes "planetary bias" terms that are fixed
+ * in size but compensate for long-period nutations. the amplitudes
+ * quoted in mccarthy & luzum (2003), namely dpsi = -1.5835 mas and
+ * depsilon = +1.6339 mas, are optimized for the "total nutations"
+ * method described in note 6. the luzum (2001) values used in this
+ * sofa implementation, namely -0.135 mas and +0.388 mas, are
+ * optimized for the "rigorous" method, where frame bias, precession
+ * and nutation are applied separately and in that order. during the
+ * interval 1995-2050, the sofa implementation delivers a maximum
+ * error of 1.001 mas (not including fcn).
+ *
+ * References from original Fortran subroutines:
+ *
+ * Hilton, J. et al., 2006, Celest.Mech.Dyn.Astron. 94, 351
+ *
+ * Lieske, J.H., Lederle, T., Fricke, W., Morando, B., "Expressions
+ * for the precession quantities based upon the IAU 1976 system of
+ * astronomical constants", Astron.Astrophys. 58, 1-2, 1-16. (1977)
+ *
+ * Luzum, B., private communication, 2001 (Fortran code
+ * mhb_2000_short)
+ *
+ * McCarthy, D.D. & Luzum, B.J., "An abridged model of the
+ * precession-nutation of the celestial pole", Cel.Mech.Dyn.Astron.
+ * 85, 37-49 (2003)
+ *
+ * Simon, J.-L., Bretagnon, P., Chapront, J., Chapront-Touze, M.,
+ * Francou, G., Laskar, J., Astron.Astrophys. 282, 663-683 (1994)
+ *
+ */
+
+{
+ double as2r = 0.000004848136811095359935899141; /* arcseconds to radians */
+
+ double dmas2r = as2r / 1000.0; /* milliarcseconds to radians */
+
+ double as2pi = 1296000.0; /* arc seconds in a full circle */
+
+ double d2pi = 6.283185307179586476925287; /* 2pi */
+
+ double u2r = as2r / 10000000.0; /* units of 0.1 microarcsecond to radians */
+
+ double dj0 = 2451545.0; /* reference epoch (j2000), jd */
+
+ double djc = 36525.0; /* Days per julian century */
+
+ /* Miscellaneous */
+ double t, el, elp, f, d, om, arg, dp, de, sarg, carg;
+ double dpsils, depsls, dpsipl, depspl;
+ int i, j;
+
+ int nls = NLS; /* number of terms in the luni-solar nutation model */
+
+ /* Fixed offset in lieu of planetary terms (radians) */
+ double dpplan = - 0.135 * dmas2r;
+ double deplan = + 0.388 * dmas2r;
+
+/* Tables of argument and term coefficients */
+
+ /* Coefficients for fundamental arguments */
+ /* Luni-solar argument multipliers: */
+ /* l l' f d om */
+static int nals[5*NLS]=
+ {0, 0, 0, 0, 1,
+ 0, 0, 2, -2, 2,
+ 0, 0, 2, 0, 2,
+ 0, 0, 0, 0, 2,
+ 0, 1, 0, 0, 0,
+ 0, 1, 2, -2, 2,
+ 1, 0, 0, 0, 0,
+ 0, 0, 2, 0, 1,
+ 1, 0, 2, 0, 2,
+ 0, -1, 2, -2, 2,
+ 0, 0, 2, -2, 1,
+ -1, 0, 2, 0, 2,
+ -1, 0, 0, 2, 0,
+ 1, 0, 0, 0, 1,
+ -1, 0, 0, 0, 1,
+ -1, 0, 2, 2, 2,
+ 1, 0, 2, 0, 1,
+ -2, 0, 2, 0, 1,
+ 0, 0, 0, 2, 0,
+ 0, 0, 2, 2, 2,
+ 0, -2, 2, -2, 2,
+ -2, 0, 0, 2, 0,
+ 2, 0, 2, 0, 2,
+ 1, 0, 2, -2, 2,
+ -1, 0, 2, 0, 1,
+ 2, 0, 0, 0, 0,
+ 0, 0, 2, 0, 0,
+ 0, 1, 0, 0, 1,
+ -1, 0, 0, 2, 1,
+ 0, 2, 2, -2, 2,
+ 0, 0, -2, 2, 0,
+ 1, 0, 0, -2, 1,
+ 0, -1, 0, 0, 1,
+ -1, 0, 2, 2, 1,
+ 0, 2, 0, 0, 0,
+ 1, 0, 2, 2, 2,
+ -2, 0, 2, 0, 0,
+ 0, 1, 2, 0, 2,
+ 0, 0, 2, 2, 1,
+ 0, -1, 2, 0, 2,
+ 0, 0, 0, 2, 1,
+ 1, 0, 2, -2, 1,
+ 2, 0, 2, -2, 2,
+ -2, 0, 0, 2, 1,
+ 2, 0, 2, 0, 1,
+ 0, -1, 2, -2, 1,
+ 0, 0, 0, -2, 1,
+ -1, -1, 0, 2, 0,
+ 2, 0, 0, -2, 1,
+ 1, 0, 0, 2, 0,
+ 0, 1, 2, -2, 1,
+ 1, -1, 0, 0, 0,
+ -2, 0, 2, 0, 2,
+ 3, 0, 2, 0, 2,
+ 0, -1, 0, 2, 0,
+ 1, -1, 2, 0, 2,
+ 0, 0, 0, 1, 0,
+ -1, -1, 2, 2, 2,
+ -1, 0, 2, 0, 0,
+ 0, -1, 2, 2, 2,
+ -2, 0, 0, 0, 1,
+ 1, 1, 2, 0, 2,
+ 2, 0, 0, 0, 1,
+ -1, 1, 0, 1, 0,
+ 1, 1, 0, 0, 0,
+ 1, 0, 2, 0, 0,
+ -1, 0, 2, -2, 1,
+ 1, 0, 0, 0, 2,
+ -1, 0, 0, 1, 0,
+ 0, 0, 2, 1, 2,
+ -1, 0, 2, 4, 2,
+ -1, 1, 0, 1, 1,
+ 0, -2, 2, -2, 1,
+ 1, 0, 2, 2, 1,
+ -2, 0, 2, 2, 2,
+ -1, 0, 0, 0, 2,
+ 1, 1, 2, -2, 2};
+
+ /* Luni-solar nutation coefficients, in 1e-7 arcsec */
+ /* longitude (sin, t*sin, cos), obliquity (cos, t*cos, sin) */
+static double cls[6*NLS]=
+ {-172064161.0, -174666.0, 33386.0, 92052331.0, 9086.0, 15377.0,
+ -13170906.0, -1675.0, -13696.0, 5730336.0, -3015.0, -4587.0,
+ -2276413.0, -234.0, 2796.0, 978459.0, -485.0, 1374.0,
+ 2074554.0, 207.0, -698.0, -897492.0, 470.0, -291.0,
+ 1475877.0, -3633.0, 11817.0, 73871.0, -184.0, -1924.0,
+ -516821.0, 1226.0, -524.0, 224386.0, -677.0, -174.0,
+ 711159.0, 73.0, -872.0, -6750.0, 0.0, 358.0,
+ -387298.0, -367.0, 380.0, 200728.0, 18.0, 318.0,
+ -301461.0, -36.0, 816.0, 129025.0, -63.0, 367.0,
+ 215829.0, -494.0, 111.0, -95929.0, 299.0, 132.0,
+ 128227.0, 137.0, 181.0, -68982.0, -9.0, 39.0,
+ 123457.0, 11.0, 19.0, -53311.0, 32.0, -4.0,
+ 156994.0, 10.0, -168.0, -1235.0, 0.0, 82.0,
+ 63110.0, 63.0, 27.0, -33228.0, 0.0, -9.0,
+ -57976.0, -63.0, -189.0, 31429.0, 0.0, -75.0,
+ -59641.0, -11.0, 149.0, 25543.0, -11.0, 66.0,
+ -51613.0, -42.0, 129.0, 26366.0, 0.0, 78.0,
+ 45893.0, 50.0, 31.0, -24236.0, -10.0, 20.0,
+ 63384.0, 11.0, -150.0, -1220.0, 0.0, 29.0,
+ -38571.0, -1.0, 158.0, 16452.0, -11.0, 68.0,
+ 32481.0, 0.0, 0.0, -13870.0, 0.0, 0.0,
+ -47722.0, 0.0, -18.0, 477.0, 0.0, -25.0,
+ -31046.0, -1.0, 131.0, 13238.0, -11.0, 59.0,
+ 28593.0, 0.0, -1.0, -12338.0, 10.0, -3.0,
+ 20441.0, 21.0, 10.0, -10758.0, 0.0, -3.0,
+ 29243.0, 0.0, -74.0, -609.0, 0.0, 13.0,
+ 25887.0, 0.0, -66.0, -550.0, 0.0, 11.0,
+ -14053.0, -25.0, 79.0, 8551.0, -2.0, -45.0,
+ 15164.0, 10.0, 11.0, -8001.0, 0.0, -1.0,
+ -15794.0, 72.0, -16.0, 6850.0, -42.0, -5.0,
+ 21783.0, 0.0, 13.0, -167.0, 0.0, 13.0,
+ -12873.0, -10.0, -37.0, 6953.0, 0.0, -14.0,
+ -12654.0, 11.0, 63.0, 6415.0, 0.0, 26.0,
+ -10204.0, 0.0, 25.0, 5222.0, 0.0, 15.0,
+ 16707.0, -85.0, -10.0, 168.0, -1.0, 10.0,
+ -7691.0, 0.0, 44.0, 3268.0, 0.0, 19.0,
+ -11024.0, 0.0, -14.0, 104.0, 0.0, 2.0,
+ 7566.0, -21.0, -11.0, -3250.0, 0.0, -5.0,
+ -6637.0, -11.0, 25.0, 3353.0, 0.0, 14.0,
+ -7141.0, 21.0, 8.0, 3070.0, 0.0, 4.0,
+ -6302.0, -11.0, 2.0, 3272.0, 0.0, 4.0,
+ 5800.0, 10.0, 2.0, -3045.0, 0.0, -1.0,
+ 6443.0, 0.0, -7.0, -2768.0, 0.0, -4.0,
+ -5774.0, -11.0, -15.0, 3041.0, 0.0, -5.0,
+ -5350.0, 0.0, 21.0, 2695.0, 0.0, 12.0,
+ -4752.0, -11.0, -3.0, 2719.0, 0.0, -3.0,
+ -4940.0, -11.0, -21.0, 2720.0, 0.0, -9.0,
+ 7350.0, 0.0, -8.0, -51.0, 0.0, 4.0,
+ 4065.0, 0.0, 6.0, -2206.0, 0.0, 1.0,
+ 6579.0, 0.0, -24.0, -199.0, 0.0, 2.0,
+ 3579.0, 0.0, 5.0, -1900.0, 0.0, 1.0,
+ 4725.0, 0.0, -6.0, -41.0, 0.0, 3.0,
+ -3075.0, 0.0, -2.0, 1313.0, 0.0, -1.0,
+ -2904.0, 0.0, 15.0, 1233.0, 0.0, 7.0,
+ 4348.0, 0.0, -10.0, -81.0, 0.0, 2.0,
+ -2878.0, 0.0, 8.0, 1232.0, 0.0, 4.0,
+ -4230.0, 0.0, 5.0, -20.0, 0.0, -2.0,
+ -2819.0, 0.0, 7.0, 1207.0, 0.0, 3.0,
+ -4056.0, 0.0, 5.0, 40.0, 0.0, -2.0,
+ -2647.0, 0.0, 11.0, 1129.0, 0.0, 5.0,
+ -2294.0, 0.0, -10.0, 1266.0, 0.0, -4.0,
+ 2481.0, 0.0, -7.0, -1062.0, 0.0, -3.0,
+ 2179.0, 0.0, -2.0, -1129.0, 0.0, -2.0,
+ 3276.0, 0.0, 1.0, -9.0, 0.0, 0.0,
+ -3389.0, 0.0, 5.0, 35.0, 0.0, -2.0,
+ 3339.0, 0.0, -13.0, -107.0, 0.0, 1.0,
+ -1987.0, 0.0, -6.0, 1073.0, 0.0, -2.0,
+ -1981.0, 0.0, 0.0, 854.0, 0.0, 0.0,
+ 4026.0, 0.0, -353.0, -553.0, 0.0, -139.0,
+ 1660.0, 0.0, -5.0, -710.0, 0.0, -2.0,
+ -1521.0, 0.0, 9.0, 647.0, 0.0, 4.0,
+ 1314.0, 0.0, 0.0, -700.0, 0.0, 0.0,
+ -1283.0, 0.0, 0.0, 672.0, 0.0, 0.0,
+ -1331.0, 0.0, 8.0, 663.0, 0.0, 4.0,
+ 1383.0, 0.0, -2.0, -594.0, 0.0, -2.0,
+ 1405.0, 0.0, 4.0, -610.0, 0.0, 2.0,
+ 1290.0, 0.0, 0.0, -556.0, 0.0, 0.0};
+
+ /* Interval between fundamental epoch J2000.0 and given date (JC) */
+ t = (dj - dj0) / djc;
+
+/* Luni-solar nutation */
+
+/* Fundamental (delaunay) arguments from Simon et al. (1994) */
+
+ /* Mean anomaly of the moon */
+ el = fmod (485868.249036 + (1717915923.2178 * t), as2pi) * as2r;
+
+ /* Mean anomaly of the sun */
+ elp = fmod (1287104.79305 + (129596581.0481 * t), as2pi) * as2r;
+
+ /* Mean argument of the latitude of the moon */
+ f = fmod (335779.526232 + (1739527262.8478 * t), as2pi) * as2r;
+
+ /* Mean elongation of the moon from the sun */
+ d = fmod (1072260.70369 + (1602961601.2090 * t), as2pi ) * as2r;
+
+ /* Mean longitude of the ascending node of the moon */
+ om = fmod (450160.398036 - (6962890.5431 * t), as2pi ) * as2r;
+
+ /* Initialize the nutation values */
+ dp = 0.0;
+ de = 0.0;
+
+ /* Summation of luni-solar nutation series (in reverse order) */
+ for (i = nls; i > 0; i=i-1) {
+ j = i - 1;
+
+ /* Argument and functions */
+ arg = fmod ( (double) (nals[5*j]) * el +
+ (double) (nals[1+5*j]) * elp +
+ (double) (nals[2+5*j]) * f +
+ (double) (nals[3+5*j]) * d +
+ (double) (nals[4+5*j]) * om, d2pi);
+ sarg = sin (arg);
+ carg = cos (arg);
+
+ /* Terms */
+ dp = dp + (cls[6*j] + cls[1+6*j] * t) * sarg + cls[2+6*j] * carg;
+ de = de + (cls[3+6*j] + cls[4+6*j] * t) * carg + cls[5+6*j] * sarg;
+ }
+
+ /* Convert from 0.1 microarcsec units to radians */
+ dpsils = dp * u2r;
+ depsls = de * u2r;
+
+/* In lieu of planetary nutation */
+
+ /* Fixed offset to correct for missing terms in truncated series */
+ dpsipl = dpplan;
+ depspl = deplan;
+
+/* Results */
+
+ /* Add luni-solar and planetary components */
+ *dpsi = dpsils + dpsipl;
+ *deps = depsls + depspl;
+
+ /* Mean Obliquity in radians (IAU 2006, Hilton, et al.) */
+ *eps0 = ( 84381.406 +
+ ( -46.836769 +
+ ( -0.0001831 +
+ ( 0.00200340 +
+ ( -0.000000576 +
+ ( -0.0000000434 ) * t ) * t ) * t ) * t ) * t ) * as2r;
+}
+
+
+/* ISDATE - Return 1 if string is an old or ISO FITS standard date */
+
+int
+isdate (string)
+
+char *string; /* Possible FITS date string, which may be:
+ dd/mm/yy (FITS standard before 2000)
+ dd-mm-yy (nonstandard FITS use before 2000)
+ yyyy-mm-dd (FITS standard after 1999)
+ yyyy-mm-ddThh:mm:ss.ss (FITS standard after 1999) */
+
+{
+ int iyr = 0; /* year (returned) */
+ int imon = 0; /* month (returned) */
+ int iday = 0; /* day (returned) */
+ int i;
+ char *sstr, *dstr, *tstr, *nval;
+
+ /* Translate string from ASCII to binary */
+ if (string == NULL)
+ return (0);
+
+ sstr = strchr (string,'/');
+ dstr = strchr (string,'-');
+ if (dstr == string)
+ dstr = strchr (string+1,'-');
+ tstr = strchr (string,'T');
+
+ /* Original FITS date format: dd/mm/yy */
+ if (sstr > string) {
+ *sstr = '\0';
+ iday = (int) atof (string);
+ *sstr = '/';
+ nval = sstr + 1;
+ sstr = strchr (nval,'/');
+ if (sstr == NULL)
+ sstr = strchr (nval,'-');
+ if (sstr > string) {
+ *sstr = '\0';
+ imon = (int) atof (nval);
+ *sstr = '/';
+ nval = sstr + 1;
+ iyr = (int) atof (nval);
+ if (iyr < 1000)
+ iyr = iyr + 1900;
+ }
+ if (imon > 0 && iday > 0)
+ return (1);
+ else
+ return (0);
+ }
+
+ /* New FITS date format: yyyy-mm-ddThh:mm:ss[.sss] */
+ else if (dstr > string) {
+ *dstr = '\0';
+ iyr = (int) atof (string);
+ nval = dstr + 1;
+ *dstr = '-';
+ dstr = strchr (nval,'-');
+ imon = 0;
+ iday = 0;
+
+ /* Decode year, month, and day */
+ if (dstr > string) {
+ *dstr = '\0';
+ imon = (int) atof (nval);
+ *dstr = '-';
+ nval = dstr + 1;
+ if (tstr > string)
+ *tstr = '\0';
+ iday = (int) atof (nval);
+ if (tstr > string)
+ *tstr = 'T';
+ }
+
+ /* If day is > 31, it is really year in old format */
+ if (iday > 31) {
+ i = iyr;
+ if (iday < 100)
+ iyr = iday + 1900;
+ else
+ iyr = iday;
+ iday = i;
+ }
+ if (imon > 0 && iday > 0)
+ return (1);
+ else
+ return (0);
+ }
+
+ /* If FITS date is entered as an epoch, return 0 anyway */
+ else
+ return (0);
+}
+
+
+/* Round seconds and make sure date and time numbers are within limits */
+
+static void
+fixdate (iyr, imon, iday, ihr, imn, sec, ndsec)
+
+int *iyr; /* year (returned) */
+int *imon; /* month (returned) */
+int *iday; /* day (returned) */
+int *ihr; /* hours (returned) */
+int *imn; /* minutes (returned) */
+double *sec; /* seconds (returned) */
+int ndsec; /* Number of decimal places in seconds (0=int) */
+{
+ double days;
+
+ /* Round seconds to 0 - 4 decimal places (no rounding if <0, >4) */
+ if (ndsec == 0)
+ *sec = dint (*sec + 0.5);
+ else if (ndsec < 2)
+ *sec = dint (*sec * 10.0 + 0.5) / 10.0;
+ else if (ndsec < 3)
+ *sec = dint (*sec * 100.0 + 0.5) / 100.0;
+ else if (ndsec < 4)
+ *sec = dint (*sec * 1000.0 + 0.5) / 1000.0;
+ else if (ndsec < 5)
+ *sec = dint (*sec * 10000.0 + 0.5) / 10000.0;
+
+ /* Adjust minutes and hours */
+ if (*sec > 60.0) {
+ *sec = *sec - 60.0;
+ *imn = *imn + 1;
+ }
+ if (*imn > 60) {
+ *imn = *imn - 60;
+ *ihr = *ihr + 1;
+ }
+
+ /* Return if no date */
+ if (*iyr == 0 && *imon == 0 && *iday == 0)
+ return;
+
+ /* Adjust date */
+ if (*ihr > 23) {
+ *ihr = *ihr - 24;
+ *iday = *iday + 1;
+ }
+ days = caldays (*iyr, *imon);
+ if (*iday > days) {
+ *iday = *iday - days;
+ *imon = *imon + 1;
+ }
+ if (*iday < 1) {
+ *imon = *imon - 1;
+ if (*imon < 1) {
+ *imon = *imon + 12;
+ *iyr = *iyr - 1;
+ }
+ days = caldays (*iyr, *imon);
+ *iday = *iday + days;
+ }
+ if (*imon < 1) {
+ *imon = *imon + 12;
+ *iyr = *iyr - 1;
+ days = caldays (*iyr, *imon);
+ if (*iday > days) {
+ *iday = *iday - days;
+ *imon = *imon + 1;
+ }
+ }
+ if (*imon > 12) {
+ *imon = *imon - 12;
+ *iyr = *iyr + 1;
+ }
+ return;
+}
+
+
+/* Calculate days in month 1-12 given year (Gregorian calendar only) */
+
+static int
+caldays (year, month)
+
+int year; /* 4-digit year */
+int month; /* Month (1=January, 2=February, etc.) */
+{
+ if (month < 1) {
+ month = month + 12;
+ year = year + 1;
+ }
+ if (month > 12) {
+ month = month - 12;
+ year = year + 1;
+ }
+ switch (month) {
+ case 1:
+ return (31);
+ case 2:
+ if (year%400 == 0)
+ return (29);
+ else if (year%100 == 0)
+ return (28);
+ else if (year%4 == 0)
+ return (29);
+ else
+ return (28);
+ case 3:
+ return (31);
+ case 4:
+ return (30);
+ case 5:
+ return (31);
+ case 6:
+ return (30);
+ case 7:
+ return (31);
+ case 8:
+ return (31);
+ case 9:
+ return (30);
+ case 10:
+ return (31);
+ case 11:
+ return (30);
+ case 12:
+ return (31);
+ default:
+ return (0);
+ }
+}
+
+
+static double
+dint (dnum)
+
+double dnum;
+{
+ double dn;
+
+ if (dnum < 0.0)
+ dn = -floor (-dnum);
+ else
+ dn = floor (dnum);
+ return (dn);
+}
+
+
+static double
+dmod (dnum, dm)
+
+double dnum, dm;
+{
+ double dnumx, dnumi, dnumf;
+ if (dnum < 0.0)
+ dnumx = -dnum;
+ else
+ dnumx = dnum;
+ dnumi = dint (dnumx / dm);
+ if (dnum < 0.0)
+ dnumf = dnum + (dnumi * dm);
+ else if (dnum > 0.0)
+ dnumf = dnum - (dnumi * dm);
+ else
+ dnumf = 0.0;
+ return (dnumf);
+}
+
+/* Jul 1 1999 New file, based on iolib/jcon.f and iolib/vcon.f and hgetdate()
+ * Oct 21 1999 Fix declarations after lint
+ * Oct 27 1999 Fix bug to return epoch if fractional year input
+ * Dec 9 1999 Fix bug in ts2jd() found by Pete Ratzlaff (SAO)
+ * Dec 17 1999 Add all unimplemented conversions
+ * Dec 20 1999 Add isdate(); leave date, time strings unchanged in fd2i()
+ * Dec 20 1999 Make all fd2*() subroutines deal with time alone
+ *
+ * Jan 3 2000 In old FITS format, year 100 is assumed to be 2000
+ * Jan 11 2000 Fix epoch to date conversion so .0 is 0:00, not 12:00
+ * Jan 21 2000 Add separate Besselian and Julian epoch computations
+ * Jan 28 2000 Add Modified Julian Date conversions
+ * Mar 2 2000 Implement decimal places for FITS date string
+ * Mar 14 2000 Fix bug in dealing with 2000-02-29 in ts2i()
+ * Mar 22 2000 Add lt2* and ut2* to get current time as local and UT
+ * Mar 24 2000 Fix calloc() calls
+ * Mar 24 2000 Add tsi2* and tsu2* to convert IRAF and Unix seconds
+ * May 1 2000 In old FITS format, all years < 1000 get 1900 added to them
+ * Aug 1 2000 Make ep2jd and jd2ep consistently starting at 1/1 0:00
+ *
+ * Jan 11 2001 Print all messages to stderr
+ * May 21 2001 Add day of year conversions
+ * May 25 2001 Allow fraction of day in FITS date instead of time
+ *
+ * Apr 8 2002 Change all long declaration to time_t
+ * May 13 2002 Fix bugs found by lint
+ * Jul 5 2002 Fix bug in fixdate() so fractional seconds come out
+ * Jul 8 2002 Fix rounding bug in t2i()
+ * Jul 8 2002 Try Fliegel and Van Flandern's algorithm for JD to UT date
+ * Jul 8 2002 If first character of string is -, check for other -'s in isdate
+ * Sep 10 2002 Add ET/TDT/TT conversion from UT subroutines
+ * Sep 10 2002 Add sidereal time conversions
+ *
+ * Jan 30 2003 Fix typo in ts2gst()
+ * Mar 7 2003 Add conversions for heliocentric julian dates
+ * May 20 2003 Declare nd in setdatedec()
+ * Jul 18 2003 Add code to parse Las Campanas dates
+ *
+ * Mar 24 2004 If ndec > 0, add UT to FITS date even if it is 0:00:00
+ *
+ * Oct 14 2005 Add tsd2fd() and tsd2dt()
+ *
+ * May 3 2006 Drop declaration of unused variables
+ * Jun 20 2006 Initialized uninitialized variables
+ * Aug 2 2006 Add local sidereal time
+ * Sep 13 2006 Add more local sidereal time subroutines
+ * Oct 2 2006 Add UT to old FITS date conversions
+ * Oct 6 2006 Add eqeqnx() to compute equation of the equinoxes
+ *
+ * Jan 8 2007 Remove unused variables
+ *
+ * Sep 5 2008 Replace nutation with IAU 2006 model translated from SOFA
+ * Sep 9 2008 Add ang2hr(), ang2deg(), hr2ang(), deg2ang()
+ * Sep 10 2008 Add longitude to mean standard time (default = Greenwich)
+ * Oct 8 2008 Clean up sidereal time computations
+ *
+ * Sep 24 2009 Add end to comment "Coefficients for fundamental arguments"
+ *
+ * Jan 11 2012 Add TAI, TT, GPS time
+ * Oct 19 2012 Unused l0 dropped from jd2lst(); ts2ss from jd2mst()
+ */
diff --git a/funtools/wcs/distort.c b/funtools/wcs/distort.c
new file mode 100644
index 0000000..d903dfe
--- /dev/null
+++ b/funtools/wcs/distort.c
@@ -0,0 +1,407 @@
+/*** File libwcs/distort.c
+ *** January 4, 2007
+ *** By Jessica Mink, jmink@cfa.harvard.edu,
+ *** Based on code written by Jing Li, IPAC
+ *** Harvard-Smithsonian Center for Astrophysics
+ *** Copyright (C) 2004-2007
+ *** Smithsonian Astrophysical Observatory, Cambridge, MA, USA
+
+ This library 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 2 of the License, or (at your option) any later version.
+
+ This library 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 this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Correspondence concerning WCSTools should be addressed as follows:
+ Internet email: jmink@cfa.harvard.edu
+ Postal address: Jessica Mink
+ Smithsonian Astrophysical Observatory
+ 60 Garden St.
+ Cambridge, MA 02138 USA
+
+ * Module: distort.c (World Coordinate Systems)
+ * Purpose: Convert focal plane coordinates to pixels and vice versa:
+ * Subroutine: distortinit (wcs, hstring) set distortion coefficients from FITS header
+ * Subroutine: DelDistort (header, verbose) delete distortion coefficients in FITS header
+ * Subroutine: pix2foc (wcs, x, y, u, v) pixel coordinates -> focal plane coordinates
+ * Subroutine: foc2pix (wcs, u, v, x, y) focal plane coordinates -> pixel coordinates
+ * Subroutine: setdistcode (wcs,ctype) sets distortion code from CTYPEi
+ * Subroutine: getdistcode (wcs) returns distortion code string for CTYPEi
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "wcs.h"
+
+void
+distortinit (wcs, hstring)
+struct WorldCoor *wcs; /* World coordinate system structure */
+const char *hstring; /* character string containing FITS header information
+ in the format <keyword>= <value> [/ <comment>] */
+{
+ int i, j, m;
+ char keyword[12];
+
+ /* Read distortion coefficients, if present */
+ if (wcs->distcode == DISTORT_SIRTF) {
+ if (wcs->wcsproj == WCS_OLD) {
+ wcs->wcsproj = WCS_NEW;
+ wcs->distort.a_order = 0;
+ wcs->distort.b_order = 0;
+ wcs->distort.ap_order = 0;
+ wcs->distort.bp_order = 0;
+ }
+ else {
+ if (!hgeti4 (hstring, "A_ORDER", &wcs->distort.a_order)) {
+ setwcserr ("DISTINIT: Missing A_ORDER keyword for Spitzer distortion");
+ }
+ else {
+ m = wcs->distort.a_order;
+ for (i = 0; i <= m; i++) {
+ for (j = 0; j <= m; j++) {
+ wcs->distort.a[i][j] = 0.0;
+ }
+ }
+ for (i = 0; i <= m; i++) {
+ for (j = 0; j <= m-i; j++) {
+ sprintf (keyword, "A_%d_%d", i, j);
+ hgetr8 (hstring, keyword, &wcs->distort.a[i][j]);
+ }
+ }
+ }
+ if (!hgeti4 (hstring, "B_ORDER", &wcs->distort.b_order)) {
+ setwcserr ("DISTINIT: Missing B_ORDER keyword for Spitzer distortion");
+ }
+ else {
+ m = wcs->distort.b_order;
+ for (i = 0; i <= m; i++) {
+ for (j = 0; j <= m; j++) {
+ wcs->distort.b[i][j] = 0.0;
+ }
+ }
+ for (i = 0; i <= m; i++) {
+ for (j = 0; j <= m-i; j++) {
+ sprintf (keyword, "B_%d_%d", i, j);
+ hgetr8 (hstring, keyword, &wcs->distort.b[i][j]);
+ }
+ }
+ }
+ if (!hgeti4 (hstring, "AP_ORDER", &wcs->distort.ap_order)) {
+ setwcserr ("DISTINIT: Missing AP_ORDER keyword for Spitzer distortion");
+ }
+ else {
+ m = wcs->distort.ap_order;
+ for (i = 0; i <= m; i++) {
+ for (j = 0; j <= m; j++) {
+ wcs->distort.ap[i][j] = 0.0;
+ }
+ }
+ for (i = 0; i <= m; i++) {
+ for (j = 0; j <= m-i; j++) {
+ sprintf (keyword, "AP_%d_%d", i, j);
+ hgetr8 (hstring, keyword, &wcs->distort.ap[i][j]);
+ }
+ }
+ }
+ if (!hgeti4 (hstring, "BP_ORDER", &wcs->distort.bp_order)) {
+ setwcserr ("DISTINIT: Missing BP_ORDER keyword for Spitzer distortion");
+ }
+ else {
+ m = wcs->distort.bp_order;
+ for (i = 0; i <= m; i++) {
+ for (j = 0; j <= m; j++) {
+ wcs->distort.bp[i][j] = 0.0;
+ }
+ }
+ for (i = 0; i <= m; i++) {
+ for (j = 0; j <= m-i; j++) {
+ sprintf (keyword, "BP_%d_%d", i, j);
+ hgetr8 (hstring, keyword, &wcs->distort.bp[i][j]);
+ }
+ }
+ }
+ }
+ }
+ return;
+}
+
+
+/* Delete all distortion-related fields.
+ * return 0 if at least one such field is found, else -1. */
+
+int
+DelDistort (header, verbose)
+
+char *header;
+int verbose;
+
+{
+ char keyword[16];
+ char str[32];
+ int i, j, m;
+ int lctype;
+ int n;
+
+ n = 0;
+
+ if (hgeti4 (header, "A_ORDER", &m)) {
+ for (i = 0; i <= m; i++) {
+ for (j = 0; j <= m-i; j++) {
+ sprintf (keyword, "A_%d_%d", i, j);
+ hdel (header, keyword);
+ n++;
+ }
+ }
+ hdel (header, "A_ORDER");
+ n++;
+ }
+
+ if (hgeti4 (header, "AP_ORDER", &m)) {
+ for (i = 0; i <= m; i++) {
+ for (j = 0; j <= m-i; j++) {
+ sprintf (keyword, "AP_%d_%d", i, j);
+ hdel (header, keyword);
+ n++;
+ }
+ }
+ hdel (header, "AP_ORDER");
+ n++;
+ }
+
+ if (hgeti4 (header, "B_ORDER", &m)) {
+ for (i = 0; i <= m; i++) {
+ for (j = 0; j <= m-i; j++) {
+ sprintf (keyword, "B_%d_%d", i, j);
+ hdel (header, keyword);
+ n++;
+ }
+ }
+ hdel (header, "B_ORDER");
+ n++;
+ }
+
+ if (hgeti4 (header, "BP_ORDER", &m)) {
+ for (i = 0; i <= m; i++) {
+ for (j = 0; j <= m-i; j++) {
+ sprintf (keyword, "BP_%d_%d", i, j);
+ hdel (header, keyword);
+ n++;
+ }
+ }
+ hdel (header, "BP_ORDER");
+ n++;
+ }
+
+ if (n > 0 && verbose)
+ fprintf (stderr,"%d keywords deleted\n", n);
+
+ /* Remove WCS distortion code from CTYPEi in FITS header */
+ if (hgets (header, "CTYPE1", 31, str)) {
+ lctype = strlen (str);
+ if (lctype > 8) {
+ str[8] = (char) 0;
+ hputs (header, "CTYPE1", str);
+ }
+ }
+ if (hgets (header, "CTYPE2", 31, str)) {
+ lctype = strlen (str);
+ if (lctype > 8) {
+ str[8] = (char) 0;
+ hputs (header, "CTYPE2", str);
+ }
+ }
+
+ return (n);
+}
+
+void
+foc2pix (wcs, x, y, u, v)
+
+struct WorldCoor *wcs; /* World coordinate system structure */
+double x, y; /* Focal plane coordinates */
+double *u, *v; /* Image pixel coordinates (returned) */
+{
+ int m, n, i, j, k;
+ double s[DISTMAX], sum;
+ double temp_x, temp_y;
+
+ /* Spitzer distortion */
+ if (wcs->distcode == DISTORT_SIRTF) {
+ m = wcs->distort.ap_order;
+ n = wcs->distort.bp_order;
+
+ temp_x = x - wcs->xrefpix;
+ temp_y = y - wcs->yrefpix;
+
+ /* compute u */
+ for (j = 0; j <= m; j++) {
+ s[j] = wcs->distort.ap[m-j][j];
+ for (k = j-1; k >= 0; k--) {
+ s[j] = (temp_y * s[j]) + wcs->distort.ap[m-j][k];
+ }
+ }
+
+ sum = s[0];
+ for (i=m; i>=1; i--){
+ sum = (temp_x * sum) + s[m-i+1];
+ }
+ *u = sum;
+
+ /* compute v*/
+ for (j = 0; j <= n; j++) {
+ s[j] = wcs->distort.bp[n-j][j];
+ for (k = j-1; k >= 0; k--) {
+ s[j] = temp_y*s[j] + wcs->distort.bp[n-j][k];
+ }
+ }
+
+ sum = s[0];
+ for (i = n; i >= 1; i--)
+ sum = temp_x * sum + s[n-i+1];
+
+ *v = sum;
+
+ *u = x + *u;
+ *v = y + *v;
+ }
+
+ /* If no distortion, return pixel positions unchanged */
+ else {
+ *u = x;
+ *v = y;
+ }
+
+ return;
+}
+
+
+void
+pix2foc (wcs, u, v, x, y)
+
+struct WorldCoor *wcs; /* World coordinate system structure */
+double u, v; /* Image pixel coordinates */
+double *x, *y; /* Focal plane coordinates (returned) */
+{
+ int m, n, i, j, k;
+ double s[DISTMAX], sum;
+ double temp_u, temp_v;
+
+ /* Spitzer distortion */
+ if (wcs->distcode == DISTORT_SIRTF) {
+ m = wcs->distort.a_order;
+ n = wcs->distort.b_order;
+
+ temp_u = u - wcs->xrefpix;
+ temp_v = v - wcs->yrefpix;
+
+ /* compute u */
+ for (j = 0; j <= m; j++) {
+ s[j] = wcs->distort.a[m-j][j];
+ for (k = j-1; k >= 0; k--) {
+ s[j] = (temp_v * s[j]) + wcs->distort.a[m-j][k];
+ }
+ }
+
+ sum = s[0];
+ for (i=m; i>=1; i--){
+ sum = temp_u*sum + s[m-i+1];
+ }
+ *x = sum;
+
+ /* compute v*/
+ for (j=0; j<=n; j++) {
+ s[j] = wcs->distort.b[n-j][j];
+ for (k=j-1; k>=0; k--) {
+ s[j] =temp_v*s[j] + wcs->distort.b[n-j][k];
+ }
+ }
+
+ sum = s[0];
+ for (i=n; i>=1; i--)
+ sum = temp_u*sum + s[n-i+1];
+
+ *y = sum;
+
+ *x = u + *x;
+ *y = v + *y;
+
+/* *x = u + *x + coeff.crpix1; */
+/* *y = v + *y + coeff.crpix2; */
+ }
+
+ /* If no distortion, return pixel positions unchanged */
+ else {
+ *x = u;
+ *y = v;
+ }
+
+ return;
+}
+
+
+/* SETDISTCODE -- Set WCS distortion code from CTYPEi in FITS header */
+
+void
+setdistcode (wcs, ctype)
+
+struct WorldCoor *wcs; /* World coordinate system structure */
+char *ctype; /* Value of CTYPEi from FITS header */
+
+{
+ char *extension;
+ int lctype;
+
+ lctype = strlen (ctype);
+ if (lctype < 9)
+ wcs->distcode = DISTORT_NONE;
+ else {
+ extension = ctype + 8;
+ if (!strncmp (extension, "-SIP", 4))
+ wcs->distcode = DISTORT_SIRTF;
+ else
+ wcs->distcode = DISTORT_NONE;
+ }
+ return;
+}
+
+
+/* GETDISTCODE -- Return NULL if no distortion or code from wcs.h */
+
+char *
+getdistcode (wcs)
+
+struct WorldCoor *wcs; /* World coordinate system structure */
+
+{
+ char *dcode; /* Distortion string for CTYPEi */
+
+ if (wcs->distcode == DISTORT_SIRTF) {
+ dcode = (char *) calloc (8, sizeof (char));
+ strcpy (dcode, "-SIP");
+ }
+ else
+ dcode = NULL;
+ return (dcode);
+}
+
+/* Apr 2 2003 New subroutines
+ * Nov 3 2003 Add getdistcode to return distortion code string
+ * Nov 10 2003 Include unistd.h to get definition of NULL
+ * Nov 18 2003 Include string.h to get strlen()
+ *
+ * Jan 9 2004 Add DelDistort() to delete distortion keywords
+ *
+ * Jan 4 2007 Declare header const char*
+ *
+ * Feb 25 2011 Change SIRTF to Spitzer (long overdue!)
+ */
diff --git a/funtools/wcs/dsspos.c b/funtools/wcs/dsspos.c
new file mode 100644
index 0000000..3bbd5a0
--- /dev/null
+++ b/funtools/wcs/dsspos.c
@@ -0,0 +1,318 @@
+/*** File saoimage/wcslib/dsspos.c
+ *** October 21, 1999
+ *** By Jessica Mink, jmink@cfa.harvard.edu
+ *** Harvard-Smithsonian Center for Astrophysics
+ *** Copyright (C) 1995-2002
+ *** Smithsonian Astrophysical Observatory, Cambridge, MA, USA
+
+ This library 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 2 of the License, or (at your option) any later version.
+
+ This library 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 this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Correspondence concerning WCSTools should be addressed as follows:
+ Internet email: jmink@cfa.harvard.edu
+ Postal address: Jessica Mink
+ Smithsonian Astrophysical Observatory
+ 60 Garden St.
+ Cambridge, MA 02138 USA
+
+ * Module: dsspos.c (Plate solution WCS conversion)
+ * Purpose: Compute WCS from Digital Sky Survey plate fit
+ * Subroutine: dsspos() converts from pixel location to RA,Dec
+ * Subroutine: dsspix() converts from RA,Dec to pixel location
+
+ These functions are based on the astrmcal.c portion of GETIMAGE by
+ J. Doggett and the documentation distributed with the Digital Sky Survey.
+
+*/
+
+#include <math.h>
+#include <string.h>
+#include <stdio.h>
+#include "wcs.h"
+
+int
+dsspos (xpix, ypix, wcs, xpos, ypos)
+
+/* Routine to determine accurate position for pixel coordinates */
+/* returns 0 if successful otherwise 1 = angle too large for projection; */
+/* based on amdpos() from getimage */
+
+/* Input: */
+double xpix; /* x pixel number (RA or long without rotation) */
+double ypix; /* y pixel number (dec or lat without rotation) */
+struct WorldCoor *wcs; /* WCS parameter structure */
+
+/* Output: */
+double *xpos; /* Right ascension or longitude in degrees */
+double *ypos; /* Declination or latitude in degrees */
+
+{
+ double x, y, xmm, ymm, xmm2, ymm2, xmm3, ymm3, x2y2;
+ double xi, xir, eta, etar, raoff, ra, dec;
+ double cond2r = 1.745329252e-2;
+ double cons2r = 206264.8062470964;
+ double twopi = 6.28318530717959;
+ double ctan, ccos;
+
+/* Ignore magnitude and color terms
+ double mag = 0.0;
+ double color = 0.0; */
+
+/* Convert from image pixels to plate pixels */
+ x = xpix + wcs->x_pixel_offset - 1.0 + 0.5;
+ y = ypix + wcs->y_pixel_offset - 1.0 + 0.5;
+
+/* Convert from pixels to millimeters */
+ xmm = (wcs->ppo_coeff[2] - x * wcs->x_pixel_size) / 1000.0;
+ ymm = (y * wcs->y_pixel_size - wcs->ppo_coeff[5]) / 1000.0;
+ xmm2 = xmm * xmm;
+ ymm2 = ymm * ymm;
+ xmm3 = xmm * xmm2;
+ ymm3 = ymm * ymm2;
+ x2y2 = xmm2 + ymm2;
+
+/* Compute coordinates from x,y and plate model */
+
+ xi = wcs->x_coeff[ 0]*xmm + wcs->x_coeff[ 1]*ymm +
+ wcs->x_coeff[ 2] + wcs->x_coeff[ 3]*xmm2 +
+ wcs->x_coeff[ 4]*xmm*ymm + wcs->x_coeff[ 5]*ymm2 +
+ wcs->x_coeff[ 6]*(x2y2) + wcs->x_coeff[ 7]*xmm3 +
+ wcs->x_coeff[ 8]*xmm2*ymm + wcs->x_coeff[ 9]*xmm*ymm2 +
+ wcs->x_coeff[10]*ymm3 + wcs->x_coeff[11]*xmm*(x2y2) +
+ wcs->x_coeff[12]*xmm*x2y2*x2y2;
+
+/* Ignore magnitude and color terms
+ + wcs->x_coeff[13]*mag + wcs->x_coeff[14]*mag*mag +
+ wcs->x_coeff[15]*mag*mag*mag + wcs->x_coeff[16]*mag*xmm +
+ wcs->x_coeff[17]*mag*x2y2 + wcs->x_coeff[18]*mag*xmm*x2y2 +
+ wcs->x_coeff[19]*color; */
+
+ eta = wcs->y_coeff[ 0]*ymm + wcs->y_coeff[ 1]*xmm +
+ wcs->y_coeff[ 2] + wcs->y_coeff[ 3]*ymm2 +
+ wcs->y_coeff[ 4]*xmm*ymm + wcs->y_coeff[ 5]*xmm2 +
+ wcs->y_coeff[ 6]*(x2y2) + wcs->y_coeff[ 7]*ymm3 +
+ wcs->y_coeff[ 8]*ymm2*xmm + wcs->y_coeff[ 9]*ymm*xmm2 +
+ wcs->y_coeff[10]*xmm3 + wcs->y_coeff[11]*ymm*(x2y2) +
+ wcs->y_coeff[12]*ymm*x2y2*x2y2;
+
+/* Ignore magnitude and color terms
+ + wcs->y_coeff[13]*mag + wcs->y_coeff[14]*mag*mag +
+ wcs->y_coeff[15]*mag*mag*mag + wcs->y_coeff[16]*mag*ymm +
+ wcs->y_coeff[17]*mag*x2y2) + wcs->y_coeff[18]*mag*ymm*x2y2 +
+ wcs->y_coeff[19]*color; */
+
+/* Convert to radians */
+
+ xir = xi / cons2r;
+ etar = eta / cons2r;
+
+/* Convert to RA and Dec */
+
+ ctan = tan (wcs->plate_dec);
+ ccos = cos (wcs->plate_dec);
+ raoff = atan2 (xir / ccos, 1.0 - etar * ctan);
+ ra = raoff + wcs->plate_ra;
+ if (ra < 0.0) ra = ra + twopi;
+ *xpos = ra / cond2r;
+
+ dec = atan (cos (raoff) * ((etar + ctan) / (1.0 - (etar * ctan))));
+ *ypos = dec / cond2r;
+ return 0;
+}
+
+
+int
+dsspix (xpos, ypos, wcs, xpix, ypix)
+
+/* Routine to determine pixel coordinates for sky position */
+/* returns 0 if successful otherwise 1 = angle too large for projection; */
+/* based on amdinv() from getimage */
+
+/* Input: */
+double xpos; /* Right ascension or longitude in degrees */
+double ypos; /* Declination or latitude in degrees */
+struct WorldCoor *wcs; /* WCS parameter structure */
+
+/* Output: */
+double *xpix; /* x pixel number (RA or long without rotation) */
+double *ypix; /* y pixel number (dec or lat without rotation) */
+
+{
+ double div,xi,eta,x,y,xy,x2,y2,x2y,y2x,x3,y3,x4,y4,x2y2,cjunk,dx,dy;
+ double sypos,cypos,syplate,cyplate,sxdiff,cxdiff;
+ double f,fx,fy,g,gx,gy, xmm, ymm;
+ double conr2s = 206264.8062470964;
+ double tolerance = 0.0000005;
+ int max_iterations = 50;
+ int i;
+ double xr, yr; /* position in radians */
+
+ *xpix = 0.0;
+ *ypix = 0.0;
+
+/* Convert RA and Dec in radians to standard coordinates on a plate */
+ xr = degrad (xpos);
+ yr = degrad (ypos);
+ sypos = sin (yr);
+ cypos = cos (yr);
+ if (wcs->plate_dec == 0.0)
+ wcs->plate_dec = degrad (wcs->yref);
+ syplate = sin (wcs->plate_dec);
+ cyplate = cos (wcs->plate_dec);
+ if (wcs->plate_ra == 0.0)
+ wcs->plate_ra = degrad (wcs->yref);
+ sxdiff = sin (xr - wcs->plate_ra);
+ cxdiff = cos (xr - wcs->plate_ra);
+ div = (sypos * syplate) + (cypos * cyplate * cxdiff);
+ if (div == 0.0)
+ return (1);
+ xi = cypos * sxdiff * conr2s / div;
+ eta = ((sypos * cyplate) - (cypos * syplate * cxdiff)) * conr2s / div;
+
+/* Set initial value for x,y */
+ if (wcs->plate_scale == 0.0)
+ return (1);
+ xmm = xi / wcs->plate_scale;
+ ymm = eta / wcs->plate_scale;
+
+/* Iterate by Newton's method */
+ for (i = 0; i < max_iterations; i++) {
+
+ /* X plate model */
+ xy = xmm * ymm;
+ x2 = xmm * xmm;
+ y2 = ymm * ymm;
+ x2y = x2 * ymm;
+ y2x = y2 * xmm;
+ x2y2 = x2 + y2;
+ cjunk = x2y2 * x2y2;
+ x3 = x2 * xmm;
+ y3 = y2 * ymm;
+ x4 = x2 * x2;
+ y4 = y2 * y2;
+ f = wcs->x_coeff[0]*xmm + wcs->x_coeff[1]*ymm +
+ wcs->x_coeff[2] + wcs->x_coeff[3]*x2 +
+ wcs->x_coeff[4]*xy + wcs->x_coeff[5]*y2 +
+ wcs->x_coeff[6]*x2y2 + wcs->x_coeff[7]*x3 +
+ wcs->x_coeff[8]*x2y + wcs->x_coeff[9]*y2x +
+ wcs->x_coeff[10]*y3 + wcs->x_coeff[11]*xmm*x2y2 +
+ wcs->x_coeff[12]*xmm*cjunk;
+ /* magnitude and color terms ignored
+ + wcs->x_coeff[13]*mag +
+ wcs->x_coeff[14]*mag*mag + wcs->x_coeff[15]*mag*mag*mag +
+ wcs->x_coeff[16]*mag*xmm + wcs->x_coeff[17]*mag*(x2+y2) +
+ wcs->x_coeff[18]*mag*xmm*(x2+y2) + wcs->x_coeff[19]*color;
+ */
+
+ /* Derivative of X model wrt x */
+ fx = wcs->x_coeff[0] + wcs->x_coeff[3]*2.0*xmm +
+ wcs->x_coeff[4]*ymm + wcs->x_coeff[6]*2.0*xmm +
+ wcs->x_coeff[7]*3.0*x2 + wcs->x_coeff[8]*2.0*xy +
+ wcs->x_coeff[9]*y2 + wcs->x_coeff[11]*(3.0*x2+y2) +
+ wcs->x_coeff[12]*(5.0*x4 +6.0*x2*y2+y4);
+ /* magnitude and color terms ignored
+ wcs->x_coeff[16]*mag + wcs->x_coeff[17]*mag*2.0*xmm +
+ wcs->x_coeff[18]*mag*(3.0*x2+y2);
+ */
+
+ /* Derivative of X model wrt y */
+ fy = wcs->x_coeff[1] + wcs->x_coeff[4]*xmm +
+ wcs->x_coeff[5]*2.0*ymm + wcs->x_coeff[6]*2.0*ymm +
+ wcs->x_coeff[8]*x2 + wcs->x_coeff[9]*2.0*xy +
+ wcs->x_coeff[10]*3.0*y2 + wcs->x_coeff[11]*2.0*xy +
+ wcs->x_coeff[12]*4.0*xy*x2y2;
+ /* magnitude and color terms ignored
+ wcs->x_coeff[17]*mag*2.0*ymm +
+ wcs->x_coeff[18]*mag*2.0*xy;
+ */
+
+ /* Y plate model */
+ g = wcs->y_coeff[0]*ymm + wcs->y_coeff[1]*xmm +
+ wcs->y_coeff[2] + wcs->y_coeff[3]*y2 +
+ wcs->y_coeff[4]*xy + wcs->y_coeff[5]*x2 +
+ wcs->y_coeff[6]*x2y2 + wcs->y_coeff[7]*y3 +
+ wcs->y_coeff[8]*y2x + wcs->y_coeff[9]*x2y +
+ wcs->y_coeff[10]*x3 + wcs->y_coeff[11]*ymm*x2y2 +
+ wcs->y_coeff[12]*ymm*cjunk;
+ /* magnitude and color terms ignored
+ wcs->y_coeff[13]*mag + wcs->y_coeff[14]*mag*mag +
+ wcs->y_coeff[15]*mag*mag*mag + wcs->y_coeff[16]*mag*ymm +
+ wcs->y_coeff[17]*mag*x2y2 +
+ wcs->y_coeff[18]*mag*ymm*x2y2 + wcs->y_coeff[19]*color;
+ */
+
+ /* Derivative of Y model wrt x */
+ gx = wcs->y_coeff[1] + wcs->y_coeff[4]*ymm +
+ wcs->y_coeff[5]*2.0*xmm + wcs->y_coeff[6]*2.0*xmm +
+ wcs->y_coeff[8]*y2 + wcs->y_coeff[9]*2.0*xy +
+ wcs->y_coeff[10]*3.0*x2 + wcs->y_coeff[11]*2.0*xy +
+ wcs->y_coeff[12]*4.0*xy*x2y2;
+ /* magnitude and color terms ignored
+ wcs->y_coeff[17]*mag*2.0*xmm +
+ wcs->y_coeff[18]*mag*ymm*2.0*xmm;
+ */
+
+ /* Derivative of Y model wrt y */
+ gy = wcs->y_coeff[0] + wcs->y_coeff[3]*2.0*ymm +
+ wcs->y_coeff[4]*xmm + wcs->y_coeff[6]*2.0*ymm +
+ wcs->y_coeff[7]*3.0*y2 + wcs->y_coeff[8]*2.0*xy +
+ wcs->y_coeff[9]*x2 + wcs->y_coeff[11]*(x2+3.0*y2) +
+ wcs->y_coeff[12]*(5.0*y4 + 6.0*x2*y2 + x4);
+ /* magnitude and color terms ignored
+ wcs->y_coeff[16]*mag + wcs->y_coeff[17]*mag*2.0*ymm +
+ wcs->y_coeff[18]*mag*(x2+3.0*y2);
+ */
+
+ f = f - xi;
+ g = g - eta;
+ dx = ((-f * gy) + (g * fy)) / ((fx * gy) - (fy * gx));
+ dy = ((-g * fx) + (f * gx)) / ((fx * gy) - (fy * gx));
+ xmm = xmm + dx;
+ ymm = ymm + dy;
+ if ((fabs(dx) < tolerance) && (fabs(dy) < tolerance)) break;
+ }
+
+/* Convert mm from plate center to plate pixels */
+ if (wcs->x_pixel_size == 0.0 || wcs->y_pixel_size == 0.0)
+ return (1);
+ x = (wcs->ppo_coeff[2] - xmm*1000.0) / wcs->x_pixel_size;
+ y = (wcs->ppo_coeff[5] + ymm*1000.0) / wcs->y_pixel_size;
+
+/* Convert from plate pixels to image pixels */
+ *xpix = x - wcs->x_pixel_offset + 1.0 - 0.5;
+ *ypix = y - wcs->y_pixel_offset + 1.0 - 0.5;
+
+/* If position is off of the image, return offscale code */
+ if (*xpix < 0.5 || *xpix > wcs->nxpix+0.5)
+ return -1;
+ if (*ypix < 0.5 || *ypix > wcs->nypix+0.5)
+ return -1;
+
+ return 0;
+}
+/* Mar 6 1995 Original version of this code
+ * May 4 1995 Fix eta cross terms which were all in y
+ * Jun 21 1995 Add inverse routine
+ * Oct 17 1995 Fix inverse routine (degrees -> radians)
+ * Nov 7 1995 Add half pixel to image coordinates to get astrometric
+ * plate coordinates
+ * Feb 26 1996 Fix plate to image pixel conversion error
+ *
+ * Mar 23 1998 Change names from plate*() to dss*()
+ * Apr 7 1998 Change amd_i_coeff to i_coeff
+ * Sep 4 1998 Fix possible divide by zero in dsspos() from Allen Harris, SAO
+ * Sep 10 1998 Fix possible divide by zero in dsspix() from Allen Harris, SAO
+ *
+ * Oct 21 1999 Drop declaration of cond2r in dsspix()
+ */
diff --git a/funtools/wcs/fileutil.c b/funtools/wcs/fileutil.c
new file mode 100644
index 0000000..a4189a1
--- /dev/null
+++ b/funtools/wcs/fileutil.c
@@ -0,0 +1,818 @@
+/*** File libwcs/fileutil.c
+ *** January 11, 2007
+ *** By Jessica Mink, jmink@cfa.harvard.edu
+ *** Harvard-Smithsonian Center for Astrophysics
+ *** Copyright (C) 1999-2007
+ *** Smithsonian Astrophysical Observatory, Cambridge, MA, USA
+
+ This library 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 2 of the License, or (at your option) any later version.
+
+ This library 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 this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Correspondence concerning WCSTools should be addressed as follows:
+ Internet email: jmink@cfa.harvard.edu
+ Postal address: Jessica Mink
+ Smithsonian Astrophysical Observatory
+ 60 Garden St.
+ Cambridge, MA 02138 USA
+
+ * Module: fileutil.c (ASCII file utilities)
+ * Purpose: Find out things about ASCII files
+ * Subroutine: getfilelines (filename)
+ * Return number of lines in an ASCII file
+ * Subroutine: getfilebuff (filename)
+ * Return entire file contents in a character string
+ * Subroutine: getfilesize (filename)
+ * Return size of a binary or ASCII file
+ * Subroutine: isimlist (filename)
+ * Return 1 if file is list of FITS or IRAF image files, else 0
+ * Subroutine: isimlistd (filename, rootdir)
+ * Return 1 if file is list of FITS or IRAF image files, else 0
+ * Subroutine: isfilelist (filename, rootdir)
+ * Return 1 if file is list of readable files, else 0
+ * Subroutine: isfile (filename)
+ * Return 1 if file is a readable file, else 0
+ * Subroutine: first_token (diskfile, ncmax, token)
+ * Return first token from the next line of an ASCII file
+ * Subroutine: stc2s (spchar, string)
+ * Replace character in string with space
+ * Subroutine: sts2c (spchar, string)
+ * Replace spaces in string with character
+ * Subroutine: istiff (filename)
+ * Return 1 if file is a readable TIFF graphics file, else 0
+ * Subroutine: isjpeg (filename)
+ * Return 1 if file is a readable JPEG graphics file, else 0
+ * int setoken (tokens, string, cwhite)
+ * Tokenize a string for easy decoding
+ * int nextoken (tokens, token, maxchars)
+ * Get next token from tokenized string
+ * int getoken (tokens, itok, token, maxchars)
+ * Get specified token from tokenized string
+ */
+
+#include <stdlib.h>
+#ifndef VMS
+#include <unistd.h>
+#endif
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/file.h>
+#include <errno.h>
+#include <string.h>
+#include "fitsfile.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+
+
+/* GETFILELINES -- return number of lines in one file */
+
+int
+getfilelines (filename)
+
+char *filename; /* Name of file for which to find number of lines */
+{
+
+ char *buffer, *bufline;
+ int nlines = 0;
+ char newline = 10;
+
+ /* Read file */
+ buffer = getfilebuff (filename);
+
+ /* Count lines in file */
+ if (buffer != NULL) {
+ bufline = buffer;
+ nlines = 0;
+ while ((bufline = strchr (bufline, newline)) != NULL) {
+ bufline = bufline + 1;
+ nlines++;
+ }
+ free (buffer);
+ return (nlines);
+ }
+ else {
+ return (0);
+ }
+}
+
+
+/* GETFILEBUFF -- return entire file contents in one character string */
+
+char *
+getfilebuff (filename)
+
+char *filename; /* Name of file for which to find number of lines */
+{
+
+ FILE *diskfile;
+ int lfile, nr, lbuff, ipt, ibuff;
+ char *buffer, *newbuff, *nextbuff;
+
+ /* Treat stdin differently */
+ if (!strcmp (filename, "stdin")) {
+ lbuff = 5000;
+ lfile = lbuff;
+ buffer = NULL;
+ ipt = 0;
+ for (ibuff = 0; ibuff < 10; ibuff++) {
+ if ((newbuff = realloc (buffer, lfile+1)) != NULL) {
+ buffer = newbuff;
+ nextbuff = buffer + ipt;
+ nr = fread (nextbuff, 1, lbuff, stdin);
+ if (nr == lbuff)
+ break;
+ else {
+ ipt = ipt + lbuff;
+ lfile = lfile + lbuff;
+ }
+ }
+ else {
+ fprintf (stderr,"GETFILEBUFF: No room for %d-byte buffer\n",
+ lfile);
+ break;
+ }
+ }
+ return (buffer);
+ }
+
+ /* Open file */
+ if ((diskfile = fopen (filename, "rb")) == NULL)
+ return (NULL);
+
+ /* Find length of file */
+ if (fseek (diskfile, 0, 2) == 0)
+ lfile = ftell (diskfile);
+ else
+ lfile = 0;
+ if (lfile < 1) {
+ fprintf (stderr,"GETFILEBUFF: File %s is empty\n", filename);
+ fclose (diskfile);
+ return (NULL);
+ }
+
+ /* Allocate buffer to hold entire file and read it */
+ if ((buffer = calloc (1, lfile+1)) != NULL) {
+ fseek (diskfile, 0, 0);
+ nr = fread (buffer, 1, lfile, diskfile);
+ if (nr < lfile) {
+ fprintf (stderr,"GETFILEBUFF: File %s: read %d / %d bytes\n",
+ filename, nr, lfile);
+ free (buffer);
+ fclose (diskfile);
+ return (NULL);
+ }
+ buffer[lfile] = (char) 0;
+ fclose (diskfile);
+ return (buffer);
+ }
+ else {
+ fprintf (stderr,"GETFILEBUFF: File %s: no room for %d-byte buffer\n",
+ filename, lfile);
+ fclose (diskfile);
+ return (NULL);
+ }
+}
+
+
+/* GETFILESIZE -- return size of one file in bytes */
+
+int
+getfilesize (filename)
+
+char *filename; /* Name of file for which to find size */
+{
+ struct stat statbuff;
+
+ if (stat (filename, &statbuff))
+ return (0);
+ else
+ return ((int) statbuff.st_size);
+}
+
+int
+getfilesize0 (filename)
+
+char *filename; /* Name of file for which to find size */
+{
+ FILE *diskfile;
+ long filesize;
+
+ /* Open file */
+ if ((diskfile = fopen (filename, "rb")) == NULL)
+ return (-1);
+
+ /* Move to end of the file */
+ if (fseek (diskfile, 0, 2) == 0)
+
+ /* Position is the size of the file */
+ filesize = ftell (diskfile);
+
+ else
+ filesize = -1;
+
+ fclose (diskfile);
+
+ return ((int) filesize);
+}
+
+
+/* ISIMLIST -- Return 1 if list of FITS or IRAF files, else 0 */
+int
+isimlist (filename)
+
+char *filename; /* Name of possible list file */
+{
+ FILE *diskfile;
+ char token[256];
+ int ncmax = 254;
+
+ if ((diskfile = fopen (filename, "r")) == NULL)
+ return (0);
+ else {
+ first_token (diskfile, ncmax, token);
+ fclose (diskfile);
+ if (isfits (token) | isiraf (token))
+ return (1);
+ else
+ return (0);
+ }
+}
+
+
+/* ISIMLISTD -- Return 1 if list of FITS or IRAF files, else 0 */
+int
+isimlistd (filename, rootdir)
+
+char *filename; /* Name of possible list file */
+char *rootdir; /* Name of root directory for files in list */
+{
+ FILE *diskfile;
+ char token[256];
+ char filepath[256];
+ int ncmax = 254;
+
+ if ((diskfile = fopen (filename, "r")) == NULL)
+ return (0);
+ else {
+ first_token (diskfile, ncmax, token);
+ fclose (diskfile);
+ if (rootdir != NULL) {
+ strcpy (filepath, rootdir);
+ strcat (filepath, "/");
+ strcat (filepath, token);
+ }
+ else
+ strcpy (filepath, token);
+ if (isfits (filepath) | isiraf (filepath))
+ return (1);
+ else
+ return (0);
+ }
+}
+
+
+/* ISFILELIST -- Return 1 if list of readable files, else 0 */
+int
+isfilelist (filename, rootdir)
+
+char *filename; /* Name of possible list file */
+char *rootdir; /* Name of root directory for files in list */
+{
+ FILE *diskfile;
+ char token[256];
+ char filepath[256];
+ int ncmax = 254;
+
+ if ((diskfile = fopen (filename, "r")) == NULL)
+ return (0);
+ else {
+ first_token (diskfile, ncmax, token);
+ fclose (diskfile);
+ if (rootdir != NULL) {
+ strcpy (filepath, rootdir);
+ strcat (filepath, "/");
+ strcat (filepath, token);
+ }
+ else
+ strcpy (filepath, token);
+ if (isfile (filepath))
+ return (1);
+ else
+ return (0);
+ }
+}
+
+
+/* ISFILE -- Return 1 if file is a readable file, else 0 */
+
+int
+isfile (filename)
+
+char *filename; /* Name of file to check */
+{
+ if (!strcasecmp (filename, "stdin"))
+ return (1);
+ else if (access (filename, R_OK))
+ return (0);
+ else
+ return (1);
+}
+
+
+/* FIRST_TOKEN -- Return first token from the next line of an ASCII file */
+
+int
+first_token (diskfile, ncmax, token)
+
+FILE *diskfile; /* File descriptor for ASCII file */
+int ncmax; /* Maximum number of characters returned */
+char *token; /* First token on next line (returned) */
+{
+ char *lastchar, *lspace;
+
+ /* If line can be read, add null at the end of the first token */
+ if (fgets (token, ncmax, diskfile) != NULL) {
+ if (token[0] == '#') {
+ (void) fgets (token, ncmax, diskfile);
+ }
+
+ /* If only character is a control character, return a NULL */
+ if ((strlen(token)==1) && (token[0]<32)){
+ token[0]=0;
+ return (1);
+ }
+ lastchar = token + strlen (token) - 1;
+
+ /* Remove trailing spaces or control characters */
+ while (*lastchar <= 32)
+ *lastchar-- = 0;
+
+ if ((lspace = strchr (token, ' ')) != NULL) {
+ *lspace = (char) 0;
+ }
+ return (1);
+ }
+ else
+ return (0);
+}
+
+
+/* Replace character in string with space */
+
+int
+stc2s (spchar, string)
+
+char *spchar; /* Character to replace with spaces */
+char *string;
+{
+ int i, lstr, n;
+ lstr = strlen (string);
+ n = 0;
+ for (i = 0; i < lstr; i++) {
+ if (string[i] == spchar[0]) {
+ n++;
+ string[i] = ' ';
+ }
+ }
+ return (n);
+}
+
+
+/* Replace spaces in string with character */
+
+int
+sts2c (spchar, string)
+
+char *spchar; /* Character with which to replace spaces */
+char *string;
+{
+ int i, lstr, n;
+ lstr = strlen (string);
+ n = 0;
+ for (i = 0; i < lstr; i++) {
+ if (string[i] == ' ') {
+ n++;
+ string[i] = spchar[0];
+ }
+ }
+ return (n);
+}
+
+
+/* ISTIFF -- Return 1 if TIFF file, else 0 */
+int
+istiff (filename)
+
+char *filename; /* Name of file to check */
+{
+ int diskfile;
+ char keyword[16];
+ int nbr;
+
+ /* First check to see if this is an assignment */
+ if (strchr (filename, '='))
+ return (0);
+
+ /* Check file extension */
+ if (strsrch (filename, ".tif") ||
+ strsrch (filename, ".tiff") ||
+ strsrch (filename, ".TIFF") ||
+ strsrch (filename, ".TIF"))
+ return (1);
+
+ /* If no TIFF file suffix, try opening the file */
+ else {
+ if ((diskfile = open (filename, O_RDONLY)) < 0)
+ return (0);
+ else {
+ nbr = read (diskfile, keyword, 4);
+ close (diskfile);
+ if (nbr < 4)
+ return (0);
+ else if (!strncmp (keyword, "II", 2))
+ return (1);
+ else if (!strncmp (keyword, "MM", 2))
+ return (1);
+ else
+ return (0);
+ }
+ }
+}
+
+
+/* ISJPEG -- Return 1 if JPEG file, else 0 */
+int
+isjpeg (filename)
+
+char *filename; /* Name of file to check */
+{
+ int diskfile;
+ char keyword[16];
+ int nbr;
+
+ /* First check to see if this is an assignment */
+ if (strchr (filename, '='))
+ return (0);
+
+ /* Check file extension */
+ if (strsrch (filename, ".jpg") ||
+ strsrch (filename, ".jpeg") ||
+ strsrch (filename, ".JPEG") ||
+ strsrch (filename, ".jfif") ||
+ strsrch (filename, ".jfi") ||
+ strsrch (filename, ".JFIF") ||
+ strsrch (filename, ".JFI") ||
+ strsrch (filename, ".JPG"))
+ return (1);
+
+ /* If no JPEG file suffix, try opening the file */
+ else {
+ if ((diskfile = open (filename, O_RDONLY)) < 0)
+ return (0);
+ else {
+ nbr = read (diskfile, keyword, 2);
+ close (diskfile);
+ if (nbr < 4)
+ return (0);
+ else if (keyword[0] == (char) 0xFF &&
+ keyword[1] == (char) 0xD8)
+ return (1);
+ else
+ return (0);
+ }
+ }
+}
+
+
+/* ISGIF -- Return 1 if GIF file, else 0 */
+int
+isgif (filename)
+
+char *filename; /* Name of file to check */
+{
+ int diskfile;
+ char keyword[16];
+ int nbr;
+
+ /* First check to see if this is an assignment */
+ if (strchr (filename, '='))
+ return (0);
+
+ /* Check file extension */
+ if (strsrch (filename, ".gif") ||
+ strsrch (filename, ".GIF"))
+ return (1);
+
+ /* If no GIF file suffix, try opening the file */
+ else {
+ if ((diskfile = open (filename, O_RDONLY)) < 0)
+ return (0);
+ else {
+ nbr = read (diskfile, keyword, 6);
+ close (diskfile);
+ if (nbr < 4)
+ return (0);
+ else if (!strncmp (keyword, "GIF", 3))
+ return (1);
+ else
+ return (0);
+ }
+ }
+}
+
+
+static int maxtokens = MAXTOKENS; /* Set maximum number of tokens from wcscat.h*/
+
+/* -- SETOKEN -- tokenize a string for easy decoding */
+
+int
+setoken (tokens, string, cwhite)
+
+struct Tokens *tokens; /* Token structure returned */
+char *string; /* character string to tokenize */
+char *cwhite; /* additional whitespace characters
+ * if = tab, disallow spaces and commas */
+{
+ char squote, dquote, jch, newline;
+ char *iq, *stri, *wtype, *str0, *inew;
+ int i,j,naddw, ltok;
+
+ newline = (char) 10;
+ squote = (char) 39;
+ dquote = (char) 34;
+ if (string == NULL)
+ return (0);
+
+ /* Line is terminated by newline or NULL */
+ inew = strchr (string, newline);
+ if (inew != NULL)
+ tokens->lline = inew - string - 1;
+ else
+ tokens->lline = strlen (string);
+
+ /* Save current line in structure */
+ tokens->line = string;
+
+ /* Add extra whitespace characters */
+ if (cwhite == NULL)
+ naddw = 0;
+ else
+ naddw = strlen (cwhite);
+
+ /* if character is tab, allow only tabs and nulls as separators */
+ if (naddw > 0 && !strncmp (cwhite, "tab", 3)) {
+ tokens->white[0] = (char) 9; /* Tab */
+ tokens->white[1] = (char) 0; /* NULL (end of string) */
+ tokens->nwhite = 2;
+ }
+
+ /* if character is bar, allow only bars and nulls as separators */
+ else if (naddw > 0 && !strncmp (cwhite, "bar", 3)) {
+ tokens->white[0] = '|'; /* Bar */
+ tokens->white[1] = (char) 0; /* NULL (end of string) */
+ tokens->nwhite = 2;
+ }
+
+ /* otherwise, allow spaces, tabs, commas, nulls, and cwhite */
+ else {
+ tokens->nwhite = 4 + naddw;;
+ tokens->white[0] = ' '; /* Space */
+ tokens->white[1] = (char) 9; /* Tab */
+ tokens->white[2] = ','; /* Comma */
+ tokens->white[3] = (char) 124; /* Vertical bar */
+ tokens->white[4] = (char) 0; /* Null (end of string) */
+ if (tokens->nwhite > 20)
+ tokens->nwhite = 20;
+ if (naddw > 0) {
+ i = 0;
+ for (j = 4; j < tokens->nwhite; j++) {
+ tokens->white[j] = cwhite[i];
+ i++;
+ }
+ }
+ }
+ tokens->white[tokens->nwhite] = (char) 0;
+
+ tokens->ntok = 0;
+ tokens->itok = 0;
+ iq = string - 1;
+ for (i = 0; i < maxtokens; i++) {
+ tokens->tok1[i] = NULL;
+ tokens->ltok[i] = 0;
+ }
+
+ /* Process string one character at a time */
+ stri = string;
+ str0 = string;
+ while (stri < string+tokens->lline) {
+
+ /* Keep stuff between quotes in one token */
+ if (stri <= iq)
+ continue;
+ jch = *stri;
+
+ /* Handle quoted strings */
+ if (jch == squote)
+ iq = strchr (stri+1, squote);
+ else if (jch == dquote)
+ iq = strchr (stri+1, dquote);
+ else
+ iq = stri;
+ if (iq > stri) {
+ tokens->ntok = tokens->ntok + 1;
+ if (tokens->ntok > maxtokens) return (maxtokens);
+ tokens->tok1[tokens->ntok] = stri + 1;
+ tokens->ltok[tokens->ntok] = (iq - stri) - 1;
+ stri = iq + 1;
+ str0 = iq + 1;
+ continue;
+ }
+
+ /* Search for unquoted tokens */
+ wtype = strchr (tokens->white, jch);
+
+ /* If this is one of the additional whitespace characters,
+ * pass as a separate token */
+ if (wtype > tokens->white + 3) {
+
+ /* Terminate token before whitespace */
+ if (stri > str0) {
+ tokens->ntok = tokens->ntok + 1;
+ if (tokens->ntok > maxtokens) return (maxtokens);
+ tokens->tok1[tokens->ntok] = str0;
+ tokens->ltok[tokens->ntok] = stri - str0;
+ }
+
+ /* Make whitespace character next token; start new one */
+ tokens->ntok = tokens->ntok + 1;
+ if (tokens->ntok > maxtokens) return (maxtokens);
+ tokens->tok1[tokens->ntok] = stri;
+ tokens->ltok[tokens->ntok] = 1;
+ stri++;
+ str0 = stri;
+ }
+
+ /* Pass previous token if regular whitespace or NULL */
+ else if (wtype != NULL || jch == (char) 0) {
+
+ /* Ignore leading whitespace */
+ if (stri == str0) {
+ stri++;
+ str0 = stri;
+ }
+
+ /* terminate token before whitespace; start new one */
+ else {
+ tokens->ntok = tokens->ntok + 1;
+ if (tokens->ntok > maxtokens) return (maxtokens);
+ tokens->tok1[tokens->ntok] = str0;
+ tokens->ltok[tokens->ntok] = stri - str0;
+ stri++;
+ str0 = stri;
+ }
+ }
+
+ /* Keep going if not whitespace */
+ else
+ stri++;
+ }
+
+ /* Add token terminated by end of line */
+ if (str0 < stri) {
+ tokens->ntok = tokens->ntok + 1;
+ if (tokens->ntok > maxtokens)
+ return (maxtokens);
+ tokens->tok1[tokens->ntok] = str0;
+ ltok = stri - str0 + 1;
+ tokens->ltok[tokens->ntok] = ltok;
+
+ /* Deal with white space just before end of line */
+ jch = str0[ltok-1];
+ if (strchr (tokens->white, jch)) {
+ ltok = ltok - 1;
+ tokens->ltok[tokens->ntok] = ltok;
+ tokens->ntok = tokens->ntok + 1;
+ tokens->tok1[tokens->ntok] = str0 + ltok;
+ tokens->ltok[tokens->ntok] = 0;
+ }
+ }
+
+ tokens->itok = 0;
+
+ return (tokens->ntok);
+}
+
+
+/* NEXTOKEN -- get next token from tokenized string */
+
+int
+nextoken (tokens, token, maxchars)
+
+struct Tokens *tokens; /* Token structure returned */
+char *token; /* token (returned) */
+int maxchars; /* Maximum length of token */
+{
+ int ltok; /* length of token string (returned) */
+ int it, i;
+ int maxc = maxchars - 1;
+
+ tokens->itok = tokens->itok + 1;
+ it = tokens->itok;
+ if (it > tokens->ntok)
+ it = tokens->ntok;
+ else if (it < 1)
+ it = 1;
+ ltok = tokens->ltok[it];
+ if (ltok > maxc)
+ ltok = maxc;
+ strncpy (token, tokens->tok1[it], ltok);
+ for (i = ltok; i < maxc; i++)
+ token[i] = (char) 0;
+ return (ltok);
+}
+
+
+/* GETOKEN -- get specified token from tokenized string */
+
+int
+getoken (tokens, itok, token, maxchars)
+
+struct Tokens *tokens; /* Token structure returned */
+int itok; /* token sequence number of token
+ * if <0, get whole string after token -itok
+ * if =0, get whole string */
+char *token; /* token (returned) */
+int maxchars; /* Maximum length of token */
+{
+ int ltok; /* length of token string (returned) */
+ int it, i;
+ int maxc = maxchars - 1;
+
+ it = itok;
+ if (it > 0 ) {
+ if (it > tokens->ntok)
+ it = tokens->ntok;
+ ltok = tokens->ltok[it];
+ if (ltok > maxc)
+ ltok = maxc;
+ strncpy (token, tokens->tok1[it], ltok);
+ }
+ else if (it < 0) {
+ if (it < -tokens->ntok)
+ it = -tokens->ntok;
+ ltok = tokens->line + tokens->lline - tokens->tok1[-it];
+ if (ltok > maxc)
+ ltok = maxc;
+ strncpy (token, tokens->tok1[-it], ltok);
+ }
+ else {
+ ltok = tokens->lline;
+ if (ltok > maxc)
+ ltok = maxc;
+ strncpy (token, tokens->tok1[1], ltok);
+ }
+ for (i = ltok; i < maxc; i++)
+ token[i] = (char) 0;
+
+ return (ltok);
+}
+
+/*
+ * Jul 14 1999 New subroutines
+ * Jul 15 1999 Add getfilebuff()
+ * Oct 15 1999 Fix format eror in error message
+ * Oct 21 1999 Fix declarations after lint
+ * Dec 9 1999 Add next_token(); set pointer to next token in first_token
+ *
+ * Sep 25 2001 Add isfilelist(); move isfile() from catutil.c
+ *
+ * Jan 4 2002 Allow getfilebuffer() to read from stdin
+ * Jan 8 2002 Add sts2c() and stc2s() for space-replaced strings
+ * Mar 22 2002 Clean up isfilelist()
+ * Aug 1 2002 Return 1 if file is stdin in isfile()
+ *
+ * Feb 4 2003 Open catalog file rb instead of r (Martin Ploner, Bern)
+ * Mar 5 2003 Add isimlistd() to check image lists with root directory
+ * May 27 2003 Use file stat call in getfilesize() instead of opening file
+ * Jul 17 2003 Add root directory argument to isfilelist()
+ *
+ * Sep 29 2004 Drop next_token() to avoid conflict with subroutine in catutil.c
+ *
+ * Sep 26 2005 In first_token, return NULL if token is only control character
+ *
+ * Feb 23 2006 Add istiff(), isjpeg(), isgif() to check TIFF, JPEG, GIF files
+ * Jun 20 2006 Cast call to fgets() void
+ *
+ * Jan 5 2007 Change stc2s() and sts2c() to pass single character as pointer
+ * Jan 11 2007 Move token access subroutines from catutil.c
+ */
diff --git a/funtools/wcs/fitsfile.c b/funtools/wcs/fitsfile.c
new file mode 100644
index 0000000..0ff9479
--- /dev/null
+++ b/funtools/wcs/fitsfile.c
@@ -0,0 +1,2308 @@
+/*** File libwcs/fitsfile.c
+ *** September 15, 2011
+ *** By Jessica Mink, jmink@cfa.harvard.edu
+ *** Harvard-Smithsonian Center for Astrophysics
+ *** Copyright (C) 1996-2011
+ *** Smithsonian Astrophysical Observatory, Cambridge, MA, USA
+
+ This library 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 2 of the License, or (at your option) any later version.
+
+ This library 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 this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Correspondence concerning WCSTools should be addressed as follows:
+ Internet email: jmink@cfa.harvard.edu
+ Postal address: Jessica Mink
+ Smithsonian Astrophysical Observatory
+ 60 Garden St.
+ Cambridge, MA 02138 USA
+
+ * Module: fitsfile.c (FITS file reading and writing)
+ * Purpose: Read and write FITS image and table files
+ * fitsropen (inpath)
+ * Open a FITS file for reading, returning a FILE pointer
+ * fitsrhead (filename, lhead, nbhead)
+ * Read FITS header and return it
+ * fitsrtail (filename, lhead, nbhead)
+ * Read appended FITS header and return it
+ * fitsrsect (filename, nbhead, header, fd, x0, y0, nx, ny)
+ * Read section of a FITS image, having already read the header
+ * fitsrimage (filename, nbhead, header)
+ * Read FITS image, having already ready the header
+ * fitsrfull (filename, nbhead, header)
+ * Read a FITS image of any dimension
+ * fitsrtopen (inpath, nk, kw, nrows, nchar, nbhead)
+ * Open a FITS table file for reading; return header information
+ * fitsrthead (header, nk, kw, nrows, nchar, nbhead)
+ * Extract FITS table information from a FITS header
+ * fitsrtline (fd, nbhead, lbuff, tbuff, irow, nbline, line)
+ * Read next line of FITS table file
+ * ftgetr8 (entry, kw)
+ * Extract column from FITS table line as double
+ * ftgetr4 (entry, kw)
+ * Extract column from FITS table line as float
+ * ftgeti4 (entry, kw)
+ * Extract column from FITS table line as int
+ * ftgeti2 (entry, kw)
+ * Extract column from FITS table line as short
+ * ftgetc (entry, kw, string, maxchar)
+ * Extract column from FITS table line as a character string
+ * fitswimage (filename, header, image)
+ * Write FITS header and image
+ * fitswext (filename, header, image)
+ * Write FITS header and image as extension to existing FITS file
+ * fitswhdu (fd, filename, header, image)
+ * Write FITS header and image as extension to file descriptor
+ * fitscimage (filename, header, filename0)
+ * Write FITS header and copy FITS image
+ * fitswhead (filename, header)
+ * Write FITS header and keep file open for further writing
+ * fitswexhead (filename, header)
+ * Write FITS header only to FITS extension without writing data
+ * isfits (filename)
+ * Return 1 if file is a FITS file, else 0
+ * fitsheadsize (header)
+ * Return size of FITS header in bytes
+ */
+
+#include <stdlib.h>
+#ifndef VMS
+#include <unistd.h>
+#endif
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/file.h>
+#include <errno.h>
+#include <string.h>
+#include "fitsfile.h"
+
+static int verbose=0; /* Print diagnostics */
+static char fitserrmsg[80];
+static int fitsinherit = 1; /* Append primary header to extension header */
+void
+setfitsinherit (inh)
+int inh;
+{fitsinherit = inh; return;}
+
+static off_t ibhead = 0; /* Number of bytes read before header starts */
+
+off_t
+getfitsskip()
+{return (ibhead);}
+
+/* FITSRHEAD -- Read a FITS header */
+
+char *
+fitsrhead (filename, lhead, nbhead)
+
+char *filename; /* Name of FITS image file */
+int *lhead; /* Allocated length of FITS header in bytes (returned) */
+int *nbhead; /* Number of bytes before start of data (returned) */
+ /* This includes all skipped image extensions */
+
+{
+ int fd;
+ char *header; /* FITS image header (filled) */
+ int extend;
+ int nbytes,naxis, i;
+ int ntry,nbr,irec,nrec, nbh, ipos, npos, nbprim, lprim, lext;
+ int nax1, nax2, nax3, nax4, nbpix, ibpix, nblock, nbskip;
+ char fitsbuf[2884];
+ char *headend; /* Pointer to last line of header */
+ char *headnext; /* Pointer to next line of header to be added */
+ int hdu; /* header/data unit counter */
+ int extnum; /* desired header data number
+ (0=primary -1=first with data -2=use EXTNAME) */
+ char extname[32]; /* FITS extension name */
+ char extnam[32]; /* Desired FITS extension name */
+ char *ext; /* FITS extension name or number in header, if any */
+ char *pheader; /* Primary header (naxis is 0) */
+ char cext = 0;
+ char *rbrac; /* Pointer to right bracket if present in file name */
+ char *mwcs; /* Pointer to WCS name separated by % */
+ char *newhead; /* New larger header */
+ int nbh0; /* Length of old too small header */
+ char *pheadend;
+ int inherit = 1; /* Value of INHERIT keyword in FITS extension header */
+ int extfound = 0; /* Set to one if desired FITS extension is found */
+ int npcount;
+
+ pheader = NULL;
+ lprim = 0;
+ header = NULL;
+
+ /* Check for FITS WCS specification and ignore for file opening */
+ mwcs = strchr (filename, '%');
+ if (mwcs != NULL)
+ *mwcs = (char) 0;
+
+ /* Check for FITS extension and ignore for file opening */
+ rbrac = NULL;
+ ext = strchr (filename, ',');
+ if (ext == NULL) {
+ ext = strchr (filename, '[');
+ if (ext != NULL) {
+ rbrac = strchr (filename, ']');
+ if (rbrac != NULL)
+ *rbrac = (char) 0;
+ }
+ }
+ if (ext != NULL) {
+ cext = *ext;
+ *ext = (char) 0;
+ }
+
+ /* Open the image file and read the header */
+ if (strncasecmp (filename,"stdin",5)) {
+ fd = -1;
+ fd = fitsropen (filename);
+ }
+#ifndef VMS
+ else {
+ fd = STDIN_FILENO;
+ extnum = -1;
+ }
+#endif
+
+ if (ext != NULL) {
+ if (isnum (ext+1))
+ extnum = atoi (ext+1);
+ else {
+ extnum = -2;
+ strcpy (extnam, ext+1);
+ }
+ }
+ else
+ extnum = -1;
+
+ /* Repair the damage done to the file-name string during parsing */
+ if (ext != NULL)
+ *ext = cext;
+ if (rbrac != NULL)
+ *rbrac = ']';
+ if (mwcs != NULL)
+ *mwcs = '%';
+
+ if (fd < 0) {
+ fprintf (stderr,"FITSRHEAD: cannot read file %s\n", filename);
+ return (NULL);
+ }
+
+ nbytes = FITSBLOCK;
+ *nbhead = 0;
+ headend = NULL;
+ nbh = FITSBLOCK * 20 + 4;
+ header = (char *) calloc ((unsigned int) nbh, 1);
+ (void) hlength (header, nbh);
+ headnext = header;
+ nrec = 1;
+ hdu = 0;
+ ibhead = 0;
+
+ /* Read FITS header from input file one FITS block at a time */
+ irec = 0;
+ ibhead = 0;
+ while (irec < 200) {
+ nbytes = FITSBLOCK;
+ for (ntry = 0; ntry < 10; ntry++) {
+ for (i = 0; i < 2884; i++) fitsbuf[i] = 0;
+ nbr = read (fd, fitsbuf, nbytes);
+
+ /* Short records allowed only if they have the last header line */
+ if (nbr < nbytes) {
+ headend = ksearch (fitsbuf,"END");
+ if (headend == NULL) {
+ if (ntry < 9) {
+ if (verbose)
+ fprintf (stderr,"FITSRHEAD: %d / %d bytes read %d\n",
+ nbr,nbytes,ntry);
+ }
+ else {
+ snprintf(fitserrmsg,79,"FITSRHEAD: '%d / %d bytes of header read from %s\n"
+ ,nbr,nbytes,filename);
+#ifndef VMS
+ if (fd != STDIN_FILENO)
+#endif
+ (void)close (fd);
+ free (header);
+ /* if (pheader != NULL)
+ return (pheader); */
+ if (extnum != -1 && !extfound) {
+ *ext = (char) 0;
+ if (extnum < 0) {
+ snprintf (fitserrmsg,79,
+ "FITSRHEAD: Extension %s not found in file %s",
+ extnam, filename);
+ }
+ else {
+ snprintf (fitserrmsg,79,
+ "FITSRHEAD: Extension %d not found in file %s",
+ extnum, filename);
+ }
+ *ext = cext;
+ }
+ else if (hdu > 0) {
+ snprintf (fitserrmsg,79,
+ "FITSRHEAD: No extensions found in file %s", filename);
+ hdu = 0;
+ if (pheader != NULL) {
+ *lhead = nbprim;
+ *nbhead = nbprim;
+ return (pheader);
+ }
+ break;
+ }
+ else {
+ snprintf (fitserrmsg,79,
+ "FITSRHEAD: No header found in file %s", filename);
+ }
+ return (NULL);
+ }
+ }
+ else
+ break;
+ }
+ else
+ break;
+ }
+
+ /* Move current FITS record into header string */
+ for (i = 0; i < 2880; i++)
+ if (fitsbuf[i] < 32 || i > nbr) fitsbuf[i] = 32;
+ if (nbr < 2880)
+ nbr = 2880;
+ strncpy (headnext, fitsbuf, nbr);
+ *nbhead = *nbhead + nbr;
+ nrec = nrec + 1;
+ *(headnext+nbr) = 0;
+ ibhead = ibhead + 2880;
+
+ /* Check to see if this is the final record in this header */
+ headend = ksearch (fitsbuf,"END");
+ if (headend == NULL) {
+
+ /* Increase size of header buffer by 4 blocks if too small */
+ if (nrec * FITSBLOCK > nbh) {
+ nbh0 = nbh;
+ nbh = (nrec + 4) * FITSBLOCK + 4;
+ newhead = (char *) calloc (1,(unsigned int) nbh);
+ for (i = 0; i < nbh0; i++)
+ newhead[i] = header[i];
+ free (header);
+ header = newhead;
+ (void) hlength (header, nbh);
+ headnext = header + *nbhead - FITSBLOCK;
+ }
+ headnext = headnext + FITSBLOCK;
+ }
+
+ else {
+ naxis = 0;
+ hgeti4 (header,"NAXIS",&naxis);
+
+ /* If header has no data, save it for appending to desired header */
+ if (naxis < 1) {
+ nbprim = nrec * FITSBLOCK;
+ headend = ksearch (header,"END");
+ lprim = headend + 80 - header;
+ pheader = (char *) calloc ((unsigned int) nbprim, 1);
+ for (i = 0; i < lprim; i++)
+ pheader[i] = header[i];
+ strncpy (pheader, header, lprim);
+ }
+
+ /* If header has no data, start with the next record */
+ if (naxis < 1 && extnum == -1) {
+ extend = 0;
+ hgetl (header,"EXTEND",&extend);
+ if (naxis == 0 && extend) {
+ headnext = header;
+ *headend = ' ';
+ headend = NULL;
+ nrec = 1;
+ hdu = hdu + 1;
+ }
+ else {
+ break;
+ }
+ }
+
+ /* If this is the desired header data unit, keep it */
+ else if (extnum != -1) {
+ if (extnum > -1 && hdu == extnum) {
+ extfound = 1;
+ break;
+ }
+ else if (extnum < 0) {
+ extname[0] = 0;
+ hgets (header, "EXTNAME", 32, extname);
+ if (!strcmp (extnam,extname)) {
+ extfound = 1;
+ break;
+ }
+ }
+
+ /* If this is not desired header data unit, skip over data */
+ hdu = hdu + 1;
+ nblock = 0;
+ ibhead = 0;
+ if (naxis > 0) {
+ ibpix = 0;
+ hgeti4 (header,"BITPIX",&ibpix);
+ if (ibpix < 0) {
+ nbpix = -ibpix / 8;
+ }
+ else {
+ nbpix = ibpix / 8;
+ }
+ nax1 = 1;
+ hgeti4 (header,"NAXIS1",&nax1);
+ nax2 = 1;
+ if (naxis > 1) {
+ hgeti4 (header,"NAXIS2",&nax2);
+ }
+ nax3 = 1;
+ if (naxis > 2) {
+ hgeti4 (header,"NAXIS3",&nax3);
+ }
+ nax4 = 1;
+ if (naxis > 3) {
+ hgeti4 (header,"NAXIS4",&nax4);
+ }
+ nbskip = nax1 * nax2 * nax3 * nax4 * nbpix;
+ nblock = nbskip / 2880;
+ if (nblock*2880 < nbskip) {
+ nblock = nblock + 1;
+ }
+ npcount = 0;
+ hgeti4 (header,"PCOUNT", &npcount);
+ if (npcount > 0) {
+ nbskip = nbskip + npcount;
+ nblock = nbskip / 2880;
+ if (nblock*2880 < nbskip)
+ nblock = nblock + 1;
+ }
+ }
+ else {
+ nblock = 0;
+ }
+ *nbhead = *nbhead + (nblock * 2880);
+
+ /* Set file pointer to beginning of next header/data unit */
+ if (nblock > 0) {
+#ifndef VMS
+ if (fd != STDIN_FILENO) {
+ ipos = lseek (fd, *nbhead, SEEK_SET);
+ npos = *nbhead;
+ }
+ else {
+#else
+ {
+#endif
+ ipos = 0;
+ for (i = 0; i < nblock; i++) {
+ nbytes = FITSBLOCK;
+ nbr = read (fd, fitsbuf, nbytes);
+ if (nbr < nbytes) {
+ ipos = ipos + nbr;
+ break;
+ }
+ else {
+ ipos = ipos + nbytes;
+ }
+ }
+ npos = nblock * 2880;
+ }
+ if (ipos < npos) {
+ snprintf (fitserrmsg,79,"FITSRHEAD: %d / %d bytes skipped\n",
+ ipos,npos);
+ extfound = 0;
+ break;
+ }
+ }
+ headnext = header;
+ headend = NULL;
+ nrec = 1;
+ }
+ else {
+ break;
+ }
+ }
+ }
+
+#ifndef VMS
+ if (fd != STDIN_FILENO)
+ (void)close (fd);
+#endif
+
+/* Print error message and return null if extension not found */
+ if (extnum != -1 && !extfound) {
+ if (extnum < 0)
+ fprintf (stderr, "FITSRHEAD: Extension %s not found in file %s\n",extnam, filename);
+ else
+ fprintf (stderr, "FITSRHEAD: Extension %d not found in file %s\n",extnum, filename);
+ if (pheader != NULL) {
+ free (pheader);
+ pheader = NULL;
+ }
+ return (NULL);
+ }
+
+ /* Allocate an extra block for good measure */
+ *lhead = (nrec + 1) * FITSBLOCK;
+ if (*lhead > nbh) {
+ newhead = (char *) calloc (1,(unsigned int) *lhead);
+ for (i = 0; i < nbh; i++)
+ newhead[i] = header[i];
+ free (header);
+ header = newhead;
+ (void) hlength (header, *lhead);
+ }
+ else
+ *lhead = nbh;
+
+ /* If INHERIT keyword is FALSE, never append primary header */
+ if (hgetl (header, "INHERIT", &inherit)) {
+ if (!inherit && fitsinherit)
+ fitsinherit = 0;
+ }
+
+ /* Append primary data header to extension header */
+ if (pheader != NULL && extnum != 0 && fitsinherit && hdu > 0) {
+ extname[0] = 0;
+ hgets (header, "XTENSION", 32, extname);
+ if (!strcmp (extname,"IMAGE")) {
+ strncpy (header, "SIMPLE ", 8);
+ hputl (header, "SIMPLE", 1);
+ }
+ headend = blsearch (header,"END");
+ if (headend == NULL)
+ headend = ksearch (header, "END");
+ lext = headend - header;
+
+ /* Update primary header for inclusion at end of extension header */
+ hchange (pheader, "SIMPLE", "ROOTHEAD");
+ hchange (pheader, "NEXTEND", "NUMEXT");
+ hdel (pheader, "BITPIX");
+ hdel (pheader, "NAXIS");
+ hdel (pheader, "EXTEND");
+ hputl (pheader, "ROOTEND",1);
+ pheadend = ksearch (pheader,"END");
+ lprim = pheadend + 320 - pheader;
+ if (lext + lprim > nbh) {
+ nrec = (lext + lprim) / FITSBLOCK;
+ if (FITSBLOCK*nrec < lext+lprim)
+ nrec = nrec + 1;
+ *lhead = (nrec+1) * FITSBLOCK;
+ newhead = (char *) calloc (1,(unsigned int) *lhead);
+ for (i = 0; i < nbh; i++)
+ newhead[i] = header[i];
+ free (header);
+ header = newhead;
+ headend = header + lext;
+ (void) hlength (header, *lhead);
+ }
+ hputs (header,"COMMENT","-------------------------------------------");
+ hputs (header,"COMMENT","Information from Primary Header");
+ hputs (header,"COMMENT","-------------------------------------------");
+ headend = blsearch (header,"END");
+ if (headend == NULL)
+ headend = ksearch (header, "END");
+ pheader[lprim] = 0;
+ strncpy (headend, pheader, lprim);
+ if (pheader != NULL) {
+ free (pheader);
+ pheader = NULL;
+ }
+ }
+
+ ibhead = *nbhead - ibhead;
+
+ return (header);
+}
+
+
+/* FITSRTAIL -- Read FITS header appended to graphics file */
+
+char *
+fitsrtail (filename, lhead, nbhead)
+
+char *filename; /* Name of image file */
+int *lhead; /* Allocated length of FITS header in bytes (returned) */
+int *nbhead; /* Number of bytes before start of data (returned) */
+ /* This includes all skipped image extensions */
+
+{
+ int fd;
+ char *header; /* FITS image header (filled) */
+ int nbytes, i, ndiff;
+ int nbr, irec;
+ off_t offset;
+ char *mwcs; /* Pointer to WCS name separated by % */
+ char *headstart;
+ char *newhead;
+
+ header = NULL;
+
+ /* Check for FITS WCS specification and ignore for file opening */
+ mwcs = strchr (filename, '%');
+ if (mwcs != NULL)
+ *mwcs = (char) 0;
+
+ /* Open the image file and read the header */
+ if (strncasecmp (filename,"stdin",5)) {
+ fd = -1;
+ fd = fitsropen (filename);
+ }
+#ifndef VMS
+ else {
+ fd = STDIN_FILENO;
+ }
+#endif
+
+ /* Repair the damage done to the file-name string during parsing */
+ if (mwcs != NULL)
+ *mwcs = '%';
+
+ if (fd < 0) {
+ fprintf (stderr,"FITSRTAIL: cannot read file %s\n", filename);
+ return (NULL);
+ }
+
+ nbytes = FITSBLOCK;
+ *nbhead = 0;
+ *lhead = 0;
+
+ /* Read FITS header from end of input file one FITS block at a time */
+ irec = 0;
+ while (irec < 100) {
+ nbytes = FITSBLOCK * (irec + 2);
+ header = (char *) calloc ((unsigned int) nbytes, 1);
+ offset = lseek (fd, -nbytes, SEEK_END);
+ if (offset < 0) {
+ free (header);
+ header = NULL;
+ nbytes = 0;
+ break;
+ }
+ for (i = 0; i < nbytes; i++) header[i] = 0;
+ nbr = read (fd, header, nbytes);
+
+ /* Check for SIMPLE at start of header */
+ for (i = 0; i < nbr; i++)
+ if (header[i] < 32) header[i] = 32;
+ if ((headstart = ksearch (header,"SIMPLE"))) {
+ if (headstart != header) {
+ ndiff = headstart - header;
+ newhead = (char *) calloc ((unsigned int) nbytes, 1);
+ for (i = 0; i < nbytes-ndiff; i++)
+ newhead[i] = headstart[i];
+ free (header);
+ header = newhead;
+ }
+ *lhead = nbytes;
+ *nbhead = nbytes;
+ break;
+ }
+ free (header);
+ }
+ (void) hlength (header, nbytes);
+
+#ifndef VMS
+ if (fd != STDIN_FILENO)
+ (void)close (fd);
+#endif
+
+ return (header);
+}
+
+
+/* FITSRSECT -- Read a piece of a FITS image, having already read the header */
+
+char *
+fitsrsect (filename, header, nbhead, x0, y0, nx, ny, nlog)
+
+char *filename; /* Name of FITS image file */
+char *header; /* FITS header for image (previously read) */
+int nbhead; /* Actual length of image header(s) in bytes */
+int x0, y0; /* FITS image coordinate of first pixel */
+int nx; /* Number of columns to read (less than NAXIS1) */
+int ny; /* Number of rows to read (less than NAXIS2) */
+int nlog; /* Note progress mod this rows */
+{
+ int fd; /* File descriptor */
+ int nbimage, naxis1, naxis2, bytepix, nbread;
+ int bitpix, naxis, nblocks, nbytes, nbr;
+ int x1, y1, nbline, nyleft;
+ off_t impos, nblin;
+ char *image, *imline, *imlast;
+ int ilog = 0;
+ int row;
+
+ /* Open the image file and read the header */
+ if (strncasecmp (filename,"stdin", 5)) {
+ fd = -1;
+
+ fd = fitsropen (filename);
+ if (fd < 0) {
+ snprintf (fitserrmsg,79, "FITSRSECT: cannot read file %s\n", filename);
+ return (NULL);
+ }
+
+ /* Skip over FITS header and whatever else needs to be skipped */
+ if (lseek (fd, nbhead, SEEK_SET) < 0) {
+ (void)close (fd);
+ snprintf (fitserrmsg,79, "FITSRSECT: cannot skip header of file %s\n",
+ filename);
+ return (NULL);
+ }
+ }
+#ifndef VMS
+ else
+ fd = STDIN_FILENO;
+#endif
+
+ /* Compute size of image in bytes using relevant header parameters */
+ naxis = 1;
+ hgeti4 (header,"NAXIS",&naxis);
+ naxis1 = 1;
+ hgeti4 (header,"NAXIS1",&naxis1);
+ naxis2 = 1;
+ hgeti4 (header,"NAXIS2",&naxis2);
+ bitpix = 0;
+ hgeti4 (header,"BITPIX",&bitpix);
+ if (bitpix == 0) {
+ /* snprintf (fitserrmsg,79, "FITSRSECT: BITPIX is 0; image not read\n"); */
+ (void)close (fd);
+ return (NULL);
+ }
+ bytepix = bitpix / 8;
+ if (bytepix < 0) bytepix = -bytepix;
+
+ /* Keep X coordinates within image limits */
+ if (x0 < 1)
+ x0 = 1;
+ else if (x0 > naxis1)
+ x0 = naxis1;
+ x1 = x0 + nx - 1;
+ if (x1 < 1)
+ x1 = 1;
+ else if (x1 > naxis1)
+ x1 = naxis1;
+ nx = x1 - x0 + 1;
+
+ /* Keep Y coordinates within image limits */
+ if (y0 < 1)
+ y0 = 1;
+ else if (y0 > naxis2)
+ y0 = naxis2;
+ y1 = y0 + ny - 1;
+ if (y1 < 1)
+ y1 = 1;
+ else if (y1 > naxis2)
+ y1 = naxis2;
+ ny = y1 - y0 + 1;
+
+ /* Number of bytes in output image */
+ nbline = nx * bytepix;
+ nbimage = nbline * ny;
+
+ /* Set number of bytes to integral number of 2880-byte blocks */
+ nblocks = nbimage / FITSBLOCK;
+ if (nblocks * FITSBLOCK < nbimage)
+ nblocks = nblocks + 1;
+ nbytes = nblocks * FITSBLOCK;
+
+ /* Allocate image section to be read */
+ image = (char *) malloc (nbytes);
+ nyleft = ny;
+ imline = image;
+ nbr = 0;
+
+ /* Computer pointer to first byte of input image to read */
+ nblin = naxis1 * bytepix;
+ impos = ((y0 - 1) * nblin) + ((x0 - 1) * bytepix);
+ row = y0 - 1;
+
+ /* Read image section one line at a time */
+ while (nyleft-- > 0) {
+ if (lseek (fd, impos, SEEK_CUR) >= 0) {
+ nbread = read (fd, imline, nbline);
+ nbr = nbr + nbread;
+ impos = nblin - nbread;
+ imline = imline + nbline;
+ row++;
+ if (++ilog == nlog) {
+ ilog = 0;
+ fprintf (stderr, "Row %5d extracted ", row);
+ (void) putc (13,stderr);
+ }
+ }
+ }
+ if (nlog)
+ fprintf (stderr, "\n");
+
+ /* Fill rest of image with zeroes */
+ imline = image + nbimage;
+ imlast = image + nbytes;
+ while (imline++ < imlast)
+ *imline = (char) 0;
+
+ /* Byte-reverse image, if necessary */
+ if (imswapped ())
+ imswap (bitpix, image, nbytes);
+
+ return (image);
+}
+
+
+/* FITSRIMAGE -- Read a FITS image */
+
+char *
+fitsrimage (filename, nbhead, header)
+
+char *filename; /* Name of FITS image file */
+int nbhead; /* Actual length of image header(s) in bytes */
+char *header; /* FITS header for image (previously read) */
+{
+ int fd;
+ int nbimage, naxis1, naxis2, bytepix, nbread;
+ int bitpix, naxis, nblocks, nbytes, nbleft, nbr;
+ int simple;
+ char *image, *imleft;
+
+ /* Open the image file and read the header */
+ if (strncasecmp (filename,"stdin", 5)) {
+ fd = -1;
+
+ fd = fitsropen (filename);
+ if (fd < 0) {
+ snprintf (fitserrmsg,79, "FITSRIMAGE: cannot read file %s\n", filename);
+ return (NULL);
+ }
+
+ /* Skip over FITS header and whatever else needs to be skipped */
+ if (lseek (fd, nbhead, SEEK_SET) < 0) {
+ (void)close (fd);
+ snprintf (fitserrmsg,79, "FITSRIMAGE: cannot skip header of file %s\n",
+ filename);
+ return (NULL);
+ }
+ }
+#ifndef VMS
+ else
+ fd = STDIN_FILENO;
+#endif
+
+ /* If SIMPLE=F in header, simply put post-header part of file in buffer */
+ hgetl (header, "SIMPLE", &simple);
+ if (!simple) {
+ nbytes = getfilesize (filename) - nbhead;
+ if ((image = (char *) malloc (nbytes + 1)) == NULL) {
+ /* snprintf (fitserrmsg,79, "FITSRIMAGE: %d-byte image buffer cannot be allocated\n"); */
+ (void)close (fd);
+ return (NULL);
+ }
+ hputi4 (header, "NBDATA", nbytes);
+ nbread = read (fd, image, nbytes);
+ return (image);
+ }
+
+ /* Compute size of image in bytes using relevant header parameters */
+ naxis = 1;
+ hgeti4 (header,"NAXIS",&naxis);
+ naxis1 = 1;
+ hgeti4 (header,"NAXIS1",&naxis1);
+ naxis2 = 1;
+ hgeti4 (header,"NAXIS2",&naxis2);
+ bitpix = 0;
+ hgeti4 (header,"BITPIX",&bitpix);
+ if (bitpix == 0) {
+ /* snprintf (fitserrmsg,79, "FITSRIMAGE: BITPIX is 0; image not read\n"); */
+ (void)close (fd);
+ return (NULL);
+ }
+ bytepix = bitpix / 8;
+ if (bytepix < 0) bytepix = -bytepix;
+
+ /* If either dimension is one and image is 3-D, read all three dimensions */
+ if (naxis == 3 && (naxis1 ==1 || naxis2 == 1)) {
+ int naxis3;
+ hgeti4 (header,"NAXIS3",&naxis3);
+ nbimage = naxis1 * naxis2 * naxis3 * bytepix;
+ }
+ else
+ nbimage = naxis1 * naxis2 * bytepix;
+
+ /* Set number of bytes to integral number of 2880-byte blocks */
+ nblocks = nbimage / FITSBLOCK;
+ if (nblocks * FITSBLOCK < nbimage)
+ nblocks = nblocks + 1;
+ nbytes = nblocks * FITSBLOCK;
+
+ /* Allocate and read image */
+ image = (char *) malloc (nbytes);
+ nbleft = nbytes;
+ imleft = image;
+ nbr = 0;
+ while (nbleft > 0) {
+ nbread = read (fd, imleft, nbleft);
+ nbr = nbr + nbread;
+#ifndef VMS
+ if (fd == STDIN_FILENO && nbread < nbleft && nbread > 0) {
+ nbleft = nbleft - nbread;
+ imleft = imleft + nbread;
+ }
+ else
+#endif
+ nbleft = 0;
+ }
+#ifndef VMS
+ if (fd != STDIN_FILENO)
+ (void)close (fd);
+#endif
+ if (nbr < nbimage) {
+ snprintf (fitserrmsg,79, "FITSRIMAGE: %d of %d bytes read from file %s\n",
+ nbr, nbimage, filename);
+ return (NULL);
+ }
+
+ /* Byte-reverse image, if necessary */
+ if (imswapped ())
+ imswap (bitpix, image, nbytes);
+
+ return (image);
+}
+
+
+/* FITSRFULL -- Read a FITS image of any dimension */
+
+char *
+fitsrfull (filename, nbhead, header)
+
+char *filename; /* Name of FITS image file */
+int nbhead; /* Actual length of image header(s) in bytes */
+char *header; /* FITS header for image (previously read) */
+{
+ int fd;
+ int nbimage, naxisi, iaxis, bytepix, nbread;
+ int bitpix, naxis, nblocks, nbytes, nbleft, nbr, simple;
+ char keyword[16];
+ char *image, *imleft;
+
+ /* Open the image file and read the header */
+ if (strncasecmp (filename,"stdin", 5)) {
+ fd = -1;
+
+ fd = fitsropen (filename);
+ if (fd < 0) {
+ snprintf (fitserrmsg,79, "FITSRFULL: cannot read file %s\n", filename);
+ return (NULL);
+ }
+
+ /* Skip over FITS header and whatever else needs to be skipped */
+ if (lseek (fd, nbhead, SEEK_SET) < 0) {
+ (void)close (fd);
+ snprintf (fitserrmsg,79, "FITSRFULL: cannot skip header of file %s\n",
+ filename);
+ return (NULL);
+ }
+ }
+#ifndef VMS
+ else
+ fd = STDIN_FILENO;
+#endif
+
+ /* If SIMPLE=F in header, simply put post-header part of file in buffer */
+ hgetl (header, "SIMPLE", &simple);
+ if (!simple) {
+ nbytes = getfilesize (filename) - nbhead;
+ if ((image = (char *) malloc (nbytes + 1)) == NULL) {
+ snprintf (fitserrmsg,79, "FITSRFULL: %d-byte image buffer cannot be allocated\n",nbytes+1);
+ (void)close (fd);
+ return (NULL);
+ }
+ hputi4 (header, "NBDATA", nbytes);
+ nbread = read (fd, image, nbytes);
+ return (image);
+ }
+
+ /* Find number of bytes per pixel */
+ bitpix = 0;
+ hgeti4 (header,"BITPIX",&bitpix);
+ if (bitpix == 0) {
+ snprintf (fitserrmsg,79, "FITSRFULL: BITPIX is 0; image not read\n");
+ (void)close (fd);
+ return (NULL);
+ }
+ bytepix = bitpix / 8;
+ if (bytepix < 0) bytepix = -bytepix;
+ nbimage = bytepix;
+
+ /* Compute size of image in bytes using relevant header parameters */
+ naxis = 1;
+ hgeti4 (header,"NAXIS",&naxis);
+ for (iaxis = 1; iaxis <= naxis; iaxis++) {
+ sprintf (keyword, "NAXIS%d", iaxis);
+ naxisi = 1;
+ hgeti4 (header,keyword,&naxisi);
+ nbimage = nbimage * naxisi;
+ }
+
+ /* Set number of bytes to integral number of 2880-byte blocks */
+ nblocks = nbimage / FITSBLOCK;
+ if (nblocks * FITSBLOCK < nbimage)
+ nblocks = nblocks + 1;
+ nbytes = nblocks * FITSBLOCK;
+
+ /* Allocate and read image */
+ image = (char *) malloc (nbytes);
+ nbleft = nbytes;
+ imleft = image;
+ nbr = 0;
+ while (nbleft > 0) {
+ nbread = read (fd, imleft, nbleft);
+ nbr = nbr + nbread;
+#ifndef VMS
+ if (fd == STDIN_FILENO && nbread < nbleft && nbread > 0) {
+ nbleft = nbleft - nbread;
+ imleft = imleft + nbread;
+ }
+ else
+#endif
+ nbleft = 0;
+ }
+#ifndef VMS
+ if (fd != STDIN_FILENO)
+ (void)close (fd);
+#endif
+ if (nbr < nbimage) {
+ snprintf (fitserrmsg,79, "FITSRFULL: %d of %d image bytes read from file %s\n",
+ nbr, nbimage, filename);
+ return (NULL);
+ }
+
+ /* Byte-reverse image, if necessary */
+ if (imswapped ())
+ imswap (bitpix, image, nbytes);
+
+ return (image);
+}
+
+
+/* FITSROPEN -- Open a FITS file, returning the file descriptor */
+
+int
+fitsropen (inpath)
+
+char *inpath; /* Pathname for FITS tables file to read */
+
+{
+ int ntry;
+ int fd; /* file descriptor for FITS tables file (returned) */
+ char *ext; /* extension name or number */
+ char cext = 0;
+ char *rbrac;
+ char *mwcs; /* Pointer to WCS name separated by % */
+
+/* Check for FITS WCS specification and ignore for file opening */
+ mwcs = strchr (inpath, '%');
+
+/* Check for FITS extension and ignore for file opening */
+ ext = strchr (inpath, ',');
+ rbrac = NULL;
+ if (ext == NULL) {
+ ext = strchr (inpath, '[');
+ if (ext != NULL) {
+ rbrac = strchr (inpath, ']');
+ }
+ }
+
+/* Open input file */
+ for (ntry = 0; ntry < 3; ntry++) {
+ if (ext != NULL) {
+ cext = *ext;
+ *ext = 0;
+ }
+ if (rbrac != NULL)
+ *rbrac = (char) 0;
+ if (mwcs != NULL)
+ *mwcs = (char) 0;
+ fd = open (inpath, O_RDONLY);
+ if (ext != NULL)
+ *ext = cext;
+ if (rbrac != NULL)
+ *rbrac = ']';
+ if (mwcs != NULL)
+ *mwcs = '%';
+ if (fd >= 0)
+ break;
+ else if (ntry == 2) {
+ snprintf (fitserrmsg,79, "FITSROPEN: cannot read file %s\n", inpath);
+ return (-1);
+ }
+ }
+
+ if (verbose)
+ fprintf (stderr,"FITSROPEN: input file %s opened\n",inpath);
+
+ return (fd);
+}
+
+
+static int offset1=0;
+static int offset2=0;
+
+/* FITSRTOPEN -- Open FITS table file and fill structure with
+ * pointers to selected keywords
+ * Return file descriptor (-1 if unsuccessful)
+ */
+
+int
+fitsrtopen (inpath, nk, kw, nrows, nchar, nbhead)
+
+char *inpath; /* Pathname for FITS tables file to read */
+int *nk; /* Number of keywords to use */
+struct Keyword **kw; /* Structure for desired entries */
+int *nrows; /* Number of rows in table (returned) */
+int *nchar; /* Number of characters in one table row (returned) */
+int *nbhead; /* Number of characters before table starts */
+
+{
+ char temp[16];
+ int fd;
+ int lhead; /* Maximum length in bytes of FITS header */
+ char *header; /* Header for FITS tables file to read */
+
+/* Read FITS header from input file */
+ header = fitsrhead (inpath, &lhead, nbhead);
+ if (!header) {
+ snprintf (fitserrmsg,79,"FITSRTOPEN: %s is not a FITS file\n",inpath);
+ return (0);
+ }
+
+/* Make sure this file is really a FITS table file */
+ temp[0] = 0;
+ (void) hgets (header,"XTENSION",16,temp);
+ if (strlen (temp) == 0) {
+ snprintf (fitserrmsg,79,
+ "FITSRTOPEN: %s is not a FITS table file\n",inpath);
+ free ((void *) header);
+ return (0);
+ }
+
+/* If it is a FITS file, get table information from the header */
+ else if (!strcmp (temp, "TABLE") || !strcmp (temp, "BINTABLE")) {
+ if (fitsrthead (header, nk, kw, nrows, nchar)) {
+ snprintf (fitserrmsg,79,
+ "FITSRTOPEN: Cannot read FITS table from %s\n",inpath);
+ free ((void *) header);
+ return (-1);
+ }
+ else {
+ fd = fitsropen (inpath);
+ offset1 = 0;
+ offset2 = 0;
+ free ((void *) header);
+ return (fd);
+ }
+ }
+
+/* If it is another FITS extension note it and return */
+ else {
+ snprintf (fitserrmsg,79,
+ "FITSRTOPEN: %s is a %s extension, not table\n",
+ inpath, temp);
+ free ((void *) header);
+ return (0);
+ }
+}
+
+static struct Keyword *pw; /* Structure for all entries */
+static int *lpnam; /* length of name for each field */
+static int bfields = 0;
+
+/* FITSRTHEAD -- From FITS table header, read pointers to selected keywords */
+
+int
+fitsrthead (header, nk, kw, nrows, nchar)
+
+char *header; /* Header for FITS tables file to read */
+int *nk; /* Number of keywords to use */
+struct Keyword **kw; /* Structure for desired entries */
+int *nrows; /* Number of rows in table (returned) */
+int *nchar; /* Number of characters in one table row (returned) */
+
+{
+ struct Keyword *rw; /* Structure for desired entries */
+ int nfields;
+ int ifield, ik, i, ikf, ltform, kl;
+ char *h0, *h1, *tf1, *tf2;
+ char tname[12];
+ char temp[16];
+ char tform[16];
+ int tverb;
+ int bintable = 0;
+
+ h0 = header;
+
+/* Make sure this is really a FITS table file header */
+ temp[0] = 0;
+ hgets (header,"XTENSION",16,temp);
+ if (strlen (temp) == 0) {
+ snprintf (fitserrmsg,79, "FITSRTHEAD: Not a FITS table header\n");
+ return (-1);
+ }
+ else if (!strcmp (temp, "BINTABLE")) {
+ bintable = 1;
+ }
+ else if (strcmp (temp, "TABLE")) {
+ snprintf (fitserrmsg,79, "FITSRTHEAD: %s extension, not TABLE\n",temp);
+ return (-1);
+ }
+
+/* Get table size from FITS header */
+ *nchar = 0;
+ hgeti4 (header,"NAXIS1",nchar);
+ *nrows = 0;
+ hgeti4 (header,"NAXIS2", nrows);
+ if (*nrows <= 0 || *nchar <= 0) {
+ snprintf (fitserrmsg,79, "FITSRTHEAD: cannot read %d x %d table\n",
+ *nrows,*nchar);
+ return (-1);
+ }
+
+/* Set up table for access to individual fields */
+ nfields = 0;
+ hgeti4 (header,"TFIELDS",&nfields);
+ if (verbose)
+ fprintf (stderr, "FITSRTHEAD: %d fields per table entry\n", nfields);
+ if (nfields > bfields) {
+ if (bfields > 0)
+ free ((void *)pw);
+ pw = (struct Keyword *) calloc (nfields, sizeof(struct Keyword));
+ if (pw == NULL) {
+ snprintf (fitserrmsg,79,"FITSRTHEAD: cannot allocate table structure\n");
+ return (-1);
+ }
+ if (bfields > 0)
+ free ((void *)lpnam);
+ lpnam = (int *) calloc (nfields, sizeof(int));
+ if (lpnam == NULL) {
+ snprintf (fitserrmsg,79,"FITSRTHEAD: cannot allocate length structure\n");
+ return (-1);
+ }
+ bfields = nfields;
+ }
+
+ tverb = verbose;
+ verbose = 0;
+ ikf = 0;
+
+ for (ifield = 0; ifield < nfields; ifield++) {
+
+ /* Name of field */
+ for (i = 0; i < 12; i++) tname[i] = 0;
+ sprintf (tname, "TTYPE%d", ifield+1);;
+ temp[0] = 0;
+ h1 = ksearch (h0,tname);
+ h0 = h1;
+ hgets (h0,tname,16,temp);
+ strcpy (pw[ifield].kname,temp);
+ pw[ifield].lname = strlen (pw[ifield].kname);
+
+ /* Sequence of field on line */
+ pw[ifield].kn = ifield + 1;
+
+ /* First column of field */
+ if (bintable)
+ pw[ifield].kf = ikf;
+ else {
+ for (i = 0; i < 12; i++) tname[i] = 0;
+ sprintf (tname, "TBCOL%d", ifield+1);
+ pw[ifield].kf = 0;
+ hgeti4 (h0,tname, &pw[ifield].kf);
+ }
+
+ /* Length of field */
+ for (i = 0; i < 12; i++) tname[i] = 0;
+ sprintf (tname, "TFORM%d", ifield+1);;
+ tform[0] = 0;
+ hgets (h0,tname,16,tform);
+ strcpy (pw[ifield].kform, tform);
+ ltform = strlen (tform);
+ if (tform[ltform-1] == 'A') {
+ pw[ifield].kform[0] = 'A';
+ for (i = 0; i < ltform-1; i++)
+ pw[ifield].kform[i+1] = tform[i];
+ pw[ifield].kform[ltform] = (char) 0;
+ tf1 = pw[ifield].kform + 1;
+ kl = atof (tf1);
+ }
+ else if (!strcmp (tform,"I"))
+ kl = 2;
+ else if (!strcmp (tform, "J"))
+ kl = 4;
+ else if (!strcmp (tform, "E"))
+ kl = 4;
+ else if (!strcmp (tform, "D"))
+ kl = 8;
+ else {
+ tf1 = tform + 1;
+ tf2 = strchr (tform,'.');
+ if (tf2 != NULL)
+ *tf2 = ' ';
+ kl = atoi (tf1);
+ }
+ pw[ifield].kl = kl;
+ ikf = ikf + kl;
+ }
+
+/* Set up table for access to desired fields */
+ verbose = tverb;
+ if (verbose)
+ fprintf (stderr, "FITSRTHEAD: %d keywords read\n", *nk);
+
+/* If nk = 0, allocate and return structures for all table fields */
+ if (*nk <= 0) {
+ *kw = pw;
+ *nk = nfields;
+ return (0);
+ }
+ else
+ rw = *kw;
+
+/* Find each desired keyword in the header */
+ for (ik = 0; ik < *nk; ik++) {
+ if (rw[ik].kn <= 0) {
+ for (ifield = 0; ifield < nfields; ifield++) {
+ if (rw[ik].lname != pw[ifield].lname)
+ continue;
+ if (strcmp (pw[ifield].kname, rw[ik].kname) == 0) {
+ break;
+ }
+ }
+ }
+ else
+ ifield = rw[ik].kn - 1;
+
+/* Set pointer, lentth, and name in returned array of structures */
+ rw[ik].kn = ifield + 1;
+ rw[ik].kf = pw[ifield].kf - 1;
+ rw[ik].kl = pw[ifield].kl;
+ strcpy (rw[ik].kform, pw[ifield].kform);
+ strcpy (rw[ik].kname, pw[ifield].kname);
+ }
+
+ return (0);
+}
+
+
+int
+fitsrtline (fd, nbhead, lbuff, tbuff, irow, nbline, line)
+
+int fd; /* File descriptor for FITS file */
+int nbhead; /* Number of bytes in FITS header */
+int lbuff; /* Number of bytes in table buffer */
+char *tbuff; /* FITS table buffer */
+int irow; /* Number of table row to read */
+int nbline; /* Number of bytes to read for this line */
+char *line; /* One line of FITS table (returned) */
+
+{
+ int nbuff, nlbuff;
+ int nbr = 0;
+ int offset, offend, ntry, ioff;
+ char *tbuff1;
+
+ offset = nbhead + (nbline * irow);
+ offend = offset + nbline - 1;
+
+/* Read a new buffer of the FITS table into memory if needed */
+ if (offset < offset1 || offend > offset2) {
+ nlbuff = lbuff / nbline;
+ nbuff = nlbuff * nbline;
+ for (ntry = 0; ntry < 3; ntry++) {
+ ioff = lseek (fd, offset, SEEK_SET);
+ if (ioff < offset) {
+ if (ntry == 2)
+ return (0);
+ else
+ continue;
+ }
+ nbr = read (fd, tbuff, nbuff);
+ if (nbr < nbline) {
+ if (verbose)
+ fprintf (stderr, "FITSRTLINE: %d / %d bytes read %d\n",
+ nbr,nbuff,ntry);
+ if (ntry == 2)
+ return (nbr);
+ }
+ else
+ break;
+ }
+ offset1 = offset;
+ offset2 = offset + nbr - 1;
+ strncpy (line, tbuff, nbline);
+ return (nbline);
+ }
+ else {
+ tbuff1 = tbuff + (offset - offset1);
+ strncpy (line, tbuff1, nbline);
+ return (nbline);
+ }
+}
+
+
+void
+fitsrtlset ()
+{
+ offset1 = 0;
+ offset2 = 0;
+ return;
+}
+
+
+/* FTGETI2 -- Extract n'th column from FITS table line as short */
+
+short
+ftgeti2 (entry, kw)
+
+char *entry; /* Row or entry from table */
+struct Keyword *kw; /* Table column information from FITS header */
+{
+ char temp[30];
+ short i;
+ int j;
+ float r;
+ double d;
+
+ if (ftgetc (entry, kw, temp, 30)) {
+ if (!strcmp (kw->kform, "I"))
+ moveb (temp, (char *) &i, 2, 0, 0);
+ else if (!strcmp (kw->kform, "J")) {
+ moveb (temp, (char *) &j, 4, 0, 0);
+ i = (short) j;
+ }
+ else if (!strcmp (kw->kform, "E")) {
+ moveb (temp, (char *) &r, 4, 0, 0);
+ i = (short) r;
+ }
+ else if (!strcmp (kw->kform, "D")) {
+ moveb (temp, (char *) &d, 8, 0, 0);
+ i = (short) d;
+ }
+ else
+ i = (short) atof (temp);
+ return (i);
+ }
+ else
+ return ((short) 0);
+}
+
+
+/* FTGETI4 -- Extract n'th column from FITS table line as int */
+
+int
+ftgeti4 (entry, kw)
+
+char *entry; /* Row or entry from table */
+struct Keyword *kw; /* Table column information from FITS header */
+{
+ char temp[30];
+ short i;
+ int j;
+ float r;
+ double d;
+
+ if (ftgetc (entry, kw, temp, 30)) {
+ if (!strcmp (kw->kform, "I")) {
+ moveb (temp, (char *) &i, 2, 0, 0);
+ j = (int) i;
+ }
+ else if (!strcmp (kw->kform, "J"))
+ moveb (temp, (char *) &j, 4, 0, 0);
+ else if (!strcmp (kw->kform, "E")) {
+ moveb (temp, (char *) &r, 4, 0, 0);
+ j = (int) r;
+ }
+ else if (!strcmp (kw->kform, "D")) {
+ moveb (temp, (char *) &d, 8, 0, 0);
+ j = (int) d;
+ }
+ else
+ j = (int) atof (temp);
+ return (j);
+ }
+ else
+ return (0);
+}
+
+
+/* FTGETR4 -- Extract n'th column from FITS table line as float */
+
+float
+ftgetr4 (entry, kw)
+
+char *entry; /* Row or entry from table */
+struct Keyword *kw; /* Table column information from FITS header */
+{
+ char temp[30];
+ short i;
+ int j;
+ float r;
+ double d;
+
+ if (ftgetc (entry, kw, temp, 30)) {
+ if (!strcmp (kw->kform, "I")) {
+ moveb (temp, (char *) &i, 2, 0, 0);
+ r = (float) i;
+ }
+ else if (!strcmp (kw->kform, "J")) {
+ moveb (temp, (char *) &j, 4, 0, 0);
+ r = (float) j;
+ }
+ else if (!strcmp (kw->kform, "E"))
+ moveb (temp, (char *) &r, 4, 0, 0);
+ else if (!strcmp (kw->kform, "D")) {
+ moveb (temp, (char *) &d, 8, 0, 0);
+ r = (float) d;
+ }
+ else
+ r = (float) atof (temp);
+ return (r);
+ }
+ else
+ return ((float) 0.0);
+}
+
+
+/* FTGETR8 -- Extract n'th column from FITS table line as double */
+
+double
+ftgetr8 (entry, kw)
+
+char *entry; /* Row or entry from table */
+struct Keyword *kw; /* Table column information from FITS header */
+{
+ char temp[30];
+ short i;
+ int j;
+ float r;
+ double d;
+
+ if (ftgetc (entry, kw, temp, 30)) {
+ if (!strcmp (kw->kform, "I")) {
+ moveb (temp, (char *) &i, 2, 0, 0);
+ d = (double) i;
+ }
+ else if (!strcmp (kw->kform, "J")) {
+ moveb (temp, (char *) &j, 4, 0, 0);
+ d = (double) j;
+ }
+ else if (!strcmp (kw->kform, "E")) {
+ moveb (temp, (char *) &r, 4, 0, 0);
+ d = (double) r;
+ }
+ else if (!strcmp (kw->kform, "D"))
+ moveb (temp, (char *) &d, 8, 0, 0);
+ else
+ d = atof (temp);
+ return (d);
+ }
+ else
+ return ((double) 0.0);
+}
+
+
+/* FTGETC -- Extract n'th column from FITS table line as character string */
+
+int
+ftgetc (entry, kw, string, maxchar)
+
+char *entry; /* Row or entry from table */
+struct Keyword *kw; /* Table column information from FITS header */
+char *string; /* Returned string */
+int maxchar; /* Maximum number of characters in returned string */
+{
+ int length = maxchar;
+
+ if (kw->kl < length)
+ length = kw->kl;
+ if (length > 0) {
+ strncpy (string, entry+kw->kf, length);
+ string[length] = 0;
+ return ( 1 );
+ }
+ else
+ return ( 0 );
+}
+
+extern int errno;
+
+
+/*FITSWIMAGE -- Write FITS header and image */
+
+int
+fitswimage (filename, header, image)
+
+char *filename; /* Name of FITS image file */
+char *header; /* FITS image header */
+char *image; /* FITS image pixels */
+
+{
+ int fd;
+
+ /* Open the output file */
+ if (strcasecmp (filename,"stdout") ) {
+
+ if (!access (filename, 0)) {
+ fd = open (filename, O_WRONLY);
+ if (fd < 3) {
+ snprintf (fitserrmsg,79, "FITSWIMAGE: file %s not writeable\n", filename);
+ return (0);
+ }
+ }
+ else {
+ fd = open (filename, O_RDWR+O_CREAT, 0666);
+ if (fd < 3) {
+ snprintf (fitserrmsg,79, "FITSWIMAGE: cannot create file %s\n", filename);
+ return (0);
+ }
+ }
+ }
+#ifndef VMS
+ else
+ fd = STDOUT_FILENO;
+#endif
+
+ return (fitswhdu (fd, filename, header, image));
+}
+
+
+/*FITSWEXT -- Write FITS header and image as extension to a file */
+
+int
+fitswext (filename, header, image)
+
+char *filename; /* Name of IFTS image file */
+char *header; /* FITS image header */
+char *image; /* FITS image pixels */
+
+{
+ int fd;
+
+ /* Open the output file */
+ if (strcasecmp (filename,"stdout") ) {
+
+ if (!access (filename, 0)) {
+ fd = open (filename, O_WRONLY);
+ if (fd < 3) {
+ snprintf (fitserrmsg,79, "FITSWEXT: file %s not writeable\n",
+ filename);
+ return (0);
+ }
+ }
+ else {
+ fd = open (filename, O_APPEND, 0666);
+ if (fd < 3) {
+ snprintf (fitserrmsg,79, "FITSWEXT: cannot append to file %s\n",
+ filename);
+ return (0);
+ }
+ }
+ }
+#ifndef VMS
+ else
+ fd = STDOUT_FILENO;
+#endif
+
+ return (fitswhdu (fd, filename, header, image));
+}
+
+
+/* FITSWHDU -- Write FITS head and image as extension */
+
+int
+fitswhdu (fd, filename, header, image)
+
+int fd; /* File descriptor */
+char *filename; /* Name of IFTS image file */
+char *header; /* FITS image header */
+char *image; /* FITS image pixels */
+{
+ int nbhead, nbimage, nblocks, bytepix, i, nbhw;
+ int bitpix, naxis, iaxis, naxisi, nbytes, nbw, nbpad, nbwp, simple;
+ char *endhead, *padding;
+ double bzero, bscale;
+ char keyword[32];
+
+ /* Change BITPIX=-16 files to BITPIX=16 with BZERO and BSCALE */
+ bitpix = 0;
+ hgeti4 (header,"BITPIX",&bitpix);
+ if (bitpix == -16) {
+ if (!hgetr8 (header, "BZERO", &bzero) &&
+ !hgetr8 (header, "BSCALE", &bscale)) {
+ bitpix = 16;
+ hputi4 (header, "BITPIX", bitpix);
+ hputr8 (header, "BZERO", 32768.0);
+ hputr8 (header, "BSCALE", 1.0);
+ }
+ }
+
+ /* Write header to file */
+ endhead = ksearch (header,"END") + 80;
+ nbhead = endhead - header;
+ nbhw = write (fd, header, nbhead);
+ if (nbhw < nbhead) {
+ snprintf (fitserrmsg,79, "FITSWHDU: wrote %d / %d bytes of header to file %s\n",
+ nbhw, nbhead, filename);
+ (void)close (fd);
+ return (0);
+ }
+
+ /* Write extra spaces to make an integral number of 2880-byte blocks */
+ nblocks = nbhead / FITSBLOCK;
+ if (nblocks * FITSBLOCK < nbhead)
+ nblocks = nblocks + 1;
+ nbytes = nblocks * FITSBLOCK;
+ nbpad = nbytes - nbhead;
+ padding = (char *)calloc (1, nbpad);
+ for (i = 0; i < nbpad; i++)
+ padding[i] = ' ';
+ nbwp = write (fd, padding, nbpad);
+ if (nbwp < nbpad) {
+ snprintf (fitserrmsg,79, "FITSWHDU: wrote %d / %d bytes of header padding to file %s\n",
+ nbwp, nbpad, filename);
+ (void)close (fd);
+ return (0);
+ }
+ nbhw = nbhw + nbwp;
+ free (padding);
+
+ /* Return if file has no data */
+ if (bitpix == 0 || image == NULL) {
+ /* snprintf (fitserrmsg,79, "FITSWHDU: BITPIX is 0; image not written\n"); */
+ (void)close (fd);
+ return (0);
+ }
+
+ /* If SIMPLE=F in header, just write whatever is in the buffer */
+ hgetl (header, "SIMPLE", &simple);
+ if (!simple) {
+ hgeti4 (header, "NBDATA", &nbytes);
+ nbimage = nbytes;
+ }
+
+ else {
+
+ /* Compute size of pixel in bytes */
+ bytepix = bitpix / 8;
+ if (bytepix < 0) bytepix = -bytepix;
+ nbimage = bytepix;
+
+ /* Compute size of image in bytes using relevant header parameters */
+ naxis = 1;
+ hgeti4 (header,"NAXIS",&naxis);
+ for (iaxis = 1; iaxis <= naxis; iaxis++) {
+ sprintf (keyword, "NAXIS%d", iaxis);
+ naxisi = 1;
+ hgeti4 (header,keyword,&naxisi);
+ nbimage = nbimage * naxisi;
+ }
+
+ /* Number of bytes to write is an integral number of FITS blocks */
+ nblocks = nbimage / FITSBLOCK;
+ if (nblocks * FITSBLOCK < nbimage)
+ nblocks = nblocks + 1;
+ nbytes = nblocks * FITSBLOCK;
+
+ /* Byte-reverse image before writing, if necessary */
+ if (imswapped ())
+ imswap (bitpix, image, nbimage);
+ }
+
+ /* Write image to file */
+ nbw = write (fd, image, nbimage);
+ if (nbw < nbimage) {
+ snprintf (fitserrmsg,79, "FITSWHDU: wrote %d / %d bytes of image to file %s\n",
+ nbw, nbimage, filename);
+ return (0);
+ }
+
+ /* Write extra zeroes to make an integral number of 2880-byte blocks */
+ nbpad = nbytes - nbimage;
+ if (nbpad > 0) {
+ padding = (char *)calloc (1, nbpad);
+ nbwp = write (fd, padding, nbpad);
+ if (nbwp < nbpad) {
+ snprintf (fitserrmsg,79, "FITSWHDU: wrote %d / %d bytes of image padding to file %s\n",
+ nbwp, nbpad, filename);
+ (void)close (fd);
+ return (0);
+ }
+ free (padding);
+ }
+ else
+ nbwp = 0;
+
+ (void)close (fd);
+
+ /* Byte-reverse image after writing, if necessary */
+ if (imswapped ())
+ imswap (bitpix, image, nbimage);
+
+ nbw = nbw + nbwp + nbhw;
+ return (nbw);
+}
+
+
+/*FITSCIMAGE -- Write FITS header and copy FITS image
+ Return number of bytes in output image, 0 if failure */
+
+int
+fitscimage (filename, header, filename0)
+
+char *filename; /* Name of output FITS image file */
+char *header; /* FITS image header */
+char *filename0; /* Name of input FITS image file */
+
+{
+ int fdout, fdin;
+ int nbhead, nbimage, nblocks, bytepix;
+ int bitpix, naxis, naxis1, naxis2, nbytes, nbw, nbpad, nbwp;
+ char *endhead, *lasthead, *padding;
+ char *image; /* FITS image pixels */
+ char *oldhead; /* Input file image header */
+ int nbhead0; /* Length of input file image header */
+ int lhead0;
+ int nbbuff, nbuff, ibuff, nbr, nbdata;
+
+ /* Compute size of image in bytes using relevant header parameters */
+ naxis = 1;
+ hgeti4 (header, "NAXIS", &naxis);
+ naxis1 = 1;
+ hgeti4 (header, "NAXIS1", &naxis1);
+ naxis2 = 1;
+ hgeti4 (header, "NAXIS2", &naxis2);
+ hgeti4 (header, "BITPIX", &bitpix);
+ bytepix = bitpix / 8;
+ if (bytepix < 0) bytepix = -bytepix;
+
+ /* If either dimension is one and image is 3-D, read all three dimensions */
+ if (naxis == 3 && (naxis1 ==1 || naxis2 == 1)) {
+ int naxis3;
+ hgeti4 (header,"NAXIS3",&naxis3);
+ nbimage = naxis1 * naxis2 * naxis3 * bytepix;
+ }
+ else
+ nbimage = naxis1 * naxis2 * bytepix;
+
+ nblocks = nbimage / FITSBLOCK;
+ if (nblocks * FITSBLOCK < nbimage)
+ nblocks = nblocks + 1;
+ nbytes = nblocks * FITSBLOCK;
+
+ /* Allocate image buffer */
+ nbbuff = FITSBLOCK * 100;
+ if (nbytes < nbbuff)
+ nbbuff = nbytes;
+ image = (char *) calloc (1, nbbuff);
+ nbuff = nbytes / nbbuff;
+ if (nbytes > nbuff * nbbuff)
+ nbuff = nbuff + 1;
+
+ /* Read input file header */
+ if ((oldhead = fitsrhead (filename0, &lhead0, &nbhead0)) == NULL) {
+ snprintf (fitserrmsg, 79,"FITSCIMAGE: header of input file %s cannot be read\n",
+ filename0);
+ return (0);
+ }
+
+ /* Find size of output header */
+ nbhead = fitsheadsize (header);
+
+ /* If overwriting, be more careful if new header is longer than old */
+ if (!strcmp (filename, filename0) && nbhead > nbhead0) {
+ if ((image = fitsrimage (filename0, nbhead0, oldhead)) == NULL) {
+ snprintf (fitserrmsg,79, "FITSCIMAGE: cannot read image from file %s\n",
+ filename0);
+ free (oldhead);
+ return (0);
+ }
+ return (fitswimage (filename, header, image));
+ }
+ free (oldhead);
+
+ /* Open the input file and skip over the header */
+ if (strcasecmp (filename0,"stdin")) {
+ fdin = -1;
+ fdin = fitsropen (filename0);
+ if (fdin < 0) {
+ snprintf (fitserrmsg, 79,"FITSCIMAGE: cannot read file %s\n", filename0);
+ return (0);
+ }
+
+ /* Skip over FITS header */
+ if (lseek (fdin, nbhead0, SEEK_SET) < 0) {
+ (void)close (fdin);
+ snprintf (fitserrmsg,79, "FITSCIMAGE: cannot skip header of file %s\n",
+ filename0);
+ return (0);
+ }
+ }
+#ifndef VMS
+ else
+ fdin = STDIN_FILENO;
+#endif
+
+ /* Open the output file */
+ if (!access (filename, 0)) {
+ fdout = open (filename, O_WRONLY);
+ if (fdout < 3) {
+ snprintf (fitserrmsg,79, "FITSCIMAGE: file %s not writeable\n", filename);
+ return (0);
+ }
+ }
+ else {
+ fdout = open (filename, O_RDWR+O_CREAT, 0666);
+ if (fdout < 3) {
+ snprintf (fitserrmsg,79, "FITSCHEAD: cannot create file %s\n", filename);
+ return (0);
+ }
+ }
+
+ /* Pad header with spaces */
+ endhead = ksearch (header,"END") + 80;
+ lasthead = header + nbhead;
+ while (endhead < lasthead)
+ *(endhead++) = ' ';
+
+ /* Write header to file */
+ nbw = write (fdout, header, nbhead);
+ if (nbw < nbhead) {
+ snprintf (fitserrmsg, 79,"FITSCIMAGE: wrote %d / %d bytes of header to file %s\n",
+ nbw, nbytes, filename);
+ (void)close (fdout);
+ (void)close (fdin);
+ return (0);
+ }
+
+ /* Return if no data */
+ if (bitpix == 0) {
+ (void)close (fdout);
+ (void)close (fdin);
+ return (nbhead);
+ }
+
+ nbdata = 0;
+ for (ibuff = 0; ibuff < nbuff; ibuff++) {
+ nbr = read (fdin, image, nbbuff);
+ if (nbr > 0) {
+ nbw = write (fdout, image, nbr);
+ nbdata = nbdata + nbw;
+ }
+ }
+
+ /* Write extra to make integral number of 2880-byte blocks */
+ nblocks = nbdata / FITSBLOCK;
+ if (nblocks * FITSBLOCK < nbdata)
+ nblocks = nblocks + 1;
+ nbytes = nblocks * FITSBLOCK;
+ nbpad = nbytes - nbdata;
+ padding = (char *)calloc (1,nbpad);
+ nbwp = write (fdout, padding, nbpad);
+ nbw = nbdata + nbwp;
+ free (padding);
+
+ (void)close (fdout);
+ (void)close (fdin);
+
+ if (nbw < nbimage) {
+ snprintf (fitserrmsg, 79, "FITSWIMAGE: wrote %d / %d bytes of image to file %s\n",
+ nbw, nbimage, filename);
+ return (0);
+ }
+ else
+ return (nbw);
+}
+
+
+/* FITSWHEAD -- Write FITS header and keep file open for further writing */
+
+int
+fitswhead (filename, header)
+
+char *filename; /* Name of IFTS image file */
+char *header; /* FITS image header */
+
+{
+ int fd;
+ int nbhead, nblocks;
+ int nbytes, nbw;
+ char *endhead, *lasthead;
+
+ /* Open the output file */
+ if (!access (filename, 0)) {
+ fd = open (filename, O_WRONLY);
+ if (fd < 3) {
+ snprintf (fitserrmsg, 79, "FITSWHEAD: file %s not writeable\n", filename);
+ return (0);
+ }
+ }
+ else {
+ fd = open (filename, O_RDWR+O_CREAT, 0666);
+ if (fd < 3) {
+ snprintf (fitserrmsg, 79, "FITSWHEAD: cannot create file %s\n", filename);
+ return (0);
+ }
+ }
+
+ /* Write header to file */
+ endhead = ksearch (header,"END") + 80;
+ nbhead = endhead - header;
+ nblocks = nbhead / FITSBLOCK;
+ if (nblocks * FITSBLOCK < nbhead)
+ nblocks = nblocks + 1;
+ nbytes = nblocks * FITSBLOCK;
+
+ /* Pad header with spaces */
+ lasthead = header + nbytes;
+ while (endhead < lasthead)
+ *(endhead++) = ' ';
+
+ nbw = write (fd, header, nbytes);
+ if (nbw < nbytes) {
+ fprintf (stderr, "FITSWHEAD: wrote %d / %d bytes of header to file %s\n",
+ nbw, nbytes, filename);
+ (void)close (fd);
+ return (0);
+ }
+ return (fd);
+}
+
+
+/* FITSWEXHEAD -- Write FITS header in place */
+
+int
+fitswexhead (filename, header)
+
+char *filename; /* Name of FITS image file with ,extension */
+char *header; /* FITS image header */
+
+{
+ int fd;
+ int nbhead, lhead;
+ int nbw, nbnew, nbold;
+ char *endhead, *lasthead, *oldheader;
+ char *ext, cext;
+
+ /* Compare size of existing header to size of new header */
+ fitsinherit = 0;
+ oldheader = fitsrhead (filename, &lhead, &nbhead);
+ if (oldheader == NULL) {
+ snprintf (fitserrmsg, 79, "FITSWEXHEAD: file %s cannot be read\n", filename);
+ return (-1);
+ }
+ nbold = fitsheadsize (oldheader);
+ nbnew = fitsheadsize (header);
+
+ /* Return if the new header is bigger than the old header */
+ if (nbnew > nbold) {
+ snprintf (fitserrmsg, 79, "FITSWEXHEAD: old header %d bytes, new header %d bytes\n", nbold,nbnew);
+ free (oldheader);
+ oldheader = NULL;
+ return (-1);
+ }
+
+ /* Add blank lines if new header is smaller than the old header */
+ else if (nbnew < nbold) {
+ strcpy (oldheader, header);
+ endhead = ksearch (oldheader,"END");
+ lasthead = oldheader + nbold;
+ while (endhead < lasthead)
+ *(endhead++) = ' ';
+ strncpy (lasthead-80, "END", 3);
+ }
+
+ /* Pad header with spaces */
+ else {
+ endhead = ksearch (header,"END") + 80;
+ lasthead = header + nbnew;
+ while (endhead < lasthead)
+ *(endhead++) = ' ';
+ strncpy (oldheader, header, nbnew);
+ }
+
+ /* Check for FITS extension and ignore for file opening */
+ ext = strchr (filename, ',');
+ if (ext == NULL)
+ ext = strchr (filename, '[');
+ if (ext != NULL) {
+ cext = *ext;
+ *ext = (char) 0;
+ }
+
+ /* Open the output file */
+ fd = open (filename, O_WRONLY);
+ if (ext != NULL)
+ *ext = cext;
+ if (fd < 3) {
+ snprintf (fitserrmsg, 79, "FITSWEXHEAD: file %s not writeable\n", filename);
+ return (-1);
+ }
+
+ /* Skip to appropriate place in file */
+ (void) lseek (fd, ibhead, SEEK_SET);
+
+ /* Write header to file */
+ nbw = write (fd, oldheader, nbold);
+ (void)close (fd);
+ free (oldheader);
+ oldheader = NULL;
+ if (nbw < nbold) {
+ fprintf (stderr, "FITSWHEAD: wrote %d / %d bytes of header to file %s\n",
+ nbw, nbold, filename);
+ return (-1);
+ }
+ return (0);
+}
+
+
+/* ISFITS -- Return 1 if FITS file, else 0 */
+int
+isfits (filename)
+
+char *filename; /* Name of file for which to find size */
+{
+ int diskfile;
+ char keyword[16];
+ char *comma;
+ int nbr;
+
+ /* First check to see if this is an assignment */
+ if (strchr (filename, '='))
+ return (0);
+
+ /* Check for stdin (input from pipe) */
+ else if (!strcasecmp (filename,"stdin"))
+ return (1);
+
+ /* Then check file extension
+ else if (strsrch (filename, ".fit") ||
+ strsrch (filename, ".fits") ||
+ strsrch (filename, ".fts"))
+ return (1); */
+
+ /* If no FITS file extension, try opening the file */
+ else {
+ if ((comma = strchr (filename,',')))
+ *comma = (char) 0;
+ if ((diskfile = open (filename, O_RDONLY)) < 0) {
+ if (comma)
+ *comma = ',';
+ return (0);
+ }
+ else {
+ nbr = read (diskfile, keyword, 8);
+ if (comma)
+ *comma = ',';
+ close (diskfile);
+ if (nbr < 8)
+ return (0);
+ else if (!strncmp (keyword, "SIMPLE", 6))
+ return (1);
+ else
+ return (0);
+ }
+ }
+}
+
+
+/* FITSHEADSIZE -- Find size of FITS header */
+
+int
+fitsheadsize (header)
+
+char *header; /* FITS header */
+{
+ char *endhead;
+ int nbhead, nblocks;
+
+ endhead = ksearch (header,"END") + 80;
+ nbhead = endhead - header;
+ nblocks = nbhead / FITSBLOCK;
+ if (nblocks * FITSBLOCK < nbhead)
+ nblocks = nblocks + 1;
+ return (nblocks * FITSBLOCK);
+}
+
+
+/* Print error message */
+void
+fitserr ()
+{ fprintf (stderr, "%s\n",fitserrmsg);
+ return; }
+
+
+/* MOVEB -- Copy nbytes bytes from source+offs to dest+offd (any data type) */
+
+void
+moveb (source, dest, nbytes, offs, offd)
+
+char *source; /* Pointer to source */
+char *dest; /* Pointer to destination */
+int nbytes; /* Number of bytes to move */
+int offs; /* Offset in bytes in source from which to start copying */
+int offd; /* Offset in bytes in destination to which to start copying */
+{
+char *from, *last, *to;
+ from = source + offs;
+ to = dest + offd;
+ last = from + nbytes;
+ while (from < last) *(to++) = *(from++);
+ return;
+}
+
+/*
+ * Feb 8 1996 New subroutines
+ * Apr 10 1996 Add subroutine list at start of file
+ * Apr 17 1996 Print error message to stderr
+ * May 2 1996 Write using stream IO
+ * May 14 1996 If FITSRTOPEN NK is zero, return all keywords in header
+ * May 17 1996 Make header internal to FITSRTOPEN
+ * Jun 3 1996 Use stream I/O for input as well as output
+ * Jun 10 1996 Remove unused variables after running lint
+ * Jun 12 1996 Deal with byte-swapped images
+ * Jul 11 1996 Rewrite code to separate header and data reading
+ * Aug 6 1996 Fixed small defects after lint
+ * Aug 6 1996 Drop unused NBHEAD argument from FITSRTHEAD
+ * Aug 13 1996 If filename is stdin, read from standard input instead of file
+ * Aug 30 1996 Use write for output, not fwrite
+ * Sep 4 1996 Fix mode when file is created
+ * Oct 15 1996 Drop column argument from FGET* subroutines
+ * Oct 15 1996 Drop unused variable
+ * Dec 17 1996 Add option to skip bytes in file before reading the header
+ * Dec 27 1996 Turn nonprinting header characters into spaces
+ *
+ * Oct 9 1997 Add FITS extension support as filename,extension
+ * Dec 15 1997 Fix minor bugs after lint
+ *
+ * Feb 23 1998 Do not append primary header if getting header for ext. 0
+ * Feb 23 1998 Accept either bracketed or comma extension
+ * Feb 24 1998 Add SIMPLE keyword to start of extracted extension
+ * Apr 30 1998 Fix error return if not table file after Allan Brighton
+ * May 4 1998 Fix error in argument sequence in HGETS call
+ * May 27 1998 Include fitsio.h and imio.h
+ * Jun 1 1998 Add VMS fixes from Harry Payne at STScI
+ * Jun 3 1998 Fix bug reading EXTNAME
+ * Jun 11 1998 Initialize all header parameters before reading them
+ * Jul 13 1998 Clarify argument definitions
+ * Aug 6 1998 Rename fitsio.c to fitsfile.c to avoid conflict with CFITSIO
+ * Aug 13 1998 Add FITSWHEAD to write only header
+ * Sep 25 1998 Allow STDIN or stdin for standard input reading
+ * Oct 5 1998 Add isfits() to decide whether a file is FITS
+ * Oct 9 1998 Assume stdin and STDIN to be FITS files in isfits()
+ * Nov 30 1998 Fix bug found by Andreas Wicenec when reading large headers
+ * Dec 8 1998 Fix bug introduced by previous bug fix
+ *
+ * Jan 4 1999 Do not print error message if BITPIX is 0
+ * Jan 27 1999 Read and write all of 3D images if one dimension is 1
+ * Jan 27 1999 Pad out data to integral number of 2880-byte blocks
+ * Apr 29 1999 Write BITPIX=-16 files as BITPIX=16 with BSCALE and BZERO
+ * Apr 30 1999 Add % as alternative to , to denote sub-images
+ * May 25 1999 Set buffer offsets to 0 when FITS table file is opened
+ * Jul 14 1999 Do not try to write image data if BITPIX is 0
+ * Sep 27 1999 Add STDOUT as output filename option in fitswimage()
+ * Oct 6 1999 Set header length global variable hget.lhead0 in fitsrhead()
+ * Oct 14 1999 Update header length as it is changed in fitsrhead()
+ * Oct 20 1999 Change | in if statements to ||
+ * Oct 25 1999 Change most malloc() calls to calloc()
+ * Nov 24 1999 Add fitscimage()
+ *
+ * Feb 23 2000 Fix problem with some error returns in fitscimage()
+ * Mar 17 2000 Drop unused variables after lint
+ * Jul 20 2000 Drop BITPIX and NAXIS from primary header if extension printerd
+ * Jul 20 2000 Start primary part of header with ROOTHEAD keyword
+ * Jul 28 2000 Add loop to deal with buffered stdin
+ *
+ * Jan 11 2001 Print all messages to stderr
+ * Jan 12 2001 Add extension back onto filename after fitsropen() (Guy Rixon)
+ * Jan 18 2001 Drop EXTEND keyword when extracting an extension
+ * Jan 18 2001 Add fitswext() to append HDU and fitswhdu() to do actual writing
+ * Jan 22 2001 Ignore WCS name or letter following a : in file name in fitsrhead()
+ * Jan 30 2001 Fix FITSCIMAGE so it doesn't overwrite data when overwriting a file
+ * Feb 20 2001 Ignore WCS name or letter following a : in file name in fitsropen()
+ * Feb 23 2001 Initialize rbrac in fitsropen()
+ * Mar 8 2001 Use % instead of : for WCS specification in file name
+ * Mar 9 2001 Fix bug so primary header is always appended to secondary header
+ * Mar 9 2001 Change NEXTEND to NUMEXT in appended primary header
+ * Mar 20 2001 Declare fitsheadsize() in fitschead()
+ * Apr 24 2001 When matching column names, use longest length
+ * Jun 27 2001 In fitsrthead(), allocate pw and lpnam only if more space needed
+ * Aug 24 2001 In isfits(), return 0 if argument contains an equal sign
+ *
+ * Jan 28 2002 In fitsrhead(), allow stdin to include extension and/or WCS selection
+ * Jun 18 2002 Save error messages as fitserrmsg and use fitserr() to print them
+ * Oct 21 2002 Add fitsrsect() to read a section of an image
+ *
+ * Feb 4 2003 Open catalog file rb instead of r (Martin Ploner, Bern)
+ * Apr 2 2003 Drop unused variable in fitsrsect()
+ * Jul 11 2003 Use strcasecmp() to check for stdout and stdin
+ * Aug 1 2003 If no other header, return root header from fitsrhead()
+ * Aug 20 2003 Add fitsrfull() to read n-dimensional FITS images
+ * Aug 21 2003 Modify fitswimage() to always write n-dimensional FITS images
+ * Nov 18 2003 Fix minor bug in fitswhdu()
+ * Dec 3 2003 Remove unused variable lasthead in fitswhdu()
+ *
+ * May 3 2004 Do not always append primary header to extension header
+ * May 3 2004 Add ibhead as position of header read in file
+ * May 19 2004 Do not reset ext if NULL in fitswexhead()
+ * Jul 1 2004 Initialize INHERIT to 1
+ * Aug 30 2004 Move fitsheadsize() declaration to fitsfile.h
+ * Aug 31 2004 If SIMPLE=F, put whatever is in file after header in image
+ *
+ * Mar 17 2005 Use unbuffered I/O in isfits() for robustness
+ * Jun 27 2005 Drop unused variable nblocks in fitswexhead()
+ * Aug 8 2005 Fix space-padding bug in fitswexhead() found by Armin Rest
+ * Sep 30 2005 Fix fitsrsect() to position relatively, not absolutely
+ * Oct 28 2005 Add error message if desired FITS extension is not found
+ * Oct 28 2005 Fix initialization problem found by Sergey Koposov
+ *
+ * Feb 23 2006 Add fitsrtail() to read appended FITS headers
+ * Feb 27 2006 Add file name to header-reading error messages
+ * May 3 2006 Remove declarations of unused variables
+ * Jun 20 2006 Initialize uninitialized variables
+ * Nov 2 2006 Change all realloc() calls to calloc()
+ *
+ * Jan 5 2007 In fitsrtail(), change control characters in header to spaces
+ * Apr 30 2007 Improve error reporting in FITSRFULL
+ * Nov 28 2007 Add support to BINTABLE in ftget*() and fitsrthead()
+ * Dec 20 2007 Add data heap numerated by PCOUNT when skipping HDU in fitsrhead()
+ * Dec 20 2007 Return NULL pointer if fitsrhead() cannot find requested HDU
+ *
+ * Apr 7 2008 Drop comma from name when reading file in isfits()
+ * Jun 27 2008 Do not append primary data header if it is the only header
+ * Nov 21 2008 In fitswhead(), print message if too few bytes written
+ *
+ * Sep 18 2009 In fitswexhead() write to error string instead of stderr
+ * Sep 22 2009 In fitsrthead(), fix lengths for ASCII numeric table entries
+ * Sep 25 2009 Add subroutine moveb() and fix calls to it
+ * Sep 25 2009 Fix several small errors found by Jessicalas Burke
+ *
+ * Mar 29 2010 In fitswhead(), always pad blocks to 2880 bytes with spaces
+ * Mar 31 2010 In fitsrhead(), fix bug reading long primary headers
+ *
+ * Sep 15 2011 In fitsrsect() declare impos and nblin off_t
+ * Sep 15 2011 In fitsrtail() declare offset off_t
+ * Sep 15 2011 Declare global variable ibhead off_t
+ */
diff --git a/funtools/wcs/fitsfile.h b/funtools/wcs/fitsfile.h
new file mode 100644
index 0000000..c000d18
--- /dev/null
+++ b/funtools/wcs/fitsfile.h
@@ -0,0 +1,1286 @@
+/*** File fitsfile.h FITS and IRAF file access subroutines
+ *** September 25, 2009
+ *** By Jessica Mink, jmink@cfa.harvard.edu
+ *** Harvard-Smithsonian Center for Astrophysics
+ *** Copyright (C) 1996-2009
+ *** Smithsonian Astrophysical Observatory, Cambridge, MA, USA
+
+ This library 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 2 of the License, or (at your option) any later version.
+
+ This library 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 this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Correspondence concerning WCSTools should be addressed as follows:
+ Internet email: jmink@cfa.harvard.edu
+ Postal address: Jessica Mink
+ Smithsonian Astrophysical Observatory
+ 60 Garden St.
+ Cambridge, MA 02138 USA
+ */
+
+#ifndef fitsfile_h_
+#define fitsfile_h_
+#include "fitshead.h"
+
+/* Declarations for subroutines in fitsfile.c, imhfile.c, imio.c,
+ * fileutil.c, and dateutil.c */
+
+#define FITSBLOCK 2880
+
+/* FITS table keyword structure */
+struct Keyword {
+ char kname[10]; /* Keyword for table entry */
+ int lname; /* Length of keyword name */
+ int kn; /* Index of entry on line */
+ int kf; /* Index in line of first character of entry */
+ int kl; /* Length of entry value */
+ char kform[8]; /* Format for this value */
+};
+
+/* Structure for access to tokens within a string */
+#define MAXTOKENS 1000 /* Maximum number of tokens to parse */
+#define MAXWHITE 20 /* Maximum number of different whitespace characters */
+struct Tokens {
+ char *line; /* Line which has been parsed */
+ int lline; /* Number of characters in line */
+ int ntok; /* Number of tokens on line */
+ int nwhite; /* Number of whitespace characters */
+ char white[MAXWHITE]; /* Whitespace (separator) characters */
+ char *tok1[MAXTOKENS]; /* Pointers to start of tokens */
+ int ltok[MAXTOKENS]; /* Lengths of tokens */
+ int itok; /* Current token number */
+};
+
+#ifdef __cplusplus /* C++ prototypes */
+extern "C" {
+#endif
+
+
+#ifdef __STDC__ /* Full ANSI prototypes */
+
+/* Declarations for subroutines in fitsfile.c, imhfile.c, imio.c,
+ * fileutil.c, and dateutil.c */
+
+/* FITS file access subroutines in fitsfile.c */
+ int fitsropen( /* Open a FITS file for reading, returning a FILE pointer */
+ char *inpath); /* Pathname for FITS tables file to read */
+ char *fitsrhead( /* Read a FITS header */
+ char *filename, /* Name of FITS image file */
+ int *lhead, /* Allocated length of FITS header in bytes (returned) */
+ int *nbhead); /* Number of bytes before start of data (returned) */
+ char *fitsrtail( /* Read FITS header appended to graphics file */
+ char *filename, /* Name of FITS image file */
+ int *lhead, /* Allocated length of FITS header in bytes (returned) */
+ int *nbhead); /* Number of bytes before start of data (returned) */
+ char *fitsrimage( /* Read a FITS image */
+ char *filename, /* Name of FITS image file */
+ int nbhead, /* Actual length of image header(s) in bytes */
+ char *header); /* FITS header for image (previously read) */
+ char *fitsrfull( /* Read a FITS image of any dimension */
+ char *filename, /* Name of FITS image file */
+ int nbhead, /* Actual length of image header(s) in bytes */
+ char *header); /* FITS header for image (previously read) */
+ char *fitsrsect( /* Read a piece of a FITS image, header */
+ char *filename, /* Name of FITS image file */
+ char *header, /* FITS header for image (previously read) */
+ int nbhead, /* Actual length of image header(s) in bytes */
+ int x0, /* FITS image X coordinate of first pixel */
+ int y0, /* FITS image Y coordinate of first pixel */
+ int nx, /* Number of columns to read (less than NAXIS1) */
+ int ny, /* Number of rows to read (less than NAXIS2) */
+ int nlog); /* Note progress mod this rows */
+ int fitswhead( /* Write FITS header; keep file open for further writing */
+ char *filename, /* Name of FITS image file */
+ char *header); /* FITS header for image (previously read) */
+ int fitswexhead( /* Write FITS header in place */
+ char *filename, /* Name of FITS image file */
+ char *header); /* FITS header for image */
+ int fitswext( /* Write FITS header and image as extension to a file */
+ char *filename, /* Name of FITS image file */
+ char *header, /* FITS image header */
+ char *image); /* FITS image pixels */
+ int fitswhdu( /* Write FITS head and image as extension */
+ int fd, /* File descriptor */
+ char *filename, /* Name of FITS image file */
+ char *header, /* FITS image header */
+ char *image); /* FITS image pixels */
+ int fitswimage( /* Write FITS header and image */
+ char *filename, /* Name of FITS image file */
+ char *header, /* FITS image header */
+ char *image); /* FITS image pixels */
+ int fitscimage( /* Write FITS header and copy FITS image */
+ char *filename, /* Name of output FITS image file */
+ char *header, /* FITS image header */
+ char *filename0); /* Name of input FITS image file */
+ int isfits( /* Return 1 if file is a FITS file */
+ char *filename); /* Name of file to check */
+ void fitserr(); /* Print FITS error message to stderr */
+ void setfitsinherit( /* Set flag to append primary data header */
+ int inh); /* 1 to inherit primary data header, else 0 */
+ int fitsheadsize( /* Return size of fitsheader in bytes */
+ char *header); /* FITS image header */
+
+/* FITS table file access subroutines in fitsfile.c */
+
+ int fitsrtopen( /* Open FITS table file and fill structure with
+ * pointers to selected keywords
+ * Return file descriptor (-1 if unsuccessful) */
+ char *inpath, /* Pathname for FITS tables file to read */
+ int *nk, /* Number of keywords to use */
+ struct Keyword **kw, /* Structure for desired entries */
+ int *nrows, /* Number of rows in table (returned) */
+ int *nchar, /* Number of characters in one table row (returned) */
+ int *nbhead); /* Number of characters before table starts */
+ int fitsrthead( /* Read pointers to selected keywords
+ * from FITS table header */
+ char *header, /* Header for FITS tables file */
+ int *nk, /* Number of keywords to use */
+ struct Keyword **kw, /* Structure for desired entries */
+ int *nrows, /* Number of rows in table (returned) */
+ int *nchar); /* Number of characters in one table row (returned) */
+ void fitsrtlset(void); /* Reset FITS Table buffer limits from start of data */
+ int fitsrtline( /* Return specified line of FITS table */
+ int fd, /* File descriptor for FITS file */
+ int nbhead, /* Number of bytes in FITS header */
+ int lbuff, /* Number of bytes in table buffer */
+ char *tbuff, /* FITS table buffer */
+ int irow, /* Number of table row to read */
+ int nbline, /* Number of bytes to read for this line */
+ char *line); /* One line of FITS table (returned) */
+short ftgeti2( /* Extract column for keyword from FITS table line
+ * as short */
+ char *entry, /* Row or entry from table */
+ struct Keyword *kw); /* Table column information from FITS header */
+ int ftgeti4( /* Extract column for keyword from FITS table line
+ * as int */
+ char *entry, /* Row or entry from table */
+ struct Keyword *kw); /* Table column information from FITS header */
+float ftgetr4( /* Extract column for keyword from FITS table line
+ * as float */
+ char *entry, /* Row or entry from table */
+ struct Keyword *kw); /* Table column information from FITS header */
+ double ftgetr8( /* Extract column for keyword from FITS table line
+ * as double */
+ char *entry, /* Row or entry from table */
+ struct Keyword *kw); /* Table column information from FITS header */
+ int ftgetc( /* Extract column for keyword from FITS table line
+ * as char string */
+ char *entry, /* Row or entry from table */
+ struct Keyword *kw, /* Table column information from FITS header */
+ char *string, /* Returned string */
+ int maxchar); /* Maximum number of characters in returned string */
+
+ void moveb ( /* Copy nbytes bytes from source+offs to dest+offd */
+ char *source, /* Pointer to source */
+ char *dest, /* Pointer to destination */
+ int nbytes, /* Number of bytes to move */
+ int offs, /* Offset in bytes in source from which to start copying */
+ int offd); /* Offset in bytes in destination to which to start copying */
+
+
+/* IRAF file access subroutines in imhfile.c */
+
+ char *irafrhead( /* Read IRAF .imh header file and translate to FITS header */
+ char *filename, /* Name of IRAF header file */
+ int *lihead); /* Length of IRAF image header in bytes (returned) */
+ char *irafrimage( /* Read IRAF image pixels (call after irafrhead) */
+ char *fitsheader); /* FITS image header (filled) */
+ int irafwhead( /* Write IRAF .imh header file */
+ char *hdrname, /* Name of IRAF header file */
+ int lhead, /* Length of IRAF header */
+ char *irafheader, /* IRAF header */
+ char *fitsheader); /* FITS image header */
+ int irafwimage( /* Write IRAF .imh header file and .pix image file */
+ char *hdrname, /* Name of IRAF header file */
+ int lhead, /* Length of IRAF header */
+ char *irafheader, /* IRAF header */
+ char *fitsheader, /* FITS image header */
+ char *image); /* IRAF image */
+ int isiraf( /* return 1 if IRAF imh file, else 0 */
+ char *filename); /* Name of file to check */
+ char *iraf2fits( /* Convert IRAF image header to FITS image header,
+ * returning FITS header */
+ char *hdrname, /* IRAF header file name (may be path) */
+ char *irafheader, /* IRAF image header */
+ int nbiraf, /* Number of bytes in IRAF header */
+ int *nbfits); /* Number of bytes in FITS header (returned) */
+
+ char *fits2iraf( /* Convert FITS image header to IRAF image header,
+ * returning IRAF header */
+ char *fitsheader, /* FITS image header */
+ char *irafheader, /* IRAF image header (returned updated) */
+ int nbhead, /* Length of IRAF header */
+ int *nbiraf); /* Length of returned IRAF header */
+
+/* Image pixel access subroutines in imio.c */
+
+ double getpix( /* Read one pixel from any data type 2-D array (0,0)*/
+ char *image, /* Image array as 1-D vector */
+ int bitpix, /* FITS bits per pixel
+ * 16 = short, -16 = unsigned short, 32 = int
+ * -32 = float, -64 = double */
+ int w, /* Image width in pixels */
+ int h, /* Image height in pixels */
+ double bzero, /* Zero point for pixel scaling */
+ double bscale, /* Scale factor for pixel scaling */
+ int x, /* Zero-based horizontal pixel number */
+ int y); /* Zero-based vertical pixel number */
+ double getpix1( /* Read one pixel from any data type 2-D array (1,1)*/
+ char *image, /* Image array as 1-D vector */
+ int bitpix, /* FITS bits per pixel */
+ int w, /* Image width in pixels */
+ int h, /* Image height in pixels */
+ double bzero, /* Zero point for pixel scaling */
+ double bscale, /* Scale factor for pixel scaling */
+ int x, /* One-based horizontal pixel number */
+ int y); /* One-based vertical pixel number */
+ double maxvec( /* Get maximum value in vector from a image */
+ char *image, /* Image array from which to extract vector */
+ int bitpix, /* Number of bits per pixel in image */
+ double bzero, /* Zero point for pixel scaling */
+ double bscale, /* Scale factor for pixel scaling */
+ int pix1, /* Offset of first pixel to extract */
+ int npix); /* Number of pixels to extract */
+ double minvec( /* Get minimum value in vector from a image */
+ char *image, /* Image array from which to extract vector */
+ int bitpix, /* Number of bits per pixel in image */
+ double bzero, /* Zero point for pixel scaling */
+ double bscale, /* Scale factor for pixel scaling */
+ int pix1, /* Offset of first pixel to extract */
+ int npix); /* Number of pixels to extract */
+ void putpix( /* Write one pixel to any data type 2-D array (0,0)*/
+ char *image, /* Image array as 1-D vector */
+ int bitpix, /* FITS bits per pixel */
+ int w, /* Image width in pixels */
+ int h, /* Image height in pixels */
+ double bzero, /* Zero point for pixel scaling */
+ double bscale, /* Scale factor for pixel scaling */
+ int x, /* Zero-based horizontal pixel number */
+ int y, /* Zero-based vertical pixel number */
+ double dpix); /* Value to put into image pixel */
+ void putpix1( /* Write one pixel to any data type 2-D array (1,1) */
+ char *image, /* Image array as 1-D vector */
+ int bitpix, /* FITS bits per pixel */
+ int w, /* Image width in pixels */
+ int h, /* Image height in pixels */
+ double bzero, /* Zero point for pixel scaling */
+ double bscale, /* Scale factor for pixel scaling */
+ int x, /* One-based horizontal pixel number */
+ int y, /* One-based vertical pixel number */
+ double dpix); /* Value to put into image pixel */
+ void addpix( /* Add to one pixel in any data type 2-D array (0,0)*/
+ char *image, /* Image array as 1-D vector */
+ int bitpix, /* FITS bits per pixel */
+ int w, /* Image width in pixels */
+ int h, /* Image height in pixels */
+ double bzero, /* Zero point for pixel scaling */
+ double bscale, /* Scale factor for pixel scaling */
+ int x, /* Zero-based horizontal pixel number */
+ int y, /* Zero-based vertical pixel number */
+ double dpix); /* Value to add to image pixel */
+ void addpix1( /* Add to one pixel in any data type 2-D array (1,1)*/
+ char *image, /* Image array as 1-D vector */
+ int bitpix, /* FITS bits per pixel */
+ int w, /* Image width in pixels */
+ int h, /* Image height in pixels */
+ double bzero, /* Zero point for pixel scaling */
+ double bscale, /* Scale factor for pixel scaling */
+ int x, /* One-based horizontal pixel number */
+ int y, /* One-based vertical pixel number */
+ double dpix); /* Value to add to image pixel */
+ void movepix( /* Move one pixel value between two 2-D arrays (0,0) */
+ char *image1, /* Pointer to first pixel in input image */
+ int bitpix1, /* Bits per input pixel (FITS codes) */
+ int w1, /* Number of horizontal pixels in input image */
+ int x1, /* Zero-based row for input pixel */
+ int y1, /* Zero-based column for input pixel */
+ char *image2, /* Pointer to first pixel in output image */
+ int bitpix2, /* Bits per output pixel (FITS codes) */
+ int w2, /* Number of horizontal pixels in output image */
+ int x2, /* Zero-based row for output pixel */
+ int y2); /* Zero-based column for output pixel */
+ void movepix1( /* Move one pixel value between two 2-D arrays (1,1) */
+ char *image1, /* Pointer to first pixel in input image */
+ int bitpix1, /* Bits per input pixel (FITS codes) */
+ int w1, /* Number of horizontal pixels in input image */
+ int x1, /* One-based row for input pixel */
+ int y1, /* One-based column for input pixel */
+ char *image2, /* Pointer to first pixel in output image */
+ int bitpix2, /* Bits per output pixel (FITS codes) */
+ int w2, /* Number of horizontal pixels in output image */
+ int x2, /* One-based row for output pixel */
+ int y2); /* One-based column for output pixel */
+
+/* Image vector processing subroutines in imio.c */
+
+ void addvec( /* Add constant to vector from 2-D array */
+ char *image, /* Image array as 1-D vector */
+ int bitpix, /* FITS bits per pixel */
+ double bzero, /* Zero point for pixel scaling */
+ double bscale, /* Scale factor for pixel scaling */
+ int pix1, /* Offset of first pixel to which to add */
+ int npix, /* Number of pixels to which to add */
+ double dpix); /* Value to add to pixels */
+ void multvec( /* Multiply vector from 2-D array by a constant */
+ char *image, /* Image array as 1-D vector */
+ int bitpix, /* FITS bits per pixel */
+ double bzero, /* Zero point for pixel scaling */
+ double bscale, /* Scale factor for pixel scaling */
+ int pix1, /* Offset of first pixel to multiply */
+ int npix, /* Number of pixels to multiply */
+ double dpix); /* Value to add to pixels */
+ void getvec( /* Read vector from 2-D array */
+ char *image, /* Image array as 1-D vector */
+ int bitpix, /* FITS bits per pixel */
+ double bzero, /* Zero point for pixel scaling */
+ double bscale, /* Scale factor for pixel scaling */
+ int pix1, /* Offset of first pixel to extract */
+ int npix, /* Number of pixels to extract */
+ double *dvec0); /* Vector of pixels (returned) */
+ void putvec( /* Write vector into 2-D array */
+ char *image, /* Image array as 1-D vector */
+ int bitpix, /* FITS bits per pixel */
+ double bzero, /* Zero point for pixel scaling */
+ double bscale, /* Scale factor for pixel scaling */
+ int pix1, /* Offset of first pixel to insert */
+ int npix, /* Number of pixels to insert */
+ double *dvec0); /* Vector of pixels to insert */
+ void fillvec( /* Write constant into a vector */
+ char *image, /* Image array as 1-D vector */
+ int bitpix, /* FITS bits per pixel */
+ double bzero, /* Zero point for pixel scaling */
+ double bscale, /* Scale factor for pixel scaling */
+ int pix1, /* Zero-based offset of first pixel to multiply */
+ int npix, /* Number of pixels to multiply */
+ double dpix); /* Value to which to set pixels */
+ void fillvec1( /* Write constant into a vector */
+ char *image, /* Image array as 1-D vector */
+ int bitpix, /* FITS bits per pixel */
+ double bzero, /* Zero point for pixel scaling */
+ double bscale, /* Scale factor for pixel scaling */
+ int pix1, /* One-based offset of first pixel to multiply */
+ int npix, /* Number of pixels to multiply */
+ double dpix); /* Value to which to set pixels */
+
+/* Image pixel byte-swapping subroutines in imio.c */
+
+ void imswap( /* Swap alternating bytes in a vector */
+ int bitpix, /* Number of bits per pixel */
+ char *string, /* Address of starting point of bytes to swap */
+ int nbytes); /* Number of bytes to swap */
+ void imswap2( /* Swap bytes in a vector of 2-byte (short) integers */
+ char *string, /* Address of starting point of bytes to swap */
+ int nbytes); /* Number of bytes to swap */
+ void imswap4( /* Reverse bytes in a vector of 4-byte numbers */
+ char *string, /* Address of starting point of bytes to swap */
+ int nbytes); /* Number of bytes to swap */
+ void imswap8( /* Reverse bytes in a vector of 8-byte numbers */
+ char *string, /* Address of starting point of bytes to swap */
+ int nbytes); /* Number of bytes to swap */
+ int imswapped(void); /* Return 1 if machine byte order is not FITS order */
+
+/* File utilities from fileutil.c */
+
+ int getfilelines( /* Return number of lines in an ASCII file */
+ char *filename); /* Name of file to check */
+ char *getfilebuff( /* Return entire file contents in a character string */
+ char *filename); /* Name of file to read */
+ int getfilesize( /* Return size of a binary or ASCII file */
+ char *filename); /* Name of file to check */
+ int isimlist( /* Return 1 if file is list of FITS or IRAF image files, else 0 */
+ char *filename); /* Name of file to check */
+ int isimlistd( /* Return 1 if file is list of FITS or IRAF image files, else 0 */
+ char *filename, /* Name of file to check */
+ char *rootdir); /* Name of root directory for files in list */
+ int isfilelist( /* Return 1 if list of readable files, else 0 */
+ char *filename, /* Name of file to check */
+ char *rootdir); /* Name of root directory for files in list */
+ int isfile( /* Return 1 if file is a readable file, else 0 */
+ char *filename); /* Name of file to check */
+ int istiff( /* Return 1 if TIFF image file, else 0 */
+ char *filename); /* Name of file to check */
+ int isjpeg( /* Return 1 if JPEG image file, else 0 */
+ char *filename); /* Name of file to check */
+ int isgif( /* Return 1 if GIF image file, else 0 */
+ char *filename); /* Name of file to check */
+ int first_token( /* Return first token from the next line of an ASCII file */
+ FILE *diskfile, /* File descriptor for ASCII file */
+ int ncmax, /* Maximum number of characters returned */
+ char *token); /* First token on next line (returned) */
+ int stc2s ( /* Replace character in string with space */
+ char *spchar, /* Character to replace with spaces */
+ char *string); /* Character string to process */
+ int sts2c ( /* Replace spaces in string with character */
+ char *spchar, /* Character with which to replace spaces */
+ char *string); /* Character string to process */
+
+/* Subroutines for access to tokens within a string from fileutil.c */
+ int setoken( /* Tokenize a string for easy decoding */
+ struct Tokens *tokens, /* Token structure returned */
+ char *string, /* character string to tokenize */
+ char *cwhite); /* additional whitespace characters
+ * if = tab, disallow spaces and commas */
+ int nextoken( /* Get next token from tokenized string */
+ struct Tokens *tokens, /* Token structure returned */
+ char *token, /* token (returned) */
+ int maxchars); /* Maximum length of token */
+ int getoken( /* Get specified token from tokenized string */
+ struct Tokens *tokens, /* Token structure returned */
+ int itok, /* token sequence number of token
+ * if <0, get whole string after token -itok
+ * if =0, get whole string */
+ char *token, /* token (returned) */
+ int maxchars); /* Maximum length of token */
+
+/* Subroutines for translating dates and times in dateutil.c */
+
+ /* Subroutines to convert between floating point and vigesimal angles */
+
+ void ang2hr ( /* Fractional degrees to hours as hh:mm:ss.ss */
+ double angle, /* Angle in fractional degrees */
+ int lstr, /* Maximum number of characters in string */
+ char *string); /* Character string (hh:mm:ss.ss returned) */
+ void ang2deg ( /* Fractional degrees to degrees as dd:mm:ss.ss */
+ double angle, /* Angle in fractional degrees */
+ int lstr, /* Maximum number of characters in string */
+ char *string); /* Character string (dd:mm:ss.ss returned) */
+ double deg2ang ( /* Degrees as dd:mm:ss.ss to fractional degrees */
+ char *angle); /* Angle as dd:mm:ss.ss */
+ double hr2ang ( /* Hours as hh:mm:ss.ss to fractional degrees */
+ char *angle); /* Angle in sexigesimal hours (hh:mm:ss.sss) */
+
+ /* Subroutines to convert from year and day of year */
+
+ void doy2dt( /* Year and day of year to yyyy.mmdd hh.mmss */
+ int year, /* Year */
+ double doy, /* Day of year with fraction */
+ double *date, /* Date as yyyy.mmdd (returned) */
+ double *time); /* Time as hh.mmssxxxx (returned) */
+ double doy2ep( /* Year and day of year to fractional year (epoch) */
+ int year, /* Year */
+ double doy); /* Day of year with fraction */
+ double doy2epb( /* year and day of year to Besselian epoch */
+ int year, /* Year */
+ double doy); /* Day of year with fraction */
+ double doy2epj( /* year and day of year to Julian epoch */
+ int year, /* Year */
+ double doy); /* Day of year with fraction */
+ char *doy2fd( /* year and day of year to FITS date */
+ int year, /* Year */
+ double doy); /* Day of year with fraction */
+ double doy2jd( /* year and day of year to Julian Day */
+ int year, /* Year */
+ double doy); /* Day of year with fraction */
+ double doy2mjd( /* year and day of year to Modified Julian Day */
+ int year, /* Year */
+ double doy); /* Day of year with fraction */
+ double doy2ts( /* year and day of year to seconds since 1950.0 */
+ int year, /* Year */
+ double doy); /* Day of year with fraction */
+ int doy2tsi( /* year and day of year to IRAF seconds since 1980-01-01 */
+ int year, /* Year */
+ double doy); /* Day of year with fraction */
+ time_t doy2tsu( /* year and day of year to Unix seconds since 1970-01-01 */
+ int year, /* Year */
+ double doy); /* Day of year with fraction */
+
+ /* Subroutines to convert from date and time */
+
+ void dt2doy( /* yyyy.mmdd hh.mmss to year and day of year */
+ double date, /* Date as yyyy.mmdd
+ * yyyy = calendar year (e.g. 1973)
+ * mm = calendar month (e.g. 04 = april)
+ * dd = calendar day (e.g. 15) */
+ double time, /* Time as hh.mmssxxxx
+ * if time<0, it is time as -(fraction of a day)
+ * hh = hour of day (0 .le. hh .le. 23)
+ * nn = minutes (0 .le. nn .le. 59)
+ * ss = seconds (0 .le. ss .le. 59)
+ * xxxx = tenths of milliseconds (0 .le. xxxx .le. 9999) */
+ int *year, /* Year (returned) */
+ double *doy); /* Day of year with fraction (returned) */
+ double dt2ep( /* yyyy.ddmm and hh.mmsss to fractional year (epoch) */
+ double date, /* Date as yyyy.mmdd */
+ double time); /* Time as hh.mmssxxxx */
+ double dt2epb( /* yyyy.ddmm and hh.mmsss to Besselian epoch */
+ double date, /* Date as yyyy.mmdd */
+ double time); /* Time as hh.mmssxxxx */
+ double dt2epj( /* yyyy.ddmm and hh.mmsss to Julian epoch */
+ double date, /* Date as yyyy.mmdd */
+ double time); /* Time as hh.mmssxxxx */
+ char *dt2fd( /* yyyy.ddmm and hh.mmsss to FITS date string */
+ double date, /* Date as yyyy.mmdd */
+ double time); /* Time as hh.mmssxxxx */
+ void dt2i( /* yyyy.ddmm and hh.mmsss to year, month, day, hrs, min, sec */
+ double date, /* Date as yyyy.mmdd */
+ double time, /* Time as hh.mmssxxxx */
+ int *iyr, /* year (returned) */
+ int *imon, /* month (returned) */
+ int *iday, /* day (returned) */
+ int *ihr, /* hours (returned) */
+ int *imn, /* minutes (returned) */
+ double *sec, /* seconds (returned) */
+ int ndsec); /* Number of decimal places in seconds (0=int) */
+ double dt2jd( /* yyyy.ddmm and hh.mmsss to Julian Day */
+ double date, /* Date as yyyy.mmdd */
+ double time); /* Time as hh.mmssxxxx */
+ double dt2mjd( /* yyyy.ddmm and hh.mmsss to Modified Julian Day */
+ double date, /* Date as yyyy.mmdd */
+ double time); /* Time as hh.mmssxxxx */
+ double dt2ts( /* yyyy.ddmm and hh.mmsss to seconds since 1950.0 */
+ double date, /* Date as yyyy.mmdd */
+ double time); /* Time as hh.mmssxxxx */
+ int dt2tsi( /* yyyy.ddmm and hh.mmsss to IRAF seconds since 1980-01-01 */
+ double date, /* Date as yyyy.mmdd */
+ double time); /* Time as hh.mmssxxxx */
+ time_t dt2tsu( /* yyyy.ddmm and hh.mmsss to Unix seconds since 1970-01-01 */
+ double date, /* Date as yyyy.mmdd */
+ double time); /* Time as hh.mmssxxxx */
+
+ /* Subroutines to convert from epoch (various types of fractional year) */
+
+ void ep2dt( /* Fractional year to yyyy.mmdd hh.mmssss */
+ double epoch, /* Date as fractional year */
+ double *date, /* Date as yyyy.mmdd (returned) */
+ double *time); /* Time as hh.mmssxxxx (returned) */
+ void epb2dt( /* Besselian epoch to yyyy.mmdd hh.mmssss */
+ double epoch, /* Besselian epoch (fractional 365.242198781-day years) */
+ double *date, /* Date as yyyy.mmdd (returned) */
+ double *time); /* Time as hh.mmssxxxx (returned) */
+ void epj2dt( /* Julian epoch to yyyy.mmdd hh.mmssss */
+ double epoch, /* Julian epoch (fractional 365.25-day years) */
+ double *date, /* Date as yyyy.mmdd (returned)*/
+ double *time); /* Time as hh.mmssxxxx (returned) */
+ char *ep2fd( /* Fractional year to FITS date string yyyy-mm-ddThh:mm:ss.ss */
+ double epoch); /* Date as fractional year */
+ char *epb2fd( /* Besselian epoch to FITS date string yyyy-mm-ddThh:mm:ss.ss */
+ double epoch); /* Besselian epoch (fractional 365.242198781-day years) */
+ char *epj2fd( /* Julian epoch to FITS date string yyyy-mm-ddThh:mm:ss.ss */
+ double epoch); /* Julian epoch (fractional 365.25-day years) */
+ void ep2i( /* Fractional year to year, month, day, hours, min., sec. */
+ double epoch, /* Date as fractional year */
+ int *iyr, /* year (returned) */
+ int *imon, /* month (returned) */
+ int *iday, /* day (returned) */
+ int *ihr, /* hours (returned) */
+ int *imn, /* minutes (returned) */
+ double *sec, /* seconds (returned) */
+ int ndsec); /* Number of decimal places in seconds (0=int) */
+ void epb2i( /* Besselian epoch to year, month, day, hours, min., sec. */
+ double epoch, /* Besselian epoch (fractional 365.242198781-day years) */
+ int *iyr, /* year (returned) */
+ int *imon, /* month (returned) */
+ int *iday, /* day (returned) */
+ int *ihr, /* hours (returned) */
+ int *imn, /* minutes (returned) */
+ double *sec, /* seconds (returned) */
+ int ndsec); /* Number of decimal places in seconds (0=int) */
+ void epj2i( /* Julian epoch to year, month, day, hours, min., sec. */
+ double epoch, /* Julian epoch (fractional 365.25-day years) */
+ int *iyr, /* year (returned) */
+ int *imon, /* month (returned) */
+ int *iday, /* day (returned) */
+ int *ihr, /* hours (returned) */
+ int *imn, /* minutes (returned) */
+ double *sec, /* seconds (returned) */
+ int ndsec); /* Number of decimal places in seconds (0=int) */
+ double ep2jd( /* Fractional year to Julian Date */
+ double epoch); /* Date as fractional year */
+ double epb2jd( /* Besselian epoch to Julian Date */
+ double epoch); /* Besselian epoch (fractional 365.242198781-day years) */
+ double epj2jd( /* Julian epoch to Julian Date */
+ double epoch); /* Julian epoch (fractional 365.25-day years) */
+ double ep2mjd( /* Fractional year to Modified Julian Date */
+ double epoch); /* Date as fractional year */
+ double epb2mjd( /* Besselian epoch to Modified Julian Date */
+ double epoch); /* Besselian epoch (fractional 365.242198781-day years) */
+ double epj2mjd( /* Julian epoch to Modified Julian Date */
+ double epoch); /* Julian epoch (fractional 365.25-day years) */
+ double ep2epb( /* Fractional year to Besselian epoch */
+ double epoch); /* Date as fractional year */
+ double ep2epj( /* Fractional year to Julian epoch */
+ double epoch); /* Date as fractional year */
+ double epb2epj( /* Besselian epoch to Julian epoch */
+ double epoch); /* Besselian epoch (fractional 365.242198781-day years) */
+ double epj2epb( /* Julian epoch to Besselian epoch */
+ double epoch); /* Julian epoch (fractional 365.25-day years) */
+ double epb2ep( /* Besselian epoch to fractional year */
+ double epoch); /* Besselian epoch (fractional 365.242198781-day years) */
+ double epj2ep( /* Julian epoch to fractional year */
+ double epoch); /* Julian epoch (fractional 365.25-day years) */
+ double ep2ts( /* Fractional year to seconds since 1950.0 */
+ double epoch); /* Date as fractional year */
+ double epb2ts( /* Besselian epoch to seconds since 1950.0 */
+ double epoch); /* Besselian epoch (fractional 365.242198781-day years) */
+ double epj2ts( /* Julian epoch to seconds since 1950.0 */
+ double epoch); /* Julian epoch (fractional 365.25-day years) */
+
+ /* Convert from FITS standard date string */
+
+ void fd2dt( /* FITS standard date string to date and time */
+ char *string, /* FITS date string, which may be:
+ * fractional year
+ * dd/mm/yy (FITS standard before 2000)
+ * dd-mm-yy (nonstandard use before 2000)
+ * yyyy-mm-dd (FITS standard after 1999)
+ * yyyy-mm-ddThh:mm:ss.ss (FITS standard after 1999) */
+ double *date, /* Date as yyyy.mmdd (returned)*/
+ double *time); /* Time as hh.mmssxxxx (returned) */
+ void fd2doy( /* FITS standard date string to year, day of year */
+ char *string, /* FITS date string */
+ int *year, /* Year (returned) */
+ double *doy); /* Day of year with fraction (returned) */
+ double fd2ep( /* FITS standard date string to fractional year (epoch) */
+ char *string); /* FITS date string */
+ double fd2epb( /* FITS standard date string to Besselian epoch */
+ char *string); /* FITS date string */
+ double fd2epj( /* FITS standard date string to Julian epoch */
+ char *string); /* FITS date string */
+ char *fd2fd( /* Any FITS standard date string to ISO FITS date string */
+ char *string); /* FITS date string */
+ char *fd2of( /* Any FITS standard date string to old FITS date and time */
+ char *string); /* FITS date string */
+ char *fd2ofd( /* Any FITS standard date string to old FITS date string */
+ char *string); /* FITS date string */
+ char *fd2oft( /* Any FITS standard date string to old FITS time string */
+ char *string); /* FITS date string */
+ void fd2i( /* FITS standard date string to year, mon, day, hrs, min, sec */
+ char *string, /* FITS date string */
+ int *iyr, /* year (returned) */
+ int *imon, /* month (returned) */
+ int *iday, /* day (returned) */
+ int *ihr, /* hours (returned) */
+ int *imn, /* minutes (returned) */
+ double *sec, /* seconds (returned) */
+ int ndsec); /* Number of decimal places in seconds (0=int) */
+ double fd2jd( /* FITS standard date string to Julian Day */
+ char *string); /* FITS date string */
+ double fd2mjd( /* FITS standard date string to Modified Julian Day */
+ char *string); /* FITS date string */
+ double fd2ts( /* FITS standard date to seconds since 1950-01-01 */
+ char *string); /* FITS date string */
+ int fd2tsi( /* FITS standard date to IRAF seconds since 1980-01-01 */
+ char *string); /* FITS date string */
+ time_t fd2tsu( /* FITS standard date to Unix seconds since 1970-01-01 */
+ char *string); /* FITS date string */
+
+ /* Convert from Julian Day */
+
+ void jd2doy( /* Julian Day to year and day of year */
+ double dj, /* Julian Day */
+ int *year, /* Year (returned) */
+ double *doy); /* Day of year with fraction (returned) */
+ void jd2dt( /* Julian Day to yyyy.mmdd hh.mmssss */
+ double dj, /* Julian Day */
+ double *date, /* Date as yyyy.mmdd (returned)*/
+ double *time); /* Time as hh.mmssxxxx (returned) */
+ double jd2ep( /* Julian Day to fractional year */
+ double dj); /* Julian Day */
+ double jd2epb( /* Julian Day to Besselian epoch */
+ double dj); /* Julian Day */
+ double jd2epj( /* Julian Day to Julian epoch */
+ double dj); /* Julian Day */
+ char *jd2fd( /* Julian Day to FITS date string yyyy-mm-ddThh:mm:ss.ss */
+ double dj); /* Julian Day */
+ void jd2i( /* Julian Day to year, month, day, hours, min., sec. */
+ double dj, /* Julian Day */
+ int *iyr, /* year (returned) */
+ int *imon, /* month (returned) */
+ int *iday, /* day (returned) */
+ int *ihr, /* hours (returned) */
+ int *imn, /* minutes (returned) */
+ double *sec, /* seconds (returned) */
+ int ndsec); /* Number of decimal places in seconds (0=int) */
+ double jd2mjd( /* Julian Day to Modified Julian day */
+ double dj); /* Julian Day */
+ double jd2ts( /* Julian Day to seconds since 1950.0 */
+ double dj); /* Julian Day */
+ time_t jd2tsu( /* Julian Day to Unix seconds since 1970-01-01T00:00 */
+ double dj); /* Julian Day */
+ int jd2tsi( /* Julian Day to IRAF seconds since 1980-01-01T00:00 */
+ double dj); /* Julian Day */
+
+ /* Convert current local time to various formats */
+
+ void lt2dt( /* Current local time to date (yyyy.mmdd), time (hh.mmsss) */
+ double *date, /* Date as yyyy.mmdd (returned) */
+ double *time); /* Time as hh.mmssxxxx (returned) */
+ char *lt2fd(void); /* Current local time to FITS ISO date string */
+ int lt2tsi(void); /* Current local time to IRAF seconds since 1980-01-01T00:00 */
+ time_t lt2tsu(void); /* Current local time to Unix seconds since 1970-01-01T00:00 */
+ double lt2ts(void); /* Current local time to IRAF seconds since 1950-01-01T00:00 */
+
+ /* Convert from Modified Julian Day (JD - 2400000.5) */
+
+ void mjd2doy( /* Modified Julian Day to year and day of year */
+ double dj, /* Modified Julian Day */
+ int *year, /* Year (returned) */
+ double *doy); /* Day of year with fraction (returned) */
+ void mjd2dt( /* Modified Julian Day to yyyy.mmdd hh.mmssss */
+ double dj, /* Modified Julian Date */
+ double *date, /* Date as yyyy.mmdd (returned)*/
+ double *time); /* Time as hh.mmssxxxx (returned) */
+ double mjd2ep( /* Modified Julian Day to fractional year */
+ double dj); /* Modified Julian Date */
+ double mjd2epb( /* Modified Julian Day to Besselian epoch */
+ double dj); /* Modified Julian Date */
+ double mjd2epj( /* Modified Julian Day to Julian epoch */
+ double dj); /* Modified Julian Date */
+ char *mjd2fd( /* Modified Julian Day to FITS date yyyy-mm-ddThh:mm:ss.ss */
+ double dj); /* Modified Julian Date */
+ void mjd2i( /* Modified Julian Day to year, month, day, hours, min, sec */
+ double dj, /* Modified Julian Date */
+ int *iyr, /* year (returned) */
+ int *imon, /* month (returned) */
+ int *iday, /* day (returned) */
+ int *ihr, /* hours (returned) */
+ int *imn, /* minutes (returned) */
+ double *sec, /* seconds (returned) */
+ int ndsec); /* Number of decimal places in seconds (0=int) */
+ double mjd2jd( /* Modified Julian Day to Julian day */
+ double dj); /* Modified Julian Date */
+ double mjd2ts( /* Modified Julian Day to seconds since 1950.0 */
+ double dj); /* Modified Julian Date */
+
+ /* Convert from seconds since 1950-01-01 0:00 (JPL Ephemeris time) */
+
+ void ts2dt( /* Seconds since 1950.0 to yyyy.mmdd hh.mmssss */
+ double tsec, /* seconds since 1950.0 */
+ double *date, /* Date as yyyy.mmdd (returned)*/
+ double *time); /* Time as hh.mmssxxxx (returned) */
+ double ts2ep( /* Seconds since 1950.0 to fractional year */
+ double tsec); /* seconds since 1950.0 */
+ double ts2epb( /* Seconds since 1950.0 to Besselian epoch */
+ double tsec); /* seconds since 1950.0 */
+ double ts2epj( /* Seconds since 1950.0 to Julian epoch */
+ double tsec); /* seconds since 1950.0 */
+ char *ts2fd( /* Seconds since 1950.0 to FITS date, yyyy-mm-ddT00:00:00.000 */
+ double tsec); /* seconds since 1950.0 */
+ void ts2i( /* Seconds since 1950.0 to year, month, day, hours, min, sec */
+ double tsec, /* seconds since 1950.0 */
+ int *iyr, /* year (returned) */
+ int *imon, /* month (returned) */
+ int *iday, /* day (returned) */
+ int *ihr, /* hours (returned) */
+ int *imn, /* minutes (returned) */
+ double *sec, /* seconds (returned) */
+ int ndsec); /* Number of decimal places in seconds (0=int) */
+ double ts2jd( /* Seconds since 1950.0 to Julian Day */
+ double tsec); /* seconds since 1950.0 */
+ double ts2mjd( /* Seconds since 1950.0 to Modified Julian Day */
+ double tsec); /* seconds since 1950.0 */
+
+ /* Convert from IRAF time (seconds since 1980-01-01 0:00 UT) */
+
+ char *tsi2fd( /* Seconds since 1980-01-01 to FITS standard date string */
+ int isec); /* Seconds past 1980-01-01 */
+ double tsi2ts( /* Seconds since 1980-01-01 to seconds since 1950-01-01 */
+ int isec); /* Seconds past 1980-01-01 */
+ void tsi2dt( /* Seconds since 1980-01-01 to date yyyy.mmdd, time hh.mmssss */
+ int isec, /* Seconds past 1980-01-01 */
+ double *date, /* Date as yyyy.mmdd (returned) */
+ double *time); /* Time as hh.mmssxxxx (returned) */
+
+ /* Convert from Unix time (seconds since 1970-01-01 0:00 UT) */
+
+ void tsu2dt( /* Seconds since 1970-01-01 to date yyyy.ddmm, time hh.mmsss */
+ time_t isec, /* Seconds past 1970-01-01 */
+ double *date, /* Date as yyyy.mmdd (returned) */
+ double *time); /* Time as hh.mmssxxxx (returned) */
+ char *tsu2fd( /* Seconds since 1970-01-01 to FITS standard date string */
+ time_t isec); /* Seconds past 1970-01-01 */
+ double tsu2ts( /* Seconds since 1970-01-01 to seconds since 1950-01-01 */
+ time_t isec); /* Seconds past 1970-01-01 */
+ int tsu2tsi( /* Seconds since 1970-01-01 to local seconds since 1980-01-01 */
+ time_t isec); /* Seconds past 1970-01-01 */
+
+ /* Convert times within a day */
+
+ char *tsd2fd( /* Seconds since start of day to FITS standard time string */
+ double tsec); /* Seconds since start of day */
+ double tsd2dt( /* Seconds since start of day to hh.mmsssss */
+ double tsec); /* Seconds since start of day */
+
+ /* Convert from current Universal Time */
+
+ void ut2dt( /* Current Universal Time to date (yyyy.mmdd), time (hh.mmsss) */
+ double *date, /* Date as yyyy.mmdd (returned) */
+ double *time); /* Time as hh.mmssxxxx (returned) */
+ void ut2doy( /* Current Universal Time to year, day of year */
+ int *year, /* Year (returned) */
+ double *doy); /* Day of year (returned) */
+ double ut2ep(void); /* Current Universal Time to fractional year */
+ double ut2epb(void); /* Current Universal Time to Besselian Epoch */
+ double ut2epj(void); /* Current Universal Time to Julian Epoch */
+ char *ut2fd(void); /* Current Universal Time to FITS ISO date string */
+ double ut2jd(void); /* Current Universal Time to Julian Date */
+ double ut2mjd(void); /* Current Universal Time to Modified Julian Date */
+ int ut2tsi(void); /* Current UT to IRAF seconds since 1980-01-01T00:00 */
+ time_t ut2tsu(void); /* Current UT to Unix seconds since 1970-01-01T00:00 */
+ double ut2ts(void); /* Current UT to seconds since 1950-01-01T00:00 */
+
+ int isdate( /* Return 1 if string is FITS old or ISO date */
+ char *string); /* Possible FITS date string, which may be:
+ * dd/mm/yy (FITS standard before 2000)
+ * dd-mm-yy (nonstandard FITS use before 2000)
+ * yyyy-mm-dd (FITS standard after 1999)
+ * yyyy-mm-ddThh:mm:ss.ss (FITS standard after 1999) */
+
+ /* Ephemeris time conversions (ET, TT, and TDT) */
+
+ char *et2fd( /* ET (or TDT or TT) in FITS format to UT in FITS format */
+ char *string); /* Ephemeris Time as FITS date string (E not T) */
+ char *fd2et( /* UT in FITS format to ET (or TDT or TT) in FITS format */
+ char *string); /* FITS date string */
+ void dt2et( /* yyyy.ddmm and hh.mmsss to Ephemeris Time */
+ double *date, /* Date as yyyy.mmdd */
+ double *time); /* Time as hh.mmssxxxx
+ *if time<0, it is time as -(fraction of a day) */
+ double jd2jed( /* Convert from Julian Date to Julian Ephemeris Date */
+ double dj); /* Julian Date */
+ double jed2jd( /* Convert from Julian Ephemeris Date to Julian Date */
+ double dj); /* Julian Ephemeris Date */
+ double ets2ts( /* ET in seconds since 1950-01-01 to UT in same format */
+ double tsec); /* ET in seconds since 1950-01-01 */
+ double ts2ets( /* UT in seconds since 1950-01-01 to ET in same format */
+ double tsec); /* UT in seconds since 1950-01-01 */
+ void edt2dt( /* yyyy.ddmm and hh.mmsss Ephemeris Time to UT */
+ double *date, /* Date as yyyy.mmdd */
+ double *time); /* Time as hh.mmssxxxx
+ * If time<0, it is time as -(fraction of a day) */
+ double utdt( /* Compute difference between UT and dynamical time (ET-UT) */
+ double dj); /* Julian Date (UT) */
+
+ /* Sidereal Time conversions */
+
+ char *fd2gst( /* Convert from FITS UT date to Greenwich Sidereal Time */
+ char *string); /* FITS date string */
+ void dt2gst( /* Convert from UT as yyyy.mmdd hh.mmssss to Greenwich Sidereal Time */
+ double *date, /* Date as yyyy.mmdd */
+ double *time); /* Time as hh.mmssxxxx
+ * If time<0, it is time as -(fraction of a day) */
+ double jd2gst( /* Calculate Greenwich Sidereal Time given Julian Date */
+ double dj); /* Julian Date (UT) */
+ double ts2gst( /* Calculate Greenwich Sidereal Time given Universal Time */
+ double tsec); /* Time since 1950.0 in UT seconds */
+ char *fd2lst( /* Convert from FITS UT date to Local Sidereal Time */
+ char *string); /* FITS date string */
+ void dt2lst( /* Convert from UT as yyyy.mmdd hh.mmssss to Local Sidereal Time */
+ double *date, /* Date as yyyy.mmdd */
+ double *time); /* Time as hh.mmssxxxx
+ * If time<0, it is time as -(fraction of a day) */
+ double ts2lst( /* Calculate Local Sidereal Time given Universal Time */
+ double tsec); /* Time since 1950.0 in UT seconds */
+ double jd2lst( /* Calculate Local Sidereal Time given Julian Date */
+ double dj); /* Julian Date (UT) */
+ double eqeqnx( /* Compute equation of eqinoxes from Julian Date */
+ double dj); /* Julian Date (UT) */
+ char *fd2mst( /* Convert from FITS UT date to Mean Sidereal Time */
+ char *string); /* FITS date string */
+ double jd2mst( /* Convert from Julian Date to Mean Sidereal Time */
+ double dj); /* Julian Date (UT) */
+ double jd2mst2( /* Convert from Julian Date to Mean Sidereal Time */
+ double dj); /* Julian Date (UT) */
+ void dt2mst( /* Convert from UT as yyyy.mmdd hh.mmssss to Mean Sidereal Time */
+ double *date, /* Date as yyyy.mmdd */
+ double *time); /* Time as hh.mmssxxxx
+ * If time<0, it is time as -(fraction of a day) */
+ double lst2dt( /* Calculate UT as hh.mmsss given UT date and
+ * Local Sidereal Time */
+ double date0, /* UT date as yyyy.mmdd */
+ double time0); /* LST as hh.mmssss */
+ double lst2jd( /* Calculate UT as Julian Date given UT date and
+ * Local Sidereal Time */
+ double sdj); /* Julian Date of desired day at 0:00 UT + sidereal time */
+ char *lst2fd( /* Calculate FITS UT date and time given UT date and
+ * Local Sidereal Time */
+ char *string); /* UT Date, LST as yyyy-mm-ddShh:mm:ss.ss */
+ char *gst2fd( /* Calculate FITS UT date and time given Greenwich Sidereal Time */
+ char *string); /* UT Date, GST as yyyy-mm-ddShh:mm:ss.ss */
+ double gst2jd( /* Calculate FITS UT Julian Date given Greenwich Sidereal Time */
+ double sdj); /* UT Date, GST as Julian Date */
+ char *mst2fd( /* Calculate FITS UT date and time given Mean Sidereal Time */
+ char *string); /* UT Date, MST as yyyy-mm-ddShh:mm:ss.ss */
+ double mst2jd( /* Calculate FITS UT Julian Date given Mean Sidereal Time */
+ double sdj); /* UT Date, MST as Julian Date */
+ double ts2mst( /* Calculate Mean Sidereal Time given Universal Time */
+ double tsec); /* time since 1950.0 in UT seconds */
+ void setlongitude( /* Longitude for sidereal time in or out */
+ double longitude); /* longitude of observatory in degrees (+=west) */
+ void compnut( /* Compute nutation in longitude and obliquity and mean obliquity*/
+ double dj, /* TDB (loosely ET or TT) as Julian Date */
+ double *dpsi, /* Nutation in longitude in radians (returned) */
+ double *deps, /* Nutation in obliquity in radians (returned) */
+ double *eps0); /* Mean obliquity in radians (returned) */
+
+ /* Heliocentric Julian Date conversions */
+
+ double mjd2mhjd( /* Convert from Modified Julian Date to Heliocentric MJD */
+ double mjd, /* Julian date (geocentric) */
+ double ra, /* Right ascension (degrees) */
+ double dec, /* Declination (degrees) */
+ int sys); /* J2000, B1950, GALACTIC, ECLIPTIC */
+ double mjd2hjd( /* Convert from Modified Julian Date to Heliocentric JD */
+ double mjd, /* Julian date (geocentric) */
+ double ra, /* Right ascension (degrees) */
+ double dec, /* Declination (degrees) */
+ int sys); /* J2000, B1950, GALACTIC, ECLIPTIC */
+ double mhjd2mjd( /* Convert from Heliocentric Modified Julian Date to MJD */
+ double mhjd, /* Modified Heliocentric Julian date */
+ double ra, /* Right ascension (degrees) */
+ double dec, /* Declination (degrees) */
+ int sys); /* J2000, B1950, GALACTIC, ECLIPTIC */
+ double jd2hjd( /* Convert from Julian Date to Heliocentric Julian Date */
+ double dj, /* Julian date (geocentric) */
+ double ra, /* Right ascension (degrees) */
+ double dec, /* Declination (degrees) */
+ int sys); /* J2000, B1950, GALACTIC, ECLIPTIC */
+ double hjd2jd( /* Convert from Heliocentric Julian Date to Julian Date */
+ double dj, /* Heliocentric Julian date */
+ double ra, /* Right ascension (degrees) */
+ double dec, /* Declination (degrees) */
+ int sys); /* J2000, B1950, GALACTIC, ECLIPTIC */
+
+ void setdatedec( /* Set number of decimal places in FITS dates */
+ int nd); /* Number of decimal places in FITS dates */
+
+#else /* K&R prototypes */
+
+/* FITS file access subroutines in fitsfile.c */
+extern int fitsropen();
+extern char *fitsrhead();
+extern char *fitsrtail();
+extern char *fitsrimage();
+extern char *fitsrfull();
+extern char *fitsrsect();
+extern int fitswhead();
+extern int fitswexhead();
+extern int fitswext();
+extern int fitswhdu();
+extern int fitswimage();
+extern int fitscimage();
+extern int isfits(); /* Return 1 if file is a FITS file */
+extern void fitserr(); /* Print FITS error message to stderr */
+extern void setfitsinherit(); /* Set flag to append primary data header */
+extern int fitsheadsize(); /* Return size of fitsheader in bytes */
+
+/* FITS table file access subroutines in fitsfile.c */
+extern int fitsrtopen();
+extern int fitsrthead();
+extern void fitsrtlset();
+extern int fitsrtline();
+extern short ftgeti2();
+extern int ftgeti4();
+extern float ftgetr4();
+extern double ftgetr8();
+extern int ftgetc();
+extern void moveb(); /* Copy nbytes bytes from source+offs to dest+offd */
+
+/* IRAF file access subroutines in imhfile.c */
+extern char *irafrhead();
+extern char *irafrimage();
+extern int irafwhead();
+extern int irafwimage();
+extern int isiraf();
+extern char *iraf2fits();
+extern char *fits2iraf();
+
+/* Image pixel access subroutines in imio.c */
+extern double getpix(); /* Read one pixel from any data type 2-D array (0,0)*/
+extern double getpix1(); /* Read one pixel from any data type 2-D array (1,1)*/
+extern double maxvec(); /* Get maximum value in vector from a image */
+extern double minvec(); /* Get minimum value in vector from a image */
+extern void putpix(); /* Write one pixel to any data type 2-D array (0,0)*/
+extern void putpix1(); /* Write one pixel to any data type 2-D array (1,1) */
+extern void addpix(); /* Add to one pixel in any data type 2-D array (0,0)*/
+extern void addpix1(); /* Add to one pixel in any data type 2-D array (1,1)*/
+extern void movepix(); /* Move one pixel value between two 2-D arrays (0,0) */
+extern void movepix1(); /* Move one pixel value between two 2-D arrays (1,1) */
+extern void addvec(); /* Add constant to vector from 2-D array */
+extern void multvec(); /* Multiply vector from 2-D array by a constant */
+extern void getvec(); /* Read vector from 2-D array */
+extern void putvec(); /* Write vector into 2-D array */
+extern void fillvec(); /* Write constant into a vector */
+extern void fillvec1(); /* Write constant into a vector */
+extern void imswap(); /* Swap alternating bytes in a vector */
+extern void imswap2(); /* Swap bytes in a vector of 2-byte (short) integers */
+extern void imswap4(); /* Reverse bytes in a vector of 4-byte numbers */
+extern void imswap8(); /* Reverse bytes in a vector of 8-byte numbers */
+extern int imswapped(); /* Return 1 if machine byte order is not FITS order */
+
+/* File utilities from fileutil.c */
+extern int getfilelines();
+extern char *getfilebuff();
+extern int getfilesize();
+extern int isimlist();
+extern int isimlistd();
+extern int isfilelist();
+extern int isfile();
+extern int istiff();
+extern int isjpeg();
+extern int isgif();
+extern int first_token();
+
+/* Subroutines for access to tokens within a string from fileutil.c */
+int setoken(); /* Tokenize a string for easy decoding */
+int nextoken(); /* Get next token from tokenized string */
+int getoken(); /* Get specified token from tokenized string */
+
+/* Subroutines for translating dates and times in dateutil.c */
+
+void ang2hr(); /* Fractional degrees to hours as hh:mm:ss.ss */
+void ang2deg(); /* Fractional degrees to degrees as dd:mm:ss.ss */
+double deg2ang(); /* Degrees as dd:mm:ss.ss to fractional degrees */
+double hr2ang(); /* Hours as hh:mm:ss.ss to fractional degrees */
+
+void doy2dt(); /* year and day of year to yyyy.mmdd hh.mmss */
+double doy2ep(); /* year and day of year to fractional year (epoch) */
+double doy2epb(); /* year and day of year to Besselian epoch */
+double doy2epj(); /* year and day of year to Julian epoch */
+char *doy2fd(); /* year and day of year to FITS date */
+double doy2jd(); /* year and day of year to Julian date */
+double doy2mjd(); /* year and day of year to modified Julian date */
+double doy2ts(); /* year and day of year to seconds since 1950.0 */
+int doy2tsi(); /* year and day of year to IRAF seconds since 1980-01-01 */
+
+time_t doy2tsu(); /* year and day of year to Unix seconds since 1970-01-01 */
+void dt2doy(); /* yyyy.mmdd hh.mmss to year and day of year */
+double dt2ep(); /* yyyy.ddmm and hh.mmsss to fractional year (epoch) */
+double dt2epb(); /* yyyy.ddmm and hh.mmsss to Besselian epoch */
+double dt2epj(); /* yyyy.ddmm and hh.mmsss to Julian epoch */
+char *dt2fd(); /* yyyy.ddmm and hh.mmsss to FITS date string */
+void dt2i(); /* yyyy.ddmm and hh.mmsss to year, month, day, hrs, min, sec */
+double dt2jd(); /* yyyy.ddmm and hh.mmsss to Julian date */
+double dt2mjd(); /* yyyy.ddmm and hh.mmsss to modified Julian date */
+double dt2ts(); /* yyyy.ddmm and hh.mmsss to seconds since 1950.0 */
+int dt2tsi(); /* yyyy.ddmm and hh.mmsss to IRAF seconds since 1980-01-01 */
+time_t dt2tsu(); /* yyyy.ddmm and hh.mmsss to Unix seconds since 1970-01-01 */
+
+void ep2dt(); /* Fractional year to yyyy.mmdd hh.mmssss */
+void epb2dt(); /* Besselian epoch to yyyy.mmdd hh.mmssss */
+void epj2dt(); /* Julian epoch to yyyy.mmdd hh.mmssss */
+char *ep2fd(); /* Fractional year to FITS date string yyyy-mm-ddThh:mm:ss.ss */
+char *epb2fd(); /* Besselian epoch to FITS date string yyyy-mm-ddThh:mm:ss.ss */
+char *epj2fd(); /* Julian epoch to FITS date string yyyy-mm-ddThh:mm:ss.ss */
+void ep2i(); /* Fractional year to year, month, day, hours, min., sec. */
+void epb2i(); /* Besselian epoch to year, month, day, hours, min., sec. */
+void epj2i(); /* Julian epoch to year, month, day, hours, min., sec. */
+double ep2jd(); /* Fractional year to Julian Date */
+double epb2jd(); /* Besselian epoch to Julian Date */
+double epj2jd(); /* Julian epoch to Julian Date */
+double ep2mjd(); /* Fractional year to modified Julian Date */
+double epb2mjd(); /* Besselian epoch to modified Julian Date */
+double epj2mjd(); /* Julian epoch to modified Julian Date */
+double ep2epb(); /* Fractional year to Besselian epoch */
+double ep2epj(); /* Fractional year to Julian epoch */
+double epb2epj(); /* Besselian epoch to Julian epoch */
+double epj2epb(); /* Julian epoch to Besselian epoch */
+double epb2ep(); /* Besselian epoch to fractional year */
+double epj2ep(); /* Julian epoch to fractional year */
+double ep2ts(); /* Fractional year to seconds since 1950.0 */
+double epb2ts(); /* Besselian epoch to seconds since 1950.0 */
+double epj2ts(); /* Julian epoch to seconds since 1950.0 */
+
+void fd2dt(); /* FITS standard date string to Julian date */
+void fd2doy(); /* FITS standard date string to year, day of year */
+double fd2ep(); /* FITS standard date string to fractional year (epoch) */
+double fd2epb(); /* FITS standard date string to Besselian epoch */
+double fd2epj(); /* FITS standard date string to Julian epoch */
+char *fd2fd(); /* Any FITS standard date string to ISO FITS date string */
+char *fd2of(); /* Any FITS standard date string to old FITS date and time */
+char *fd2ofd(); /* Any FITS standard date string to old FITS date string */
+char *fd2oft(); /* Any FITS standard date string to old FITS time string */
+void fd2i(); /* FITS standard date string to year, mon, day, hrs, min, sec */
+double fd2jd(); /* FITS standard date string to Julian date */
+double fd2mjd(); /* FITS standard date string to modified Julian date */
+double fd2ts(); /* FITS standard date to seconds since 1950-01-01 */
+int fd2tsi(); /* FITS standard date to IRAF seconds since 1980-01-01 */
+time_t fd2tsu(); /* FITS standard date to Unix seconds since 1970-01-01 */
+void jd2doy(); /* Julian date to year and day of year */
+void jd2dt(); /* Julian date to yyyy.mmdd hh.mmssss */
+double jd2ep(); /* Julian date to fractional year */
+double jd2epb(); /* Julian date to Besselian epoch */
+double jd2epj(); /* Julian date to Julian epoch */
+char *jd2fd(); /* Julian date to FITS date string yyyy-mm-ddThh:mm:ss.ss */
+void jd2i(); /* Julian date to year, month, day, hours, min., sec. */
+double jd2mjd(); /* Julian date to modified Julian date */
+double jd2ts(); /* Julian date to seconds since 1950.0 */
+time_t jd2tsu(); /* Julian date to Unix seconds since 1970-01-01T00:00 */
+int jd2tsi(); /* Julian date to IRAF seconds since 1980-01-01T00:00 */
+
+void lt2dt(); /* Current local time to date (yyyy.mmdd), time (hh.mmsss) */
+char *lt2fd(); /* Current local time to FITS ISO date string */
+int lt2tsi(); /* Current local time to IRAF seconds since 1980-01-01T00:00 */
+time_t lt2tsu(); /* Current local time to Unix seconds since 1970-01-01T00:00 */
+double lt2ts(); /* Current local time to IRAF seconds since 1950-01-01T00:00 */
+
+void mjd2doy(); /* Convert from Modified Julian Date to Day of Year */
+void mjd2dt(); /* Modified Julian date to yyyy.mmdd hh.mmssss */
+double mjd2ep(); /* Modified Julian date to fractional year */
+double mjd2epb(); /* Modified Julian date to Besselian epoch */
+double mjd2epj(); /* Modified Julian date to Julian epoch */
+char *mjd2fd(); /* Modified Julian date to FITS date yyyy-mm-ddThh:mm:ss.ss */
+void mjd2i(); /* Modified Julian date to year, month, day, hours, min, sec */
+double mjd2jd(); /* Modified Julian date to Julian date */
+double mjd2ts(); /* Modified Julian date to seconds since 1950.0 */
+
+void ts2dt(); /* Seconds since 1950.0 to yyyy.mmdd hh.mmssss */
+double ts2ep(); /* Seconds since 1950.0 to fractional year */
+double ts2epb(); /* Seconds since 1950.0 to Besselian epoch */
+double ts2epj(); /* Seconds since 1950.0 to Julian epoch */
+char *ts2fd(); /* Seconds since 1950.0 to FITS date, yyyy-mm-ddT00:00:00.000 */
+void ts2i(); /* Seconds since 1950.0 to year, month, day, hours, min, sec */
+double ts2jd(); /* Seconds since 1950.0 to Julian date */
+double ts2mjd(); /* Seconds since 1950.0 to modified Julian date */
+char *tsi2fd(); /* Seconds since 1980-01-01 to FITS standard date string */
+double tsi2ts(); /* Seconds since 1980-01-01 to seconds since 1950-01-01 */
+double tsi2ts(); /* Seconds since 1980-01-01 to seconds since 1950-01-01 */
+void tsi2dt(); /* Seconds since 1980-01-01 to date yyyy.mmdd, time hh.mmssss */
+void tsu2dt(); /* Seconds since 1970-01-01 to date yyyy.ddmm, time hh.mmsss */
+char *tsu2fd(); /* Seconds since 1970-01-01 to FITS standard date string */
+char *tsd2fd(); /* Seconds since start of day to FITS standard time string */
+double tsd2dt(); /* Seconds since start of day to hh.mmsssss */
+double tsu2ts(); /* Seconds since 1970-01-01 to seconds since 1950-01-01 */
+int tsu2tsi(); /* Seconds since 1970-01-01 to local seconds since 1980-01-01 */
+int isdate(); /* Return 1 if string is FITS old or ISO date */
+void ut2dt(); /* Current Universal Time to date (yyyy.mmdd), time (hh.mmsss) */
+void ut2doy(); /* Current Universal Time to year, day of year */
+double ut2ep(); /* Current Universal Time to fractional year */
+double ut2epb(); /* Current Universal Time to Besselian Epoch */
+double ut2epj(); /* Current Universal Time to Julian Epoch */
+char *ut2fd(); /* Current Universal Time to FITS ISO date string */
+double ut2jd(); /* Current Universal Time to Julian Date */
+double ut2mjd(); /* Current Universal Time to Modified Julian Date */
+int ut2tsi(); /* Current UT to IRAF seconds since 1980-01-01T00:00 */
+time_t ut2tsu(); /* Current UT to Unix seconds since 1970-01-01T00:00 */
+double ut2ts(); /* Current UT to IRAF seconds since 1950-01-01T00:00 */
+int sts2c(); /* Replaces spaces in a string with a specified character */
+int stc2s(); /* Replaces a specified character in a string with spaces */
+char *et2fd(); /* ET (or TDT or TT) in FITS format to UT in FITS format */
+char *fd2et(); /* UT in FITS format to ET (or TDT or TT) in FITS format */
+double jd2jed(); /* Convert from Julian Date to Julian Ephemeris Date */
+double jed2jd(); /* Convert from Julian Ephemeris Date to Julian Date */
+double ets2ts(); /* ET in seconds since 1950-01-01 to UT in same format */
+double ts2ets(); /* UT in seconds since 1950-01-01 to ET in same format */
+void dt2et(); /* yyyy.ddmm and hh.mmsss to Ephemeris Time */
+void edt2dt(); /* yyyy.ddmm and hh.mmsss Ephemeris Time to UT */
+double utdt(); /* Compute difference between UT and dynamical time (ET-UT) */
+char *fd2gst(); /* Convert from FITS UT date to Greenwich Sidereal Time */
+void dt2gst(); /* Convert from UT as yyyy.mmdd hh.mmssss to Greenwich Sidereal Time */
+double jd2gst(); /* Calculate Greenwich Sidereal Time given Julian Date */
+double ts2gst(); /* Calculate Greenwich Sidereal Time given Universal Time */
+char *fd2lst(); /* Convert from FITS UT date to Local Sidereal Time */
+void dt2lst(); /* Convert from UT as yyyy.mmdd hh.mmssss to Local Sidereal Time */
+double ts2lst(); /* Calculate Local Sidereal Time given Universal Time */
+double jd2lst(); /* Calculate Local Sidereal Time given Julian Date */
+double eqeqnx(); /* Compute equation of eqinoxes from Julian Date */
+char *fd2mst(); /* Convert from FITS UT date to Mean Sidereal Time */
+double jd2mst(); /* Convert from Julian Date to Mean Sidereal Time */
+double jd2mst2(); /* Convert from Julian Date to Mean Sidereal Time */
+void dt2mst(); /* Convert from UT as yyyy.mmdd hh.mmssss to Mean Sidereal Time */
+double lst2ts(); /* Calculate Universal Time given Local Sidereal Time */
+double lst2dt(); /* Calculate UT as yyyy.mmdd hh.mmsss given UT date and Local Sidereal Time */
+double lst2jd(); /* Calculate UT as Julian Date given UT date and Local Sidereal Time */
+char *lst2fd(); /* Calculate FITS UT date and time given UT date and Local Sidereal Time */
+char *gst2fd(); /* Calculate FITS UT date and time given Greenwich Sidereal Time */
+double gst2jd(); /* Calculate FITS UT Julian Date given Greenwich Sidereal Time */
+char *mst2fd(); /* Calculate FITS UT date and time given Mean Sidereal Time */
+double mst2jd(); /* Calculate FITS UT Julian Date given Mean Sidereal Time */
+char *fd2mst(); /* Convert from FITS UT date to Mean Sidereal Time */
+void dt2mst(); /* Convert from UT as yyyy.mmdd hh.mmssss to Mean Sidereal Time */
+double ts2mst(); /* Calculate Mean Sidereal Time given Universal Time */
+double mjd2mhjd(); /* Convert from Modified Julian Date to Heliocentric MJD */
+double mjd2hjd(); /* Convert from Modified Julian Date to Heliocentric JD */
+double mhjd2mjd(); /* Convert from Heliocentric Modified Julian Date to MJD */
+double jd2hjd(); /* Convert from Julian Date to Heliocentric Julian Date */
+double jd2mhjd(); /* Convert from Julian Date to Modified Heliocentric JD */
+double hjd2jd(); /* Convert from Heliocentric Julian Date to Julian Date */
+double hjd2mjd(); /* Convert from Heliocentric Julian Date to Modified JD */
+double hjd2mhjd(); /* Convert from Heliocentric Julian Date to Modified HJD */
+void setdatedec(); /* Set number of decimal places in FITS dates */
+void setlongitude(); /* Longitude for sidereal time in or out */
+
+void compnut(); /* Compute nutation in longitude and obliquity and mean obliquity*/
+
+#endif /* __STDC__ */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* fitsfile_h_ */
+
+/* May 31 1996 Use stream I/O for reading as well as writing
+ * Jun 12 1996 Add byte-swapping subroutines
+ * Jul 10 1996 FITS header now allocated in subroutines
+ * Jul 17 1996 Add FITS table column extraction subroutines
+ * Aug 6 1996 Add MOVEPIX, HDEL and HCHANGE declarations
+ *
+ * Oct 10 1997 FITS file opening subroutines now return int instead of FILE *
+ *
+ * May 27 1998 Split off fitsio and imhio subroutines to fitsio.h
+ * Jun 4 1998 Change fits2iraf from int to int *
+ * Jul 24 1998 Make IRAF header char instead of int
+ * Aug 18 1998 Change name to fitsfile.h from fitsio.h
+ * Oct 5 1998 Add isiraf() and isfits()
+ * Oct 7 1998 Note separation of imhfile.c into two files
+ *
+ * Jul 15 1999 Add fileutil.c subroutines
+ * Sep 28 1999 Add (1,1)-based image access subroutines
+ * Oct 21 1999 Add fitswhead()
+ * Nov 2 1999 Add date utilities from wcscat.h
+ * Nov 23 1999 Add fitscimage()
+ * Dec 15 1999 Fix misdeclaration of *2fd() subroutines, add fd2i(), dt2i()
+ * Dec 20 1999 Add isdate()
+ *
+ * Jan 20 2000 Add conversions to and from Besselian and Julian epochs
+ * Jan 21 2000 Add conversions to old FITS date and time
+ * Jan 26 2000 Add conversion to modified Julian date (JD - 2400000.5
+ * Mar 22 2000 Add lt2* and ut2* to get current time as local and UT
+ * Mar 24 2000 Add tsi2* and tsu2* to convert IRAF and Unix seconds
+ * Sep 8 2000 Improve comments
+ *
+ * Apr 24 2001 Add length of column name to column data structure
+ * May 22 2001 Add day of year date conversion subroutines
+ * Sep 25 2001 Add isfilelist() and isfile()
+ *
+ * Jan 8 2002 Add sts2c() and stc2s()
+ * Apr 8 2002 Change all long declarations to time_t for compatibility
+ * Jun 18 2002 Add fitserr() to print error messages
+ * Aug 30 2002 Add Ephemeris Time date conversions
+ * Sep 10 2002 Add Sidereal Time conversions
+ * Oct 21 2002 Add fitsrsect() to read sections of FITS images
+ *
+ * Mar 5 2003 Add isimlistd() to check image lists with root directory
+ * Aug 20 2003 Add fitsrfull() to read n-dimensional simple FITS images
+ *
+ * Feb 27 2004 Add fillvec() and fillvec1()
+ * May 3 2004 Add setfitsinherit()
+ * May 6 2004 Add fitswexhead()
+ * Aug 27 2004 Add fitsheadsize()
+ *
+ * Oct 14 2005 Add tsd2fd(), tsd2dt(), epj2ep(), epb2ep(), tsi2dt()
+ *
+ * Feb 23 2006 Add fitsrtail() to read appended FITS header
+ * Feb 23 2006 Add istiff(), isjpeg(), isgif() to check TIFF, JPEG, GIF files
+ * Sep 6 2006 Add heliocentric time conversions
+ * Oct 5 2006 Add local sidereal time conversions
+ *
+ * Jan 9 2007 Add ANSI prototypes
+ * Jan 11 2007 Add token subroutines from catutil.c/wcscat.h to fileutil.c
+ * Jun 11 2007 Add minvec() subroutine in imio.c
+ * Nov 28 2007 Add kform format to FITS table keyword data structure
+ *
+ * Sep 8 2008 Add ag2hr(), ang2deg(), deg2ang(), and hr2ang()
+ *
+ * Sep 25 2009 Add moveb()
+ */
diff --git a/funtools/wcs/fitshead.h b/funtools/wcs/fitshead.h
new file mode 100644
index 0000000..1212709
--- /dev/null
+++ b/funtools/wcs/fitshead.h
@@ -0,0 +1,438 @@
+/*** File fitshead.h FITS header access subroutines
+ *** January 9, 2007
+ *** By Jessica Mink, jmink@cfa.harvard.edu
+ *** Harvard-Smithsonian Center for Astrophysics
+ *** Copyright (C) 1996-2007
+ *** Smithsonian Astrophysical Observatory, Cambridge, MA, USA
+
+ This library 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 2 of the License, or (at your option) any later version.
+
+ This library 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 this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Correspondence concerning WCSTools should be addressed as follows:
+ Internet email: jmink@cfa.harvard.edu
+ Postal address: Jessica Mink
+ Smithsonian Astrophysical Observatory
+ 60 Garden St.
+ Cambridge, MA 02138 USA
+ */
+
+/* Declarations for subroutines in hget.c, hput.c, and iget.c */
+
+#ifndef _fitshead_h_
+#define _fitshead_h_
+
+#include <sys/types.h>
+
+#ifdef __cplusplus /* C++ prototypes */
+extern "C" {
+#endif
+
+
+#ifdef __STDC__ /* Full ANSI prototypes */
+
+/* Subroutines in hget.c */
+ int hgeti2( /* Extract short value from FITS header */
+ const char* hstring, /* FITS header string */
+ const char* keyword, /* FITS keyword */
+ short* val); /* short integer value (returned) */
+ int hgeti4c( /* Extract int value from FITS header */
+ const char* hstring, /* FITS header string */
+ const char* keyword, /* FITS keyword */
+ const char* wchar, /* WCS to use (A-Z or null) */
+ int* val); /* integer value (returned) */
+ int hgeti4( /* Extract int value from FITS header */
+ const char* hstring, /* FITS header string */
+ const char* keyword, /* FITS keyword */
+ int* val); /* integer value (returned) */
+ int hgetr4( /* Extract float value from FITS header */
+ const char* hstring, /* FITS header string */
+ const char* keyword, /* FITS keyword */
+ float* val); /* float value (returned) */
+ int hgetr8c( /* Extract double value from FITS header */
+ const char* hstring, /* FITS header string */
+ const char* keyword, /* FITS keyword */
+ const char* wchar, /* WCS to use (A-Z or null) */
+ double* val); /* double value (returned) */
+ int hgetr8( /* Extract double value from FITS header */
+ const char* hstring, /* FITS header string */
+ const char* keyword, /* FITS keyword */
+ double* val); /* double value (returned) */
+ int hgetra( /* Extract right ascension from FITS header */
+ const char* hstring, /* FITS header string */
+ const char* keyword, /* FITS keyword */
+ double* ra); /* RA in degrees (returned) */
+ int hgetdec( /* Extract declination from FITS header */
+ const char* hstring, /* FITS header string */
+ const char* keyword, /* FITS keyword */
+ double* dec); /* Dec in degrees (returned) */
+ int hgetdate( /* Extract date from FITS header */
+ const char* hstring, /* FITS header string */
+ const char* keyword, /* FITS keyword */
+ double* date); /* Date in fractional years (returned) */
+ int hgetl( /* Extract boolean value from FITS header */
+ const char* hstring, /* FITS header string */
+ const char* keyword, /* FITS keyword */
+ int* lval); /* 1 if T, 0 if F (returned) */
+ int hgetsc( /* Extract string value from FITS header */
+ const char* hstring, /* FITS header string */
+ const char* keyword, /* FITS keyword */
+ const char* wchar, /* WCS to use (A-Z or null) */
+ const int lstr, /* maximum length of returned string */
+ char* string); /* null-terminated string value (returned) */
+ int hgets( /* Extract string value from FITS header */
+ const char* hstring, /* FITS header string */
+ const char* keyword, /* FITS keyword */
+ const int lstr, /* maximum length of returned string */
+ char* string); /* null-terminated string value (returned) */
+ int hgetm ( /* Extract string from multiple keywords */
+ const char* hstring, /* FITS header string */
+ const char* keyword, /* FITS keyword */
+ const int lstr, /* maximum length of returned string */
+ char* string); /* null-terminated string value (returned) */
+ int hgetndec( /* Find number of decimal places in FITS value*/
+ const char* hstring, /* FITS header string */
+ const char* keyword, /* FITS keyword */
+ int* ndec); /* number of decimal places (returned) */
+
+ char* hgetc( /* Return pointer to value for FITS keyword */
+ const char* hstring, /* FITS header string */
+ const char* keyword); /* FITS keyword */
+
+ char* ksearch( /* Return pointer to keyword in FITS header */
+ const char* hstring, /* FITS header string */
+ const char* keyword); /* FITS keyword */
+ char *blsearch (
+ const char* hstring, /* FITS header string */
+ const char* keyword); /* FITS keyword */
+
+ char *strsrch ( /* Find string s2 within string s1 */
+ const char* s1, /* String to search */
+ const char* s2); /* String to look for */
+ char *strnsrch ( /* Find string s2 within string s1 */
+ const char* s1, /* String to search */
+ const char* s2, /* String to look for */
+ const int ls1); /* Length of string being searched */
+
+ char *strcsrch ( /* Find string s2 within string s1 (no case) */
+ const char* s1, /* String to search */
+ const char* s2); /* String to look for */
+ char *strncsrch ( /* Find string s2 within string s1 (no case) */
+ const char* s1, /* String to search */
+ const char* s2, /* String to look for */
+ const int ls1); /* Length of string being searched */
+
+ int hlength( /* Set length of unterminated FITS header */
+ const char *header, /* FITS header */
+ const int lhead); /* Allocated length of FITS header */
+ int gethlength( /* Get length of current FITS header */
+ char* header); /* FITS header */
+
+ double str2ra( /* Return RA in degrees from string */
+ const char* in); /* Character string (hh:mm:ss.sss or dd.dddd) */
+ double str2dec( /* Return Dec in degrees from string */
+ const char* in); /* Character string (dd:mm:ss.sss or dd.dddd) */
+
+ int isnum( /* Return 1 if number, else 0 */
+ const char* string); /* Character string which may be a number */
+ int notnum( /* Return 0 if number, else 1 */
+ const char* string); /* Character string which may be a number */
+ int numdec( /* Return number of decimal places in number */
+ const char* string); /* Character string which may be a number */
+ void strfix( /* Clean up extraneous characters in string */
+ char* string, /* Character string which may be a number */
+ int fillblank, /* If 1, blanks are replaced by underscores */
+ int dropzero); /* If 1, drop trailing zeroes from string */
+
+ char *getltime(void); /* Return current local time in ISO format */
+ char *getutime(void); /* Return current UT as an ISO-format string */
+
+/* Subroutines in iget.c */
+ int mgetstr( /* Extract string from multiline FITS keyword */
+ const char* hstring, /* FITS header string */
+ const char* mkey, /* FITS keyword root _n added for extra lines */
+ const char* keyword, /* IRAF keyword */
+ const int lstr, /* maximum length of returned string */
+ char* string); /* null-terminated string value (returned) */
+ int mgeti4( /* Extract int from multiline FITS keyword */
+ const char* hstring, /* FITS header string */
+ const char* mkey, /* FITS keyword root _n added for extra lines */
+ const char* keyword, /* IRAF keyword */
+ int* ival); /* int keyword value (returned) */
+ int mgetr8( /* Extract double from multiline FITS keyword */
+ const char* hstring, /* FITS header string */
+ const char* mkey, /* FITS keyword root _n added for extra lines */
+ const char* keyword, /* IRAF keyword */
+ double* dval); /* double keyword value (returned) */
+ int igeti4( /* Extract int from IRAF keyword string */
+ const char* hstring, /* Multiline IRAF keyword string value */
+ const char* keyword, /* IRAF keyword */
+ int* val); /* int value (returned) */
+ int igetr4( /* Extract float from IRAF keyword string */
+ const char* hstring, /* Multiline IRAF keyword string value */
+ const char* keyword, /* IRAF keyword */
+ float* val); /* float value (returned) */
+ int igetr8( /* Extract double from IRAF keyword string */
+ const char* hstring, /* Multiline IRAF keyword string value */
+ const char* keyword, /* IRAF keyword */
+ double* val); /* double value (returned) */
+ int igets( /* Extract string from IRAF keyword string */
+ const char* hstring, /* Multiline IRAF keyword string value */
+ const char* keyword, /* IRAF keyword */
+ const int lstr, /* maximum length of returned string */
+ char* string); /* null-terminated string value (returned) */
+ char *igetc( /* Extract string from IRAF keyword string */
+ const char* hstring, /* Multiline IRAF keyword string value */
+ const char* keyword); /* IRAF keyword */
+
+/* Subroutines in hput.c */
+/* All hput* routines return 0 if successful, else -1 */
+ int hputi2( /* Implant short value into FITS header */
+ char* hstring, /* FITS header string (modified) */
+ const char* keyword, /* FITS keyword */
+ short ival); /* short value */
+ int hputi4( /* Implant int value into FITS header */
+ char* hstring, /* FITS header string (modified) */
+ const char* keyword, /* FITS keyword */
+ const int ival); /* int value */
+ int hputr4( /* Implant float value into FITS header */
+ char* hstring, /* FITS header string (modified) */
+ const char* keyword, /* FITS keyword */
+ const float* rval); /* float (4 byte) value */
+ int hputr8( /* Implant short into FITS header */
+ char* hstring, /* FITS header string (modified) */
+ const char* keyword, /* FITS keyword */
+ const double dval); /* double value */
+ int hputnr8( /* double with specified number of decimal places */
+ char* hstring, /* FITS header string (modified) */
+ const char* keyword, /* FITS keyword */
+ const int ndec, /* Number of decimal places in keyword value */
+ const double dval); /* double value */
+ int hputs( /* Quoted character string into FITS header */
+ char* hstring, /* FITS header string (modified) */
+ const char* keyword, /* FITS keyword */
+ const char* cval); /* Character string value */
+ int hputm( /* Quoted character string, mutiple keywords */
+ char* hstring, /* FITS header string (modified) */
+ const char* keyword, /* FITS keyword */
+ const char* cval); /* Character string value */
+ int hputcom( /* Add comment to keyword line in FITS header */
+ char* hstring, /* FITS header string (modified) */
+ const char* keyword, /* FITS keyword */
+ const char* comment); /* Comment string */
+ int hputra( /* Right ascension in degrees into hh:mm:ss.sss */
+ char* hstring, /* FITS header string (modified) */
+ const char* keyword, /* FITS keyword */
+ const double ra); /* Right ascension in degrees */
+ int hputdec( /* Declination in degrees into dd:mm:ss.ss */
+ char* hstring, /* FITS header string (modified) */
+ const char* keyword, /* FITS keyword */
+ const double dec); /* Declination in degrees */
+ int hputl( /* Implant boolean value into FITS header */
+ char* hstring, /* FITS header string (modified) */
+ const char* keyword, /* FITS keyword */
+ const int lval); /* 0->F, else ->T */
+ int hputc( /* Implant character string without quotes */
+ char* hstring, /* FITS header string (modified) */
+ const char* keyword, /* FITS keyword */
+ const char* cval); /* Character string value */
+
+ int hdel( /* Delete a keyword line from a FITS header */
+ char* hstring, /* FITS header string (modified) */
+ const char* keyword); /* FITS keyword to delete */
+ int hadd( /* Add a keyword line from a FITS header */
+ char* hplace, /* Location in FITS header string (modified) */
+ const char* keyword); /* FITS keyword to add */
+ int hchange( /* Change a keyword name in a FITS header */
+ char* hstring, /* FITS header string (modified) */
+ const char* keyword1, /* Current FITS keyword name */
+ const char* keyword2); /* New FITS keyword name */
+
+ void ra2str( /* Convert degrees to hh:mm:ss.ss */
+ char *string, /* Character string (returned) */
+ int lstr, /* Length of string */
+ const double ra, /* Right ascension in degrees */
+ const int ndec); /* Number of decimal places in seconds */
+ void dec2str( /* Convert degrees to dd:mm:ss.ss */
+ char *string, /* Character string (returned) */
+ int lstr, /* Length of string */
+ const double dec, /* Declination in degrees */
+ const int ndec); /* Number of decimal places in arcseconds */
+ void deg2str( /* Format angle into decimal degrees string */
+ char *string, /* Character string (returned) */
+ int lstr, /* Length of string */
+ const double deg, /* Angle in degrees */
+ const int ndec); /* Number of decimal places in degrees */
+ void num2str( /* Format number into string */
+ char *string, /* Character string (returned) */
+ const double num, /* Number */
+ const int field, /* Total field size in characters */
+ const int ndec); /* Number of decimal places */
+ void setheadshrink( /* 0 to keep blank line when keyword deleted */
+ const int hsh); /* 1 to shrink header by one line */
+ void setleaveblank( /* 1 to keep blank line where keyword deleted */
+ const int hsh); /* 0 to shrink header by one line */
+
+#else /* K&R prototypes */
+
+/* Subroutines in hget.c */
+
+/* Extract a value from a FITS header for given keyword */
+extern int hgeti4(); /* int (Multiple WCS) */
+extern int hgeti4c(); /* int */
+extern int hgeti2(); /* short */
+extern int hgetr4(); /* float */
+extern int hgetr8(); /* double */
+extern int hgetr8c(); /* double (Multiple WCS) */
+extern int hgetra(); /* Right ascension in degrees from string */
+extern int hgetdec(); /* Declination in degrees from string */
+extern int hgetdate(); /* Date in years from FITS date string */
+extern int hgetl(); /* T->1, F->0 from FITS logical entry */
+extern int hgets(); /* Previously allocated string */
+extern int hgetsc(); /* Previously allocated string (Multiple WCS) */
+extern int hgetm(); /* Previously allocated string from multiple keywords */
+extern char *hgetc(); /* Return pointer to string */
+extern int hgetndec(); /* Number of decimal places in keyword value */
+
+/* Subroutines to convert strings to RA and Dec in degrees */
+extern double str2ra();
+extern double str2dec();
+
+/* Check to see whether a string is a number or not */
+extern int isnum();
+extern int notnum();
+extern int decnum();
+
+/* Find given keyword entry in FITS header */
+extern char *ksearch();
+
+/* Find beginning of fillable blank line before FITS header keyword */
+extern char *blsearch();
+
+/* Search for substring s2 within string s1 */
+extern char *strsrch (); /* s1 null-terminated */
+extern char *strnsrch (); /* s1 ls1 characters long */
+extern char *strcsrch (); /* s1 null-terminated (case-insensitive) */
+extern char *strncsrch (); /* s1 ls1 characters long (case-insensitive) */
+extern void strfix(); /* Drop or change extraneous characters in string */
+
+/* Set length of header which is not null-terminated */
+extern int hlength();
+
+/* Get length of current FITS header */
+extern int gethlength();
+
+/* Subroutines in iget.c */
+extern int mgetstr(); /* Previously allocated string from multiline keyword */
+extern int mgetr8(); /* double from multiline keyword */
+extern int mgeti4(); /* int from multiline keyword */
+extern int igeti4(); /* long integer from IRAF compound keyword value */
+extern int igetr4(); /* real from IRAF compound keyword value */
+extern int igetr8(); /* double from IRAF compound keyword value */
+extern int igets(); /* character string from IRAF compound keyword value */
+extern char *igetc(); /* Extract string from IRAF keyword string */
+
+/* Subroutines in hput.c */
+
+/* Implant a value into a FITS header for given keyword */
+extern int hputi4(); /* int */
+extern int hputi2(); /* short */
+extern int hputr4(); /* float */
+extern int hputr8(); /* double */
+extern int hputnr8(); /* double with specified number of decimal places */
+extern int hputra(); /* Right ascension in degrees into hh:mm:ss.sss */
+extern int hputdec(); /* Declination in degrees into dd:mm:ss.ss */
+extern int hputl(); /* 0 -> F, else T FITS logical entry */
+extern int hputs(); /* Quoted character string */
+extern int hputm(); /* Quoted character string into mutiple keywords */
+extern int hputc(); /* Character string without quotes (returns 0 if OK) */
+extern int hputcom(); /* Comment after keyword=value (returns 0 if OK) */
+
+extern int hdel(); /* Delete a keyword line from a FITS header */
+extern int hadd(); /* Add a keyword line to a FITS header */
+extern int hchange(); /* Change a keyword name in a FITS header */
+extern void setheadshrink(); /* Set flag for deleted keyword space disposition*/
+extern void setleaveblank(); /* Set flag for deleted keyword space disposition*/
+
+/* Subroutines to convert RA and Dec in degrees to strings */
+extern void ra2str();
+extern void dec2str();
+
+extern void deg2str();
+extern void num2str();
+extern int numdec(); /* Return number of decimal places in number */
+
+extern char *getltime(); /* Return current local time in ISO format */
+extern char *getutime(); /* Return current UT as an ISO-format string */
+
+#endif /* __STDC__ */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* fitshead_h_ */
+
+/* Apr 26 1996 Add HGETDATE to get year from date string
+ * May 22 1996 Return double from STR2RA and STR2DEC
+ * May 31 1996 Use stream I/O for reading as well as writing
+ * Jun 12 1996 Add byte-swapping subroutines
+ * Jul 10 1996 FITS header now allocated in subroutines
+ * Jul 17 1996 Add FITS table column extraction subroutines
+ * Jul 19 1996 Add declarations for header implanting subroutines
+ * Aug 5 1996 Add HLENGTH for FITS headers which are not null-terminated
+ * Aug 5 1996 Add STRNSRCH for FITS headers which are not null-terminated
+ * Aug 6 1996 Add HPUTNR8 to save a specified number of decimal places
+ * Aug 6 1996 Add MOVEPIX, HDEL and HCHANGE declarations
+ * Nov 1 1996 Add DEG2STR
+ * Dec 12 1996 Add ISNUM
+ *
+ * Oct 10 1997 FITS file opening subroutines now return int instead of FILE *
+ *
+ * Mar 12 1998 Add NOTNUM
+ * Apr 30 1998 Clean up declarations and add more comments
+ * May 12 1998 Add MGETS, MGETR8, MGETI4 for IRAF multi-line keywords
+ * May 26 1998 Add HGETNDEC for number of decimal places in keyword value
+ * May 27 1998 Add BLSEARCH to find usable blank lines in header
+ * May 27 1998 Split off fitsio and imhio subroutines to fitsio.h
+ * May 27 1998 Add all subroutines in hget.c, hput.c, and iget.c to C++ dec.
+ * Jun 24 1998 Add string lengths to ra2str(), dec2str, and deg2str() calls
+ * Jun 25 1998 Fix other C++ declarations with added string lengths
+ * Aug 31 1998 Add current date subroutines getltime() and getutime()
+ * Oct 28 1998 Add missing hgetc() to non c++ declarations
+ *
+ * Oct 6 1999 Add gethlength() to return current size of header
+ * Oct 14 1999 All HPUT subroutines now return an error code, 0 if OK, else -1
+ * Oct 15 1999 Add hputcom() declaration
+ * Oct 21 1999 Add hgetm() declaration
+ *
+ * Mar 22 2000 Add int to iget*() declarations
+ * Mar 27 2000 Add hputm() declaration
+ *
+ * Apr 3 2002 Add hgeti4c(), hgetr8c(), and hgetsc()
+ * Apr 8 2002 Include sys/types.h
+ * Aug 30 2002 Add strcsrch() and strncsrch()
+ *
+ * Sep 23 2003 Change mgets() to mgetstr() to avoid name collision at UCO Lick
+ * Oct 20 2003 Add numdec() to return the number of decimal places in a string
+ *
+ * Feb 26 2004 Add igetc(), formerly internal to iget.c
+ * Jul 1 2004 Add setheadshrink() for hdel()
+ * Aug 30 2004 Add numdec() to non-C++ declarations
+ *
+ * May 22 2006 Add setleaveblank() to leave blank line where keyword is deleted
+ * Jun 28 2006 Add strfix() to clean up characters in strings
+ * Nov 29 2006 Drop semicolon at end of C++ ifdef
+ *
+ * Jan 9 2007 Fix declarations so ANSI prototypes are not just for C++
+ */
diff --git a/funtools/wcs/hget.c b/funtools/wcs/hget.c
new file mode 100644
index 0000000..653e8eb
--- /dev/null
+++ b/funtools/wcs/hget.c
@@ -0,0 +1,1913 @@
+/*** File libwcs/hget.c
+ *** May 19, 2011
+ *** By Jessica Mink, jmink@cfa.harvard.edu
+ *** Harvard-Smithsonian Center for Astrophysics
+ *** Copyright (C) 1994-2011
+ *** Smithsonian Astrophysical Observatory, Cambridge, MA, USA
+
+ This library 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 2 of the License, or (at your option) any later version.
+
+ This library 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 this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Correspondence concerning WCSTools should be addressed as follows:
+ Internet email: jmink@cfa.harvard.edu
+ Postal address: Jessica Mink
+ Smithsonian Astrophysical Observatory
+ 60 Garden St.
+ Cambridge, MA 02138 USA
+
+ * Module: hget.c (Get FITS Header parameter values)
+ * Purpose: Extract values for variables from FITS header string
+ * Subroutine: hgeti2 (hstring,keyword,ival) returns short integer
+ * Subroutine: hgeti4c (hstring,keyword,wchar,ival) returns long integer
+ * Subroutine: hgeti4 (hstring,keyword,ival) returns long integer
+ * Subroutine: hgetr4 (hstring,keyword,rval) returns real
+ * Subroutine: hgetra (hstring,keyword,ra) returns double RA in degrees
+ * Subroutine: hgetdec (hstring,keyword,dec) returns double Dec in degrees
+ * Subroutine: hgetr8c (hstring,keyword,wchar,dval) returns double
+ * Subroutine: hgetr8 (hstring,keyword,dval) returns double
+ * Subroutine: hgetl (hstring,keyword,lval) returns logical int (0=F, 1=T)
+ * Subroutine: hgetsc (hstring,keyword,wchar,lstr,str) returns character string
+ * Subroutine: hgets (hstring,keyword, lstr, str) returns character string
+ * Subroutine: hgetm (hstring,keyword, lstr, str) returns multi-keyword string
+ * Subroutine: hgetdate (hstring,keyword,date) returns date as fractional year
+ * Subroutine: hgetndec (hstring, keyword, ndec) returns number of dec. places
+ * Subroutine: hgetc (hstring,keyword) returns character string
+ * Subroutine: blsearch (hstring,keyword) returns pointer to blank lines
+ before keyword
+ * Subroutine: ksearch (hstring,keyword) returns pointer to header string entry
+ * Subroutine: str2ra (in) converts string to right ascension in degrees
+ * Subroutine: str2dec (in) converts string to declination in degrees
+ * Subroutine: strsrch (s1, s2) finds string s2 in null-terminated string s1
+ * Subroutine: strnsrch (s1, s2, ls1) finds string s2 in ls1-byte string s1
+ * Subroutine: hlength (header,lhead) sets length of FITS header for searching
+ * Subroutine: isnum (string) returns 1 if integer, 2 if fp number, else 0
+ * Subroutine: notnum (string) returns 0 if number, else 1
+ * Subroutine: numdec (string) returns number of decimal places in numeric string
+ * Subroutine: strfix (string,blankfill,zerodrop) removes extraneous characters
+ */
+
+#include <string.h> /* NULL, strlen, strstr, strcpy */
+#include <stdio.h>
+#include "fitshead.h" /* FITS header extraction subroutines */
+#include <stdlib.h>
+#ifndef VMS
+#include <limits.h>
+#else
+#define INT_MAX 2147483647 /* Biggest number that can fit in long */
+#define SHRT_MAX 32767
+#endif
+#define VLENGTH 81
+
+#ifdef USE_SAOLIB
+static int use_saolib=0;
+#endif
+
+char *hgetc ();
+
+static char val[VLENGTH+1];
+static int multiline = 0;
+
+static int lhead0 = 0; /* Length of header string */
+
+/* Set the length of the header string, if not terminated by NULL */
+int
+hlength (header, lhead)
+const char *header; /* FITS header */
+int lhead; /* Maximum length of FITS header */
+{
+ char *hend;
+ if (lhead > 0)
+ lhead0 = lhead;
+ else {
+ lhead0 = 0;
+ hend = ksearch (header,"END");
+ lhead0 = hend + 80 - header;
+ }
+ return (lhead0);
+}
+
+/* Return the length of the header string, computing it if lhead0 not set */
+int
+gethlength (header)
+char *header; /* FITS header */
+{
+ if (lhead0 > 0)
+ return (lhead0);
+ else
+ return (hlength (header, 0));
+}
+
+
+/* Extract Integer*4 value for variable from FITS header string */
+
+int
+hgeti4c (hstring,keyword,wchar,ival)
+
+const char *hstring; /* character string containing FITS header information
+ in the format <keyword>= <value> {/ <comment>} */
+const char *keyword; /* character string containing the name of the keyword
+ the value of which is returned. hget searches for
+ a line beginning with this string. if "[n]" is
+ present, the n'th token in the value is returned.
+ (the first 8 characters must be unique) */
+const char *wchar; /* Character of multiple WCS header; =0 if unused */
+int *ival; /* Keyword value returned */
+{
+ char keyword1[16];
+ int lkey;
+
+ if (wchar[0] < (char) 64)
+ return (hgeti4 (hstring, keyword, ival));
+ else {
+ strcpy (keyword1, keyword);
+ lkey = strlen (keyword);
+ keyword1[lkey] = wchar[0];
+ keyword1[lkey+1] = (char) 0;
+ return (hgeti4 (hstring, keyword1, ival));
+ }
+}
+
+
+/* Extract long value for variable from FITS header string */
+
+int
+hgeti4 (hstring,keyword,ival)
+
+const char *hstring; /* character string containing FITS header information
+ in the format <keyword>= <value> {/ <comment>} */
+const char *keyword; /* character string containing the name of the keyword
+ the value of which is returned. hget searches for a
+ line beginning with this string. if "[n]" is present,
+ the n'th token in the value is returned.
+ (the first 8 characters must be unique) */
+int *ival;
+{
+ char *value;
+ double dval;
+ int minint;
+ int lval;
+ char *dchar;
+
+ /* Get value and comment from header string */
+ value = hgetc (hstring,keyword);
+
+ /* Translate value from ASCII to binary */
+ if (value != NULL) {
+ if (value[0] == '#') value++;
+ minint = -INT_MAX - 1;
+ lval = strlen (value);
+ if (lval > VLENGTH) {
+ strncpy (val, value, VLENGTH);
+ val[VLENGTH] = (char) 0;
+ }
+ else
+ strcpy (val, value);
+ if (isnum (val) == 2) {
+ if ((dchar = strchr (val, 'D')))
+ *dchar = 'e';
+ if ((dchar = strchr (val, 'd')))
+ *dchar = 'e';
+ if ((dchar = strchr (val, 'E')))
+ *dchar = 'e';
+ }
+ dval = atof (val);
+ if (dval+0.001 > INT_MAX)
+ *ival = INT_MAX;
+ else if (dval >= 0)
+ *ival = (int) (dval + 0.001);
+ else if (dval-0.001 < minint)
+ *ival = minint;
+ else
+ *ival = (int) (dval - 0.001);
+ return (1);
+ }
+ else {
+ return (0);
+ }
+}
+
+
+/* Extract integer*2 value for variable from fits header string */
+
+int
+hgeti2 (hstring,keyword,ival)
+
+const char *hstring; /* character string containing FITS header information
+ in the format <keyword>= <value> {/ <comment>} */
+const char *keyword; /* character string containing the name of the keyword
+ the value of which is returned. hget searches for a
+ line beginning with this string. if "[n]" is present,
+ the n'th token in the value is returned.
+ (the first 8 characters must be unique) */
+short *ival;
+{
+ char *value;
+ double dval;
+ int minshort;
+ int lval;
+ char *dchar;
+
+ /* Get value and comment from header string */
+ value = hgetc (hstring,keyword);
+
+ /* Translate value from ASCII to binary */
+ if (value != NULL) {
+ if (value[0] == '#') value++;
+ lval = strlen (value);
+ if (lval > VLENGTH) {
+ strncpy (val, value, VLENGTH);
+ val[VLENGTH] = (char) 0;
+ }
+ else
+ strcpy (val, value);
+ if (isnum (val) == 2) {
+ if ((dchar = strchr (val, 'D')))
+ *dchar = 'e';
+ if ((dchar = strchr (val, 'd')))
+ *dchar = 'e';
+ if ((dchar = strchr (val, 'E')))
+ *dchar = 'e';
+ }
+ dval = atof (val);
+ minshort = -SHRT_MAX - 1;
+ if (dval+0.001 > SHRT_MAX)
+ *ival = SHRT_MAX;
+ else if (dval >= 0)
+ *ival = (short) (dval + 0.001);
+ else if (dval-0.001 < minshort)
+ *ival = minshort;
+ else
+ *ival = (short) (dval - 0.001);
+ return (1);
+ }
+ else {
+ return (0);
+ }
+}
+
+/* Extract real value for variable from FITS header string */
+
+int
+hgetr4 (hstring,keyword,rval)
+
+const char *hstring; /* character string containing FITS header information
+ in the format <keyword>= <value> {/ <comment>} */
+const char *keyword; /* character string containing the name of the keyword
+ the value of which is returned. hget searches for a
+ line beginning with this string. if "[n]" is present,
+ the n'th token in the value is returned.
+ (the first 8 characters must be unique) */
+float *rval;
+{
+ char *value;
+ int lval;
+ char *dchar;
+
+ /* Get value and comment from header string */
+ value = hgetc (hstring,keyword);
+
+ /* translate value from ASCII to binary */
+ if (value != NULL) {
+ if (value[0] == '#') value++;
+ lval = strlen (value);
+ if (lval > VLENGTH) {
+ strncpy (val, value, VLENGTH);
+ val[VLENGTH] = (char) 0;
+ }
+ else
+ strcpy (val, value);
+ if (isnum (val) == 2) {
+ if ((dchar = strchr (val, 'D')))
+ *dchar = 'e';
+ if ((dchar = strchr (val, 'd')))
+ *dchar = 'e';
+ if ((dchar = strchr (val, 'E')))
+ *dchar = 'e';
+ }
+ *rval = (float) atof (val);
+ return (1);
+ }
+ else {
+ return (0);
+ }
+}
+
+
+/* Extract real*8 right ascension in degrees from FITS header string */
+
+int
+hgetra (hstring,keyword,dval)
+
+const char *hstring; /* character string containing FITS header information
+ in the format <keyword>= <value> {/ <comment>} */
+const char *keyword; /* character string containing the name of the keyword
+ the value of which is returned. hget searches for a
+ line beginning with this string. if "[n]" is present,
+ the n'th token in the value is returned.
+ (the first 8 characters must be unique) */
+double *dval; /* Right ascension in degrees (returned) */
+{
+ char *value;
+
+ /* Get value from header string */
+ value = hgetc (hstring,keyword);
+
+ /* Translate value from ASCII colon-delimited string to binary */
+ if (value != NULL) {
+ *dval = str2ra (value);
+ return (1);
+ }
+ else
+ return (0);
+}
+
+
+/* Extract real*8 declination in degrees from FITS header string */
+
+int
+hgetdec (hstring,keyword,dval)
+
+const char *hstring; /* character string containing FITS header information
+ in the format <keyword>= <value> {/ <comment>} */
+const char *keyword; /* character string containing the name of the keyword
+ the value of which is returned. hget searches for a
+ line beginning with this string. if "[n]" is present,
+ the n'th token in the value is returned.
+ (the first 8 characters must be unique) */
+double *dval; /* Right ascension in degrees (returned) */
+{
+ char *value;
+
+ /* Get value from header string */
+ value = hgetc (hstring,keyword);
+
+ /* Translate value from ASCII colon-delimited string to binary */
+ if (value != NULL) {
+ *dval = str2dec (value);
+ return (1);
+ }
+ else
+ return (0);
+}
+
+
+/* Extract real*8 value for variable from FITS header string */
+
+int
+hgetr8c (hstring,keyword,wchar,dval)
+
+const char *hstring; /* character string containing FITS header information
+ in the format <keyword>= <value> {/ <comment>} */
+const char *keyword; /* character string containing the name of the keyword
+ the value of which is returned. hget searches for
+ a line beginning with this string. if "[n]" is
+ present, the n'th token in the value is returned.
+ (the first 8 characters must be unique) */
+const char *wchar; /* Character of multiple WCS header; =0 if unused */
+double *dval; /* Keyword value returned */
+{
+ char keyword1[16];
+ int lkey;
+
+ if (wchar[0] < (char) 64)
+ return (hgetr8 (hstring, keyword, dval));
+ else {
+ strcpy (keyword1, keyword);
+ lkey = strlen (keyword);
+ keyword1[lkey] = wchar[0];
+ keyword1[lkey+1] = (char) 0;
+ return (hgetr8 (hstring, keyword1, dval));
+ }
+}
+
+
+
+/* Extract real*8 value for variable from FITS header string */
+
+int
+hgetr8 (hstring,keyword,dval)
+
+const char *hstring; /* character string containing FITS header information
+ in the format <keyword>= <value> {/ <comment>} */
+const char *keyword; /* character string containing the name of the keyword
+ the value of which is returned. hget searches for a
+ line beginning with this string. if "[n]" is present,
+ the n'th token in the value is returned.
+ (the first 8 characters must be unique) */
+double *dval;
+{
+ char *value;
+ int lval;
+ char *dchar;
+
+ /* Get value and comment from header string */
+ value = hgetc (hstring,keyword);
+
+ /* Translate value from ASCII to binary */
+ if (value != NULL) {
+ if (value[0] == '#') value++;
+ lval = strlen (value);
+ if (lval > VLENGTH) {
+ strncpy (val, value, VLENGTH);
+ val[VLENGTH] = (char) 0;
+ }
+ else
+ strcpy (val, value);
+ if (isnum (val) == 2) {
+ if ((dchar = strchr (val, 'D')))
+ *dchar = 'e';
+ if ((dchar = strchr (val, 'd')))
+ *dchar = 'e';
+ if ((dchar = strchr (val, 'E')))
+ *dchar = 'e';
+ }
+ *dval = atof (val);
+ return (1);
+ }
+ else {
+ return (0);
+ }
+}
+
+
+/* Extract logical value for variable from FITS header string */
+
+int
+hgetl (hstring,keyword,ival)
+
+const char *hstring; /* character string containing FITS header information
+ in the format <keyword>= <value> {/ <comment>} */
+const char *keyword; /* character string containing the name of the keyword
+ the value of which is returned. hget searches for a
+ line beginning with this string. if "[n]" is present,
+ the n'th token in the value is returned.
+ (the first 8 characters must be unique) */
+int *ival;
+{
+ char *value;
+ char newval;
+ int lval;
+
+ /* Get value and comment from header string */
+ value = hgetc (hstring,keyword);
+
+ /* Translate value from ASCII to binary */
+ if (value != NULL) {
+ lval = strlen (value);
+ if (lval > VLENGTH) {
+ strncpy (val, value, VLENGTH);
+ val[VLENGTH] = (char) 0;
+ }
+ else
+ strcpy (val, value);
+ newval = val[0];
+ if (newval == 't' || newval == 'T')
+ *ival = 1;
+ else
+ *ival = 0;
+ return (1);
+ }
+ else {
+ return (0);
+ }
+}
+
+
+/* Extract real*8 date from FITS header string (dd/mm/yy or dd-mm-yy) */
+
+int
+hgetdate (hstring,keyword,dval)
+
+const char *hstring; /* character string containing FITS header information
+ in the format <keyword>= <value> {/ <comment>} */
+const char *keyword; /* character string containing the name of the keyword
+ the value of which is returned. hget searches for a
+ line beginning with this string. if "[n]" is present,
+ the n'th token in the value is returned.
+ (the first 8 characters must be unique) */
+double *dval;
+{
+ double yeardays, seconds, fday;
+ char *value,*sstr, *dstr, *tstr, *cstr, *nval;
+ int year, month, day, yday, i, hours, minutes;
+ static int mday[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
+
+ /* Get value and comment from header string */
+ value = hgetc (hstring,keyword);
+
+ /* Translate value from ASCII to binary */
+ if (value != NULL) {
+ sstr = strchr (value,'/');
+ dstr = strchr (value,'-');
+
+ /* Original FITS date format: dd/mm/yy */
+ if (sstr > value) {
+ *sstr = '\0';
+ day = (int) atof (value);
+ *sstr = '/';
+ nval = sstr + 1;
+ sstr = strchr (nval,'/');
+ if (sstr == NULL)
+ sstr = strchr (nval,'-');
+ if (sstr > value) {
+ *sstr = '\0';
+ month = (int) atof (nval);
+ *sstr = '/';
+ nval = sstr + 1;
+ year = (int) atof (nval);
+ if (day > 31) {
+ yday = year;
+ year = day;
+ day = yday;
+ }
+ if (year >= 0 && year <= 49)
+ year = year + 2000;
+ else if (year < 100)
+ year = year + 1900;
+ if ((year % 4) == 0)
+ mday[1] = 29;
+ else
+ mday[1] = 28;
+ if ((year % 100) == 0 && (year % 400) != 0)
+ mday[1] = 28;
+ if (day > mday[month-1])
+ day = mday[month-1];
+ else if (day < 1)
+ day = 1;
+ if (mday[1] == 28)
+ yeardays = 365.0;
+ else
+ yeardays = 366.0;
+ yday = day - 1;
+ for (i = 0; i < month-1; i++)
+ yday = yday + mday[i];
+ *dval = (double) year + ((double)yday / yeardays);
+ return (1);
+ }
+ else
+ return (0);
+ }
+
+ /* New FITS date format: yyyy-mm-ddThh:mm:ss[.sss] */
+ else if (dstr > value) {
+ *dstr = '\0';
+ year = (int) atof (value);
+ *dstr = '-';
+ nval = dstr + 1;
+ dstr = strchr (nval,'-');
+ month = 1;
+ day = 1;
+ tstr = NULL;
+ if (dstr > value) {
+ *dstr = '\0';
+ month = (int) atof (nval);
+ *dstr = '-';
+ nval = dstr + 1;
+ tstr = strchr (nval,'T');
+ if (tstr > value)
+ *tstr = '\0';
+ day = (int) atof (nval);
+ if (tstr > value)
+ *tstr = 'T';
+ }
+
+ /* If year is < 32, it is really day of month in old format */
+ if (year < 32) {
+ i = year;
+ year = day + 1900;
+ day = i;
+ }
+
+ if ((year % 4) == 0)
+ mday[1] = 29;
+ else
+ mday[1] = 28;
+ if ((year % 100) == 0 && (year % 400) != 0)
+ mday[1] = 28;
+ if (day > mday[month-1])
+ day = mday[month-1];
+ else if (day < 1)
+ day = 1;
+ if (mday[1] == 28)
+ yeardays = 365.0;
+ else
+ yeardays = 366.0;
+ yday = day - 1;
+ for (i = 0; i < month-1; i++)
+ yday = yday + mday[i];
+ *dval = (double) year + ((double)yday / yeardays);
+
+ /* Extract time, if it is present */
+ if (tstr > value) {
+ nval = tstr + 1;
+ hours = 0.0;
+ minutes = 0.0;
+ seconds = 0.0;
+ cstr = strchr (nval,':');
+ if (cstr > value) {
+ *cstr = '\0';
+ hours = (int) atof (nval);
+ *cstr = ':';
+ nval = cstr + 1;
+ cstr = strchr (nval,':');
+ if (cstr > value) {
+ *cstr = '\0';
+ minutes = (int) atof (nval);
+ *cstr = ':';
+ nval = cstr + 1;
+ seconds = atof (nval);
+ }
+ else {
+ minutes = (int) atof (nval);
+ seconds = 0.0;
+ }
+ }
+ fday = ((3.6e3 * (double)hours) + (6.e1 * (double)minutes) +
+ seconds) / 8.64e4;
+ *dval = *dval + (fday / yeardays);
+ }
+ return (1);
+ }
+ else
+ return (0);
+ }
+ else
+ return (0);
+}
+
+
+/* Extract IRAF multiple-keyword string value from FITS header string */
+
+int
+hgetm (hstring, keyword, lstr, str)
+
+const char *hstring; /* character string containing FITS header information
+ in the format <keyword>= <value> {/ <comment>} */
+const char *keyword; /* character string containing the root name of the keyword
+ the value of which is returned. hget searches for a
+ line beginning with this string. if "[n]" is present,
+ the n'th token in the value is returned.
+ (the first 8 characters must be unique) */
+const int lstr; /* Size of str in characters */
+char *str; /* String (returned) */
+{
+ char *value;
+ char *stri;
+ char keywordi[16];
+ int lval, lstri, ikey;
+ char keyform[8];
+
+ stri = str;
+ lstri = lstr;
+
+ sprintf (keywordi, "%s_1", keyword);
+ if (ksearch (hstring, keywordi))
+ strcpy (keyform, "%s_%d");
+ else {
+ sprintf (keywordi, "%s_01", keyword);
+ if (ksearch (hstring, keywordi))
+ strcpy (keyform, "%s_%02d");
+ else {
+ sprintf (keywordi, "%s_001", keyword);
+ if (ksearch (hstring, keywordi))
+ strcpy (keyform, "%s_%03d");
+ else if (ksearch (hstring, keywordi))
+ strcpy (keyform, "%s_%03d");
+ else
+ return (0);
+ }
+ }
+
+ /* Loop through sequentially-named keywords */
+ multiline = 1;
+ for (ikey = 1; ikey < 500; ikey++) {
+ sprintf (keywordi, keyform, keyword, ikey);
+
+ /* Get value for this keyword */
+ value = hgetc (hstring, keywordi);
+ if (value != NULL) {
+ lval = strlen (value);
+ if (lval < lstri)
+ strcpy (stri, value);
+ else if (lstri > 1) {
+ strncpy (stri, value, lstri-1);
+ stri[lstri] = (char) 0;
+ break;
+ }
+ else {
+ str[0] = value[0];
+ break;
+ }
+ }
+ else
+ break;
+ stri = stri + lval;
+ lstri = lstri - lval;
+ }
+ multiline = 0;
+
+ /* Return 1 if any keyword found, else 0 */
+ if (ikey > 1)
+ return (1);
+ else
+ return (0);
+}
+
+
+/* Extract string value for variable from FITS header string */
+
+int
+hgetsc (hstring,keyword,wchar,lstr,str)
+
+const char *hstring; /* character string containing FITS header information
+ in the format <keyword>= <value> {/ <comment>} */
+const char *keyword; /* character string containing the name of the keyword
+ the value of which is returned. hget searches for
+ a line beginning with this string. if "[n]" is
+ present, the n'th token in the value is returned.
+ (the first 8 characters must be unique) */
+const char *wchar; /* Character of multiple WCS header; =0 if unused */
+const int lstr; /* Size of str in characters */
+char *str; /* String (returned) */
+{
+ char keyword1[16];
+ int lkey;
+
+ if (wchar[0] < (char) 64)
+ return (hgets (hstring, keyword, lstr, str));
+ else {
+ strcpy (keyword1, keyword);
+ lkey = strlen (keyword);
+ keyword1[lkey] = wchar[0];
+ keyword1[lkey+1] = (char) 0;
+ return (hgets (hstring, keyword1, lstr, str));
+ }
+}
+
+
+/* Extract string value for variable from FITS header string */
+
+int
+hgets (hstring, keyword, lstr, str)
+
+const char *hstring; /* character string containing FITS header information
+ in the format <keyword>= <value> {/ <comment>} */
+const char *keyword; /* character string containing the name of the keyword
+ the value of which is returned. hget searches for a
+ line beginning with this string. if "[n]" is present,
+ the n'th token in the value is returned.
+ (the first 8 characters must be unique) */
+const int lstr; /* Size of str in characters */
+char *str; /* String (returned) */
+{
+ char *value;
+ int lval;
+
+ /* Get value and comment from header string */
+ value = hgetc (hstring,keyword);
+
+ if (value != NULL) {
+ lval = strlen (value);
+ if (lval < lstr)
+ strcpy (str, value);
+ else if (lstr > 1)
+ strncpy (str, value, lstr-1);
+ else
+ str[0] = value[0];
+ return (1);
+ }
+ else
+ return (0);
+}
+
+
+/* Extract number of decimal places for value in FITS header string */
+
+int
+hgetndec (hstring, keyword, ndec)
+
+const char *hstring; /* character string containing FITS header information
+ in the format <keyword>= <value> {/ <comment>} */
+const char *keyword; /* character string containing the name of the keyword
+ the value of which is returned. hget searches for a
+ line beginning with this string. if "[n]" is present,
+ the n'th token in the value is returned.
+ (the first 8 characters must be unique) */
+int *ndec; /* Number of decimal places in keyword value */
+{
+ char *value;
+ int i, nchar;
+
+ /* Get value and comment from header string */
+ value = hgetc (hstring,keyword);
+
+ /* Find end of string and count backward to decimal point */
+ *ndec = 0;
+ if (value != NULL) {
+ nchar = strlen (value);
+ for (i = nchar-1; i >= 0; i--) {
+ if (value[i] == '.')
+ return (1);
+ *ndec = *ndec + 1;
+ }
+ return (1);
+ }
+ else
+ return (0);
+}
+
+
+/* Extract character value for variable from FITS header string */
+
+char *
+hgetc (hstring,keyword0)
+
+const char *hstring; /* character string containing FITS header information
+ in the format <keyword>= <value> {/ <comment>} */
+const char *keyword0; /* character string containing the name of the keyword
+ the value of which is returned. hget searches for a
+ line beginning with this string. if "[n]" is present,
+ the n'th token in the value is returned.
+ (the first 8 characters must be unique) */
+{
+ static char cval[80];
+ char *value;
+ char cwhite[2];
+ char squot[2], dquot[2], lbracket[2], rbracket[2], slash[2], comma[2];
+ char space;
+ char keyword[81]; /* large for ESO hierarchical keywords */
+ char line[100];
+ char *vpos, *cpar;
+ char *q1, *q2, *v1, *v2, *c1, *brack1, *brack2;
+ int ipar, i, lkey;
+
+#ifdef USE_SAOLIB
+ int iel=1, ip=1, nel, np, ier;
+ char *get_fits_head_str();
+
+ if( !use_saolib ){
+#endif
+
+ squot[0] = (char) 39;
+ squot[1] = (char) 0;
+ dquot[0] = (char) 34;
+ dquot[1] = (char) 0;
+ lbracket[0] = (char) 91;
+ lbracket[1] = (char) 0;
+ comma[0] = (char) 44;
+ comma[1] = (char) 0;
+ rbracket[0] = (char) 93;
+ rbracket[1] = (char) 0;
+ slash[0] = (char) 47;
+ slash[1] = (char) 0;
+ space = (char) 32;
+
+ /* Find length of variable name */
+ strncpy (keyword,keyword0, sizeof(keyword)-1);
+ brack1 = strsrch (keyword,lbracket);
+ if (brack1 == NULL)
+ brack1 = strsrch (keyword,comma);
+ if (brack1 != NULL) {
+ *brack1 = '\0';
+ brack1++;
+ }
+
+ /* Search header string for variable name */
+ vpos = ksearch (hstring,keyword);
+
+ /* Exit if not found */
+ if (vpos == NULL)
+ return (NULL);
+
+ /* Initialize line to nulls */
+ for (i = 0; i < 100; i++)
+ line[i] = 0;
+
+/* In standard FITS, data lasts until 80th character */
+
+ /* Extract entry for this variable from the header */
+ strncpy (line,vpos,80);
+
+ /* Check for quoted value */
+ q1 = strsrch (line,squot);
+ c1 = strsrch (line,slash);
+ if (q1 != NULL) {
+ if (c1 != NULL && q1 < c1) {
+ q2 = strsrch (q1+1,squot);
+ if (q2 == NULL) {
+ q2 = c1 - 1;
+ while (*q2 == space)
+ q2--;
+ q2++;
+ }
+ else if (c1 < q2)
+ c1 = strsrch (q2,slash);
+ }
+ else if (c1 == NULL) {
+ q2 = strsrch (q1+1,squot);
+ if (q2 == NULL) {
+ q2 = line + 79;
+ while (*q2 == space)
+ q2--;
+ q2++;
+ }
+ }
+ else
+ q1 = NULL;
+ }
+ else {
+ q1 = strsrch (line,dquot);
+ if (q1 != NULL) {
+ if (c1 != NULL && q1 < c1) {
+ q2 = strsrch (q1+1,dquot);
+ if (q2 == NULL) {
+ q2 = c1 - 1;
+ while (*q2 == space)
+ q2--;
+ q2++;
+ }
+ else if (c1 < q2)
+ c1 = strsrch (q2,slash);
+ }
+ else if (c1 == NULL) {
+ q2 = strsrch (q1+1,dquot);
+ if (q2 == NULL) {
+ q2 = line + 79;
+ while (*q2 == space)
+ q2--;
+ q2++;
+ }
+ }
+ else
+ q1 = NULL;
+ }
+ else {
+ q1 = NULL;
+ q2 = line + 10;
+ }
+ }
+
+ /* Extract value and remove excess spaces */
+ if (q1 != NULL) {
+ v1 = q1 + 1;
+ v2 = q2;
+ }
+ else {
+ v1 = strsrch (line,"=");
+ if (v1 == NULL)
+ v1 = line + 9;
+ else
+ v1 = v1 + 1;
+ c1 = strsrch (line,"/");
+ if (c1 != NULL)
+ v2 = c1;
+ else
+ v2 = line + 79;
+ }
+
+ /* Ignore leading spaces if not multiline */
+ if (!multiline) {
+ while (*v1 == ' ' && v1 < v2) {
+ v1++;
+ }
+ }
+
+ /* Drop trailing spaces */
+ *v2 = '\0';
+ if (!multiline) {
+ v2--;
+ while ((*v2 == ' ' || *v2 == (char) 13) && v2 > v1) {
+ *v2 = '\0';
+ v2--;
+ }
+ }
+
+ /* Convert -zero to just plain 0 */
+ if (!strcmp (v1, "-0"))
+ v1++;
+ strcpy (cval,v1);
+ value = cval;
+
+ /* If keyword has brackets, extract appropriate token from value */
+ if (brack1 != NULL) {
+ brack2 = strsrch (brack1,rbracket);
+ if (brack2 != NULL)
+ *brack2 = '\0';
+ if (isnum (brack1)) {
+ ipar = atoi (brack1);
+ cwhite[0] = ' ';
+ cwhite[1] = '\0';
+ if (ipar > 0) {
+ for (i = 1; i <= ipar; i++) {
+ cpar = strtok (v1,cwhite);
+ v1 = NULL;
+ }
+ if (cpar != NULL) {
+ strcpy (cval,cpar);
+ value = cval;
+ }
+ else
+ value = NULL;
+ }
+
+ /* If token counter is negative, include rest of value */
+ else if (ipar < 0) {
+ for (i = 1; i < -ipar; i++) {
+ v1 = strchr (v1, ' ');
+ if (v1 == NULL)
+ break;
+ else
+ v1 = v1 + 1;
+ }
+ if (v1 != NULL) {
+ strcpy (cval, v1);
+ value = cval;
+ }
+ else
+ value = NULL;
+ }
+ }
+ else {
+ lkey = strlen (brack1);
+ for (i = 0; i < lkey; i++) {
+ if (brack1[i] > 64 && brack1[i] < 91)
+ brack1[i] = brack1[i] + 32;
+ }
+ v1 = igetc (cval, brack1);
+ if (v1) {
+ strcpy (cval,v1);
+ value = cval;
+ }
+ else
+ value = NULL;
+ }
+ }
+
+ return (value);
+#ifdef USE_SAOLIB
+ } else {
+ return(get_fits_head_str(keyword0, iel, ip, &nel, &np, &ier, hstring));
+ }
+#endif
+}
+
+
+/* Find beginning of fillable blank line before FITS header keyword line */
+
+char *
+blsearch (hstring,keyword)
+
+/* Find entry for keyword keyword in FITS header string hstring.
+ (the keyword may have a maximum of eight letters)
+ NULL is returned if the keyword is not found */
+
+const char *hstring; /* character string containing fits-style header
+ information in the format <keyword>= <value> {/ <comment>}
+ the default is that each entry is 80 characters long;
+ however, lines may be of arbitrary length terminated by
+ nulls, carriage returns or linefeeds, if packed is true. */
+const char *keyword; /* character string containing the name of the variable
+ to be returned. ksearch searches for a line beginning
+ with this string. The string may be a character
+ literal or a character variable terminated by a null
+ or '$'. it is truncated to 8 characters. */
+{
+ const char *headlast;
+ char *loc, *headnext, *pval, *lc, *line;
+ char *bval;
+ int icol, nextchar, lkey, nleft, lhstr;
+
+ pval = 0;
+
+ /* Search header string for variable name */
+ if (lhead0)
+ lhstr = lhead0;
+ else {
+ lhstr = 0;
+ while (lhstr < 256000 && hstring[lhstr] != 0)
+ lhstr++;
+ }
+ headlast = hstring + lhstr;
+ headnext = (char *) hstring;
+ pval = NULL;
+ while (headnext < headlast) {
+ nleft = headlast - headnext;
+ loc = strncsrch (headnext, keyword, nleft);
+
+ /* Exit if keyword is not found */
+ if (loc == NULL) {
+ break;
+ }
+
+ icol = (loc - hstring) % 80;
+ lkey = strlen (keyword);
+ nextchar = (int) *(loc + lkey);
+
+ /* If this is not in the first 8 characters of a line, keep searching */
+ if (icol > 7)
+ headnext = loc + 1;
+
+ /* If parameter name in header is longer, keep searching */
+ else if (nextchar != 61 && nextchar > 32 && nextchar < 127)
+ headnext = loc + 1;
+
+ /* If preceeding characters in line are not blanks, keep searching */
+ else {
+ line = loc - icol;
+ for (lc = line; lc < loc; lc++) {
+ if (*lc != ' ')
+ headnext = loc + 1;
+ }
+
+ /* Return pointer to start of line if match */
+ if (loc >= headnext) {
+ pval = line;
+ break;
+ }
+ }
+ }
+
+ /* Return NULL to calling program if keyword is not found */
+ if (pval == NULL)
+ return (pval);
+
+ /* Return NULL if keyword is found at start of FITS header string */
+ if (pval == hstring)
+ return (NULL);
+
+ /* Find last nonblank in FITS header string line before requested keyword */
+ bval = pval - 80;
+ while (!strncmp (bval," ",8) && bval >= hstring)
+ bval = bval - 80;
+ bval = bval + 80;
+
+ /* Return pointer to calling program if blank lines found */
+ if (bval < pval && bval >= hstring)
+ return (bval);
+ else
+ return (NULL);
+}
+
+
+/* Find FITS header line containing specified keyword */
+
+char *
+ksearch (hstring,keyword)
+
+/* Find entry for keyword keyword in FITS header string hstring.
+ (the keyword may have a maximum of eight letters)
+ NULL is returned if the keyword is not found */
+
+const char *hstring; /* character string containing fits-style header
+ information in the format <keyword>= <value> {/ <comment>}
+ the default is that each entry is 80 characters long;
+ however, lines may be of arbitrary length terminated by
+ nulls, carriage returns or linefeeds, if packed is true. */
+const char *keyword; /* character string containing the name of the variable
+ to be returned. ksearch searches for a line beginning
+ with this string. The string may be a character
+ literal or a character variable terminated by a null
+ or '$'. it is truncated to 8 characters. */
+{
+ const char *headlast;
+ char *loc, *headnext, *pval, *lc, *line;
+ int icol, nextchar, lkey, nleft, lhead, lmax;
+
+#ifdef USE_SAOLIB
+ int iel=1, ip=1, nel, np, ier;
+ char *get_fits_head_str();
+
+ if( !use_saolib ){
+#endif
+
+ pval = 0;
+
+/* Find current length of header string */
+ if (lhead0)
+ lmax = lhead0;
+ else
+ lmax = 256000;
+ for (lhead = 0; lhead < lmax; lhead++) {
+ if (hstring[lhead] <= (char) 0)
+ break;
+ }
+
+/* Search header string for variable name */
+ headlast = hstring + lhead;
+ headnext = (char *) hstring;
+ pval = NULL;
+ while (headnext < headlast) {
+ nleft = headlast - headnext;
+ loc = strncsrch (headnext, keyword, nleft);
+
+ /* Exit if keyword is not found */
+ if (loc == NULL) {
+ break;
+ }
+
+ icol = (loc - hstring) % 80;
+ lkey = strlen (keyword);
+ nextchar = (int) *(loc + lkey);
+
+ /* If this is not in the first 8 characters of a line, keep searching */
+ if (icol > 7)
+ headnext = loc + 1;
+
+ /* If parameter name in header is longer, keep searching */
+ else if (nextchar != 61 && nextchar > 32 && nextchar < 127)
+ headnext = loc + 1;
+
+ /* If preceeding characters in line are not blanks, keep searching */
+ else {
+ line = loc - icol;
+ for (lc = line; lc < loc; lc++) {
+ if (*lc != ' ')
+ headnext = loc + 1;
+ }
+
+ /* Return pointer to start of line if match */
+ if (loc >= headnext) {
+ pval = line;
+ break;
+ }
+ }
+ }
+
+/* Return pointer to calling program */
+ return (pval);
+
+#ifdef USE_SAOLIB
+ }
+ else {
+ if (get_fits_head_str(keyword,iel,ip,&nel,&np,&ier,hstring) != NULL)
+ return(hstring);
+ else
+ return(NULL);
+ }
+#endif
+}
+
+
+/* Return the right ascension in degrees from sexagesimal hours or decimal degrees */
+
+double
+str2ra (in)
+
+const char *in; /* Character string of sexigesimal hours or decimal degrees */
+
+{
+ double ra; /* Right ascension in degrees (returned) */
+
+ ra = str2dec (in);
+ if (strsrch (in,":"))
+ ra = ra * 15.0;
+
+ return (ra);
+}
+
+
+/* Return the declination in degrees from sexagesimal or decimal degrees */
+
+double
+str2dec (in)
+
+const char *in; /* Character string of sexigesimal or decimal degrees */
+
+{
+ double dec; /* Declination in degrees (returned) */
+ double deg, min, sec, sign;
+ char *value, *c1, *c2;
+ int lval;
+ char *dchar;
+
+ dec = 0.0;
+
+ /* Return 0.0 if string is null */
+ if (in == NULL)
+ return (dec);
+
+ /* Translate value from ASCII colon-delimited string to binary */
+ if (in[0]) {
+ value = (char *) in;
+
+ /* Remove leading spaces */
+ while (*value == ' ')
+ value++;
+
+ /* Save sign */
+ if (*value == '-') {
+ sign = -1.0;
+ value++;
+ }
+ else if (*value == '+') {
+ sign = 1.0;
+ value++;
+ }
+ else
+ sign = 1.0;
+
+ /* Turn comma into space */
+ if ((c1 = strsrch (value,",")) != NULL)
+ *c1 = ' ';
+
+ /* Remove trailing spaces */
+ lval = strlen (value);
+ while (value[lval-1] == ' ')
+ lval--;
+
+ if ((c1 = strsrch (value,":")) == NULL)
+ c1 = strnsrch (value," ",lval);
+ if (c1 != NULL) {
+ *c1 = 0;
+ deg = (double) atoi (value);
+ *c1 = ':';
+ value = c1 + 1;
+ if ((c2 = strsrch (value,":")) == NULL)
+ c2 = strsrch (value," ");
+ if (c2 != NULL) {
+ *c2 = 0;
+ min = (double) atoi (value);
+ *c2 = ':';
+ value = c2 + 1;
+ sec = atof (value);
+ }
+ else {
+ sec = 0.0;
+ if ((c1 = strsrch (value,".")) != NULL)
+ min = atof (value);
+ if (strlen (value) > 0)
+ min = (double) atoi (value);
+ }
+ dec = sign * (deg + (min / 60.0) + (sec / 3600.0));
+ }
+ else if (isnum (value) == 2) {
+ if ((dchar = strchr (value, 'D')))
+ *dchar = 'e';
+ if ((dchar = strchr (value, 'd')))
+ *dchar = 'e';
+ if ((dchar = strchr (value, 'E')))
+ *dchar = 'e';
+ dec = sign * atof (value);
+ }
+ else
+ dec = sign * (double) atoi (value);
+ }
+ return (dec);
+}
+
+
+/* Find string s2 within null-terminated string s1 */
+
+char *
+strsrch (s1, s2)
+
+const char *s1; /* String to search */
+const char *s2; /* String to look for */
+
+{
+ int ls1;
+ ls1 = strlen (s1);
+ return (strnsrch (s1, s2, ls1));
+}
+
+
+/* Find string s2 within string s1 */
+
+char *
+strnsrch (s1, s2, ls1)
+
+const char *s1; /* String to search */
+const char *s2; /* String to look for */
+const int ls1; /* Length of string being searched */
+
+{
+ char *s,*s1e;
+ char cfirst,clast;
+ int i,ls2;
+
+ /* Return null string if either pointer is NULL */
+ if (s1 == NULL || s2 == NULL)
+ return (NULL);
+
+ /* A zero-length pattern is found in any string */
+ ls2 = strlen (s2);
+ if (ls2 ==0)
+ return ((char *) s1);
+
+ /* Only a zero-length string can be found in a zero-length string */
+ if (ls1 ==0)
+ return (NULL);
+
+ cfirst = (char) s2[0];
+ clast = (char) s2[ls2-1];
+ s1e = (char *) s1 + (int) ls1 - ls2 + 1;
+ s = (char *) s1;
+ while (s < s1e) {
+
+ /* Search for first character in pattern string */
+ if (*s == cfirst) {
+
+ /* If single character search, return */
+ if (ls2 == 1)
+ return (s);
+
+ /* Search for last character in pattern string if first found */
+ if (s[ls2-1] == clast) {
+
+ /* If two-character search, return */
+ if (ls2 == 2)
+ return (s);
+
+ /* If 3 or more characters, check for rest of search string */
+ i = 1;
+ while (i < ls2 && s[i] == s2[i])
+ i++;
+
+ /* If entire string matches, return */
+ if (i >= ls2)
+ return (s);
+ }
+ }
+ s++;
+ }
+ return (NULL);
+}
+
+
+/* Find string s2 within null-terminated string s1 (case-free search) */
+
+char *
+strcsrch (s1, s2)
+
+const char *s1; /* String to search */
+const char *s2; /* String to look for */
+
+{
+ int ls1;
+ ls1 = strlen ((char *) s1);
+ return (strncsrch (s1, s2, ls1));
+}
+
+
+/* Find string s2 within string s1 (case-free search) */
+
+char *
+strncsrch (s1, s2, ls1)
+
+const char *s1; /* String to search */
+const char *s2; /* String to look for */
+const int ls1; /* Length of string being searched */
+
+{
+ char *s,*s1e, sl, *os2;
+ char cfirst,ocfirst;
+ char clast = ' ';
+ char oclast = ' ';
+ int i,ls2;
+
+ /* Return null string if either pointer is NULL */
+ if (s1 == NULL || s2 == NULL)
+ return (NULL);
+
+ /* A zero-length pattern is found in any string */
+ ls2 = strlen (s2);
+ if (ls2 ==0)
+ return ((char *) s1);
+
+ /* Only a zero-length string can be found in a zero-length string */
+ os2 = NULL;
+ if (ls1 ==0)
+ return (NULL);
+
+ /* For one or two characters, set opposite case first and last letters */
+ if (ls2 < 3) {
+ cfirst = (char) s2[0];
+ if (cfirst > 96 && cfirst < 123)
+ ocfirst = cfirst - 32;
+ else if (cfirst > 64 && cfirst < 91)
+ ocfirst = cfirst + 32;
+ else
+ ocfirst = cfirst;
+ if (ls2 > 1) {
+ clast = s2[1];
+ if (clast > 96 && clast < 123)
+ oclast = clast - 32;
+ else if (clast > 64 && clast < 91)
+ oclast = clast + 32;
+ else
+ oclast = clast;
+ }
+ }
+
+ /* Else duplicate string with opposite case letters for comparison */
+ else {
+ os2 = (char *) calloc (ls2, 1);
+ for (i = 0; i < ls2; i++) {
+ if (s2[i] > 96 && s2[i] < 123)
+ os2[i] = s2[i] - 32;
+ else if (s2[i] > 64 && s2[i] < 91)
+ os2[i] = s2[i] + 32;
+ else
+ os2[i] = s2[i];
+ }
+ cfirst = s2[0];
+ ocfirst = os2[0];
+ clast = s2[ls2-1];
+ oclast = os2[ls2-1];
+ }
+
+ /* Loop through input string, character by character */
+ s = (char *) s1;
+ s1e = s + (int) ls1 - ls2 + 1;
+ while (s < s1e) {
+
+ /* Search for first character in pattern string */
+ if (*s == cfirst || *s == ocfirst) {
+
+ /* If single character search, return */
+ if (ls2 == 1) {
+ if (os2 != NULL)
+ free (os2);
+ return (s);
+ }
+
+ /* Search for last character in pattern string if first found */
+ sl = s[ls2-1];
+ if (sl == clast || sl == oclast) {
+
+ /* If two-character search, return */
+ if (ls2 == 2) {
+ if (os2 != NULL)
+ free (os2);
+ return (s);
+ }
+
+ /* If 3 or more characters, check for rest of search string */
+ i = 1;
+ while (i < ls2 && (s[i] == (char) s2[i] || s[i] == os2[i]))
+ i++;
+
+ /* If entire string matches, return */
+ if (i >= ls2) {
+ if (os2 != NULL)
+ free (os2);
+ return (s);
+ }
+ }
+ }
+ s++;
+ }
+ if (os2 != NULL)
+ free (os2);
+ return (NULL);
+}
+
+
+int
+notnum (string)
+
+const char *string; /* Character string */
+{
+ if (isnum (string))
+ return (0);
+ else
+ return (1);
+}
+
+
+/* ISNUM-- Return 1 if string is an integer number,
+ 2 if floating point,
+ 3 if sexigesimal, with or without decimal point
+ else 0
+ */
+
+int
+isnum (string)
+
+const char *string; /* Character string */
+{
+ int lstr, i, nd, cl;
+ char cstr, cstr1;
+ int fpcode;
+
+ /* Return 0 if string is NULL */
+ if (string == NULL)
+ return (0);
+
+ lstr = strlen (string);
+ nd = 0;
+ cl = 0;
+ fpcode = 1;
+
+ /* Return 0 if string starts with a D or E */
+ cstr = string[0];
+ if (cstr == 'D' || cstr == 'd' ||
+ cstr == 'E' || cstr == 'e') {
+ return (0);
+ }
+
+ /* Remove trailing spaces */
+ while (string[lstr-1] == ' ')
+ lstr--;
+
+ /* Numeric strings contain 0123456789-+ and d or e for exponents */
+ for (i = 0; i < lstr; i++) {
+ cstr = string[i];
+ if (cstr == '\n')
+ break;
+
+ /* Ignore leading spaces */
+ if (cstr == ' ' && nd == 0)
+ continue;
+
+ if ((cstr < 48 || cstr > 57) &&
+ cstr != '+' && cstr != '-' &&
+ cstr != 'D' && cstr != 'd' &&
+ cstr != 'E' && cstr != 'e' &&
+ cstr != ':' && cstr != '.')
+ return (0);
+ else if (cstr == '+' || cstr == '-') {
+ if (string[i+1] == '-' || string[i+1] == '+')
+ return (0);
+ else if (i > 0) {
+ cstr1 = string[i-1];
+ if (cstr1 != 'D' && cstr1 != 'd' &&
+ cstr1 != 'E' && cstr1 != 'e' &&
+ cstr1 != ':' && cstr1 != ' ')
+ return (0);
+ }
+ }
+ else if (cstr >= 47 && cstr <= 57)
+ nd++;
+
+ /* Check for colon */
+ else if (cstr == 58)
+ cl++;
+ if (cstr=='.' || cstr=='d' || cstr=='e' || cstr=='d' || cstr=='e')
+ fpcode = 2;
+ }
+ if (nd > 0) {
+ if (cl)
+ fpcode = 3;
+ return (fpcode);
+ }
+ else
+ return (0);
+}
+
+
+/* NUMDEC -- Return number of decimal places in numeric string (-1 if not number) */
+
+int
+numdec (string)
+
+const char *string; /* Numeric string */
+{
+ char *cdot;
+ int lstr;
+
+ if (notnum (string) && !strchr (string, ':'))
+ return (-1);
+ else {
+ lstr = strlen (string);
+ if ((cdot = strchr (string, '.')) == NULL)
+ return (0);
+ else
+ return (lstr - (cdot - string) - 1);
+ }
+}
+
+
+#ifdef USE_SAOLIB
+int set_saolib(hstring)
+ void *hstring;
+{
+ if( *((int *)hstring) == 142857 )
+ use_saolib = 1;
+ else
+ use_saolib = 0;
+}
+
+#endif
+
+
+/* Remove exponent, leading #, surrounding parentheses,
+ and/or trailing zeroes, if reasonable */
+void
+strfix (string, fillblank, dropzero)
+
+char *string; /* String to modify */
+int fillblank; /* If nonzero, fill blanks with underscores */
+int dropzero; /* If nonzero, drop trailing zeroes */
+{
+ char *sdot, *s, *strend, *str, ctemp, *slast;
+ int ndek, lstr, i;
+
+ /* If number, ignore leading # and remove trailing non-numeric character */
+ if (string[0] == '#') {
+ strend = string + strlen (string);
+ str = string + 1;
+ strend = str + strlen (str) - 1;
+ ctemp = *strend;
+ if (!isnum (strend))
+ *strend = (char) 0;
+ if (isnum (str)) {
+ strend = string + strlen (string);
+ for (str = string; str < strend; str++)
+ *str = *(str + 1);
+ }
+ else
+ *strend = ctemp;
+ }
+
+ /* Remove parentheses if they enclose the string */
+ if (string[0] == '(') {
+ lstr = strlen (string);
+ if (string[lstr-1] == ')') {
+ string[lstr-1] = (char) 0;
+ strend = string + lstr - 1;
+ for (str = string; str < strend; str++)
+ *str = *(str+1);
+ string[lstr-2] = (char) 0;
+ }
+ }
+
+ /* Remove positive exponent if there are enough digits given */
+ if (isnum (string) > 1 && strsrch (string, "E+") != NULL) {
+ lstr = strlen (string);
+ ndek = (int) (string[lstr-1] - 48);
+ ndek = ndek + (10 * ((int) (string[lstr-2] - 48)));
+ if (ndek < lstr - 7) {
+ lstr = lstr - 4;
+ string[lstr] = (char) 0;
+ string[lstr+1] = (char) 0;
+ string[lstr+2] = (char) 0;
+ string[lstr+3] = (char) 0;
+ sdot = strchr (string, '.');
+ if (ndek > 0 && sdot != NULL) {
+ for (i = 1; i <= ndek; i++) {
+ *sdot = *(sdot+1);
+ sdot++;
+ *sdot = '.';
+ }
+ }
+ }
+ }
+
+ /* Remove trailing zeroes if they are not significant */
+ if (dropzero) {
+ if (isnum (string) > 1 && strchr (string, '.') != NULL &&
+ strsrch (string, "E-") == NULL &&
+ strsrch (string, "E+") == NULL &&
+ strsrch (string, "e-") == NULL &&
+ strsrch (string, "e+") == NULL) {
+ lstr = strlen (string);
+ s = string + lstr - 1;
+ while (*s == '0' && lstr > 1) {
+ if (*(s - 1) != '.') {
+ *s = (char) 0;
+ lstr --;
+ }
+ s--;
+ }
+ }
+ }
+
+ /* Remove trailing decimal point */
+ lstr = strlen (string);
+ s = string + lstr - 1;
+ if (*s == '.')
+ *s = (char) 0;
+
+ /* Replace embedded blanks with underscores, if requested to */
+ if (fillblank) {
+ lstr = strlen (string);
+ slast = string + lstr;
+ for (s = string; s < slast; s++) {
+ if (*s == ' ') *s = '_';
+ }
+ }
+
+ return;
+
+}
+
+/* Oct 28 1994 New program
+ *
+ * Mar 1 1995 Search for / after second quote, not first one
+ * May 2 1995 Initialize line in HGETC; deal with logicals in HGETL better
+ * May 4 1995 Declare STRSRCH in KSEARCH
+ * Aug 7 1995 Fix line initialization in HGETC
+ * Dec 22 1995 Add HGETRA and HGETDEC to get degrees from xx:xx:xx.xxx string
+ *
+ * Jan 26 1996 Fix HGETL to not crash when parameter is not present
+ * Feb 1 1996 Fix HGETC to deal with quotes correctly
+ * Feb 1 1996 Fix HGETDEG to deal with sign correctly
+ * Feb 6 1996 Add HGETS to update character strings
+ * Feb 8 1996 Fix STRSRCH to find final characters in string
+ * Feb 23 1996 Add string to degree conversions
+ * Apr 26 1996 Add HGETDATE to get fractional year from date string
+ * May 22 1996 Fix documentation; return double from STR2RA and STR2DEC
+ * May 28 1996 Fix string translation of RA and Dec when no seconds
+ * Jun 10 1996 Remove unused variables after running lint
+ * Jun 17 1996 Fix bug which failed to return single character strings
+ * Jul 1 1996 Skip sign when reading declination after testing for it
+ * Jul 19 1996 Do not divide by 15 if RA header value is already in degrees
+ * Aug 5 1996 Add STRNSRCH to search strings which are not null-terminated
+ * Aug 6 1996 Make minor changes after lint
+ * Aug 8 1996 Fix ksearch bug which finds wrong keywords
+ * Aug 13 1996 Fix sign bug in STR2DEC for degrees
+ * Aug 26 1996 Drop unused variables ICOL0, NLINE, PREVCHAR from KSEARCH
+ * Sep 10 1996 Fix header length setting code
+ * Oct 15 1996 Clean up loops and fix ICOL assignment
+ * Nov 13 1996 Handle integer degrees correctly in STR2DEC
+ * Nov 21 1996 Make changes for Linux thanks to Sidik Isani
+ * Dec 12 1996 Add ISNUM to check to see whether strings are numbers
+ *
+ * Jan 22 1997 Add ifdefs for Eric Mandel (SAOtng)
+ * Jan 27 1997 Convert to integer through ATOF so exponents are recognized
+ * Jul 25 1997 Implement FITS version of ISO date format
+ *
+ * Feb 24 1998 Implement code to return IRAF multiple-keyword strings
+ * Mar 12 1998 Add subroutine NOTNUM
+ * Mar 27 1998 Add changes to match SKYCAT version
+ * Apr 30 1998 Add BLSEARCH() to find blank lines before END
+ * May 27 1998 Add HGETNDEC() to get number of decimal places in entry
+ * Jun 1 1998 Add VMS patch from Harry Payne at StSci
+ * Jun 18 1998 Fix code which extracts tokens from string values
+ * Jul 21 1998 Drop minus sign for values of -0
+ * Sep 29 1998 Treat hyphen-separated date as old format if 2-digit year
+ * Oct 7 1998 Clean up search for last blank line
+ *
+ * Apr 5 1999 Check lengths of strings before copying them
+ * May 5 1999 values.h -> POSIX limits.h: MAXINT->INT_MAX, MAXSHORT->SHRT_MAX
+ * Jul 15 1999 Add hgetm() options of 1- or 2-digit keyword extensions
+ * Oct 6 1999 Add gethlength() to return header length
+ * Oct 14 1999 In ksearch(), search only to null not to end of buffer
+ * Oct 15 1999 Return 1 from hgetndec() if successful
+ * Oct 20 1999 Drop unused variable after lint (val in hgetndec)
+ * Dec 3 1999 Fix isnum() to reject strings starting with a d or e
+ * Dec 20 1999 Update hgetdate() to get minutes and seconds right
+ *
+ * Feb 10 2000 Parse RA and Dec with spaces as well as colons as separators
+ * Feb 11 2000 Add null at end of multi-line keyword value character string
+ * Feb 25 2000 Change max search string length from 57600 to 256000
+ * Mar 15 2000 Deal with missing second quotes in string values
+ * Mar 17 2000 Return 2 from isnum() if number is floating point (.de)
+ * Mar 17 2000 Ignore leading # for numeric values in header
+ * Mar 21 2000 Implement -n to get string value starting with nth token
+ * Apr 5 2000 Reject +- in isnum()
+ * Jun 9 2000 Read keyword values even if no equal sign is present
+ * Sep 20 2000 Ignore linefeed at end of number in isnum()
+ * Oct 23 2000 Fix handling of embedded + or - in isnum()
+ *
+ * Jan 19 2000 Return 0 from isnum(), str2ra(), and str2dec() if string is null
+ * Mar 30 2001 Fix header length finding algorithm in ksearch()
+ * Jul 13 2001 Make val[] static int instead of int; drop unused variables
+ * Sep 12 2001 Read yyyy/mm/dd dates as well as dd/mm/yyyy
+ * Sep 20 2001 Ignore leading spaces in str2dec()
+ * Sep 20 2001 Ignore trailing spaces in isnum()
+ *
+ * Apr 3 2002 Add hgetr8c(), hgeti4c(), and hgetsc() for multiple WCS handling
+ * Apr 26 2002 Fix bug in hgetsc(), hgeti4c(), and hgetr8c() found by Bill Joye
+ * Jun 26 2002 Do not drop leading or trailing spaces in multi-line values
+ * Aug 6 2002 Add strcsrch() and strncsrch() for case-insensitive searches
+ * Aug 30 2002 Fix bug so strcsrch() really is case-insensitive
+ * Oct 20 2003 Add numdec() to return number of decimal places in a string
+ * Dec 9 2003 Fix numdec() to return 0 if no digits after decimal point
+ *
+ * Feb 26 2004 Extract value from keyword=value strings within a keyword value
+ * Apr 9 2004 Use strncsrch() in ksearch() to find differently-cased keywords
+ * Apr 28 2004 Free os2 in strncsrch() only if it is allocated
+ * Jul 13 2004 Accept D, d, E, or e as exponent delimiter in floating points
+ * Aug 30 2004 Change numdec() to accept sexigesimal numbers (:'s)
+ *
+ * Jun 27 2005 Drop unused variables
+ * Aug 30 2005 Adjust code in hlength()
+ *
+ * Jun 20 2006 Initialize uninitialized variables in strnsrch()
+ * Jun 29 2006 Add new subroutine strfix() to clean strings for other uses
+ * Jul 13 2006 Increase maximum number of multiline keywords from 20 to 500
+ *
+ * Jan 4 2007 Declare header, keyword to be const
+ * Jan 4 2007 Change WCS letter from char to char*
+ * Feb 28 2007 If header length is not set in hlength, set it to 0
+ * May 31 2007 Add return value of 3 to isnum() if string has colon(s)
+ * Aug 22 2007 If closing quote not found, make one up
+ *
+ * Nov 12 2009 In strfix(), if drop enclosing parantheses
+ *
+ * Apr 19 2011 In str2dec(), change comma to space
+ * May 19 2011 In strncsrch() always free allocated memory before returning
+ */
diff --git a/funtools/wcs/hput.c b/funtools/wcs/hput.c
new file mode 100644
index 0000000..7ec81ab
--- /dev/null
+++ b/funtools/wcs/hput.c
@@ -0,0 +1,1316 @@
+/*** File libwcs/hput.c
+ *** September 9, 2011
+ *** By Jessica Mink, jmink@cfa.harvard.edu
+ *** Harvard-Smithsonian Center for Astrophysics
+ *** Copyright (C) 1995-2011
+ *** Smithsonian Astrophysical Observatory, Cambridge, MA, USA
+
+ This library 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 2 of the License, or (at your option) any later version.
+
+ This library 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 this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Correspondence concerning WCSTools should be addressed as follows:
+ Internet email: jmink@cfa.harvard.edu
+ Postal address: Jessica Mink
+ Smithsonian Astrophysical Observatory
+ 60 Garden St.
+ Cambridge, MA 02138 USA
+
+ * Module: hput.c (Put FITS Header parameter values)
+ * Purpose: Implant values for parameters into FITS header string
+ * Subroutine: hputi4 (hstring,keyword,ival) sets int ival
+ * Subroutine: hputr4 (hstring,keyword,rval) sets real*4 rval
+ * Subroutine: hputr8 (hstring,keyword,dval) sets real*8 dval
+ * Subroutine: hputnr8 (hstring,keyword,ndec,dval) sets real*8 dval
+ * Subroutine: hputra (hstring,keyword,lval) sets right ascension as string
+ * Subroutine: hputdec (hstring,keyword,lval) sets declination as string
+ * Subroutine: hputl (hstring,keyword,lval) sets logical lval
+ * Subroutine: hputs (hstring,keyword,cval) sets character string adding ''
+ * Subroutine: hputm (hstring,keyword,cval) sets multi-line character string
+ * Subroutine: hputc (hstring,keyword,cval) sets character string cval
+ * Subroutine: hdel (hstring,keyword) deletes entry for keyword keyword
+ * Subroutine: hadd (hplace,keyword) adds entry for keyword at hplace
+ * Subroutine: hchange (hstring,keyword1,keyword2) changes keyword for entry
+ * Subroutine: hputcom (hstring,keyword,comment) sets comment for parameter keyword
+ * Subroutine: ra2str (out, lstr, ra, ndec) converts RA from degrees to string
+ * Subroutine: dec2str (out, lstr, dec, ndec) converts Dec from degrees to string
+ * Subroutine: deg2str (out, lstr, deg, ndec) converts degrees to string
+ * Subroutine: num2str (out, num, field, ndec) converts number to string
+ * Subroutine: getltime () returns current local time as ISO-style string
+ * Subroutine: getutime () returns current UT as ISO-style string
+ */
+#include <sys/time.h>
+#include <string.h> /* NULL, strlen, strstr, strcpy */
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include "fitshead.h"
+
+static int verbose=0; /* Set to 1 to print error messages and other info */
+
+static void fixnegzero();
+
+
+/* HPUTI4 - Set int keyword = ival in FITS header string */
+
+int
+hputi4 (hstring,keyword,ival)
+
+char *hstring; /* FITS-style header information in the format
+ <keyword>= <value> {/ <comment>}
+ each entry is padded with spaces to 80 characters */
+
+const char *keyword; /* Name of the variable in header to be returned.
+ If no line begins with this string, one is created.
+ The first 8 characters of keyword must be unique. */
+int ival; /* int number */
+{
+ char value[30];
+
+ /* Translate value from binary to ASCII */
+ sprintf (value,"%d",ival);
+
+ /* Put value into header string */
+ return (hputc (hstring,keyword,value));
+}
+
+
+/* HPUTR4 - Set float keyword = rval in FITS header string */
+
+int
+hputr4 (hstring, keyword, rval)
+
+char *hstring; /* FITS header string */
+const char *keyword; /* Keyword name */
+const float *rval; /* float number */
+
+{
+ char value[30];
+
+ /* Translate value from binary to ASCII */
+ sprintf (value, "%f", *rval);
+
+ /* Remove sign if string is -0 or extension thereof */
+ fixnegzero (value);
+
+ /* Put value into header string */
+ return (hputc (hstring, keyword, value));
+}
+
+
+/* HPUTR8 - Set double keyword = dval in FITS header string */
+
+int
+hputr8 (hstring, keyword, dval)
+
+char *hstring; /* FITS header string */
+const char *keyword; /* Keyword name */
+const double dval; /* double number */
+{
+ char value[30];
+
+ /* Translate value from binary to ASCII */
+ sprintf (value, "%g", dval);
+
+ /* Remove sign if string is -0 or extension thereof */
+ fixnegzero (value);
+
+ /* Put value into header string */
+ return (hputc (hstring, keyword, value));
+}
+
+
+/* HPUTNR8 - Set double keyword = dval in FITS header string */
+
+int
+hputnr8 (hstring, keyword, ndec, dval)
+
+char *hstring; /* FITS header string */
+const char *keyword; /* Keyword name */
+const int ndec; /* Number of decimal places to print */
+const double dval; /* double number */
+{
+ char value[30];
+ char format[8];
+ int i, lval;
+
+ /* Translate value from binary to ASCII */
+ if (ndec < 0) {
+ sprintf (format, "%%.%dg", -ndec);
+ sprintf (value, format, dval);
+ lval = (int) strlen (value);
+ for (i = 0; i < lval; i++)
+ if (value[i] == 'e') value[i] = 'E';
+ }
+ else {
+ sprintf (format, "%%.%df", ndec);
+ sprintf (value, format, dval);
+ }
+
+ /* Remove sign if string is -0 or extension thereof */
+ fixnegzero (value);
+
+ /* Put value into header string */
+ return (hputc (hstring, keyword, value));
+}
+
+
+/* HPUTRA - Set double keyword = hh:mm:ss.sss in FITS header string */
+
+int
+hputra (hstring, keyword, ra)
+
+char *hstring; /* FITS header string */
+const char *keyword; /* Keyword name */
+const double ra; /* Right ascension in degrees */
+{
+ char value[30];
+
+ /* Translate value from binary to ASCII */
+ ra2str (value, 30, ra, 3);
+
+ /* Remove sign if string is -0 or extension thereof */
+ fixnegzero (value);
+
+ /* Put value into header string */
+ return (hputs (hstring, keyword, value));
+}
+
+
+/* HPUTDEC - Set double keyword = dd:mm:ss.sss in FITS header string */
+
+int
+hputdec (hstring, keyword, dec)
+
+char *hstring; /* FITS header string */
+const char *keyword; /* Keyword name */
+const double dec; /* Declination in degrees */
+{
+ char value[30];
+
+ /* Translate value from binary to ASCII */
+ dec2str (value, 30, dec, 2);
+
+ /* Remove sign if string is -0 or extension thereof */
+ fixnegzero (value);
+
+ /* Put value into header string */
+ return (hputs (hstring, keyword, value));
+}
+
+
+/* FIXNEGZERO -- Drop - sign from beginning of any string which is all zeros */
+
+static void
+fixnegzero (string)
+
+char *string;
+{
+ int i, lstr;
+
+ if (string[0] != '-')
+ return;
+
+ /* Drop out if any non-zero digits in this string */
+ lstr = (int) strlen (string);
+ for (i = 1; i < lstr; i++) {
+ if (string[i] > '0' && string[i] <= '9')
+ return;
+ if (string[i] == 'd' || string[i] == 'e' || string[i] == ' ')
+ break;
+ }
+
+ /* Drop - from start of string; overwrite string in place */
+ for (i = 1; i < lstr; i++)
+ string[i-1] = string[i];
+ string[lstr-1] = (char) 0;
+
+ return;
+}
+
+
+
+/* HPUTL - Set keyword = F if lval=0, else T, in FITS header string */
+
+int
+hputl (hstring, keyword,lval)
+
+char *hstring; /* FITS header */
+const char *keyword; /* Keyword name */
+const int lval; /* logical variable (0=false, else true) */
+{
+ char value[8];
+
+ /* Translate value from binary to ASCII */
+ if (lval)
+ strcpy (value, "T");
+ else
+ strcpy (value, "F");
+
+ /* Put value into header string */
+ return (hputc (hstring,keyword,value));
+}
+
+
+/* HPUTM - Set multi-line character string in FITS header string */
+/* return number of keywords written */
+
+int
+hputm (hstring,keyword,cval)
+
+char *hstring; /* FITS header */
+const char *keyword; /* Keyword name root (6 characters or less) */
+const char *cval; /* character string containing the value for variable
+ keyword. trailing and leading blanks are removed. */
+{
+ int lroot, lcv, i, ii, nkw, lkw, lval;
+ int comment = 0;
+ const char *v;
+ char keyroot[8], newkey[12], value[80];
+ char squot = 39;
+
+ /* If COMMENT or HISTORY, use the same keyword on every line */
+ lkw = (int) strlen (keyword);
+ if (lkw == 7 && (strncmp (keyword,"COMMENT",7) == 0 ||
+ strncmp (keyword,"HISTORY",7) == 0)) {
+ comment = 1;
+ lroot = 0;
+ }
+
+ /* Set up keyword root, shortening it to 6 characters, if necessary */
+ else {
+ comment = 0;
+ strcpy (keyroot, keyword);
+ lroot = (int) strlen (keyroot);
+ if (lroot > 6) {
+ keyroot[6] = (char) 0;
+ lroot = 6;
+ }
+ }
+
+ /* Write keyword value one line of up to 67 characters at a time */
+ ii = '1';
+ nkw = 0;
+ lcv = (int) strlen (cval);
+ if (!comment) {
+ strcpy (newkey, keyroot);
+ strcat (newkey, "_");
+ newkey[lroot+2] = (char) 0;
+ }
+ v = cval;
+ while (lcv > 0) {
+ if (lcv > 67)
+ lval = 67;
+ else
+ lval = lcv;
+ value[0] = squot;
+ for (i = 1; i <= lval; i++)
+ value[i] = *v++;
+
+ /* Pad short strings to 8 characters */
+ if (lval < 8) {
+ for (i = lval+1; i < 9; i++)
+ value[i] = ' ';
+ lval = 8;
+ }
+ value[lval+1] = squot;
+ value[lval+2] = (char) 0;
+
+ /* Add this line to the header */
+ if (comment)
+ i = hputc (hstring, keyroot, value);
+ else {
+ newkey[lroot+1] = ii;
+ ii++;
+ i = hputc (hstring, newkey, value);
+ }
+ if (i != 0) return (i);
+ nkw++;
+ if (lcv > 67)
+ lcv = lcv - 67;
+ else
+ break;
+ }
+ return (nkw);
+}
+
+
+/* HPUTS - Set character string keyword = 'cval' in FITS header string */
+
+int
+hputs (hstring,keyword,cval)
+
+char *hstring; /* FITS header */
+const char *keyword; /* Keyword name */
+const char *cval; /* character string containing the value for variable
+ keyword. trailing and leading blanks are removed. */
+{
+ char squot = 39;
+ char value[80];
+ int lcval, i, lkeyword;
+
+ /* If COMMENT or HISTORY, just add it as is */
+ lkeyword = (int) strlen (keyword);
+ if (lkeyword == 7 && (strncmp (keyword,"COMMENT",7) == 0 ||
+ strncmp (keyword,"HISTORY",7) == 0))
+ return (hputc (hstring,keyword,cval));
+
+ /* find length of variable string */
+ lcval = (int) strlen (cval);
+ if (lcval > 67)
+ lcval = 67;
+
+ /* Put single quote at start of string */
+ value[0] = squot;
+ strncpy (&value[1],cval,lcval);
+
+ /* If string is less than eight characters, pad it with spaces */
+ if (lcval < 8) {
+ for (i = lcval; i < 8; i++) {
+ value[i+1] = ' ';
+ }
+ lcval = 8;
+ }
+
+ /* Add single quote and null to end of string */
+ value[lcval+1] = squot;
+ value[lcval+2] = (char) 0;
+
+ /* Put value into header string */
+ return (hputc (hstring,keyword,value));
+}
+
+
+/* HPUTC - Set character string keyword = value in FITS header string */
+/* Return -1 if error, 0 if OK */
+
+int
+hputc (hstring,keyword,value)
+
+char *hstring;
+const char *keyword;
+const char *value; /* character string containing the value for variable
+ keyword. trailing and leading blanks are removed. */
+{
+ char squot = 39;
+ char line[100];
+ char newcom[50];
+ char *vp, *v1, *v2, *q1, *q2, *c1, *ve;
+ int lkeyword, lcom, lval, lc, lv1, lhead, lblank, ln, nc, i;
+
+ /* Find length of keyword, value, and header */
+ lkeyword = (int) strlen (keyword);
+ lval = (int) strlen (value);
+ lhead = gethlength (hstring);
+
+ /* If COMMENT or HISTORY, always add it just before the END */
+ if (lkeyword == 7 && (strncmp (keyword,"COMMENT",7) == 0 ||
+ strncmp (keyword,"HISTORY",7) == 0)) {
+
+ /* First look for blank lines before END */
+ v1 = blsearch (hstring, "END");
+
+ /* Otherwise, create a space for it at the end of the header */
+ if (v1 == NULL) {
+
+ /* Find end of header */
+ v1 = ksearch (hstring,"END");
+
+ /* Align pointer at start of 80-character line */
+ lc = v1 - hstring;
+ ln = lc / 80;
+ nc = ln * 80;
+ v1 = hstring + nc;
+ v2 = v1 + 80;
+
+ /* If header length is exceeded, return error code */
+ if (v2 - hstring > lhead) {
+ return (-1);
+ }
+
+ /* Move END down 80 characters */
+ strncpy (v2, v1, 80);
+ }
+ else
+ v2 = v1 + 80;
+
+ /* Insert keyword */
+ strncpy (v1,keyword,7);
+
+ /* Pad with spaces */
+ for (vp = v1+lkeyword; vp < v2; vp++)
+ *vp = ' ';
+
+ if (lval > 71)
+ lv1 = 71;
+ else
+ lv1 = lval;
+
+ /* Insert comment */
+ strncpy (v1+9,value,lv1);
+ return (0);
+ }
+
+ /* Otherwise search for keyword */
+ else
+ v1 = ksearch (hstring,keyword);
+
+ /* If parameter is not found, find a place to put it */
+ if (v1 == NULL) {
+
+ /* First look for blank lines before END */
+ v1 = blsearch (hstring, "END");
+
+ /* Otherwise, create a space for it at the end of the header */
+ if (v1 == NULL) {
+ ve = ksearch (hstring,"END");
+ v1 = ve;
+
+ /* Align pointer at start of 80-character line */
+ lc = v1 - hstring;
+ ln = lc / 80;
+ nc = ln * 80;
+ v1 = hstring + nc;
+ v2 = v1 + 80;
+
+ /* If header length is exceeded, return error code */
+ if (v2 - hstring > lhead) {
+ return (-1);
+ }
+
+ strncpy (v2, ve, 80);
+ }
+ else
+ v2 = v1 + 80;
+ lcom = 0;
+ newcom[0] = 0;
+ }
+
+ /* Otherwise, extract the entry for this keyword from the header */
+ else {
+
+ /* Align pointer at start of 80-character line */
+ lc = v1 - hstring;
+ ln = lc / 80;
+ nc = ln * 80;
+ v1 = hstring + nc;
+ v2 = v1 + 80;
+
+ strncpy (line, v1, 80);
+ line[80] = 0;
+ v2 = v1 + 80;
+
+ /* check for quoted value */
+ q1 = strchr (line, squot);
+ if (q1 != NULL) {
+ q2 = strchr (q1+1,squot);
+ if (q2 != NULL)
+ c1 = strchr (q2,'/');
+ else
+ c1 = strrchr (line+79,'/');
+ }
+ else
+ c1 = strchr (line,'/');
+
+ /* extract comment and discount trailing spaces */
+ if (c1 != NULL) {
+ lcom = 80 - (c1 + 2 - line);
+ strncpy (newcom, c1+2, lcom);
+ vp = newcom + lcom - 1;
+ while (vp-- > newcom && *vp == ' ')
+ lcom--;
+ }
+ else {
+ newcom[0] = 0;
+ lcom = 0;
+ }
+ }
+
+ /* Fill new entry with spaces */
+ for (vp = v1; vp < v2; vp++)
+ *vp = ' ';
+
+ /* Copy keyword to new entry */
+ strncpy (v1, keyword, lkeyword);
+
+ /* Add parameter value in the appropriate place */
+ vp = v1 + 8;
+ *vp = '=';
+ vp = v1 + 9;
+ *vp = ' ';
+ vp = vp + 1;
+ if (*value == squot) {
+ strncpy (vp, value, lval);
+ if (lval+12 > 31)
+ lc = lval + 12;
+ else
+ lc = 30;
+ }
+ else {
+ vp = v1 + 30 - lval;
+ strncpy (vp, value, lval);
+ lc = 30;
+ }
+
+ /* Add comment in the appropriate place */
+ if (lcom > 0) {
+ if (lc+2+lcom > 80)
+ lcom = 77 - lc;
+ vp = v1 + lc; /* Jul 16 1997: was vp = v1 + lc * 2 */
+ *vp++ = ' ';
+ *vp++ = '/';
+ *vp++ = ' ';
+ lblank = v2 - vp;
+ for (i = 0; i < lblank; i++)
+ vp[i] = ' ';
+ if (lcom > lblank)
+ lcom = lblank;
+ strncpy (vp, newcom, lcom);
+ }
+
+ if (verbose) {
+ if (lcom > 0)
+ fprintf (stderr,"HPUT: %s = %s / %s\n",keyword, value, newcom);
+ else
+ fprintf (stderr,"HPUT: %s = %s\n",keyword, value);
+ }
+
+ return (0);
+}
+
+
+/* HPUTCOM - Set comment for keyword or on line in FITS header string */
+
+int
+hputcom (hstring,keyword,comment)
+
+ char *hstring;
+ const char *keyword;
+ const char *comment;
+{
+ char squot, slash, space;
+ char line[100];
+ int lkeyword, lcom, lhead, i, lblank, ln, nc, lc;
+ char *vp, *v1, *v2, *c0, *c1, *q1, *q2;
+
+ squot = (char) 39;
+ slash = (char) 47;
+ space = (char) 32;
+
+ /* Find length of variable name */
+ lkeyword = (int) strlen (keyword);
+ lhead = gethlength (hstring);
+ lcom = (int) strlen (comment);
+
+ /* If COMMENT or HISTORY, always add it just before the END */
+ if (lkeyword == 7 && (strncmp (keyword,"COMMENT",7) == 0 ||
+ strncmp (keyword,"HISTORY",7) == 0)) {
+
+ /* Find end of header */
+ v1 = ksearch (hstring,"END");
+
+ /* Align pointer at start of 80-character line */
+ lc = v1 - hstring;
+ ln = lc / 80;
+ nc = ln * 80;
+ v1 = hstring + nc;
+ v2 = v1 + 80;
+
+ /* If header length is exceeded, return error code */
+ if (v2 - hstring > lhead) {
+ return (-1);
+ }
+
+ /* Move END down 80 characters */
+ strncpy (v2, v1, 80);
+
+ /* blank out new line and insert keyword */
+ for (vp = v1; vp < v2; vp++)
+ *vp = ' ';
+ strncpy (v1, keyword, lkeyword);
+ c0 = v1 + lkeyword;
+ }
+
+ /* Search header string for variable name */
+ else {
+ v1 = ksearch (hstring,keyword);
+
+ /* If parameter is not found, return without doing anything */
+ if (v1 == NULL) {
+ if (verbose)
+ fprintf (stderr,"HPUTCOM: %s not found\n",keyword);
+ return (-1);
+ }
+
+ /* Align pointer at start of 80-character line */
+ lc = v1 - hstring;
+ ln = lc / 80;
+ nc = ln * 80;
+ v1 = hstring + nc;
+ v2 = v1 + 80;
+
+ /* Extract entry for this variable from the header */
+ strncpy (line, v1, 80);
+ line[80] = '\0'; /* Null-terminate line before strchr call */
+
+ /* check for quoted value */
+ q1 = strchr (line,squot);
+ c1 = strchr (line,slash);
+ if (q1 != NULL) {
+ if (c1 != NULL && q1 < c1) {
+ q2 = strchr (q1+1, squot);
+ if (q2 == NULL) {
+ q2 = c1 - 1;
+ while (*q2 == space)
+ q2--;
+ q2++;
+ }
+ else if (c1 < q2)
+ c1 = strchr (q2, slash);
+ }
+ else if (c1 == NULL) {
+ q2 = strchr (q1+1, squot);
+ if (q2 == NULL) {
+ q2 = line + 79;
+ while (*q2 == space)
+ q2--;
+ q2++;
+ }
+ }
+ else
+ q1 = NULL;
+ q2 = NULL;
+ }
+
+ else
+ q2 = NULL;
+
+ if (c1 != NULL)
+ c0 = v1 + (c1 - line) - 1;
+ else if (q2 == NULL || q2-line < 30)
+ c0 = v1 + 30;
+ else
+ c0 = v1 + (q2 - line) + 1; /* allan: 1997-09-30, was c0=q2+2 */
+
+ /* If comment will not fit at all, return */
+ if (c0 - v1 > 77)
+ return (-1);
+ strncpy (c0, " / ",3);
+ }
+
+ /* Create new entry */
+ if (lcom > 0) {
+ c1 = c0 + 3;
+ lblank = v1 + 79 - c1;
+ if (lcom > lblank)
+ lcom = lblank;
+ for (i = 0; i < lblank; i++)
+ c1[i] = ' ';
+ strncpy (c1, comment, lcom);
+ }
+
+ if (verbose) {
+ fprintf (stderr,"HPUTCOM: %s / %s\n",keyword,comment);
+ }
+ return (0);
+}
+
+
+static int leaveblank = 0; /* If 1, leave blank line when deleting */
+void
+setleaveblank (lb)
+int lb; { leaveblank = lb; return; }
+
+static int headshrink=1; /* Set to 1 to drop line after deleting keyword */
+void
+setheadshrink (hsh)
+int hsh;
+{headshrink = hsh; return;}
+
+/* HDEL - Set character string keyword = value in FITS header string
+ * returns 1 if entry deleted, else 0
+ */
+
+int
+hdel (hstring,keyword)
+
+char *hstring; /* FITS header */
+const char *keyword; /* Keyword of entry to be deleted */
+{
+ char *v, *v1, *v2, *ve;
+
+ /* Search for keyword */
+ v1 = ksearch (hstring,keyword);
+
+ /* If keyword is not found, return header unchanged */
+ if (v1 == NULL) {
+ return (0);
+ }
+
+ /* Find end of header */
+ ve = ksearch (hstring,"END");
+
+ /* If headshrink is 0, leave END where it is */
+ if (!leaveblank && !headshrink)
+ ve = ve - 80;
+
+ /* Cover deleted keyword line with spaces */
+ if (leaveblank) {
+ v2 = v1 + 80;
+ for (v = ve; v < v2; v++)
+ *v = ' ';
+ }
+
+ /* Shift rest of header up one line */
+ else {
+ for (v = v1; v < ve; v = v + 80) {
+ v2 = v + 80;
+ strncpy (v, v2, 80);
+ }
+
+ /* Cover former last line with spaces */
+ v2 = ve + 80;
+ for (v = ve; v < v2; v++)
+ *v = ' ';
+ }
+
+ return (1);
+}
+
+
+/* HADD - Add character string keyword = value to FITS header string
+ * returns 1 if entry added, else 0
+ * Call hputx() to put value into entry
+ */
+
+int
+hadd (hplace, keyword)
+
+char *hplace; /* FITS header position for new keyword */
+const char *keyword; /* Keyword of entry to be deleted */
+{
+ char *v, *v1, *v2, *ve;
+ int i, lkey;
+
+ /* Find end of header */
+ ve = ksearch (hplace,"END");
+
+ /* If END is not found, return header unchanged */
+ if (ve == NULL) {
+ return (0);
+ }
+
+ v1 = hplace;
+
+ /* Shift rest of header down one line */
+ /* limit bug found by Paolo Montegriffo fixed 2000-04-19 */
+ for (v = ve; v >= v1; v = v - 80) {
+ v2 = v + 80;
+ strncpy (v2, v, 80);
+ }
+
+ /* Cover former first line with new keyword */
+ lkey = (int) strlen (keyword);
+ strncpy (hplace, keyword, lkey);
+ if (lkey < 8) {
+ for (i = lkey; i < 8; i++)
+ hplace[i] = ' ';
+ hplace[8] = '=';
+ }
+ for (i = 9; i < 80; i++)
+ hplace[i] = ' ';
+
+ return (1);
+}
+
+
+/* HCHANGE - Changes keyword for entry from keyword1 to keyword2 in FITS
+ header string
+ * returns 1 if entry changed, else 0
+ */
+
+int
+hchange (hstring, keyword1, keyword2)
+
+char *hstring; /* FITS header */
+const char *keyword1; /* Keyword to be changed */
+const char *keyword2; /* New keyword name */
+{
+ char *v, *v1;
+ const char *v2;
+ int lv2, i;
+
+ /* Search for keyword */
+ v1 = ksearch (hstring,keyword1);
+
+ /* If keyword is not found, return header unchanged */
+ if (!v1)
+ return (0);
+
+ else {
+ lv2 = (int) strlen (keyword2);
+ v = v1;
+ v2 = keyword2;
+ for (i = 0; i < 8; i++) {
+ if (i < lv2)
+ v[i] = v2[i];
+ else
+ v[i] = ' ';
+ }
+ }
+
+ return (1);
+}
+
+
+/* Write the right ascension ra in sexagesimal format into string*/
+
+void
+ra2str (string, lstr, ra, ndec)
+
+char *string; /* Character string (returned) */
+int lstr; /* Maximum number of characters in string */
+double ra; /* Right ascension in degrees */
+int ndec; /* Number of decimal places in seconds */
+
+{
+ double a,b;
+ double seconds;
+ char tstring[64];
+ int hours;
+ int minutes;
+ int isec, ltstr;
+ double dsgn;
+
+ /* Keep RA between 0 and 360 */
+ if (ra < 0.0 ) {
+ ra = -ra;
+ dsgn = -1.0;
+ }
+ else
+ dsgn = 1.0;
+ ra = fmod(ra, 360.0);
+ ra *= dsgn;
+ if (ra < 0.0)
+ ra = ra + 360.0;
+
+ a = ra / 15.0;
+
+ /* Convert to hours */
+ hours = (int) a;
+
+ /* Compute minutes */
+ b = (a - (double)hours) * 60.0;
+ minutes = (int) b;
+
+ /* Compute seconds */
+ seconds = (b - (double)minutes) * 60.0;
+
+ if (ndec > 5) {
+ if (seconds > 59.999999) {
+ seconds = 0.0;
+ minutes = minutes + 1;
+ }
+ if (minutes > 59) {
+ minutes = 0;
+ hours = hours + 1;
+ }
+ hours = hours % 24;
+ (void) sprintf (tstring,"%02d:%02d:%09.6f",hours,minutes,seconds);
+ }
+ else if (ndec > 4) {
+ if (seconds > 59.99999) {
+ seconds = 0.0;
+ minutes = minutes + 1;
+ }
+ if (minutes > 59) {
+ minutes = 0;
+ hours = hours + 1;
+ }
+ hours = hours % 24;
+ (void) sprintf (tstring,"%02d:%02d:%08.5f",hours,minutes,seconds);
+ }
+ else if (ndec > 3) {
+ if (seconds > 59.9999) {
+ seconds = 0.0;
+ minutes = minutes + 1;
+ }
+ if (minutes > 59) {
+ minutes = 0;
+ hours = hours + 1;
+ }
+ hours = hours % 24;
+ (void) sprintf (tstring,"%02d:%02d:%07.4f",hours,minutes,seconds);
+ }
+ else if (ndec > 2) {
+ if (seconds > 59.999) {
+ seconds = 0.0;
+ minutes = minutes + 1;
+ }
+ if (minutes > 59) {
+ minutes = 0;
+ hours = hours + 1;
+ }
+ hours = hours % 24;
+ (void) sprintf (tstring,"%02d:%02d:%06.3f",hours,minutes,seconds);
+ }
+ else if (ndec > 1) {
+ if (seconds > 59.99) {
+ seconds = 0.0;
+ minutes = minutes + 1;
+ }
+ if (minutes > 59) {
+ minutes = 0;
+ hours = hours + 1;
+ }
+ hours = hours % 24;
+ (void) sprintf (tstring,"%02d:%02d:%05.2f",hours,minutes,seconds);
+ }
+ else if (ndec > 0) {
+ if (seconds > 59.9) {
+ seconds = 0.0;
+ minutes = minutes + 1;
+ }
+ if (minutes > 59) {
+ minutes = 0;
+ hours = hours + 1;
+ }
+ hours = hours % 24;
+ (void) sprintf (tstring,"%02d:%02d:%04.1f",hours,minutes,seconds);
+ }
+ else {
+ isec = (int)(seconds + 0.5);
+ if (isec > 59) {
+ isec = 0;
+ minutes = minutes + 1;
+ }
+ if (minutes > 59) {
+ minutes = 0;
+ hours = hours + 1;
+ }
+ hours = hours % 24;
+ (void) sprintf (tstring,"%02d:%02d:%02d",hours,minutes,isec);
+ }
+
+ /* Move formatted string to returned string */
+ ltstr = (int) strlen (tstring);
+ if (ltstr < lstr-1)
+ strcpy (string, tstring);
+ else {
+ strncpy (string, tstring, lstr-1);
+ string[lstr-1] = 0;
+ }
+ return;
+}
+
+
+/* Write the variable a in sexagesimal format into string */
+
+void
+dec2str (string, lstr, dec, ndec)
+
+char *string; /* Character string (returned) */
+int lstr; /* Maximum number of characters in string */
+double dec; /* Declination in degrees */
+int ndec; /* Number of decimal places in arcseconds */
+
+{
+ double a, b, dsgn, deg1;
+ double seconds;
+ char sign;
+ int degrees;
+ int minutes;
+ int isec, ltstr;
+ char tstring[64];
+
+ /* Keep angle between -180 and 360 degrees */
+ deg1 = dec;
+ if (deg1 < 0.0 ) {
+ deg1 = -deg1;
+ dsgn = -1.0;
+ }
+ else
+ dsgn = 1.0;
+ deg1 = fmod(deg1, 360.0);
+ deg1 *= dsgn;
+ if (deg1 <= -180.0)
+ deg1 = deg1 + 360.0;
+
+ a = deg1;
+
+ /* Set sign and do all the rest with a positive */
+ if (a < 0) {
+ sign = '-';
+ a = -a;
+ }
+ else
+ sign = '+';
+
+ /* Convert to degrees */
+ degrees = (int) a;
+
+ /* Compute minutes */
+ b = (a - (double)degrees) * 60.0;
+ minutes = (int) b;
+
+ /* Compute seconds */
+ seconds = (b - (double)minutes) * 60.0;
+
+ if (ndec > 5) {
+ if (seconds > 59.999999) {
+ seconds = 0.0;
+ minutes = minutes + 1;
+ }
+ if (minutes > 59) {
+ minutes = 0;
+ degrees = degrees + 1;
+ }
+ (void) sprintf (tstring,"%c%02d:%02d:%09.6f",sign,degrees,minutes,seconds);
+ }
+ else if (ndec > 4) {
+ if (seconds > 59.99999) {
+ seconds = 0.0;
+ minutes = minutes + 1;
+ }
+ if (minutes > 59) {
+ minutes = 0;
+ degrees = degrees + 1;
+ }
+ (void) sprintf (tstring,"%c%02d:%02d:%08.5f",sign,degrees,minutes,seconds);
+ }
+ else if (ndec > 3) {
+ if (seconds > 59.9999) {
+ seconds = 0.0;
+ minutes = minutes + 1;
+ }
+ if (minutes > 59) {
+ minutes = 0;
+ degrees = degrees + 1;
+ }
+ (void) sprintf (tstring,"%c%02d:%02d:%07.4f",sign,degrees,minutes,seconds);
+ }
+ else if (ndec > 2) {
+ if (seconds > 59.999) {
+ seconds = 0.0;
+ minutes = minutes + 1;
+ }
+ if (minutes > 59) {
+ minutes = 0;
+ degrees = degrees + 1;
+ }
+ (void) sprintf (tstring,"%c%02d:%02d:%06.3f",sign,degrees,minutes,seconds);
+ }
+ else if (ndec > 1) {
+ if (seconds > 59.99) {
+ seconds = 0.0;
+ minutes = minutes + 1;
+ }
+ if (minutes > 59) {
+ minutes = 0;
+ degrees = degrees + 1;
+ }
+ (void) sprintf (tstring,"%c%02d:%02d:%05.2f",sign,degrees,minutes,seconds);
+ }
+ else if (ndec > 0) {
+ if (seconds > 59.9) {
+ seconds = 0.0;
+ minutes = minutes + 1;
+ }
+ if (minutes > 59) {
+ minutes = 0;
+ degrees = degrees + 1;
+ }
+ (void) sprintf (tstring,"%c%02d:%02d:%04.1f",sign,degrees,minutes,seconds);
+ }
+ else {
+ isec = (int)(seconds + 0.5);
+ if (isec > 59) {
+ isec = 0;
+ minutes = minutes + 1;
+ }
+ if (minutes > 59) {
+ minutes = 0;
+ degrees = degrees + 1;
+ }
+ (void) sprintf (tstring,"%c%02d:%02d:%02d",sign,degrees,minutes,isec);
+ }
+
+ /* Move formatted string to returned string */
+ ltstr = (int) strlen (tstring);
+ if (ltstr < lstr-1)
+ strcpy (string, tstring);
+ else {
+ strncpy (string, tstring, lstr-1);
+ string[lstr-1] = 0;
+ }
+ return;
+}
+
+
+/* Write the angle a in decimal format into string */
+
+void
+deg2str (string, lstr, deg, ndec)
+
+char *string; /* Character string (returned) */
+int lstr; /* Maximum number of characters in string */
+double deg; /* Angle in degrees */
+int ndec; /* Number of decimal places in degree string */
+
+{
+ char degform[8];
+ int field, ltstr;
+ char tstring[64];
+ double deg1;
+ double dsgn;
+
+ /* Keep angle between -180 and 360 degrees */
+ deg1 = deg;
+ if (deg1 < 0.0 ) {
+ deg1 = -deg1;
+ dsgn = -1.0;
+ }
+ else
+ dsgn = 1.0;
+ deg1 = fmod(deg1, 360.0);
+ deg1 *= dsgn;
+ if (deg1 <= -180.0)
+ deg1 = deg1 + 360.0;
+
+ /* Write angle to string, adding 4 digits to number of decimal places */
+ field = ndec + 4;
+ if (ndec > 0) {
+ sprintf (degform, "%%%d.%df", field, ndec);
+ sprintf (tstring, degform, deg1);
+ }
+ else {
+ sprintf (degform, "%%%4d", field);
+ sprintf (tstring, degform, (int)deg1);
+ }
+
+ /* Move formatted string to returned string */
+ ltstr = (int) strlen (tstring);
+ if (ltstr < lstr-1)
+ strcpy (string, tstring);
+ else {
+ strncpy (string, tstring, lstr-1);
+ string[lstr-1] = 0;
+ }
+ return;
+}
+
+
+/* Write the variable a in decimal format into field-character string */
+
+void
+num2str (string, num, field, ndec)
+
+char *string; /* Character string (returned) */
+double num; /* Number */
+int field; /* Number of characters in output field (0=any) */
+int ndec; /* Number of decimal places in degree string */
+
+{
+ char numform[8];
+
+ if (field > 0) {
+ if (ndec > 0) {
+ sprintf (numform, "%%%d.%df", field, ndec);
+ sprintf (string, numform, num);
+ }
+ else {
+ sprintf (numform, "%%%dd", field);
+ sprintf (string, numform, (int)num);
+ }
+ }
+ else {
+ if (ndec > 0) {
+ sprintf (numform, "%%.%df", ndec);
+ sprintf (string, numform, num);
+ }
+ else {
+ sprintf (string, "%d", (int)num);
+ }
+ }
+ return;
+}
+
+/* Dec 14 1995 Original subroutines
+
+ * Feb 5 1996 Added HDEL to delete keyword entry from FITS header
+ * Feb 7 1996 Add EOS to LINE in HPUTC
+ * Feb 21 1996 Add RA2STR and DEC2STR string routines
+ * Jul 19 1996 Add HPUTRA and HPUTDEC
+ * Jul 22 1996 Add HCHANGE to change keywords
+ * Aug 5 1996 Add HPUTNR8 to save specific number of decimal places
+ * Oct 15 1996 Fix spelling
+ * Nov 1 1996 Add DEG2STR to set specific number of decimal places
+ * Nov 1 1996 Allow DEC2STR to handle upt to 6 decimal places
+ *
+ * Mar 20 1997 Fix format error in DEG2STR
+ * Jul 7 1997 Fix 2 errors in HPUTCOM found by Allan Brighton
+ * Jul 16 1997 Fix error in HPUTC found by Allan Brighton
+ * Jul 17 1997 Fix error in HPUTC found by Allan Brighton
+ * Sep 30 1997 Fix error in HPUTCOM found by Allan Brighton
+ * Dec 15 1997 Fix minor bugs after lint
+ * Dec 31 1997 Always put two hour digits in RA2STR
+ *
+ * Feb 25 1998 Add HADD to insert keywords at specific locations
+ * Mar 27 1998 If n is negative, write g format in HPUTNR8()
+ * Apr 24 1998 Add NUM2STR() for easy output formatting
+ * Apr 30 1998 Use BLSEARCH() to overwrite blank lines before END
+ * May 27 1998 Keep Dec between -90 and +90 in DEC2STR()
+ * May 28 1998 Keep RA between 0 and 360 in RA2STR()
+ * Jun 2 1998 Fix bug when filling in blank lines before END
+ * Jun 24 1998 Add string length to ra2str(), dec2str(), and deg2str()
+ * Jun 25 1998 Make string converstion subroutines more robust
+ * Aug 31 1998 Add getltime() and getutime()
+ * Sep 28 1998 Null-terminate comment in HPUTCOM (Allan Brighton)
+ * Oct 1 1998 Change clock declaration in getltime() from int (Allan Brighton)
+ *
+ * Jan 28 1999 Fix bug to avoid writing HISTORY or COMMENT past 80 characters
+ * Jul 14 1999 Pad string in hputs() to minimum of 8 characters
+ * Aug 16 1999 Keep angle between -180 and +360 in dec2str()
+ * Oct 6 1999 Reallocate header buffer if it is too small in hputc()
+ * Oct 14 1999 Do not reallocate header; return error if not successful
+ *
+ * Mar 2 2000 Do not add quotes if adding HISTORY or COMMENT with hputs()
+ * Mar 22 2000 Move getutime() and getltime() to dateutil.c
+ * Mar 27 2000 Add hputm() for muti-line keywords
+ * Mar 27 2000 Fix bug testing for space to fit comment in hputcom()
+ * Apr 19 2000 Fix bug in hadd() which overwrote line
+ * Jun 2 2000 Dropped unused variable lv in hputm() after lint
+ * Jul 20 2000 Drop unused variables blank and i in hputc()
+ *
+ * Jan 11 2001 Print all messages to stderr
+ * Jan 18 2001 Drop declaration of blsearch(); it is in fitshead.h
+ *
+ * Jan 4 2002 Fix placement of comments
+ *
+ * Jul 1 2004 Add headshrink to optionally keep blank lines in header
+ * Sep 3 2004 Fix bug so comments are not pushed onto next line if long value
+ * Sep 16 2004 Add fixnegzero() to avoid putting signed zero values in header
+ *
+ * May 22 2006 Add option to leave blank line when deleting a keyword
+ * Jun 15 2006 Fix comment alignment in hputc() and hputcom()
+ * Jun 20 2006 Initialized uninitialized variables in hputm() and hputcom()
+ *
+ * Jan 4 2007 Declare keyword to be const
+ * Jan 4 2007 Drop unused subroutine hputi2()
+ * Jan 5 2007 Drop ksearch() declarations; it is now in fitshead.h
+ * Jan 16 2007 Fix bugs in ra2str() and dec2str() so ndec=0 works
+ * Aug 20 2007 Fix bug so comments after quoted keywords work
+ * Aug 22 2007 If closing quote not found, make one up
+ *
+ * Sep 9 2011 Always initialize q2 and lroot
+ */
diff --git a/funtools/wcs/iget.c b/funtools/wcs/iget.c
new file mode 100644
index 0000000..58e54f7
--- /dev/null
+++ b/funtools/wcs/iget.c
@@ -0,0 +1,531 @@
+/*** File libwcs/iget.c
+ *** January 4, 2007
+ *** By Jessica Mink, jmink@cfa.harvard.edu
+ *** Harvard-Smithsonian Center for Astrophysics
+ *** Copyright (C) 1998-2007
+ *** Smithsonian Astrophysical Observatory, Cambridge, MA, USA
+
+ This library 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 2 of the License, or (at your option) any later version.
+
+ This library 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 this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Correspondence concerning WCSTools should be addressed as follows:
+ Internet email: jmink@cfa.harvard.edu
+ Postal address: Jessica Mink
+ Smithsonian Astrophysical Observatory
+ 60 Garden St.
+ Cambridge, MA 02138 USA
+
+ * Module: iget.c (Get IRAF FITS Header parameter values)
+ * Purpose: Extract values for variables from IRAF keyword value string
+ * Subroutine: mgeti4 (hstring,mkey,keyword,ival) returns long integer
+ * Subroutine: mgetr8 (hstring,mkey,keyword,dval) returns double
+ * Subroutine: mgetstr (hstring,mkey,keyword,lstr,str) returns character string
+ * Subroutine: igeti4 (hstring,keyword,ival) returns long integer
+ * Subroutine: igetr4 (hstring,keyword,rval) returns real
+ * Subroutine: igetr8 (hstring,keyword,dval) returns double
+ * Subroutine: igets (hstring,keyword,lstr,str) returns character string
+ * Subroutine: igetc (hstring,keyword) returns character string
+ * Subroutine: isearch (hstring,keyword) returns pointer to header string entry
+ */
+
+#include <string.h> /* NULL, strlen, strstr, strcpy */
+#include <stdio.h>
+#include "fitshead.h" /* FITS header extraction subroutines */
+#include <stdlib.h>
+#ifndef VMS
+#include <limits.h>
+#else
+#define INT_MAX 2147483647 /* Biggest number that can fit in long */
+#define SHRT_MAX 32767
+#endif
+
+#define MAX_LVAL 2000
+
+static char *isearch();
+static char val[30];
+
+/* Extract long value for variable from IRAF multiline keyword value */
+
+int
+mgeti4 (hstring, mkey, keyword, ival)
+
+const char *hstring; /* Character string containing FITS or IRAF header information
+ in the format <keyword>= <value> ... */
+const char *mkey; /* Character string containing the name of the multi-line
+ keyword, the string value of which contains the desired
+ keyword, the value of which is returned. */
+const char *keyword; /* Character string containing the name of the keyword
+ within the multiline IRAF keyword */
+int *ival; /* Integer value returned */
+{
+ char *mstring;
+
+ mstring = malloc (MAX_LVAL);
+
+ if (hgetm (hstring, mkey, MAX_LVAL, mstring)) {
+ if (igeti4 (mstring, keyword, ival)) {
+ free (mstring);
+ return (1);
+ }
+ else {
+ free (mstring);
+ return (0);
+ }
+ }
+ else {
+ free (mstring);
+ return (0);
+ }
+}
+
+/* Extract double value for variable from IRAF multiline keyword value */
+
+int
+mgetr8 (hstring, mkey, keyword, dval)
+
+const char *hstring; /* Character string containing FITS or IRAF header information
+ in the format <keyword>= <value> ... */
+const char *mkey; /* Character string containing the name of the multi-line
+ keyword, the string value of which contains the desired
+ keyword, the value of which is returned. */
+const char *keyword; /* Character string containing the name of the keyword
+ within the multiline IRAF keyword */
+double *dval; /* Integer value returned */
+{
+ char *mstring;
+ mstring = malloc (MAX_LVAL);
+
+ if (hgetm (hstring, mkey, MAX_LVAL, mstring)) {
+ if (igetr8 (mstring, keyword, dval)) {
+ free (mstring);
+ return (1);
+ }
+ else {
+ free (mstring);
+ return (0);
+ }
+ }
+ else {
+ free (mstring);
+ return (0);
+ }
+}
+
+
+/* Extract string value for variable from IRAF keyword value string */
+
+int
+mgetstr (hstring, mkey, keyword, lstr, str)
+
+const char *hstring; /* character string containing FITS header information
+ in the format <keyword>= <value> {/ <comment>} */
+const char *mkey; /* Character string containing the name of the multi-line
+ keyword, the string value of which contains the desired
+ keyword, the value of which is returned. */
+const char *keyword; /* character string containing the name of the keyword
+ the value of which is returned. hget searches for a
+ line beginning with this string. if "[n]" is present,
+ the n'th token in the value is returned.
+ (the first 8 characters must be unique) */
+const int lstr; /* Size of str in characters */
+char *str; /* String (returned) */
+{
+ char *mstring;
+ mstring = malloc (MAX_LVAL);
+
+ if (hgetm (hstring, mkey, MAX_LVAL, mstring)) {
+ if (igets (mstring, keyword, lstr, str)) {
+ free (mstring);
+ return (1);
+ }
+ else {
+ free (mstring);
+ return (0);
+ }
+ }
+ else {
+ free (mstring);
+ return (0);
+ }
+}
+
+
+/* Extract long value for variable from IRAF keyword value string */
+
+int
+igeti4 (hstring, keyword, ival)
+
+const char *hstring; /* character string containing IRAF header information
+ in the format <keyword>= <value> ... */
+const char *keyword; /* character string containing the name of the keyword
+ the value of which is returned. hget searches for a
+ line beginning with this string. if "[n]" is present,
+ the n'th token in the value is returned.
+ (the first 8 characters must be unique) */
+int *ival; /* Integer value returned */
+{
+char *value;
+double dval;
+int minint;
+
+/* Get value from header string */
+ value = igetc (hstring,keyword);
+
+/* Translate value from ASCII to binary */
+ if (value != NULL) {
+ minint = -INT_MAX - 1;
+ strcpy (val, value);
+ dval = atof (val);
+ if (dval+0.001 > INT_MAX)
+ *ival = INT_MAX;
+ else if (dval >= 0)
+ *ival = (int) (dval + 0.001);
+ else if (dval-0.001 < minint)
+ *ival = minint;
+ else
+ *ival = (int) (dval - 0.001);
+ return (1);
+ }
+ else {
+ return (0);
+ }
+}
+
+
+/* Extract integer*2 value for variable from IRAF keyword value string */
+
+int
+igeti2 (hstring,keyword,ival)
+
+const char *hstring; /* character string containing FITS header information
+ in the format <keyword>= <value> {/ <comment>} */
+const char *keyword; /* character string containing the name of the keyword
+ the value of which is returned. hget searches for a
+ line beginning with this string. if "[n]" is present,
+ the n'th token in the value is returned.
+ (the first 8 characters must be unique) */
+short *ival;
+{
+char *value;
+double dval;
+int minshort;
+
+/* Get value from header string */
+ value = igetc (hstring,keyword);
+
+/* Translate value from ASCII to binary */
+ if (value != NULL) {
+ strcpy (val, value);
+ dval = atof (val);
+ minshort = -SHRT_MAX - 1;
+ if (dval+0.001 > SHRT_MAX)
+ *ival = SHRT_MAX;
+ else if (dval >= 0)
+ *ival = (short) (dval + 0.001);
+ else if (dval-0.001 < minshort)
+ *ival = minshort;
+ else
+ *ival = (short) (dval - 0.001);
+ return (1);
+ }
+ else {
+ return (0);
+ }
+}
+
+/* Extract real value for variable from IRAF keyword value string */
+
+int
+igetr4 (hstring,keyword,rval)
+
+const char *hstring; /* character string containing FITS header information
+ in the format <keyword>= <value> {/ <comment>} */
+const char *keyword; /* character string containing the name of the keyword
+ the value of which is returned. hget searches for a
+ line beginning with this string. if "[n]" is present,
+ the n'th token in the value is returned.
+ (the first 8 characters must be unique) */
+float *rval;
+{
+ char *value;
+
+/* Get value from header string */
+ value = igetc (hstring,keyword);
+
+/* Translate value from ASCII to binary */
+ if (value != NULL) {
+ strcpy (val, value);
+ *rval = (float) atof (val);
+ return (1);
+ }
+ else {
+ return (0);
+ }
+}
+
+
+/* Extract real*8 value for variable from IRAF keyword value string */
+
+int
+igetr8 (hstring,keyword,dval)
+
+const char *hstring; /* character string containing FITS header information
+ in the format <keyword>= <value> {/ <comment>} */
+const char *keyword; /* character string containing the name of the keyword
+ the value of which is returned. hget searches for a
+ line beginning with this string. if "[n]" is present,
+ the n'th token in the value is returned.
+ (the first 8 characters must be unique) */
+double *dval;
+{
+ char *value,val[30];
+
+/* Get value from header string */
+ value = igetc (hstring,keyword);
+
+/* Translate value from ASCII to binary */
+ if (value != NULL) {
+ strcpy (val, value);
+ *dval = atof (val);
+ return (1);
+ }
+ else {
+ return (0);
+ }
+}
+
+
+/* Extract string value for variable from IRAF keyword value string */
+
+int
+igets (hstring, keyword, lstr, str)
+
+const char *hstring; /* character string containing FITS header information
+ in the format <keyword>= <value> {/ <comment>} */
+const char *keyword; /* character string containing the name of the keyword
+ the value of which is returned. hget searches for a
+ line beginning with this string. if "[n]" is present,
+ the n'th token in the value is returned.
+ (the first 8 characters must be unique) */
+const int lstr; /* Size of str in characters */
+char *str; /* String (returned) */
+{
+ char *value;
+ int lval;
+
+/* Get value from header string */
+ value = igetc (hstring,keyword);
+
+ if (value != NULL) {
+ lval = strlen (value);
+ if (lval < lstr)
+ strcpy (str, value);
+ else if (lstr > 1)
+ strncpy (str, value, lstr-1);
+ else
+ str[0] = value[0];
+ return (1);
+ }
+ else
+ return (0);
+}
+
+
+/* Extract character value for variable from IRAF keyword value string */
+
+char *
+igetc (hstring,keyword0)
+
+const char *hstring; /* character string containing IRAF keyword value string
+ in the format <keyword>= <value> {/ <comment>} */
+const char *keyword0; /* character string containing the name of the keyword
+ the value of which is returned. iget searches for a
+ line beginning with this string. if "[n]" is present,
+ the n'th token in the value is returned.
+ (the first 8 characters must be unique) */
+{
+ static char cval[MAX_LVAL];
+ char *value;
+ char cwhite[8];
+ char lbracket[2],rbracket[2];
+ char keyword[16];
+ char line[MAX_LVAL];
+ char *vpos,*cpar;
+ char *c1, *brack1, *brack2;
+ int ipar, i;
+
+ lbracket[0] = 91;
+ lbracket[1] = 0;
+ rbracket[0] = 93;
+ rbracket[1] = 0;
+
+/* Find length of variable name */
+ strcpy (keyword,keyword0);
+ brack1 = strsrch (keyword,lbracket);
+ if (brack1 != NULL) *brack1 = '\0';
+
+/* Search header string for variable name */
+ vpos = isearch (hstring,keyword);
+
+/* Exit if not found */
+ if (vpos == NULL) {
+ return (NULL);
+ }
+
+/* Initialize returned value to nulls */
+ for (i = 0; i < MAX_LVAL; i++)
+ line[i] = 0;
+
+/* If quoted value, copy until second quote is reached */
+ i = 0;
+ if (*vpos == '"') {
+ vpos++;
+ while (*vpos && *vpos != '"' && i < MAX_LVAL)
+ line[i++] = *vpos++;
+ }
+
+/* Otherwise copy until next space or tab */
+ else {
+ while (*vpos != ' ' && *vpos != (char)9 &&
+ *vpos > 0 && i < MAX_LVAL)
+ line[i++] = *vpos++;
+ }
+
+/* If keyword has brackets, extract appropriate token from value */
+ if (brack1 != NULL) {
+ c1 = (char *) (brack1 + 1);
+ brack2 = strsrch (c1, rbracket);
+ if (brack2 != NULL) {
+ *brack2 = '\0';
+ ipar = atoi (c1);
+ if (ipar > 0) {
+ cwhite[0] = ' ';
+ cwhite[1] = ',';
+ cwhite[2] = '\0';
+ cpar = strtok (line, cwhite);
+ for (i = 1; i < ipar; i++) {
+ cpar = strtok (NULL, cwhite);
+ }
+ if (cpar != NULL) {
+ strcpy (cval,cpar);
+ }
+ else
+ value = NULL;
+ }
+ }
+ }
+ else
+ strcpy (cval, line);
+
+ value = cval;
+
+ return (value);
+}
+
+
+/* Find value for specified IRAF keyword */
+
+static char *
+isearch (hstring,keyword)
+
+/* Find entry for keyword keyword in IRAF keyword value string hstring.
+ NULL is returned if the keyword is not found */
+
+const char *hstring; /* character string containing fits-style header
+ information in the format <keyword>= <value> {/ <comment>}
+ the default is that each entry is 80 characters long;
+ however, lines may be of arbitrary length terminated by
+ nulls, carriage returns or linefeeds, if packed is true. */
+const char *keyword; /* character string containing the name of the variable
+ to be returned. isearch searches for a line beginning
+ with this string. The string may be a character
+ literal or a character variable terminated by a null
+ or '$'. it is truncated to 8 characters. */
+{
+ char *loc, *headnext, *headlast, *pval;
+ int lastchar, nextchar, lkey, nleft, lhstr;
+
+/* Search header string for variable name */
+ lhstr = 0;
+ while (lhstr < 57600 && hstring[lhstr] != 0)
+ lhstr++;
+ headlast = (char *) hstring + lhstr;
+ headnext = (char *) hstring;
+ pval = NULL;
+ lkey = strlen (keyword);
+ while (headnext < headlast) {
+ nleft = headlast - headnext;
+ loc = strnsrch (headnext, keyword, nleft);
+
+ /* Exit if keyword is not found */
+ if (loc == NULL) {
+ break;
+ }
+
+ nextchar = (int) *(loc + lkey);
+ lastchar = (int) *(loc - 1);
+
+ /* If parameter name in header is longer, keep searching */
+ if (nextchar != 61 && nextchar > 32 && nextchar < 127)
+ headnext = loc + 1;
+
+ /* If start of string, keep it */
+ else if (loc == hstring) {
+ pval = loc;
+ break;
+ }
+
+ /* If preceeded by a blank or tab, keep it */
+ else if (lastchar == 32 || lastchar == 9) {
+ pval = loc;
+ break;
+ }
+
+ else
+ headnext = loc + 1;
+ }
+
+ /* Find start of value string for this keyword */
+ if (pval != NULL) {
+ pval = pval + lkey;
+ while (*pval == ' ' || *pval == '=')
+ pval++;
+ }
+
+ /* Return pointer to calling program */
+ return (pval);
+
+}
+
+/* Mar 12 1998 New subroutines
+ * Apr 15 1998 Set IGET() and ISEARCH() static when defined
+ * Apr 24 1998 Add MGETI4(), MGETR8(), and MGETS() for single step IRAF ext.
+ * Jun 1 1998 Add VMS patch from Harry Payne at STScI
+ * Jul 9 1998 Fix bracket token extraction after Paul Sydney
+
+ * May 5 1999 values.h -> POSIX limits.h: MAXINT->INT_MAX, MAXSHORT->SHRT_MAX
+ * Oct 21 1999 Fix declarations after lint
+ *
+ * Feb 11 2000 Stop search for end of quoted keyword if more than 500 chars
+ * Jul 20 2000 Drop unused variables squot, dquot, and slash in igetc()
+ *
+ * Jun 26 2002 Change maximum string length from 600 to 2000; use MAX_LVAL
+ * Jun 26 2002 Stop search for end of quoted keyword if > MAX_LVAL chars
+ *
+ * Sep 23 2003 Change mgets() to mgetstr() to avoid name collision at UCO Lick
+ *
+ * Feb 26 2004 Make igetc() accessible from outside this file
+ *
+ * Jan 4 2007 Declare header, keyword to be const
+ */
diff --git a/funtools/wcs/imhfile.c b/funtools/wcs/imhfile.c
new file mode 100644
index 0000000..b618686
--- /dev/null
+++ b/funtools/wcs/imhfile.c
@@ -0,0 +1,1941 @@
+/*** File imhfile.c
+ *** March 27, 2012
+ *** By Jessica Mink, jmink@cfa.harvard.edu
+ *** Harvard-Smithsonian Center for Astrophysics
+ *** Copyright (C) 1996-2012
+ *** Smithsonian Astrophysical Observatory, Cambridge, MA, USA
+
+ This library 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 2 of the License, or (at your option) any later version.
+
+ This library 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 this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Correspondence concerning WCSTools should be addressed as follows:
+ Internet email: jmink@cfa.harvard.edu
+ Postal address: Jessica Mink
+ Smithsonian Astrophysical Observatory
+ 60 Garden St.
+ Cambridge, MA 02138 USA
+
+ * Module: imhfile.c (IRAF .imh image file reading and writing)
+ * Purpose: Read and write IRAF image files (and translate headers)
+ * Subroutine: check_immagic (irafheader, teststring )
+ * Verify that file is valid IRAF imhdr or impix
+ * Subroutine: irafrhead (filename, lfhead, fitsheader, lihead)
+ * Read IRAF image header
+ * Subroutine: irafrimage (fitsheader)
+ * Read IRAF image pixels (call after irafrhead)
+ * Subroutine: same_path (pixname, hdrname)
+ * Put filename and header path together
+ * Subroutine: iraf2fits (hdrname, irafheader, nbiraf, nbfits)
+ * Convert IRAF image header to FITS image header
+ * Subroutine: irafwhead (hdrname, irafheader, fitsheader)
+ * Write IRAF header file
+ * Subroutine: irafwimage (hdrname, irafheader, fitsheader, image )
+ * Write IRAF image and header files
+ * Subroutine: fits2iraf (fitsheader, irafheader)
+ * Convert FITS image header to IRAF image header
+ * Subroutine: irafgeti4 (irafheader, offset)
+ * Get 4-byte integer from arbitrary part of IRAF header
+ * Subroutine: irafgetc2 (irafheader, offset)
+ * Get character string from arbitrary part of IRAF v.1 header
+ * Subroutine: irafgetc (irafheader, offset)
+ * Get character string from arbitrary part of IRAF header
+ * Subroutine: iraf2str (irafstring, nchar)
+ * Convert 2-byte/char IRAF string to 1-byte/char string
+ * Subroutine: str2iraf (string, irafstring, nchar)
+ * Convert 1-byte/char string to IRAF 2-byte/char string
+ * Subroutine: irafswap (bitpix,string,nbytes)
+ * Swap bytes in string in place, with FITS bits/pixel code
+ * Subroutine: irafswap2 (string,nbytes)
+ * Swap bytes in string in place
+ * Subroutine irafswap4 (string,nbytes)
+ * Reverse bytes of Integer*4 or Real*4 vector in place
+ * Subroutine irafswap8 (string,nbytes)
+ * Reverse bytes of Real*8 vector in place
+ * Subroutine irafsize (filename)
+ * Return length of file in bytes
+ * Subroutine isiraf (filename)
+ * Return 1 if IRAF .imh file, else 0
+
+
+ * Copyright: 2000 Smithsonian Astrophysical Observatory
+ * You may do anything you like with this file except remove
+ * this copyright. The Smithsonian Astrophysical Observatory
+ * makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without
+ * express or implied warranty.
+ */
+
+#include <stdio.h> /* define stderr, FD, and NULL */
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <time.h>
+#include <sys/types.h>
+#include "fitsfile.h"
+
+/* Parameters from iraf/lib/imhdr.h for IRAF version 1 images */
+#define SZ_IMPIXFILE 79 /* name of pixel storage file */
+#define SZ_IMHDRFILE 79 /* length of header storage file */
+#define SZ_IMTITLE 79 /* image title string */
+#define LEN_IMHDR 2052 /* length of std header */
+
+/* Parameters from iraf/lib/imhdr.h for IRAF version 2 images */
+#define SZ_IM2PIXFILE 255 /* name of pixel storage file */
+#define SZ_IM2HDRFILE 255 /* name of header storage file */
+#define SZ_IM2TITLE 383 /* image title string */
+#define LEN_IM2HDR 2046 /* length of std header */
+
+/* Offsets into header in bytes for parameters in IRAF version 1 images */
+#define IM_HDRLEN 12 /* Length of header in 4-byte ints */
+#define IM_PIXTYPE 16 /* Datatype of the pixels */
+#define IM_NDIM 20 /* Number of dimensions */
+#define IM_LEN 24 /* Length (as stored) */
+#define IM_PHYSLEN 52 /* Physical length (as stored) */
+#define IM_PIXOFF 88 /* Offset of the pixels */
+#define IM_CTIME 108 /* Time of image creation */
+#define IM_MTIME 112 /* Time of last modification */
+#define IM_LIMTIME 116 /* Time of min,max computation */
+#define IM_MAX 120 /* Maximum pixel value */
+#define IM_MIN 124 /* Maximum pixel value */
+#define IM_PIXFILE 412 /* Name of pixel storage file */
+#define IM_HDRFILE 572 /* Name of header storage file */
+#define IM_TITLE 732 /* Image name string */
+
+/* Offsets into header in bytes for parameters in IRAF version 2 images */
+#define IM2_HDRLEN 6 /* Length of header in 4-byte ints */
+#define IM2_PIXTYPE 10 /* Datatype of the pixels */
+#define IM2_SWAPPED 14 /* Pixels are byte swapped */
+#define IM2_NDIM 18 /* Number of dimensions */
+#define IM2_LEN 22 /* Length (as stored) */
+#define IM2_PHYSLEN 50 /* Physical length (as stored) */
+#define IM2_PIXOFF 86 /* Offset of the pixels */
+#define IM2_CTIME 106 /* Time of image creation */
+#define IM2_MTIME 110 /* Time of last modification */
+#define IM2_LIMTIME 114 /* Time of min,max computation */
+#define IM2_MAX 118 /* Maximum pixel value */
+#define IM2_MIN 122 /* Maximum pixel value */
+#define IM2_PIXFILE 126 /* Name of pixel storage file */
+#define IM2_HDRFILE 382 /* Name of header storage file */
+#define IM2_TITLE 638 /* Image name string */
+
+/* Codes from iraf/unix/hlib/iraf.h */
+#define TY_CHAR 2
+#define TY_SHORT 3
+#define TY_INT 4
+#define TY_LONG 5
+#define TY_REAL 6
+#define TY_DOUBLE 7
+#define TY_COMPLEX 8
+#define TY_POINTER 9
+#define TY_STRUCT 10
+#define TY_USHORT 11
+#define TY_UBYTE 12
+
+#define LEN_IRAFHDR 25000
+#define LEN_PIXHDR 1024
+#define LEN_FITSHDR 11520
+
+int check_immagic();
+int irafgeti4();
+float irafgetr4();
+char *irafgetc2();
+char *irafgetc();
+char *iraf2str();
+static char *same_path();
+static void irafputr4();
+static void irafputi4();
+static void irafputc2();
+static void irafputc();
+static void str2iraf();
+static int headswap=-1; /* =1 to swap data bytes of foreign IRAF file */
+static void irafswap();
+static void irafswap2();
+static void irafswap4();
+static void irafswap8();
+int head_version ();
+int pix_version ();
+int irafncmp ();
+static int machswap();
+static int irafsize();
+
+#define SECONDS_1970_TO_1980 315532800L
+
+/* Subroutine: irafrhead
+ * Purpose: Open and read the iraf .imh file, translating it to FITS, too.
+ * Returns: NULL if failure, else pointer to IRAF .imh image header
+ * Notes: The imhdr format is defined in iraf/lib/imhdr.h, some of
+ * which defines or mimicked, above.
+ */
+
+char *
+irafrhead (filename, lihead)
+
+char *filename; /* Name of IRAF header file */
+int *lihead; /* Length of IRAF image header in bytes (returned) */
+{
+ FILE *fd;
+ int nbr;
+ char *irafheader;
+ int nbhead, nbytes;
+ int imhver;
+
+ headswap = -1;
+ *lihead = 0;
+
+ /* open the image header file */
+ fd = fopen (filename, "rb");
+ if (fd == NULL) {
+ fprintf (stderr, "IRAFRHEAD: cannot open file %s to read\n", filename);
+ return (NULL);
+ }
+
+ /* Find size of image header file */
+ if ((nbhead = irafsize (fd)) <= 0) {
+ fprintf (stderr, "IRAFRHEAD: cannot read file %s, size = %d\n",
+ filename, nbhead);
+ return (NULL);
+ }
+
+ /* allocate initial sized buffer */
+ nbytes = nbhead + 5000;
+ irafheader = (char *) calloc (nbytes/4, 4);
+ if (irafheader == NULL) {
+ (void)fprintf(stderr, "IRAFRHEAD Cannot allocate %d-byte header\n",
+ nbytes);
+ return (NULL);
+ }
+ *lihead = nbytes;
+
+ /* Read IRAF header */
+ nbr = fread (irafheader, 1, nbhead, fd);
+ fclose (fd);
+
+ /* Reject if header less than minimum length */
+ if (nbr < LEN_PIXHDR) {
+ (void)fprintf(stderr, "IRAFRHEAD header file %s: %d / %d bytes read.\n",
+ filename,nbr,LEN_PIXHDR);
+ free (irafheader);
+ return (NULL);
+ }
+
+ /* Check header magic word */
+ imhver = head_version (irafheader);
+ if (imhver < 1) {
+ free (irafheader);
+ (void)fprintf(stderr, "IRAFRHEAD: %s is not a valid IRAF image header\n",
+ filename);
+ return(NULL);
+ }
+
+ /* check number of image dimensions
+ if (imhver == 2)
+ ndim = irafgeti4 (irafheader, IM2_NDIM])
+ else
+ ndim = irafgeti4 (irafheader, IM_NDIM])
+ if (ndim < 2) {
+ free (irafheader);
+ (void)fprintf(stderr, "File %s does not contain 2d image\n", filename);
+ return (NULL);
+ } */
+
+ return (irafheader);
+}
+
+
+char *
+irafrimage (fitsheader)
+
+char *fitsheader; /* FITS image header (filled) */
+{
+ FILE *fd;
+ char *bang;
+ int naxis, naxis1, naxis2, naxis3, npaxis1, npaxis2,bitpix, bytepix, pixswap, i;
+ char *image;
+ int nbr, nbimage, nbaxis, nbl, nbdiff, lpname;
+ char *pixheader;
+ char *linebuff, *pixchar;
+ int imhver, lpixhead, len;
+ char pixname[SZ_IM2PIXFILE+1];
+ char newpixname[SZ_IM2HDRFILE+1];
+
+ /* Convert pixel file name to character string */
+ hgetm (fitsheader, "PIXFIL", SZ_IM2PIXFILE, pixname);
+
+ /* Drop trailing spaces */
+ lpname = strlen (pixname);
+ pixchar = pixname + lpname - 1;
+ while (*pixchar == ' ')
+ *pixchar = (char) 0;
+
+ hgeti4 (fitsheader, "PIXOFF", &lpixhead);
+
+ /* Open pixel file, ignoring machine name if present */
+ if ((bang = strchr (pixname, '!')) != NULL )
+ fd = fopen (bang + 1, "rb");
+ else
+ fd = fopen (pixname, "rb");
+
+ /* If not at pathname in header, try same directory as header file */
+ if (!fd) {
+ hgetm (fitsheader, "IMHFIL", SZ_IM2HDRFILE, newpixname);
+ len = strlen (newpixname);
+ newpixname[len-3] = 'p';
+ newpixname[len-2] = 'i';
+ newpixname[len-1] = 'x';
+ fd = fopen (newpixname, "rb");
+ }
+
+ /* Print error message and exit if pixel file is not found */
+ if (!fd) {
+ (void)fprintf(stderr,
+ "IRAFRIMAGE: Cannot open IRAF pixel file %s\n", pixname);
+ return (NULL);
+ }
+
+ /* Read pixel header */
+ pixheader = (char *) calloc (lpixhead/4, 4);
+ if (pixheader == NULL) {
+ (void)fprintf(stderr, "IRAFRIMAGE Cannot allocate %d-byte pixel header\n",
+ lpixhead);
+ return (NULL);
+ }
+ nbr = fread (pixheader, 1, lpixhead, fd);
+
+ /* Check size of pixel header */
+ if (nbr < lpixhead) {
+ (void)fprintf(stderr, "IRAF pixel file %s: %d / %d bytes read.\n",
+ pixname,nbr,LEN_PIXHDR);
+ free (pixheader);
+ fclose (fd);
+ return (NULL);
+ }
+
+ /* check pixel header magic word */
+ imhver = pix_version (pixheader);
+ if (imhver < 1) {
+ (void)fprintf(stderr, "File %s not valid IRAF pixel file.\n", pixname);
+ free (pixheader);
+ fclose (fd);
+ return(NULL);
+ }
+ free (pixheader);
+
+ /* Find number of bytes to read */
+ hgeti4 (fitsheader,"NAXIS",&naxis);
+ hgeti4 (fitsheader,"NAXIS1",&naxis1);
+ hgeti4 (fitsheader,"NAXIS2",&naxis2);
+ hgeti4 (fitsheader,"NPAXIS1",&npaxis1);
+ hgeti4 (fitsheader,"NPAXIS2",&npaxis2);
+ hgeti4 (fitsheader,"BITPIX",&bitpix);
+ if (bitpix < 0)
+ bytepix = -bitpix / 8;
+ else
+ bytepix = bitpix / 8;
+
+ /* If either dimension is one and image is 3-D, read all three dimensions */
+ if (naxis == 3 && ((naxis1 == 1) | (naxis2 == 1))) {
+ hgeti4 (fitsheader,"NAXIS3",&naxis3);
+ nbimage = naxis1 * naxis2 * naxis3 * bytepix;
+ }
+ else {
+ nbimage = naxis1 * naxis2 * bytepix;
+ naxis3 = 1;
+ }
+
+ if (bytepix > 4)
+ image = (char *) calloc (nbimage/8, 8);
+ else if (bytepix > 2)
+ image = (char *) calloc (nbimage/4, 4);
+ else if (bytepix > 1)
+ image = (char *) calloc (nbimage/2, 2);
+ else
+ image = (char *) calloc (nbimage, 1);
+ if (image == NULL) {
+ (void)fprintf(stderr, "IRAFRIMAGE Cannot allocate %d-byte image buffer\n",
+ nbimage);
+ return (NULL);
+ }
+
+ /* Read IRAF image all at once if physical and image dimensions are the same */
+ if (npaxis1 == naxis1)
+ nbr = fread (image, 1, nbimage, fd);
+
+ /* Read IRAF image one line at a time if physical and image dimensions differ */
+ else {
+ nbdiff = (npaxis1 - naxis1) * bytepix;
+ nbaxis = naxis1 * bytepix;
+ linebuff = image;
+ nbr = 0;
+ if (naxis2 == 1 && naxis3 > 1)
+ naxis2 = naxis3;
+ for (i = 0; i < naxis2; i++) {
+ nbl = fread (linebuff, 1, nbaxis, fd);
+ nbr = nbr + nbl;
+ (void) fseek (fd, nbdiff, SEEK_CUR);
+ linebuff = linebuff + nbaxis;
+ }
+ }
+ fclose (fd);
+
+ /* Check size of image */
+ if (nbr < nbimage) {
+ (void)fprintf(stderr, "IRAF pixel file %s: %d / %d bytes read.\n",
+ pixname,nbr,nbimage);
+ free (image);
+ return (NULL);
+ }
+
+ /* Byte-reverse image, if necessary */
+ pixswap = 0;
+ hgetl (fitsheader, "PIXSWAP", &pixswap);
+ if (pixswap)
+ irafswap (bitpix, image, nbimage);
+
+ return (image);
+}
+
+
+/* Return IRAF image format version number from magic word in IRAF header*/
+
+int
+head_version (irafheader)
+
+char *irafheader; /* IRAF image header from file */
+
+{
+
+ /* Check header file magic word */
+ if (irafncmp (irafheader, "imhdr", 5) != 0 ) {
+ if (strncmp (irafheader, "imhv2", 5) != 0)
+ return (0);
+ else
+ return (2);
+ }
+ else
+ return (1);
+}
+
+
+/* Return IRAF image format version number from magic word in IRAF pixel file */
+
+int
+pix_version (irafheader)
+
+char *irafheader; /* IRAF image header from file */
+
+{
+
+ /* Check pixel file header magic word */
+ if (irafncmp (irafheader, "impix", 5) != 0) {
+ if (strncmp (irafheader, "impv2", 5) != 0)
+ return (0);
+ else
+ return (2);
+ }
+ else
+ return (1);
+}
+
+
+/* Verify that file is valid IRAF imhdr or impix by checking first 5 chars
+ * Returns: 0 on success, 1 on failure */
+
+int
+irafncmp (irafheader, teststring, nc)
+
+char *irafheader; /* IRAF image header from file */
+char *teststring; /* C character string to compare */
+int nc; /* Number of characters to compate */
+
+{
+ char *line;
+
+ headswap = -1;
+ if ((line = iraf2str (irafheader, nc)) == NULL)
+ return (1);
+ if (strncmp (line, teststring, nc) == 0) {
+ free (line);
+ return (0);
+ }
+ else {
+ free (line);
+ return (1);
+ }
+}
+
+/* Convert IRAF image header to FITS image header, returning FITS header */
+
+char *
+iraf2fits (hdrname, irafheader, nbiraf, nbfits)
+
+char *hdrname; /* IRAF header file name (may be path) */
+char *irafheader; /* IRAF image header */
+int nbiraf; /* Number of bytes in IRAF header */
+int *nbfits; /* Number of bytes in FITS header (returned) */
+
+{
+ char *objname; /* object name from FITS file */
+ int lstr, i, j, k, ib, nax, nbits, nl;
+ int lname = 0;
+ char *pixname, *newpixname, *bang, *chead;
+ char *fitsheader;
+ int nblock, nlines;
+ char *fhead, *fhead1, *fp, endline[81];
+ char irafchar;
+ char fitsline[81];
+ char *dstring;
+ int pixtype;
+ int imhver, n, imu, pixoff, impixoff, immax, immin, imtime;
+ int imndim, imlen, imphyslen, impixtype, pixswap, hpixswap, mtime;
+ float rmax, rmin;
+
+ headswap = -1;
+
+ /* Set up last line of FITS header */
+ (void)strncpy (endline,"END", 3);
+ for (i = 3; i < 80; i++)
+ endline[i] = ' ';
+ endline[80] = 0;
+
+ /* Check header magic word */
+ imhver = head_version (irafheader);
+ if (imhver < 1) {
+ (void)fprintf(stderr, "File %s not valid IRAF image header\n",
+ hdrname);
+ return(NULL);
+ }
+ if (imhver == 2) {
+ nlines = 24 + ((nbiraf - LEN_IM2HDR) / 81);
+ imndim = IM2_NDIM;
+ imlen = IM2_LEN;
+ imphyslen = IM2_PHYSLEN;
+ impixtype = IM2_PIXTYPE;
+ impixoff = IM2_PIXOFF;
+ imtime = IM2_MTIME;
+ immax = IM2_MAX;
+ immin = IM2_MIN;
+ }
+ else {
+ nlines = 24 + ((nbiraf - LEN_IMHDR) / 162);
+ imndim = IM_NDIM;
+ imlen = IM_LEN;
+ imphyslen = IM_PHYSLEN;
+ impixtype = IM_PIXTYPE;
+ impixoff = IM_PIXOFF;
+ imtime = IM_MTIME;
+ immax = IM_MAX;
+ immin = IM_MIN;
+ }
+
+ /* Initialize FITS header */
+ nblock = (nlines * 80) / 2880;
+ *nbfits = (nblock + 5) * 2880 + 4;
+ fitsheader = (char *) calloc (*nbfits, 1);
+ if (fitsheader == NULL) {
+ (void)fprintf(stderr, "IRAF2FITS Cannot allocate %d-byte FITS header\n",
+ *nbfits);
+ return (NULL);
+ }
+ hlength (fitsheader, *nbfits);
+ fhead = fitsheader;
+ (void)strncpy (fitsheader, endline, 80);
+ hputl (fitsheader, "SIMPLE", 1);
+ fhead = fhead + 80;
+
+ /* Set pixel size in FITS header */
+ pixtype = irafgeti4 (irafheader, impixtype);
+ switch (pixtype) {
+ case TY_CHAR:
+ nbits = 8;
+ break;
+ case TY_UBYTE:
+ nbits = 8;
+ break;
+ case TY_SHORT:
+ nbits = 16;
+ break;
+ case TY_USHORT:
+ nbits = -16;
+ break;
+ case TY_INT:
+ case TY_LONG:
+ nbits = 32;
+ break;
+ case TY_REAL:
+ nbits = -32;
+ break;
+ case TY_DOUBLE:
+ nbits = -64;
+ break;
+ default:
+ (void)fprintf(stderr,"Unsupported data type: %d\n", pixtype);
+ return (NULL);
+ }
+ hputi4 (fitsheader,"BITPIX",nbits);
+ hputcom (fitsheader,"BITPIX", "IRAF .imh pixel type");
+ fhead = fhead + 80;
+
+ /* Set image dimensions in FITS header */
+ nax = irafgeti4 (irafheader, imndim);
+ hputi4 (fitsheader,"NAXIS",nax);
+ hputcom (fitsheader,"NAXIS", "IRAF .imh naxis");
+ fhead = fhead + 80;
+
+ n = irafgeti4 (irafheader, imlen);
+ hputi4 (fitsheader, "NAXIS1", n);
+ hputcom (fitsheader,"NAXIS1", "IRAF .imh image naxis[1]");
+ fhead = fhead + 80;
+
+ if (nax > 1) {
+ n = irafgeti4 (irafheader, imlen+4);
+ hputi4 (fitsheader, "NAXIS2", n);
+ hputcom (fitsheader,"NAXIS2", "IRAF .imh image naxis[2]");
+ }
+ else
+ hputi4 (fitsheader, "NAXIS2", 1);
+ hputcom (fitsheader,"NAXIS2", "IRAF .imh naxis[2]");
+ fhead = fhead + 80;
+
+ if (nax > 2) {
+ n = irafgeti4 (irafheader, imlen+8);
+ hputi4 (fitsheader, "NAXIS3", n);
+ hputcom (fitsheader,"NAXIS3", "IRAF .imh image naxis[3]");
+ fhead = fhead + 80;
+ }
+ if (nax > 3) {
+ n = irafgeti4 (irafheader, imlen+12);
+ hputi4 (fitsheader, "NAXIS4", n);
+ hputcom (fitsheader,"NAXIS4", "IRAF .imh image naxis[4]");
+ fhead = fhead + 80;
+ }
+
+ /* Set object name in FITS header */
+ if (imhver == 2)
+ objname = irafgetc (irafheader, IM2_TITLE, SZ_IM2TITLE);
+ else
+ objname = irafgetc2 (irafheader, IM_TITLE, SZ_IMTITLE);
+ if ((lstr = strlen (objname)) < 8) {
+ for (i = lstr; i < 8; i++)
+ objname[i] = ' ';
+ objname[8] = 0;
+ }
+ hputs (fitsheader,"OBJECT",objname);
+ hputcom (fitsheader,"OBJECT", "IRAF .imh title");
+ free (objname);
+ fhead = fhead + 80;
+
+ /* Save physical axis lengths so image file can be read */
+ n = irafgeti4 (irafheader, imphyslen);
+ hputi4 (fitsheader, "NPAXIS1", n);
+ hputcom (fitsheader,"NPAXIS1", "IRAF .imh physical naxis[1]");
+ fhead = fhead + 80;
+ if (nax > 1) {
+ n = irafgeti4 (irafheader, imphyslen+4);
+ hputi4 (fitsheader, "NPAXIS2", n);
+ hputcom (fitsheader,"NPAXIS2", "IRAF .imh physical naxis[2]");
+ fhead = fhead + 80;
+ }
+ if (nax > 2) {
+ n = irafgeti4 (irafheader, imphyslen+8);
+ hputi4 (fitsheader, "NPAXIS3", n);
+ hputcom (fitsheader,"NPAXIS3", "IRAF .imh physical naxis[3]");
+ fhead = fhead + 80;
+ }
+ if (nax > 3) {
+ n = irafgeti4 (irafheader, imphyslen+12);
+ hputi4 (fitsheader, "NPAXIS4", n);
+ hputcom (fitsheader,"NPAXIS4", "IRAF .imh physical naxis[4]");
+ fhead = fhead + 80;
+ }
+
+ /* Save image minimum and maximum in header */
+ rmax = irafgetr4 (irafheader, immax);
+ rmin = irafgetr4 (irafheader, immin);
+ if (rmin != rmax) {
+ hputr4 (fitsheader, "IRAFMIN", &rmin);
+ fhead = fhead + 80;
+ hputcom (fitsheader,"IRAFMIN", "IRAF .imh minimum");
+ hputr4 (fitsheader, "IRAFMAX", &rmax);
+ hputcom (fitsheader,"IRAFMAX", "IRAF .imh maximum");
+ fhead = fhead + 80;
+ }
+
+ /* Save image header filename in header */
+ nl = hputm (fitsheader,"IMHFIL",hdrname);
+ if (nl > 0) {
+ lname = strlen (hdrname);
+ strcpy (fitsline, "IRAF header file name");
+ if (lname < 43)
+ hputcom (fitsheader,"IMHFIL_1", fitsline);
+ else if (lname > 67 && lname < 110)
+ hputcom (fitsheader,"IMHFIL_2", fitsline);
+ else if (lname > 134 && lname < 177)
+ hputcom (fitsheader,"IMHFIL_3", fitsline);
+ }
+ if (nl > 0) fhead = fhead + (nl * 80);
+
+ /* Save image pixel file pathname in header */
+ if (imhver == 2)
+ pixname = irafgetc (irafheader, IM2_PIXFILE, SZ_IM2PIXFILE);
+ else
+ pixname = irafgetc2 (irafheader, IM_PIXFILE, SZ_IMPIXFILE);
+ if (strncmp(pixname, "HDR", 3) == 0 ) {
+ newpixname = same_path (pixname, hdrname);
+ free (pixname);
+ pixname = newpixname;
+ }
+ if (strchr (pixname, '/') == NULL && strchr (pixname, '$') == NULL) {
+ newpixname = same_path (pixname, hdrname);
+ free (pixname);
+ pixname = newpixname;
+ }
+
+ if ((bang = strchr (pixname, '!')) != NULL )
+ nl = hputm (fitsheader,"PIXFIL",bang+1);
+ else
+ nl = hputm (fitsheader,"PIXFIL",pixname);
+ free (pixname);
+ if (nl > 0) {
+ strcpy (fitsline, "IRAF .pix pixel file");
+ if (lname < 43)
+ hputcom (fitsheader,"PIXFIL_1", fitsline);
+ else if (lname > 67 && lname < 110)
+ hputcom (fitsheader,"PIXFIL_2", fitsline);
+ else if (lname > 134 && lname < 177)
+ hputcom (fitsheader,"PIXFIL_3", fitsline);
+ }
+ if (nl > 0) fhead = fhead + (nl * 80);
+
+ /* Save image offset from star of pixel file */
+ pixoff = irafgeti4 (irafheader, impixoff);
+ pixoff = (pixoff - 1) * 2;
+ hputi4 (fitsheader, "PIXOFF", pixoff);
+ hputcom (fitsheader,"PIXOFF", "IRAF .pix pixel offset (Do not change!)");
+ fhead = fhead + 80;
+
+ /* Save IRAF file format version in header */
+ hputi4 (fitsheader,"IMHVER",imhver);
+ hputcom (fitsheader,"IMHVER", "IRAF .imh format version (1 or 2)");
+ fhead = fhead + 80;
+
+ /* Set flag if header numbers are byte-reversed on this machine */
+ if (machswap() != headswap)
+ hputl (fitsheader, "HEADSWAP", 1);
+ else
+ hputl (fitsheader, "HEADSWAP", 0);
+ hputcom (fitsheader,"HEADSWAP", "IRAF header, FITS byte orders differ if T");
+ fhead = fhead + 80;
+
+ /* Set flag if image pixels are byte-reversed on this machine */
+ if (imhver == 2) {
+ hpixswap = irafgeti4 (irafheader, IM2_SWAPPED);
+ if (headswap && !hpixswap)
+ pixswap = 1;
+ else if (!headswap && hpixswap)
+ pixswap = 1;
+ else
+ pixswap = 0;
+ }
+ else
+ pixswap = headswap;
+ if (machswap() != pixswap)
+ hputl (fitsheader, "PIXSWAP", 1);
+ else
+ hputl (fitsheader, "PIXSWAP", 0);
+ hputcom (fitsheader,"PIXSWAP", "IRAF pixels, FITS byte orders differ if T");
+ fhead = fhead + 80;
+
+ /* Read modification time */
+ mtime = irafgeti4 (irafheader, imtime);
+ if (mtime == 0)
+ dstring = lt2fd ();
+ else
+ dstring = tsi2fd (mtime);
+ hputs (fitsheader, "DATE-MOD", dstring);
+ hputcom (fitsheader,"DATE-MOD", "Date of latest file modification");
+ free (dstring);
+ fhead = fhead + 80;
+
+ /* Add user portion of IRAF header to FITS header */
+ fitsline[80] = 0;
+ if (imhver == 2) {
+ imu = LEN_IM2HDR;
+ chead = irafheader;
+ j = 0;
+ for (k = 0; k < 80; k++)
+ fitsline[k] = ' ';
+ for (i = imu; i < nbiraf; i++) {
+ irafchar = chead[i];
+ if (irafchar == 0)
+ break;
+ else if (irafchar == 10) {
+ (void)strncpy (fhead, fitsline, 80);
+ /* fprintf (stderr,"%80s\n",fitsline); */
+ if (strncmp (fitsline, "OBJECT ", 7) != 0) {
+ fhead = fhead + 80;
+ }
+ for (k = 0; k < 80; k++)
+ fitsline[k] = ' ';
+ j = 0;
+ }
+ else {
+ if (j > 80) {
+ if (strncmp (fitsline, "OBJECT ", 7) != 0) {
+ (void)strncpy (fhead, fitsline, 80);
+ /* fprintf (stderr,"%80s\n",fitsline); */
+ j = 9;
+ fhead = fhead + 80;
+ }
+ for (k = 0; k < 80; k++)
+ fitsline[k] = ' ';
+ }
+ if (irafchar > 32 && irafchar < 127)
+ fitsline[j] = irafchar;
+ j++;
+ }
+ }
+ }
+ else {
+ imu = LEN_IMHDR;
+ chead = irafheader;
+ if (headswap == 1)
+ ib = 0;
+ else
+ ib = 1;
+ for (k = 0; k < 80; k++)
+ fitsline[k] = ' ';
+ j = 0;
+ for (i = imu; i < nbiraf; i=i+2) {
+ irafchar = chead[i+ib];
+ if (irafchar == 0)
+ break;
+ else if (irafchar == 10) {
+ if (strncmp (fitsline, "OBJECT ", 7) != 0) {
+ (void)strncpy (fhead, fitsline, 80);
+ fhead = fhead + 80;
+ }
+ /* fprintf (stderr,"%80s\n",fitsline); */
+ j = 0;
+ for (k = 0; k < 80; k++)
+ fitsline[k] = ' ';
+ }
+ else {
+ if (j > 80) {
+ if (strncmp (fitsline, "OBJECT ", 7) != 0) {
+ (void)strncpy (fhead, fitsline, 80);
+ j = 9;
+ fhead = fhead + 80;
+ }
+ /* fprintf (stderr,"%80s\n",fitsline); */
+ for (k = 0; k < 80; k++)
+ fitsline[k] = ' ';
+ }
+ if (irafchar > 32 && irafchar < 127)
+ fitsline[j] = irafchar;
+ j++;
+ }
+ }
+ }
+
+ /* Add END to last line */
+ (void)strncpy (fhead, endline, 80);
+
+ /* Find end of last 2880-byte block of header */
+ fhead = ksearch (fitsheader, "END") + 80;
+ nblock = *nbfits / 2880;
+ fhead1 = fitsheader + (nblock * 2880);
+
+ /* Pad rest of header with spaces */
+ strncpy (endline," ",3);
+ for (fp = fhead; fp < fhead1; fp = fp + 80) {
+ (void)strncpy (fp, endline,80);
+ }
+
+ return (fitsheader);
+}
+
+
+int
+irafwhead (hdrname, lhead, irafheader, fitsheader)
+
+char *hdrname; /* Name of IRAF header file */
+int lhead; /* Length of IRAF header */
+char *irafheader; /* IRAF header */
+char *fitsheader; /* FITS image header */
+
+{
+ int fd;
+ int nbw, nbhead, lphead, pixswap;
+
+ /* Get rid of redundant header information */
+ hgeti4 (fitsheader, "PIXOFF", &lphead);
+ hgeti4 (fitsheader, "PIXSWAP", &pixswap);
+
+ /* Write IRAF header file */
+
+ /* Convert FITS header to IRAF header */
+ irafheader = fits2iraf (fitsheader, irafheader, lhead, &nbhead);
+ if (irafheader == NULL) {
+ fprintf (stderr, "IRAFWIMAGE: file %s header error\n", hdrname);
+ return (-1);
+ }
+
+ /* Open the output file */
+ if (!access (hdrname, 0)) {
+ fd = open (hdrname, O_WRONLY);
+ if (fd < 3) {
+ fprintf (stderr, "IRAFWIMAGE: file %s not writeable\n", hdrname);
+ return (0);
+ }
+ }
+ else {
+ fd = open (hdrname, O_RDWR+O_CREAT, 0666);
+ if (fd < 3) {
+ fprintf (stderr, "IRAFWIMAGE: cannot create file %s\n", hdrname);
+ return (0);
+ }
+ }
+
+ /* Write IRAF header to disk file */
+ nbw = write (fd, irafheader, nbhead);
+ (void) ftruncate (fd, nbhead);
+ close (fd);
+ if (nbw < nbhead) {
+ (void)fprintf(stderr, "IRAF header file %s: %d / %d bytes written.\n",
+ hdrname, nbw, nbhead);
+ return (-1);
+ }
+
+ return (nbw);
+}
+
+/* IRAFWIMAGE -- write IRAF .imh header file and .pix image file
+ * No matter what the input, this always writes in the local byte order */
+
+int
+irafwimage (hdrname, lhead, irafheader, fitsheader, image )
+
+char *hdrname; /* Name of IRAF header file */
+int lhead; /* Length of IRAF header */
+char *irafheader; /* IRAF header */
+char *fitsheader; /* FITS image header */
+char *image; /* IRAF image */
+
+{
+ int fd;
+ char *bang;
+ int nbw, bytepix, bitpix, naxis, naxis1, naxis2, nbimage, lphead;
+ char *pixn, *newpixname;
+ char pixname[SZ_IM2PIXFILE+1];
+ int imhver, pixswap;
+
+ hgeti4 (fitsheader, "IMHVER", &imhver);
+
+ if (!hgetm (fitsheader, "PIXFIL", SZ_IM2PIXFILE, pixname)) {
+ if (imhver == 2)
+ pixn = irafgetc (irafheader, IM2_PIXFILE, SZ_IM2PIXFILE);
+ else
+ pixn = irafgetc2 (irafheader, IM_PIXFILE, SZ_IMPIXFILE);
+ if (strncmp(pixn, "HDR", 3) == 0 ) {
+ newpixname = same_path (pixn, hdrname);
+ strcpy (pixname, newpixname);
+ free (newpixname);
+ }
+ else {
+ if ((bang = strchr (pixn, '!')) != NULL )
+ strcpy (pixname, bang+1);
+ else
+ strcpy (pixname, pixn);
+ }
+ free (pixn);
+ }
+
+ /* Find number of bytes to write */
+ hgeti4 (fitsheader,"NAXIS",&naxis);
+ hgeti4 (fitsheader,"NAXIS1",&naxis1);
+ hgeti4 (fitsheader,"NAXIS2",&naxis2);
+ hgeti4 (fitsheader,"BITPIX",&bitpix);
+ if (bitpix < 0)
+ bytepix = -bitpix / 8;
+ else
+ bytepix = bitpix / 8;
+
+ /* If either dimension is one and image is 3-D, read all three dimensions */
+ if (naxis == 3 && ((naxis1 == 1) | (naxis2 == 1))) {
+ int naxis3;
+ hgeti4 (fitsheader,"NAXIS3",&naxis3);
+ nbimage = naxis1 * naxis2 * naxis3 * bytepix;
+ }
+ else
+ nbimage = naxis1 * naxis2 * bytepix;
+
+ /* Read information about pixel file from header */
+ hgeti4 (fitsheader, "PIXOFF", &lphead);
+ hgeti4 (fitsheader, "PIXSWAP", &pixswap);
+
+ /* Write IRAF header file */
+ if (irafwhead (hdrname, lhead, irafheader, fitsheader))
+ return (0);
+
+ /* Open the output file */
+ if (!access (pixname, 0)) {
+ fd = open (pixname, O_WRONLY);
+ if (fd < 3) {
+ fprintf (stderr, "IRAFWIMAGE: file %s not writeable\n", pixname);
+ return (0);
+ }
+ }
+ else {
+ fd = open (pixname, O_RDWR+O_CREAT, 0666);
+ if (fd < 3) {
+ fprintf (stderr, "IRAFWIMAGE: cannot create file %s\n", pixname);
+ return (0);
+ }
+ }
+
+ /* Write header to IRAF pixel file */
+ if (imhver == 2)
+ irafputc ("impv2", irafheader, 0, 5);
+ else
+ irafputc2 ("impix", irafheader, 0, 5);
+ nbw = write (fd, irafheader, lphead);
+
+ /* Byte-reverse image, if necessary */
+ if (pixswap)
+ irafswap (bitpix, image, nbimage);
+
+ /* Write data to IRAF pixel file */
+ nbw = write (fd, image, nbimage);
+ close (fd);
+
+ return (nbw);
+}
+
+
+/* Put filename and header path together */
+
+static char *
+same_path (pixname, hdrname)
+
+char *pixname; /* IRAF pixel file pathname */
+char *hdrname; /* IRAF image header file pathname */
+
+{
+ int len, plen;
+ char *newpixname;
+
+ newpixname = (char *) calloc (SZ_IM2PIXFILE, 1);
+
+ /* Pixel file is in same directory as header */
+ if (strncmp(pixname, "HDR$", 4) == 0 ) {
+ (void)strncpy (newpixname, hdrname, SZ_IM2PIXFILE);
+
+ /* find the end of the pathname */
+ len = strlen (newpixname);
+#ifndef VMS
+ while( (len > 0) && (newpixname[len-1] != '/') )
+#else
+ while( (len > 0) && (newpixname[len-1] != ']') && (newpixname[len-1] != ':') )
+#endif
+ len--;
+
+ /* add name */
+ newpixname[len] = '\0';
+ plen = strlen (pixname) - 4;
+ if (len + plen > SZ_IM2PIXFILE)
+ (void)strncat (newpixname, &pixname[4], SZ_IM2PIXFILE - len);
+ else
+ (void)strncat (newpixname, &pixname[4], plen);
+ }
+
+ /* Bare pixel file with no path is assumed to be same as HDR$filename */
+ else if (strchr (pixname, '/') == NULL && strchr (pixname, '$') == NULL) {
+ (void)strncpy (newpixname, hdrname, SZ_IM2PIXFILE);
+
+ /* find the end of the pathname */
+ len = strlen (newpixname);
+#ifndef VMS
+ while( (len > 0) && (newpixname[len-1] != '/') )
+#else
+ while( (len > 0) && (newpixname[len-1] != ']') && (newpixname[len-1] != ':') )
+#endif
+ len--;
+
+ /* add name */
+ newpixname[len] = '\0';
+ (void)strncat (newpixname, pixname, SZ_IM2PIXFILE);
+ }
+
+ /* Pixel file has same name as header file, but with .pix extension */
+ else if (strncmp (pixname, "HDR", 3) == 0) {
+
+ /* load entire header name string into name buffer */
+ (void)strncpy (newpixname, hdrname, SZ_IM2PIXFILE);
+ len = strlen (newpixname);
+ newpixname[len-3] = 'p';
+ newpixname[len-2] = 'i';
+ newpixname[len-1] = 'x';
+ }
+
+ return (newpixname);
+}
+
+/* Convert FITS image header to IRAF image header, returning IRAF header */
+/* No matter what the input, this always writes in the local byte order */
+
+char *
+fits2iraf (fitsheader, irafheader, nbhead, nbiraf)
+
+char *fitsheader; /* FITS image header */
+char *irafheader; /* IRAF image header (returned updated) */
+int nbhead; /* Length of IRAF header */
+int *nbiraf; /* Length of returned IRAF header */
+
+{
+ int i, n, pixoff, lhdrdir;
+ short *irafp, *irafs, *irafu;
+ char *iraf2u, *iraf2p, *filename, *hdrdir;
+ char *fitsend, *fitsp, pixfile[SZ_IM2PIXFILE], hdrfile[SZ_IM2HDRFILE];
+ char title[SZ_IM2TITLE], temp[80];
+ int nax, nlfits, imhver, nbits, pixtype, hdrlength, mtime;
+ int imndim, imlen, imphyslen, impixtype, imhlen, imtime, immax, immin;
+ float rmax, rmin;
+
+ hgeti4 (fitsheader, "IMHVER", &imhver);
+ hdel (fitsheader, "IMHVER");
+ hdel (fitsheader, "IMHVER");
+ hgetl (fitsheader, "HEADSWAP", &headswap);
+ hdel (fitsheader, "HEADSWAP");
+ hdel (fitsheader, "HEADSWAP");
+ if (imhver == 2) {
+ imhlen = IM2_HDRLEN;
+ imndim = IM2_NDIM;
+ imlen = IM2_LEN;
+ imtime = IM2_MTIME;
+ imphyslen = IM2_PHYSLEN;
+ impixtype = IM2_PIXTYPE;
+ immax = IM2_MAX;
+ immin = IM2_MIN;
+ }
+ else {
+ imhlen = IM_HDRLEN;
+ imndim = IM_NDIM;
+ imlen = IM_LEN;
+ imtime = IM_MTIME;
+ imphyslen = IM_PHYSLEN;
+ impixtype = IM_PIXTYPE;
+ immax = IM_MAX;
+ immin = IM_MIN;
+ }
+
+ /* Delete FITS header keyword not needed by IRAF */
+ hdel (fitsheader,"SIMPLE");
+
+ /* Set IRAF image data type */
+ hgeti4 (fitsheader,"BITPIX", &nbits);
+ switch (nbits) {
+ case 8:
+ pixtype = TY_CHAR;
+ break;
+ case -8:
+ pixtype = TY_UBYTE;
+ break;
+ case 16:
+ pixtype = TY_SHORT;
+ break;
+ case -16:
+ pixtype = TY_USHORT;
+ break;
+ case 32:
+ pixtype = TY_INT;
+ break;
+ case -32:
+ pixtype = TY_REAL;
+ break;
+ case -64:
+ pixtype = TY_DOUBLE;
+ break;
+ default:
+ (void)fprintf(stderr,"Unsupported data type: %d\n", nbits);
+ return (NULL);
+ }
+ irafputi4 (irafheader, impixtype, pixtype);
+ hdel (fitsheader,"BITPIX");
+
+ /* Set IRAF image dimensions */
+ hgeti4 (fitsheader,"NAXIS",&nax);
+ irafputi4 (irafheader, imndim, nax);
+ hdel (fitsheader,"NAXIS");
+
+ hgeti4 (fitsheader, "NAXIS1", &n);
+ irafputi4 (irafheader, imlen, n);
+ irafputi4 (irafheader, imphyslen, n);
+ hdel (fitsheader,"NAXIS1");
+
+ hgeti4 (fitsheader,"NAXIS2",&n);
+ irafputi4 (irafheader, imlen+4, n);
+ irafputi4 (irafheader, imphyslen+4, n);
+ hdel (fitsheader,"NAXIS2");
+
+ if (nax > 2) {
+ hgeti4 (fitsheader,"NAXIS3",&n);
+ irafputi4 (irafheader, imlen+8, n);
+ irafputi4 (irafheader, imphyslen+8, n);
+ hdel (fitsheader,"NAXIS3");
+ }
+
+ if (nax > 3) {
+ hgeti4 (fitsheader,"NAXIS4",&n);
+ irafputi4 (irafheader, imlen+12, n);
+ irafputi4 (irafheader, imphyslen+12, n);
+ hdel (fitsheader,"NAXIS4");
+ }
+
+ /* Set image pixel value limits */
+ rmin = 0.0;
+ hgetr4 (fitsheader, "IRAFMIN", &rmin);
+ rmax = 0.0;
+ hgetr4 (fitsheader, "IRAFMAX", &rmax);
+ if (rmin != rmax) {
+ irafputr4 (irafheader, immax, rmax);
+ irafputr4 (irafheader, immin, rmin);
+ }
+ hdel (fitsheader, "IRAFMIN");
+ hdel (fitsheader, "IRAFMAX");
+
+ /* Replace pixel file name, if it is in the FITS header */
+ if (hgetm (fitsheader, "PIXFIL", SZ_IM2PIXFILE, pixfile)) {
+ if (strchr (pixfile, '/')) {
+ if (hgetm (fitsheader, "IMHFIL", SZ_IM2HDRFILE, hdrfile)) {
+ hdrdir = strrchr (hdrfile, '/');
+ if (hdrdir != NULL) {
+ lhdrdir = hdrdir - hdrfile + 1;
+ if (!strncmp (pixfile, hdrfile, lhdrdir)) {
+ filename = pixfile + lhdrdir;
+ strcpy (temp, "HDR$");
+ strcat (temp,filename);
+ strcpy (pixfile, temp);
+ }
+ }
+ if (pixfile[0] != '/' && pixfile[0] != 'H') {
+ strcpy (temp, "HDR$");
+ strcat (temp,pixfile);
+ strcpy (pixfile, temp);
+ }
+ }
+ }
+
+ if (imhver == 2)
+ irafputc (pixfile, irafheader, IM2_PIXFILE, SZ_IM2PIXFILE);
+ else
+ irafputc2 (pixfile, irafheader, IM_PIXFILE, SZ_IMPIXFILE);
+ hdel (fitsheader,"PIXFIL_1");
+ hdel (fitsheader,"PIXFIL_2");
+ hdel (fitsheader,"PIXFIL_3");
+ hdel (fitsheader,"PIXFIL_4");
+ }
+
+ /* Replace header file name, if it is in the FITS header */
+ if (hgetm (fitsheader, "IMHFIL", SZ_IM2HDRFILE, pixfile)) {
+ if (!strchr (pixfile,'/') && !strchr (pixfile,'$')) {
+ strcpy (temp, "HDR$");
+ strcat (temp,pixfile);
+ strcpy (pixfile, temp);
+ }
+ if (imhver == 2)
+ irafputc (pixfile, irafheader, IM2_HDRFILE, SZ_IM2HDRFILE);
+ else
+ irafputc2 (pixfile, irafheader, IM_HDRFILE, SZ_IMHDRFILE);
+ hdel (fitsheader, "IMHFIL_1");
+ hdel (fitsheader, "IMHFIL_2");
+ hdel (fitsheader, "IMHFIL_3");
+ hdel (fitsheader, "IMHFIL_4");
+ }
+
+ /* Replace image title, if it is in the FITS header */
+ if (hgets (fitsheader, "OBJECT", SZ_IM2TITLE, title)) {
+ if (imhver == 2)
+ irafputc (title, irafheader, IM2_TITLE, SZ_IM2TITLE);
+ else
+ irafputc2 (title, irafheader, IM_TITLE, SZ_IMTITLE);
+ hdel (fitsheader, "OBJECT");
+ }
+ hgeti4 (fitsheader, "PIXOFF", &pixoff);
+ hdel (fitsheader, "PIXOFF");
+ hdel (fitsheader, "PIXOFF");
+ hdel (fitsheader, "PIXSWAP");
+ hdel (fitsheader, "PIXSWAP");
+ hdel (fitsheader, "DATE-MOD");
+ hdel (fitsheader, "DATE-MOD");
+ fitsend = ksearch (fitsheader,"END");
+
+ /* Find length of FITS header */
+ fitsend = ksearch (fitsheader,"END");
+ nlfits = ((fitsend - fitsheader) / 80);
+
+ /* Find new length of IRAF header */
+ if (imhver == 2)
+ *nbiraf = LEN_IM2HDR + (81 * nlfits);
+ else
+ *nbiraf = LEN_IMHDR + (162 * nlfits);
+ if (*nbiraf > nbhead)
+ irafheader = realloc (irafheader, *nbiraf);
+
+ /* Reset modification time */
+ mtime = lt2tsi ();
+ irafputi4 (irafheader, imtime, mtime);
+
+ /* Replace user portion of IRAF header with remaining FITS header */
+ if (imhver == 2) {
+ iraf2u = irafheader + LEN_IM2HDR;
+ iraf2p = iraf2u;
+ for (fitsp = fitsheader; fitsp < fitsend; fitsp = fitsp + 80) {
+ for (i = 0; i < 80; i++)
+ *iraf2p++ = fitsp[i];
+ *iraf2p++ = 10;
+ }
+ *iraf2p++ = 0;
+ *nbiraf = iraf2p - irafheader;
+ hdrlength = 1 + *nbiraf / 2;
+ }
+ else {
+ irafs = (short *)irafheader;
+ irafu = irafs + (LEN_IMHDR / 2);
+ irafp = irafu;
+ for (fitsp = fitsheader; fitsp < fitsend; fitsp = fitsp + 80) {
+ for (i = 0; i < 80; i++)
+ *irafp++ = (short) fitsp[i];
+ *irafp++ = 10;
+ }
+ *irafp++ = 0;
+ *irafp++ = 32;
+ *nbiraf = 2 * (irafp - irafs);
+ hdrlength = *nbiraf / 4;
+ }
+
+ /* Length of header file */
+ irafputi4 (irafheader, imhlen, hdrlength);
+
+ /* Offset in .pix file to first pixel data
+ hputi4 (fitsheader, "PIXOFF", pixoff); */
+
+ /* Return number of bytes in new IRAF header */
+ return (irafheader);
+}
+
+
+int
+irafgeti4 (irafheader, offset)
+
+char *irafheader; /* IRAF image header */
+int offset; /* Number of bytes to skip before number */
+
+{
+ char *ctemp, *cheader;
+ int temp;
+
+ cheader = irafheader;
+ ctemp = (char *) &temp;
+
+ /* If header swap flag not set, set it now */
+ if (headswap < 0) {
+ if (cheader[offset] > 0)
+ headswap = 1;
+ else
+ headswap = 0;
+ }
+
+ if (machswap() != headswap) {
+ ctemp[3] = cheader[offset];
+ ctemp[2] = cheader[offset+1];
+ ctemp[1] = cheader[offset+2];
+ ctemp[0] = cheader[offset+3];
+ }
+ else {
+ ctemp[0] = cheader[offset];
+ ctemp[1] = cheader[offset+1];
+ ctemp[2] = cheader[offset+2];
+ ctemp[3] = cheader[offset+3];
+ }
+ return (temp);
+}
+
+
+float
+irafgetr4 (irafheader, offset)
+
+char *irafheader; /* IRAF image header */
+int offset; /* Number of bytes to skip before number */
+
+{
+ char *ctemp, *cheader;
+ float temp;
+
+ cheader = irafheader;
+ ctemp = (char *) &temp;
+
+ /* If header swap flag not set, set it now */
+ if (headswap < 0) {
+ if (cheader[offset] > 0)
+ headswap = 1;
+ else
+ headswap = 0;
+ }
+
+ if (machswap() != headswap) {
+ ctemp[3] = cheader[offset];
+ ctemp[2] = cheader[offset+1];
+ ctemp[1] = cheader[offset+2];
+ ctemp[0] = cheader[offset+3];
+ }
+ else {
+ ctemp[0] = cheader[offset];
+ ctemp[1] = cheader[offset+1];
+ ctemp[2] = cheader[offset+2];
+ ctemp[3] = cheader[offset+3];
+ }
+ return (temp);
+}
+
+
+/* IRAFGETC2 -- Get character string from arbitrary part of v.1 IRAF header */
+
+char *
+irafgetc2 (irafheader, offset, nc)
+
+char *irafheader; /* IRAF image header */
+int offset; /* Number of bytes to skip before string */
+int nc; /* Maximum number of characters in string */
+
+{
+ char *irafstring, *string;
+
+ irafstring = irafgetc (irafheader, offset, 2*(nc+1));
+ string = iraf2str (irafstring, nc);
+ free (irafstring);
+
+ return (string);
+}
+
+
+/* IRAFGETC -- Get character string from arbitrary part of IRAF header */
+
+char *
+irafgetc (irafheader, offset, nc)
+
+char *irafheader; /* IRAF image header */
+int offset; /* Number of bytes to skip before string */
+int nc; /* Maximum number of characters in string */
+
+{
+ char *ctemp, *cheader;
+ int i;
+
+ cheader = irafheader;
+ ctemp = (char *) calloc (nc+1, 1);
+ if (ctemp == NULL) {
+ (void)fprintf(stderr, "IRAFGETC Cannot allocate %d-byte variable\n",
+ nc+1);
+ return (NULL);
+ }
+ for (i = 0; i < nc; i++) {
+ ctemp[i] = cheader[offset+i];
+ if (ctemp[i] > 0 && ctemp[i] < 32)
+ ctemp[i] = ' ';
+ }
+
+ return (ctemp);
+}
+
+
+/* Convert IRAF 2-byte/char string to 1-byte/char string */
+
+char *
+iraf2str (irafstring, nchar)
+
+char *irafstring; /* IRAF 2-byte/character string */
+int nchar; /* Number of characters in string */
+{
+ char *string;
+ int i, j;
+
+ /* Set swap flag according to position of nulls in 2-byte characters */
+ if (headswap < 0) {
+ if (irafstring[0] != 0 && irafstring[1] == 0)
+ headswap = 1;
+ else if (irafstring[0] == 0 && irafstring[1] != 0)
+ headswap = 0;
+ else
+ return (NULL);
+ }
+
+ string = (char *) calloc (nchar+1, 1);
+ if (string == NULL) {
+ (void)fprintf(stderr, "IRAF2STR Cannot allocate %d-byte variable\n",
+ nchar+1);
+ return (NULL);
+ }
+
+ /* Swap bytes, if requested */
+ if (headswap)
+ j = 0;
+ else
+ j = 1;
+
+ /* Convert appropriate byte of input to output character */
+ for (i = 0; i < nchar; i++) {
+ string[i] = irafstring[j];
+ j = j + 2;
+ }
+
+ return (string);
+}
+
+
+/* IRAFPUTI4 -- Insert 4-byte integer into arbitrary part of IRAF header */
+
+static void
+irafputi4 (irafheader, offset, inum)
+
+char *irafheader; /* IRAF image header */
+int offset; /* Number of bytes to skip before number */
+int inum; /* Number to put into header */
+
+{
+ char *cn, *chead;
+
+ chead = irafheader;
+ cn = (char *) &inum;
+ if (headswap < 0)
+ headswap = 0;
+ if (headswap != machswap()) {
+ chead[offset+3] = cn[0];
+ chead[offset+2] = cn[1];
+ chead[offset+1] = cn[2];
+ chead[offset] = cn[3];
+ }
+ else {
+ chead[offset] = cn[0];
+ chead[offset+1] = cn[1];
+ chead[offset+2] = cn[2];
+ chead[offset+3] = cn[3];
+ }
+ return;
+}
+
+
+/* IRAFPUTR4 -- Insert 4-byte real number into arbitrary part of IRAF header */
+
+static void
+irafputr4 (irafheader, offset, rnum)
+
+char *irafheader; /* IRAF image header */
+int offset; /* Number of bytes to skip before number */
+float rnum; /* Number to put into header */
+
+{
+ char *cn, *chead;
+
+ chead = irafheader;
+ cn = (char *) &rnum;
+ if (headswap < 0)
+ headswap = 0;
+ if (headswap != machswap()) {
+ chead[offset+3] = cn[0];
+ chead[offset+2] = cn[1];
+ chead[offset+1] = cn[2];
+ chead[offset] = cn[3];
+ }
+ else {
+ chead[offset] = cn[0];
+ chead[offset+1] = cn[1];
+ chead[offset+2] = cn[2];
+ chead[offset+3] = cn[3];
+ }
+ return;
+}
+
+
+/* IRAFPUTC2 -- Insert character string into arbitrary part of v.1 IRAF header */
+
+static void
+irafputc2 (string, irafheader, offset, nc)
+
+char *string; /* String to insert into header */
+char *irafheader; /* IRAF image header */
+int offset; /* Number of bytes to skip before string */
+int nc; /* Maximum number of characters in string */
+
+{
+ char *irafstring;
+
+ irafstring = (char *) calloc (2 * nc, 1);
+ if (irafstring == NULL) {
+ (void)fprintf(stderr, "IRAFPUTC2 Cannot allocate %d-byte variable\n",
+ 2 * nc);
+ }
+ str2iraf (string, irafstring, nc);
+ irafputc (irafstring, irafheader, offset, 2*nc);
+
+ return;
+}
+
+
+/* IRAFPUTC -- Insert character string into arbitrary part of IRAF header */
+
+static void
+irafputc (string, irafheader, offset, nc)
+
+char *string; /* String to insert into header */
+char *irafheader; /* IRAF image header */
+int offset; /* Number of bytes to skip before string */
+int nc; /* Maximum number of characters in string */
+
+{
+ char *chead;
+ int i;
+
+ chead = irafheader;
+ for (i = 0; i < nc; i++)
+ chead[offset+i] = string[i];
+
+ return;
+}
+
+
+/* STR2IRAF -- Convert 1-byte/char string to IRAF 2-byte/char string */
+
+static void
+str2iraf (string, irafstring, nchar)
+
+char *string; /* 1-byte/character string */
+char *irafstring; /* IRAF 2-byte/character string */
+int nchar; /* Maximum number of characters in IRAF string */
+{
+ int i, j, nc, nbytes;
+
+ nc = strlen (string);
+
+ /* Fill output string with zeroes */
+ nbytes = nchar * 2;
+ for (i = 0; i < nbytes; i++)
+ irafstring[i] = 0;
+
+ /* If swapped, start with first byte of 2-byte characters */
+ if (headswap)
+ j = 0;
+ else
+ j = 1;
+
+ /* Move input characters to appropriate bytes of output */
+ for (i = 0; i < nchar; i++) {
+ if (i > nc)
+ irafstring[j] = 0;
+ else
+ irafstring[j] = string[i];
+ j = j + 2;
+ }
+
+ return;
+}
+
+
+/* IRAFSWAP -- Reverse bytes of any type of vector in place */
+
+static void
+irafswap (bitpix, string, nbytes)
+
+int bitpix; /* Number of bits per pixel */
+ /* 16 = short, -16 = unsigned short, 32 = int */
+ /* -32 = float, -64 = double */
+char *string; /* Address of starting point of bytes to swap */
+int nbytes; /* Number of bytes to swap */
+
+{
+ switch (bitpix) {
+
+ case 16:
+ if (nbytes < 2) return;
+ irafswap2 (string,nbytes);
+ break;
+
+ case 32:
+ if (nbytes < 4) return;
+ irafswap4 (string,nbytes);
+ break;
+
+ case -16:
+ if (nbytes < 2) return;
+ irafswap2 (string,nbytes);
+ break;
+
+ case -32:
+ if (nbytes < 4) return;
+ irafswap4 (string,nbytes);
+ break;
+
+ case -64:
+ if (nbytes < 8) return;
+ irafswap8 (string,nbytes);
+ break;
+
+ }
+ return;
+}
+
+
+/* IRAFSWAP2 -- Swap bytes in string in place */
+
+static void
+irafswap2 (string,nbytes)
+
+
+char *string; /* Address of starting point of bytes to swap */
+int nbytes; /* Number of bytes to swap */
+
+{
+ char *sbyte, temp, *slast;
+
+ slast = string + nbytes;
+ sbyte = string;
+ while (sbyte < slast) {
+ temp = sbyte[0];
+ sbyte[0] = sbyte[1];
+ sbyte[1] = temp;
+ sbyte= sbyte + 2;
+ }
+ return;
+}
+
+
+/* IRAFSWAP4 -- Reverse bytes of Integer*4 or Real*4 vector in place */
+
+static void
+irafswap4 (string,nbytes)
+
+char *string; /* Address of Integer*4 or Real*4 vector */
+int nbytes; /* Number of bytes to reverse */
+
+{
+ char *sbyte, *slast;
+ char temp0, temp1, temp2, temp3;
+
+ slast = string + nbytes;
+ sbyte = string;
+ while (sbyte < slast) {
+ temp3 = sbyte[0];
+ temp2 = sbyte[1];
+ temp1 = sbyte[2];
+ temp0 = sbyte[3];
+ sbyte[0] = temp0;
+ sbyte[1] = temp1;
+ sbyte[2] = temp2;
+ sbyte[3] = temp3;
+ sbyte = sbyte + 4;
+ }
+
+ return;
+}
+
+
+/* IRAFSWAP8 -- Reverse bytes of Real*8 vector in place */
+
+static void
+irafswap8 (string,nbytes)
+
+char *string; /* Address of Real*8 vector */
+int nbytes; /* Number of bytes to reverse */
+
+{
+ char *sbyte, *slast;
+ char temp[8];
+
+ slast = string + nbytes;
+ sbyte = string;
+ while (sbyte < slast) {
+ temp[7] = sbyte[0];
+ temp[6] = sbyte[1];
+ temp[5] = sbyte[2];
+ temp[4] = sbyte[3];
+ temp[3] = sbyte[4];
+ temp[2] = sbyte[5];
+ temp[1] = sbyte[6];
+ temp[0] = sbyte[7];
+ sbyte[0] = temp[0];
+ sbyte[1] = temp[1];
+ sbyte[2] = temp[2];
+ sbyte[3] = temp[3];
+ sbyte[4] = temp[4];
+ sbyte[5] = temp[5];
+ sbyte[6] = temp[6];
+ sbyte[7] = temp[7];
+ sbyte = sbyte + 8;
+ }
+ return;
+}
+
+
+/* Set flag if machine on which program is executing is not FITS byte order
+ * ( i.e., if it is an Alpha or PC instead of a Sun ) */
+
+static int
+machswap ()
+
+{
+ char *ctest;
+ int itest;
+
+ itest = 1;
+ ctest = (char *)&itest;
+ if (*ctest)
+ return (1);
+ else
+ return (0);
+}
+
+
+/* ISIRAF -- return 1 if IRAF imh file, else 0 */
+
+int
+isiraf (filename)
+
+char *filename; /* Name of file for which to find size */
+{
+ if (strchr (filename, '='))
+ return (0);
+ else if (strsrch (filename, ".imh"))
+ return (1);
+ else
+ return (0);
+}
+
+
+/* IRAFSIZE -- return size of file in bytes */
+
+static int
+irafsize (diskfile)
+
+FILE *diskfile; /* Descriptor of file for which to find size */
+{
+ long filesize;
+ long offset;
+
+ offset = (long) 0;
+
+ /* Move to end of the file */
+ if (fseek (diskfile, offset, SEEK_END) == 0) {
+
+ /* Position is the size of the file */
+ filesize = ftell (diskfile);
+
+ /* Move file pointer back tot he start of the file */
+ fseek (diskfile, offset, SEEK_SET);
+ }
+
+ else
+ filesize = -1;
+
+ return (filesize);
+}
+
+/* Feb 15 1996 New file
+ * Apr 10 1996 Add more documentation
+ * Apr 17 1996 Print error message on open failure
+ * Jun 5 1996 Add byte swapping (reversal); use streams
+ * Jun 10 1996 Make fixes after running lint
+ * Jun 12 1996 Use IMSWAP subroutines instead of local ones
+ * Jul 3 1996 Go back to using local IRAFSWAP subroutines
+ * Jul 3 1996 Write to pixel file from FITS header
+ * Jul 10 1996 Allocate all headers
+ * Aug 13 1996 Add unistd.h to include list
+ * Aug 26 1996 Allow 1-d images; fix comments; fix arguments after lint
+ * Aug 26 1996 Add IRAF header lingth argument to IRAFWIMAGE and IRAFWHEAD
+ * Aug 28 1996 Clean up code in IRAF2FITS
+ * Aug 30 1996 Use write instead of fwrite
+ * Sep 4 1996 Fix write mode bug
+ * Oct 15 1996 Drop unused variables
+ * Oct 17 1996 Minor fix after lint; cast arguments to STR2IRAF
+ *
+ * May 15 1997 Fix returned header length in IRAF2FITS
+ * Dec 19 1997 Add IRAF version 2 .imh files
+ *
+ * Jan 2 1998 Allow uneven length of user parameter lines in IRAF headers
+ * Jan 6 1998 Fix output of imh2 headers; allow newlines in imh1 headers
+ * Jan 14 1998 Handle byte reversing correctly
+ * Apr 17 1998 Add new IRAF data types unsigned char and unsigned short
+ * Apr 30 1998 Fix error return if illegal data type after Allan Brighton
+ * May 15 1998 Delete header keywords used for IRAF binary values
+ * May 15 1998 Fix bug so FITS OBJECT is put into IRAF title
+ * May 26 1998 Fix bug in fits2iraf keeping track of end of header
+ * May 27 1998 Include fitsio.h instead of fitshead.h
+ * Jun 4 1998 Write comments into header for converted IRAF binary values
+ * Jun 4 1998 Pad FITS strings to 8 character minimum
+ * Jul 24 1998 Write header file length to IRAF header file
+ * Jul 27 1998 Print error messages to stderr for all failed malloc's
+ * Jul 27 1998 Fix bug padding FITS header with spaces in iraf2fits
+ * Jul 27 1998 Write modification time to IRAF header file
+ * Aug 6 1998 Change fitsio.h to fitsfile.h; imhio.c to imhfile.c
+ * Oct 1 1998 Set irafswap flag only once per file
+ * Oct 5 1998 Add subroutines irafsize() and isiraf()
+ * Nov 16 1998 Fix byte-swap checking
+ *
+ * Jan 27 1999 Read and write all of 3D image if one dimension is =1
+ * Jul 13 1999 Improve error messages; change irafsize() argument to fd
+ * Sep 22 1999 Don't copy OBJECT keyword from .imh file; use binary title
+ * Oct 14 1999 Set FITS header length
+ * Oct 20 1999 Allocate 5000 extra bytes for IRAF header
+ * Nov 2 1999 Fix getclocktime() to use only time.h subroutines
+ * Nov 2 1999 Add modification date and time to FITS header in iraf2fits()
+ * Nov 24 1999 Delete HEADSWAP, IMHVER, DATE-MOD from header before writing
+ * Nov 29 1999 Delete PIXSWAP, IRAF-MIN, IRAF-MAX from header before writing
+ *
+ * Jan 13 2000 Fix bug which dropped characters in iraf2fits()
+ * Feb 3 2000 Declare timezone long, not time_t; drop unused variable
+ * Mar 7 2000 Add more code to keep pixel file path short
+ * Mar 10 2000 Fix bugs when writing .imh file headers
+ * Mar 21 2000 Change computation of IRAF time tags to use only data structure
+ * Mar 22 2000 Move IRAF time tag computation to lt2tsi() in dateutil.c
+ * Mar 24 2000 Use Unix file update time if none in header
+ * Mar 27 2000 Use hputm() to save file paths up to 256 characters
+ * Mar 27 2000 Write filename comments after 1st keyword with short value
+ * Mar 27 2000 Allocate pixel file name in same_path to imh2 length
+ * Mar 29 2000 Add space after last linefeed of header in fits2iraf()
+ * Apr 28 2000 Dimension pixname in irafwimage()
+ * May 1 2000 Fix code for updating pixel file name with HDR$ in fits2iraf()
+ * Jun 2 2000 Drop unused variables in fits2iraf() after lint
+ * Jun 12 2000 If pixel filename has no / or $, use same path as header file
+ * Sep 6 2000 Use header directory if pixel file not found at its pathname
+ *
+ * Jan 11 2001 Print all messages to stderr
+ * Aug 24 2001 In isiraf(), return 0 if argument contains an equal sign
+ *
+ * Apr 8 2002 Fix bug in error message for unidentified nbits in fits2iraf()
+ *
+ * Feb 4 2003 Open catalog file rb instead of r (Martin Ploner, Bern)
+ * Oct 31 2003 Read image only in irafrimage() if physical dimension > image dim.
+ * Nov 3 2003 Set NAXISi to image, not physical dimensions in iraf2fits()
+ *
+ * Jun 13 2005 Drop trailing spaces on pixel file name
+ *
+ * Jun 20 2006 Initialize uninitialized variables
+ *
+ * Jan 4 2007 Change hputr4() calls to send pointer to value
+ * Jan 8 2007 Drop unused variable nbx in irafrimage()
+ * Jan 8 2007 Align header and image buffers properly by 4 and by BITPIX
+ *
+ * May 20 2011 Free newpixname, not pixname in irafwimage()
+ *
+ * Mar 27 2012 Fix pixname's appending to newpixname to avoid overflow
+ */
diff --git a/funtools/wcs/imio.c b/funtools/wcs/imio.c
new file mode 100644
index 0000000..9bbf5a4
--- /dev/null
+++ b/funtools/wcs/imio.c
@@ -0,0 +1,1543 @@
+/*** File wcslib/imio.c
+ *** October 30, 2012
+ *** By Jessica Mink, jmink@cfa.harvard.edu
+ *** Harvard-Smithsonian Center for Astrophysics
+ *** Copyright (C) 1996-2012
+ *** Smithsonian Astrophysical Observatory, Cambridge, MA, USA
+
+ This library 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 2 of the License, or (at your option) any later version.
+
+ This library 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 this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Correspondence concerning WCSTools should be addressed as follows:
+ Internet email: jmink@cfa.harvard.edu
+ Postal address: Jessica Mink
+ Smithsonian Astrophysical Observatory
+ 60 Garden St.
+ Cambridge, MA 02138 USA
+
+ * Module: imio.c (image pixel manipulation)
+ * Purpose: Read and write pixels from arbitrary data type 2D arrays
+ * Subroutine: getpix (image, bitpix, w, h, bz, bs, x, y)
+ * Read pixel from 2D image of any numeric type (0,0 lower left)
+ * Subroutine: getpix1 (image, bitpix, w, h, bz, bs, x, y)
+ * Read pixel from 2D image of any numeric type (1,1 lower left)
+ * Subroutine: putpix (image, bitpix, w, h, bz, bs, x, y, dpix)
+ * Write pixel into 2D image of any numeric type (0,0 lower left)
+ * Subroutine: putpix1 (image, bitpix, w, h, bz, bs, x, y, dpix)
+ * Write pixel into 2D image of any numeric type (1,1 lower left)
+ * Subroutine: addpix (image, bitpix, w, h, bz, bs, x, y, dpix)
+ * Copy pixel into 2D image of any numeric type (0,0 lower left)
+ * Subroutine: addpix1 (image, bitpix, w, h, bz, bs, x, y, dpix)
+ * Add pixel into 2D image of any numeric type (1,1 lower left)
+ * Subroutine: maxvec (image, bitpix, bz, bs, pix1, npix)
+ * Get maximum of vector from 2D image of any numeric type
+ * Subroutine: minvec (image, bitpix, bz, bs, pix1, npix)
+ * Get minimum of vector from 2D image of any numeric type
+ * Subroutine: getvec (image, bitpix, bz, bs, pix1, npix, dvec)
+ * Get vector from 2D image of any numeric type
+ * Subroutine: putvec (image, bitpix, bz, bs, pix1, npix, dvec)
+ * Copy pixel vector into a vector of any numeric type
+ * Subroutine: addvec (image, bitpix, bz, bs, pix1, npix, dpix)
+ * Add constant to pixel values in a vector
+ * Subroutine: multvec (image, bitpix, bz, bs, pix1, npix, dpix)
+ * Multiply pixel values in a vector by a constant
+ * Subroutine: fillvec (image, bitpix, bz, bs, pix1, npix, dpix)
+ * Copy pixel value in a vector of any numeric type
+ * Subroutine: fillvec1 (image, bitpix, bz, bs, pix1, npix, dpix)
+ * Copy pixel value int a vector of any numeric type
+ * Subroutine: movepix (image1, bitpix, w1, x1, y1, image2, w2, x2, y2)
+ * Copy pixel from one image location to another
+ * Subroutine: imswap (bitpix,string,nbytes)
+ * Swap bytes in string in place, with FITS bits/pixel code
+ * Subroutine: imswap2 (string,nbytes)
+ * Swap bytes in string in place
+ * Subroutine imswap4 (string,nbytes)
+ * Reverse bytes of Integer*4 or Real*4 vector in place
+ * Subroutine imswap8 (string,nbytes)
+ * Reverse bytes of Real*8 vector in place
+ * Subroutine imswapped ()
+ * Return 1 if PC/DEC byte order, else 0
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "fitsfile.h"
+
+static int scale = 1; /* If 0, skip scaling step */
+void
+setscale (scale0)
+int scale0;
+{scale = scale0; return;}
+
+/* GETPIX1 -- Get pixel from 2D FITS image of any numeric type */
+
+double
+getpix1 (image, bitpix, w, h, bzero, bscale, x, y)
+
+char *image; /* Image array as 1-D vector */
+int bitpix; /* FITS bits per pixel */
+ /* 16 = short, -16 = unsigned short, 32 = int */
+ /* -32 = float, -64 = double */
+int w; /* Image width in pixels */
+int h; /* Image height in pixels */
+double bzero; /* Zero point for pixel scaling */
+double bscale; /* Scale factor for pixel scaling */
+int x; /* One-based horizontal pixel number */
+int y; /* One-based vertical pixel number */
+
+{
+ return (getpix (image, bitpix, w, h, bzero, bscale, x-1, y-1));
+}
+
+
+/* GETPIX -- Get pixel from 2D image of any numeric type */
+
+double
+getpix (image, bitpix, w, h, bzero, bscale, x, y)
+
+char *image; /* Image array as 1-D vector */
+int bitpix; /* FITS bits per pixel */
+ /* 16 = short, -16 = unsigned short, 32 = int */
+ /* -32 = float, -64 = double */
+int w; /* Image width in pixels */
+int h; /* Image height in pixels */
+double bzero; /* Zero point for pixel scaling */
+double bscale; /* Scale factor for pixel scaling */
+int x; /* Zero-based horizontal pixel number */
+int y; /* Zero-based vertical pixel number */
+
+{
+ short *im2;
+ int *im4;
+ unsigned char *im1;
+ unsigned short *imu;
+ float *imr;
+ double *imd;
+ double dpix;
+
+/* Return 0 if coordinates are not inside image */
+ if (x < 0 || x >= w)
+ return (0.0);
+ if (y < 0 || y >= h)
+ return (0.0);
+
+/* Extract pixel from appropriate type of array */
+ switch (bitpix) {
+
+ case 8:
+ im1 = (unsigned char *)image;
+ dpix = (double) im1[(y*w) + x];
+ break;
+
+ case 16:
+ im2 = (short *)image;
+ dpix = (double) im2[(y*w) + x];
+ break;
+
+ case 32:
+ im4 = (int *)image;
+ dpix = (double) im4[(y*w) + x];
+ break;
+
+ case -16:
+ imu = (unsigned short *)image;
+ dpix = (double) imu[(y*w) + x];
+ break;
+
+ case -32:
+ imr = (float *)image;
+ dpix = (double) imr[(y*w) + x];
+ break;
+
+ case -64:
+ imd = (double *)image;
+ dpix = imd[(y*w) + x];
+ break;
+
+ default:
+ dpix = 0.0;
+ }
+ if (scale)
+ return (bzero + (bscale * dpix));
+ else
+ return (dpix);
+}
+
+
+/* PUTPIX1 -- Copy pixel into 2D FITS image of any numeric type */
+
+void
+putpix1 (image, bitpix, w, h, bzero, bscale, x, y, dpix)
+
+char *image;
+int bitpix; /* Number of bits per pixel */
+ /* 16 = short, -16 = unsigned short, 32 = int */
+ /* -32 = float, -64 = double */
+int w; /* Image width in pixels */
+int h; /* Image height in pixels */
+double bzero; /* Zero point for pixel scaling */
+double bscale; /* Scale factor for pixel scaling */
+int x; /* One-based horizontal pixel number */
+int y; /* One-based vertical pixel number */
+double dpix;
+
+{
+ putpix (image, bitpix, w, h, bzero, bscale, x-1, y-1, dpix);
+ return;
+}
+
+
+/* PUTPIX -- Copy pixel into 2D image of any numeric type */
+
+void
+putpix (image, bitpix, w, h, bzero, bscale, x, y, dpix)
+
+char *image;
+int bitpix; /* Number of bits per pixel */
+ /* 16 = short, -16 = unsigned short, 32 = int */
+ /* -32 = float, -64 = double */
+int w; /* Image width in pixels */
+int h; /* Image height in pixels */
+double bzero; /* Zero point for pixel scaling */
+double bscale; /* Scale factor for pixel scaling */
+int x;
+int y;
+double dpix;
+
+{
+ double *imd;
+ float *imr;
+ int *im4;
+ short *im2;
+ unsigned short *imu;
+ unsigned char *im1;
+
+/* Return if coordinates are not inside image */
+ if (x < 0 || x >= w)
+ return;
+ if (y < 0 || y >= h)
+ return;
+
+ if (scale)
+ dpix = (dpix - bzero) / bscale;
+
+ switch (bitpix) {
+
+ case 8:
+ im1 = (unsigned char *)image;
+ if (dpix < 0)
+ im1[(y*w) + x] = (unsigned char) (dpix - 0.5);
+ else
+ im1[(y*w) + x] = (unsigned char) (dpix + 0.5);
+ break;
+
+ case 16:
+ im2 = (short *)image;
+ if (dpix < 0)
+ im2[(y*w) + x] = (short) (dpix - 0.5);
+ else
+ im2[(y*w) + x] = (short) (dpix + 0.5);
+ break;
+
+ case 32:
+ im4 = (int *)image;
+ if (dpix < 0)
+ im4[(y*w) + x] = (int) (dpix - 0.5);
+ else
+ im4[(y*w) + x] = (int) (dpix + 0.5);
+ break;
+
+ case -16:
+ imu = (unsigned short *)image;
+ if (dpix < 0)
+ imu[(y*w) + x] = (unsigned short) 0;
+ else
+ imu[(y*w) + x] = (unsigned short) (dpix + 0.5);
+ break;
+
+ case -32:
+ imr = (float *)image;
+ imr[(y*w) + x] = (float) dpix;
+ break;
+
+ case -64:
+ imd = (double *)image;
+ imd[(y*w) + x] = dpix;
+ break;
+
+ }
+ return;
+}
+
+
+/* ADDPIX1 -- Add pixel value into 2D FITS image of any numeric type */
+
+void
+addpix1 (image, bitpix, w, h, bzero, bscale, x, y, dpix)
+
+char *image;
+int bitpix; /* Number of bits per pixel */
+ /* 16 = short, -16 = unsigned short, 32 = int */
+ /* -32 = float, -64 = double */
+int w; /* Image width in pixels */
+int h; /* Image height in pixels */
+double bzero; /* Zero point for pixel scaling */
+double bscale; /* Scale factor for pixel scaling */
+int x; /* One-based horizontal pixel number */
+int y; /* One-based vertical pixel number */
+double dpix; /* Value to add to pixel */
+
+{
+ addpix (image, bitpix, w, h, bzero, bscale, x-1, y-1, dpix);
+ return;
+}
+
+
+/* ADDPIX -- Add constant to pixel values in 2D image of any numeric type */
+
+void
+addpix (image, bitpix, w, h, bzero, bscale, x, y, dpix)
+
+char *image;
+int bitpix; /* Number of bits per pixel */
+ /* 16 = short, -16 = unsigned short, 32 = int */
+ /* -32 = float, -64 = double */
+int w; /* Image width in pixels */
+int h; /* Image height in pixels */
+double bzero; /* Zero point for pixel scaling */
+double bscale; /* Scale factor for pixel scaling */
+int x; /* Zero-based horizontal pixel number */
+int y; /* Zero-based vertical pixel number */
+double dpix; /* Value to add to pixel */
+
+{
+ double *imd;
+ float *imr;
+ int *im4;
+ short *im2;
+ unsigned short *imu;
+ unsigned char *im1;
+ int ipix;
+
+/* Return if coordinates are not inside image */
+ if (x < 0 || x >= w)
+ return;
+ if (y < 0 || y >= h)
+ return;
+
+ if (scale)
+ dpix = (dpix - bzero) / bscale;
+ ipix = (y * w) + x;
+
+ switch (bitpix) {
+
+ case 8:
+ im1 = (unsigned char *)image;
+ if (dpix < 0)
+ image[ipix] = im1[ipix] + (unsigned char) (dpix - 0.5);
+ else
+ image[ipix] = im1[ipix] + (unsigned char) (dpix + 0.5);
+ break;
+
+ case 16:
+ im2 = (short *)image;
+ if (dpix < 0)
+ im2[ipix] = im2[ipix] + (short) (dpix - 0.5);
+ else
+ im2[ipix] = im2[ipix] + (short) (dpix + 0.5);
+ break;
+
+ case 32:
+ im4 = (int *)image;
+ if (dpix < 0)
+ im4[ipix] = im4[ipix] + (int) (dpix - 0.5);
+ else
+ im4[ipix] = im4[ipix] + (int) (dpix + 0.5);
+ break;
+
+ case -16:
+ imu = (unsigned short *)image;
+ if (dpix > 0)
+ imu[ipix] = imu[ipix] + (unsigned short) (dpix + 0.5);
+ break;
+
+ case -32:
+ imr = (float *)image;
+ imr[ipix] = imr[ipix] + (float) dpix;
+ break;
+
+ case -64:
+ imd = (double *)image;
+ imd[ipix] = imd[ipix] + dpix;
+ break;
+
+ }
+ return;
+}
+
+
+/* MOVEPIX -- Copy pixel between images */
+
+void
+movepix (image1, bitpix1, w1, x1, y1, image2, bitpix2, w2, x2, y2)
+
+char *image1; /* Pointer to first pixel in input image */
+int bitpix1; /* Bits per input pixel (FITS codes) */
+ /* 16 = short, -16 = unsigned short, 32 = int */
+ /* -32 = float, -64 = double */
+int w1; /* Number of horizontal pixels in input image */
+int x1, y1; /* Row and column for input pixel */
+
+char *image2; /* Pointer to first pixel in output image */
+int bitpix2; /* Bits per output pixel (FITS codes) */
+ /* 16 = short, -16 = unsigned short, 32 = int */
+ /* -32 = float, -64 = double */
+int w2; /* Number of horizontal pixels in output image */
+int x2, y2; /* Row and column for output pixel */
+
+{
+ double dpix, *imd1, *imd2;
+ float rpix, *imr1, *imr2;
+ int *imi1, *imi2;
+ short *ims1, *ims2;
+ unsigned short *imu1, *imu2;
+ unsigned char *imc1, *imc2;
+
+ if (x1 < 0 || x2 < 0 || x1 >= w1 || x2 >= w2)
+ return;
+ if (y1 < 0 || y2 < 0)
+ return;
+
+ switch (bitpix1) {
+
+ case 8:
+ imc1 = (unsigned char *)image1;
+ switch (bitpix2) {
+ case 8:
+ imc2 = (unsigned char *)image2;
+ imc2[(y2*w2) + x2] = imc1[(y1*w1) + x1];
+ break;
+ case 16:
+ ims2 = (short *)image2;
+ ims2[(y2*w2) + x2] = (short) imc1[(y1*w1) + x1];
+ break;
+ case 32:
+ imi2 = (int *)image2;
+ imi2[(y2*w2) + x2] = (int) imc1[(y1*w1) + x1];
+ break;
+ case -16:
+ imu2 = (unsigned short *)image2;
+ imu2[(y2*w2) + x2] = (unsigned short) imc1[(y1*w1) + x1];
+ break;
+ case -32:
+ imr2 = (float *)image2;
+ imr2[(y2*w2) + x2] = (float) imc1[(y1*w1) + x1];
+ break;
+ case -64:
+ imd2 = (double *)image2;
+ imd2[(y2*w2) + x2] = (double) imc1[(y1*w1) + x1];
+ break;
+ }
+ break;
+
+ case 16:
+ ims1 = (short *)image1;
+ switch (bitpix2) {
+ case 8:
+ imc2 = (unsigned char *)image1;
+ imc2[(y2*w2) + x2] = (unsigned char) ims1[(y1*w1) + x1];
+ break;
+ case 16:
+ ims2 = (short *)image2;
+ ims2[(y2*w2) + x2] = ims1[(y1*w1) + x1];
+ break;
+ case 32:
+ imi2 = (int *)image2;
+ imi2[(y2*w2) + x2] = (int) ims1[(y1*w1) + x1];
+ break;
+ case -16:
+ imu2 = (unsigned short *)image2;
+ imu2[(y2*w2) + x2] = (unsigned short) ims1[(y1*w1) + x1];
+ break;
+ case -32:
+ imr2 = (float *)image2;
+ imr2[(y2*w2) + x2] = (float) ims1[(y1*w1) + x1];
+ break;
+ case -64:
+ imd2 = (double *)image2;
+ imd2[(y2*w2) + x2] = (double) ims1[(y1*w1) + x1];
+ break;
+ }
+ break;
+
+ case 32:
+ imi1 = (int *)image1;
+ switch (bitpix2) {
+ case 8:
+ imc2 = (unsigned char *)image2;
+ imc2[(y2*w2) + x2] = (unsigned char) imi1[(y1*w1) + x1];
+ break;
+ case 16:
+ ims2 = (short *)image2;
+ ims2[(y2*w2) + x2] = (short) imi1[(y1*w1) + x1];
+ break;
+ case 32:
+ imi2 = (int *)image2;
+ imi2[(y2*w2) + x2] = imi1[(y1*w1) + x1];
+ break;
+ case -16:
+ imu2 = (unsigned short *)image2;
+ imu2[(y2*w2) + x2] = (unsigned short) imi1[(y1*w1) + x1];
+ break;
+ case -32:
+ imr2 = (float *)image2;
+ imr2[(y2*w2) + x2] = (float) imi1[(y1*w1) + x1];
+ break;
+ case -64:
+ imd2 = (double *)image2;
+ imd2[(y2*w2) + x2] = (double) imi1[(y1*w1) + x1];
+ break;
+ }
+ break;
+
+ case -16:
+ imu1 = (unsigned short *)image1;
+ switch (bitpix2) {
+ case 8:
+ imc2 = (unsigned char *)image2;
+ imc2[(y2*w2) + x2] = (unsigned char) imu1[(y1*w1) + x1];
+ break;
+ case 16:
+ ims2 = (short *)image2;
+ ims2[(y2*w2) + x2] = (short) imu1[(y1*w1) + x1];
+ break;
+ case 32:
+ imi2 = (int *)image2;
+ imi2[(y2*w2) + x2] = (int) imu1[(y1*w1) + x1];
+ break;
+ case -16:
+ imu2 = (unsigned short *)image2;
+ imu2[(y2*w2) + x2] = imu1[(y1*w1) + x1];
+ break;
+ case -32:
+ imr2 = (float *)image2;
+ imr2[(y2*w2) + x2] = (float) imu1[(y1*w1) + x1];
+ break;
+ case -64:
+ imd2 = (double *)image2;
+ imd2[(y2*w2) + x2] = (double) imu1[(y1*w1) + x1];
+ break;
+ }
+ break;
+
+ case -32:
+ imr1 = (float *)image1;
+ rpix = imr1[(y1*w1) + x1];
+ switch (bitpix2) {
+ case 8:
+ imc2 = (unsigned char *)image2;
+ if (rpix < 0.0)
+ imc2[(y2*w2) + x2] = (unsigned char) 0;
+ else
+ imc2[(y2*w2) + x2] = (unsigned char) (rpix + 0.5);
+ break;
+ case 16:
+ ims2 = (short *)image2;
+ if (rpix < 0.0)
+ ims2[(y2*w2) + x2] = (short) (rpix - 0.5);
+ else
+ ims2[(y2*w2) + x2] = (short) (rpix + 0.5);
+ break;
+ case 32:
+ imi2 = (int *)image2;
+ if (rpix < 0.0)
+ imi2[(y2*w2) + x2] = (int) (rpix - 0.5);
+ else
+ imi2[(y2*w2) + x2] = (int) (rpix + 0.5);
+ break;
+ case -16:
+ imu2 = (unsigned short *)image2;
+ if (rpix < 0.0)
+ imu2[(y2*w2) + x2] = (unsigned short) 0;
+ else
+ imu2[(y2*w2) + x2] = (unsigned short) (rpix + 0.5);
+ break;
+ case -32:
+ imr2 = (float *)image2;
+ imr2[(y2*w2) + x2] = rpix;
+ break;
+ case -64:
+ imd2 = (double *)image2;
+ imd2[(y2*w2) + x2] = (double) rpix;
+ break;
+ }
+ break;
+
+ case -64:
+ imd1 = (double *)image1;
+ dpix = imd1[(y1*w1) + x1];
+ switch (bitpix2) {
+ case 8:
+ imc2 = (unsigned char *)image2;
+ if (dpix < 0.0)
+ imc2[(y2*w2) + x2] = (unsigned char) 0;
+ else
+ imc2[(y2*w2) + x2] = (unsigned char) (dpix + 0.5);
+ break;
+ case 16:
+ ims2 = (short *)image2;
+ if (dpix < 0.0)
+ ims2[(y2*w2) + x2] = (short) (dpix - 0.5);
+ else
+ ims2[(y2*w2) + x2] = (short) (dpix + 0.5);
+ break;
+ case 32:
+ imi2 = (int *)image2;
+ if (dpix < 0.0)
+ imi2[(y2*w2) + x2] = (int) (dpix - 0.5);
+ else
+ imi2[(y2*w2) + x2] = (int) (dpix + 0.5);
+ break;
+ case -16:
+ imu2 = (unsigned short *)image2;
+ if (dpix < 0.0)
+ imu2[(y2*w2) + x2] = (unsigned short) 0;
+ else
+ imu2[(y2*w2) + x2] = (unsigned short) (dpix + 0.5);
+ break;
+ case -32:
+ imr2 = (float *)image2;
+ imr2[(y2*w2) + x2] = (float) dpix;
+ break;
+ case -64:
+ imd2 = (double *)image2;
+ imd2[(y2*w2) + x2] = dpix;
+ break;
+ }
+ break;
+ }
+ return;
+}
+
+
+/* MAXVEC -- Get maximum value in vector from 2D image of any numeric type */
+
+double
+maxvec (image, bitpix, bzero, bscale, pix1, npix)
+
+char *image; /* Image array from which to read vector */
+int bitpix; /* Number of bits per pixel in image */
+ /* 16 = short, -16 = unsigned short, 32 = int */
+ /* -32 = float, -64 = double */
+double bzero; /* Zero point for pixel scaling */
+double bscale; /* Scale factor for pixel scaling */
+int pix1; /* Offset of first pixel to check */
+int npix; /* Number of pixels to check */
+
+{
+ short *im2, imax2, ip2;
+ int *im4, imax4, ip4;
+ unsigned short *imu, imaxu, ipu;
+ float *imr, imaxr, ipr;
+ double *imd;
+ double dmax = 0.0;
+ double ipd;
+ int ipix, pix2;
+ unsigned char *imc, imaxc, ipc;
+
+ pix2 = pix1 + npix;
+
+ switch (bitpix) {
+
+ case 8:
+ imc = (unsigned char *)(image);
+ imaxc = *(imc + pix1);
+ for (ipix = pix1; ipix < pix2; ipix++) {
+ ipc = *(imc + ipix);
+ if (ipc > imaxc)
+ imaxc = ipc;
+ }
+ dmax = (double) imaxc;
+ break;
+
+ case 16:
+ im2 = (short *)image;
+ imax2 = *(im2 + pix1);
+ for (ipix = pix1; ipix < pix2; ipix++) {
+ ip2 = *(im2 + ipix);
+ if (ip2 > imax2)
+ imax2 = ip2;
+ }
+ dmax = (double) imax2;
+ break;
+
+ case 32:
+ im4 = (int *)image;
+ imax4 = *(im4 + pix1);
+ for (ipix = pix1; ipix < pix2; ipix++) {
+ ip4 = *(im4 + ipix);
+ if (ip4 > imax4)
+ imax4 = ip4;
+ }
+ dmax = (double) imax4;
+ break;
+
+ case -16:
+ imu = (unsigned short *)image;
+ imaxu = *(imu + pix1);
+ for (ipix = pix1; ipix < pix2; ipix++) {
+ ipu = *(imu + ipix);
+ if (ipu > imaxu)
+ imaxu = ipu;
+ }
+ dmax = (double) imaxu;
+ break;
+
+ case -32:
+ imr = (float *)image;
+ imaxr = *(imr + pix1);
+ for (ipix = pix1; ipix < pix2; ipix++) {
+ ipr = *(imr + ipix);
+ if (ipr > imaxr)
+ imax2 = ipr;
+ }
+ dmax = (double) imaxr;
+ break;
+
+ case -64:
+ imd = (double *)image;
+ dmax = *(imd + pix1);
+ for (ipix = pix1; ipix < pix2; ipix++) {
+ ipd = *(imd + ipix);
+ if (ipd > dmax)
+ dmax = ipd;
+ }
+ break;
+
+ }
+
+ /* Scale data if either BZERO or BSCALE keyword has been set */
+ if (scale && (bzero != 0.0 || bscale != 1.0))
+ dmax = (dmax * bscale) + bzero;
+
+ return (dmax);
+}
+
+
+/* MINVEC -- Get minimum value in vector from 2D image of any numeric type */
+
+double
+minvec (image, bitpix, bzero, bscale, pix1, npix)
+
+char *image; /* Image array from which to read vector */
+int bitpix; /* Number of bits per pixel in image */
+ /* 16 = short, -16 = unsigned short, 32 = int */
+ /* -32 = float, -64 = double */
+double bzero; /* Zero point for pixel scaling */
+double bscale; /* Scale factor for pixel scaling */
+int pix1; /* Offset of first pixel to check */
+int npix; /* Number of pixels to check */
+
+{
+ short *im2, imin2, ip2;
+ int *im4, imin4, ip4;
+ unsigned short *imu, iminu, ipu;
+ float *imr, iminr, ipr;
+ double *imd, ipd;
+ double dmin = 0.0;
+ int ipix, pix2;
+ unsigned char *imc, cmin, cp;
+
+ pix2 = pix1 + npix;
+
+ switch (bitpix) {
+
+ case 8:
+ imc = (unsigned char *)image;
+ cmin = *(imc + pix1);
+ for (ipix = pix1; ipix < pix2; ipix++) {
+ cp = *(imc + ipix);
+ if (cp < cmin)
+ cmin = cp;
+ }
+ dmin = (double) cmin;
+ break;
+
+ case 16:
+ im2 = (short *)image + pix1;
+ imin2 = *im2;
+ for (ipix = pix1; ipix < pix2; ipix++) {
+ ip2 = *(im2 + ipix);
+ if (ip2 < imin2)
+ imin2 = ip2;
+ }
+ dmin = (double) imin2;
+ break;
+
+ case 32:
+ im4 = (int *)image;
+ imin4 = *(im4 + pix1);
+ for (ipix = pix1; ipix < pix2; ipix++) {
+ ip4 = *(im4 + ipix);
+ if (ip4 < imin4)
+ imin4 = ip4;
+ }
+ dmin = (double) imin4;
+ break;
+
+ case -16:
+ imu = (unsigned short *)image;
+ iminu = *(imu + pix1);
+ for (ipix = pix1; ipix < pix2; ipix++) {
+ ipu = *(imu + ipix);
+ if (ipu < iminu)
+ iminu = ipu;
+ }
+ dmin = (double) iminu;
+ break;
+
+ case -32:
+ imr = (float *)image;
+ iminr = *(imr + pix1);
+ for (ipix = pix1; ipix < pix2; ipix++) {
+ ipr = *(imr + ipix);
+ if (ipr < iminr)
+ iminr = ipr;
+ }
+ dmin = (double) iminr;
+ break;
+
+ case -64:
+ imd = (double *)image;
+ dmin = *(imd + pix1);
+ for (ipix = pix1; ipix < pix2; ipix++) {
+ ipd = *(imd + ipix);
+ if (ipd < dmin)
+ dmin = ipd;
+ }
+ break;
+
+ }
+
+ /* Scale data if either BZERO or BSCALE keyword has been set */
+ if (scale && (bzero != 0.0 || bscale != 1.0))
+ dmin = (dmin * bscale) + bzero;
+
+ return (dmin);
+}
+
+
+/* ADDVEC -- Add constant to pixel values in 2D image of any numeric type */
+
+void
+addvec (image, bitpix, bzero, bscale, pix1, npix, dpix)
+
+char *image; /* Image array from which to extract vector */
+int bitpix; /* Number of bits per pixel in image */
+ /* 16 = short, -16 = unsigned short, 32 = int */
+ /* -32 = float, -64 = double */
+double bzero; /* Zero point for pixel scaling */
+double bscale; /* Scale factor for pixel scaling */
+int pix1; /* Offset of first pixel to extract */
+int npix; /* Number of pixels to extract */
+double dpix; /* Value to add to pixels */
+
+{
+ unsigned char *imc, ccon;
+ short *im2, jcon;
+ int *im4, icon;
+ unsigned short *imu, ucon;
+ float *imr, rcon;
+ double *imd;
+ int ipix, pix2;
+
+ pix2 = pix1 + npix;
+
+ if (scale)
+ dpix = (dpix - bzero) / bscale;
+
+ switch (bitpix) {
+
+ case 8:
+ imc = (unsigned char *) (image + pix1);
+ if (dpix < 0)
+ ccon = (unsigned char) (dpix - 0.5);
+ else
+ ccon = (unsigned char) (dpix + 0.5);
+ for (ipix = pix1; ipix < pix2; ipix++)
+ *imc++ += ccon;
+ break;
+
+ case 16:
+ im2 = (short *) (image + pix1);
+ if (dpix < 0)
+ jcon = (short) (dpix - 0.5);
+ else
+ jcon = (short) (dpix + 0.5);
+ for (ipix = pix1; ipix < pix2; ipix++)
+ *im2++ += jcon;
+ break;
+
+ case 32:
+ im4 = (int *) (image + pix1);
+ if (dpix < 0)
+ icon = (int) (dpix - 0.5);
+ else
+ icon = (int) (dpix + 0.5);
+ for (ipix = pix1; ipix < pix2; ipix++)
+ *im4++ += icon;
+ break;
+
+ case -16:
+ imu = (unsigned short *) (image + pix1);
+ if (dpix > 0) {
+ ucon = (unsigned short) (dpix + 0.5);
+ imu = (unsigned short *) (image + pix1);
+ for (ipix = pix1; ipix < pix2; ipix++)
+ *imu++ += ucon;
+ }
+ else {
+ icon = (int) (dpix - 0.5);
+ imu = (unsigned short *) (image + pix1);
+ for (ipix = pix1; ipix < pix2; ipix++) {
+ unsigned short tmp = (icon + (int) *imu);
+ *imu++ += tmp;
+ }
+ }
+ break;
+
+ case -32:
+ rcon = (float) dpix;
+ imr = (float *) (image + pix1);
+ for (ipix = pix1; ipix < pix2; ipix++)
+ *imr++ += rcon;
+ break;
+
+ case -64:
+ imd = (double *) (image + pix1);
+ for (ipix = pix1; ipix < pix2; ipix++)
+ *imd++ += dpix;
+ break;
+ }
+ return;
+}
+
+
+/* MULTVEC -- Multiply pixel values in place in 2D image of any numeric type */
+
+void
+multvec (image, bitpix, bzero, bscale, pix1, npix, dpix)
+
+char *image; /* Image array from which to extract vector */
+int bitpix; /* Number of bits per pixel in image */
+ /* 16 = short, -16 = unsigned short, 32 = int */
+ /* -32 = float, -64 = double */
+double bzero; /* Zero point for pixel scaling */
+double bscale; /* Scale factor for pixel scaling */
+int pix1; /* Offset of first pixel to extract */
+int npix; /* Number of pixels to extract */
+double dpix; /* Value by which to multiply pixels */
+
+{
+ char *imc, ccon;
+ short *im2, jcon;
+ int *im4, icon, isint;
+ unsigned short *imu, ucon;
+ float *imr, rcon;
+ double *imd, dcon, dval;
+ int ipix, pix2;
+
+ pix2 = pix1 + npix;
+
+ if (scale)
+ dpix = (dpix - bzero) / bscale;
+ ipix = (int) dpix;
+ dcon = (double) ipix;
+ if (dcon == dpix)
+ isint = 1;
+ else
+ isint = 0;
+
+ switch (bitpix) {
+
+ case 8:
+ imc = image + pix1;
+ if (isint) {
+ if (dpix < 0)
+ ccon = (char) (dpix - 0.5);
+ else
+ ccon = (char) (dpix + 0.5);
+ for (ipix = pix1; ipix < pix2; ipix++)
+ *imc++ *= ccon;
+ }
+ else {
+ for (ipix = pix1; ipix < pix2; ipix++) {
+ dval = ((double) *imc) * dpix;
+ if (dval < 256.0)
+ *imc++ = (char) dval;
+ else
+ *imc++ = (char) 255;
+ }
+ }
+ break;
+
+ case 16:
+ im2 = (short *) (image + pix1);
+ if (isint) {
+ im2 = (short *)image;
+ if (dpix < 0)
+ jcon = (short) (dpix - 0.5);
+ else
+ jcon = (short) (dpix + 0.5);
+ for (ipix = pix1; ipix < pix2; ipix++)
+ *im2++ *= jcon;
+ }
+ else {
+ for (ipix = pix1; ipix < pix2; ipix++) {
+ dval = ((double) *im2) * dpix;
+ if (dval < 32768.0)
+ *im2++ = (short) dval;
+ else
+ *im2++ = (short) 32767;
+ }
+ }
+ break;
+
+ case 32:
+ im4 = (int *) (image + pix1);
+ if (isint) {
+ if (dpix < 0)
+ icon = (int) (dpix - 0.5);
+ else
+ icon = (int) (dpix + 0.5);
+ for (ipix = pix1; ipix < pix2; ipix++)
+ *im4++ *= icon;
+ }
+ else {
+ for (ipix = pix1; ipix < pix2; ipix++) {
+ dval = ((double) *im4) * dpix;
+ if (dval < 32768.0)
+ *im4++ = (int) dval;
+ else
+ *im4++ = (int) 32767;
+ }
+ }
+ break;
+
+ case -16:
+ imu = (unsigned short *) (image + pix1);
+ if (dpix > 0) {
+ ucon = (unsigned short) (dpix + 0.5);
+ imu = (unsigned short *) (image + pix1);
+ for (ipix = pix1; ipix < pix2; ipix++)
+ *imu++ *= ucon;
+ }
+ break;
+
+ case -32:
+ rcon = (float) dpix;
+ imr = (float *) (image + pix1);
+ for (ipix = pix1; ipix < pix2; ipix++)
+ *imr++ *= rcon;
+ break;
+
+ case -64:
+ imd = (double *) (image + pix1);
+ for (ipix = pix1; ipix < pix2; ipix++)
+ *imd++ *= dpix;
+ break;
+
+ }
+ return;
+}
+
+
+/* GETVEC -- Get vector from 2D image of any numeric type */
+
+void
+getvec (image, bitpix, bzero, bscale, pix1, npix, dvec0)
+
+char *image; /* Image array from which to extract vector */
+int bitpix; /* Number of bits per pixel in image */
+ /* 16 = short, -16 = unsigned short, 32 = int */
+ /* -32 = float, -64 = double */
+double bzero; /* Zero point for pixel scaling */
+double bscale; /* Scale factor for pixel scaling */
+int pix1; /* Offset of first pixel to extract */
+int npix; /* Number of pixels to extract */
+double *dvec0; /* Vector of pixels (returned) */
+
+{
+ short *im2;
+ int *im4;
+ unsigned short *imu;
+ float *imr;
+ double *imd;
+ double *dvec;
+ int ipix, pix2;
+
+ pix2 = pix1 + npix;
+ dvec = dvec0;
+
+ switch (bitpix) {
+
+ case 8:
+ for (ipix = pix1; ipix < pix2; ipix++)
+ *dvec++ = (double) *(image + ipix);
+ break;
+
+ case 16:
+ im2 = (short *)image;
+ for (ipix = pix1; ipix < pix2; ipix++)
+ *dvec++ = (double) *(im2 + ipix);
+ break;
+
+ case 32:
+ im4 = (int *)image;
+ for (ipix = pix1; ipix < pix2; ipix++)
+ *dvec++ = (double) *(im4 + ipix);
+ break;
+
+ case -16:
+ imu = (unsigned short *)image;
+ for (ipix = pix1; ipix < pix2; ipix++)
+ *dvec++ = (double) *(imu + ipix);
+ break;
+
+ case -32:
+ imr = (float *)image;
+ for (ipix = pix1; ipix < pix2; ipix++)
+ *dvec++ = (double) *(imr + ipix);
+ break;
+
+ case -64:
+ imd = (double *)image;
+ for (ipix = pix1; ipix < pix2; ipix++)
+ *dvec++ = (double) *(imd + ipix);
+ break;
+
+ }
+
+ /* Scale data if either BZERO or BSCALE keyword has been set */
+ if (scale && (bzero != 0.0 || bscale != 1.0)) {
+ dvec = dvec0;
+ for (ipix = pix1; ipix < pix2; ipix++) {
+ *dvec = (*dvec * bscale) + bzero;
+ dvec++;
+ }
+ }
+
+ return;
+}
+
+
+/* PUTVEC -- Copy pixel vector into 2D image of any numeric type */
+
+void
+putvec (image, bitpix, bzero, bscale, pix1, npix, dvec)
+
+char *image; /* Image into which to copy vector */
+int bitpix; /* Number of bits per pixel im image */
+ /* 16 = short, -16 = unsigned short, 32 = int */
+ /* -32 = float, -64 = double */
+double bzero; /* Zero point for pixel scaling */
+double bscale; /* Scale factor for pixel scaling */
+int pix1; /* Offset of first pixel of vector in image */
+int npix; /* Number of pixels to copy */
+double *dvec; /* Vector of pixels to copy */
+
+{
+ short *im2;
+ int *im4;
+ unsigned short *imu;
+ float *imr;
+ double *imd;
+ int ipix, pix2;
+ double *dp = dvec;
+
+ pix2 = pix1 + npix;
+
+ /* Scale data if either BZERO or BSCALE keyword has been set */
+ if (scale && (bzero != 0.0 || bscale != 1.0)) {
+ for (ipix = pix1; ipix < pix2; ipix++) {
+ *dp = (*dp - bzero) / bscale;
+ dp++;
+ }
+ dp = dvec;
+ }
+
+ switch (bitpix) {
+
+ case 8:
+ for (ipix = pix1; ipix < pix2; ipix++)
+ *(image+ipix) = (char) *dp++;
+ break;
+
+ case 16:
+ im2 = (short *)image;
+ for (ipix = pix1; ipix < pix2; ipix++) {
+ if (*dp < 0.0)
+ *(im2+ipix) = (short) (*dp++ - 0.5);
+ else
+ *(im2+ipix) = (short) (*dp++ + 0.5);
+ }
+ break;
+
+ case 32:
+ im4 = (int *)image;
+ for (ipix = pix1; ipix < pix2; ipix++) {
+ if (*dp < 0.0)
+ *(im4+ipix) = (int) (*dp++ - 0.5);
+ else
+ *(im4+ipix) = (int) (*dp++ + 0.5);
+ }
+ break;
+
+ case -16:
+ imu = (unsigned short *)image;
+ for (ipix = pix1; ipix < pix2; ipix++) {
+ if (*dp < 0.0)
+ *(imu+ipix) = (unsigned short) 0;
+ else
+ *(imu+ipix) = (unsigned short) (*dp++ + 0.5);
+ }
+ break;
+
+ case -32:
+ imr = (float *)image;
+ for (ipix = pix1; ipix < pix2; ipix++)
+ *(imr+ipix) = (float) *dp++;
+ break;
+
+ case -64:
+ imd = (double *)image;
+ for (ipix = pix1; ipix < pix2; ipix++)
+ *(imd+ipix) = (double) *dp++;
+ break;
+ }
+ return;
+}
+
+
+/* FILLVEC1 -- Copy single value into a vector of any numeric type */
+
+void
+fillvec1 (image, bitpix, bzero, bscale, pix1, npix, dpix)
+
+char *image; /* Vector to fill */
+int bitpix; /* Number of bits per pixel im image */
+ /* 16 = short, -16 = unsigned short, 32 = int */
+ /* -32 = float, -64 = double */
+double bzero; /* Zero point for pixel scaling */
+double bscale; /* Scale factor for pixel scaling */
+int pix1; /* First pixel to fill */
+int npix; /* Number of pixels to fill */
+double dpix; /* Value with which to fill pixels */
+{
+ fillvec (image, bitpix, bzero, bscale, pix1-1, npix, dpix);
+ return;
+}
+
+
+/* FILLVEC -- Copy single value into a vector of any numeric type */
+
+void
+fillvec (image, bitpix, bzero, bscale, pix1, npix, dpix)
+
+char *image; /* Vector to fill */
+int bitpix; /* Number of bits per pixel im image */
+ /* 16 = short, -16 = unsigned short, 32 = int */
+ /* -32 = float, -64 = double */
+double bzero; /* Zero point for pixel scaling */
+double bscale; /* Scale factor for pixel scaling */
+int pix1; /* First pixel to fill */
+int npix; /* Number of pixels to fill */
+double dpix; /* Value with which to fill pixels */
+{
+ char ipc;
+ short *im2, ip2;
+ int *im4, ip4;
+ unsigned short *imu, ipu;
+ float *imr, ipr;
+ double *imd;
+ int ipix, pix2;
+ double dp;
+
+ pix2 = pix1 + npix;
+
+ /* Scale data if either BZERO or BSCALE keyword has been set */
+ dp = dpix;
+ if (scale && (bzero != 0.0 || bscale != 1.0))
+ dp = (dp - bzero) / bscale;
+
+ switch (bitpix) {
+
+ case 8:
+ if (dp < 0.0)
+ ipc = (char) (dp - 0.5);
+ else
+ ipc = (char) (dp + 0.5);
+ for (ipix = pix1; ipix < pix2; ipix++)
+ image[ipix] = ipc;
+ break;
+
+ case 16:
+ im2 = (short *)image;
+ if (dp < 0.0)
+ ip2 = (short) (dp - 0.5);
+ else
+ ip2 = (short) (dp + 0.5);
+ for (ipix = pix1; ipix < pix2; ipix++)
+ im2[ipix] = ip2;
+ break;
+
+ case 32:
+ im4 = (int *)image;
+ if (dp < 0.0)
+ ip4 = (int) (dp - 0.5);
+ else
+ ip4 = (int) (dp + 0.5);
+ for (ipix = pix1; ipix < pix2; ipix++)
+ im4[ipix] = ip4;
+ break;
+
+ case -16:
+ imu = (unsigned short *)image;
+ if (dp < 0.0)
+ ipu = (unsigned short) (dp - 0.5);
+ else
+ ipu = (unsigned short) (dp + 0.5);
+ for (ipix = pix1; ipix < pix2; ipix++)
+ imu[ipix] = ipu;
+ break;
+
+ case -32:
+ imr = (float *)image;
+ ipr = (float) dp;
+ for (ipix = pix1; ipix < pix2; ipix++)
+ imr[ipix] = ipr;
+ break;
+
+ case -64:
+ imd = (double *)image;
+ for (ipix = pix1; ipix < pix2; ipix++)
+ imd[ipix] = dp;
+ break;
+ }
+ return;
+}
+
+
+/* IMSWAP -- Reverse bytes of any type of vector in place */
+
+void
+imswap (bitpix, string, nbytes)
+
+int bitpix; /* Number of bits per pixel */
+ /* 16 = short, -16 = unsigned short, 32 = int */
+ /* -32 = float, -64 = double */
+char *string; /* Address of starting point of bytes to swap */
+int nbytes; /* Number of bytes to swap */
+
+{
+ switch (bitpix) {
+
+ case 8:
+ break;
+
+ case 16:
+ if (nbytes < 2) return;
+ imswap2 (string,nbytes);
+ break;
+
+ case 32:
+ if (nbytes < 4) return;
+ imswap4 (string,nbytes);
+ break;
+
+ case -16:
+ if (nbytes < 2) return;
+ imswap2 (string,nbytes);
+ break;
+
+ case -32:
+ if (nbytes < 4) return;
+ imswap4 (string,nbytes);
+ break;
+
+ case -64:
+ if (nbytes < 8) return;
+ imswap8 (string,nbytes);
+ break;
+
+ }
+ return;
+}
+
+
+/* IMSWAP2 -- Swap bytes in string in place */
+
+void
+imswap2 (string,nbytes)
+
+
+char *string; /* Address of starting point of bytes to swap */
+int nbytes; /* Number of bytes to swap */
+
+{
+ char *sbyte, temp, *slast;
+
+ slast = string + nbytes;
+ sbyte = string;
+ while (sbyte < slast) {
+ temp = sbyte[0];
+ sbyte[0] = sbyte[1];
+ sbyte[1] = temp;
+ sbyte= sbyte + 2;
+ }
+ return;
+}
+
+
+/* IMSWAP4 -- Reverse bytes of Integer*4 or Real*4 vector in place */
+
+void
+imswap4 (string,nbytes)
+
+char *string; /* Address of Integer*4 or Real*4 vector */
+int nbytes; /* Number of bytes to reverse */
+
+{
+ char *sbyte, *slast;
+ char temp0, temp1, temp2, temp3;
+
+ slast = string + nbytes;
+ sbyte = string;
+ while (sbyte < slast) {
+ temp3 = sbyte[0];
+ temp2 = sbyte[1];
+ temp1 = sbyte[2];
+ temp0 = sbyte[3];
+ sbyte[0] = temp0;
+ sbyte[1] = temp1;
+ sbyte[2] = temp2;
+ sbyte[3] = temp3;
+ sbyte = sbyte + 4;
+ }
+
+ return;
+}
+
+
+/* IMSWAP8 -- Reverse bytes of Real*8 vector in place */
+
+void
+imswap8 (string,nbytes)
+
+char *string; /* Address of Real*8 vector */
+int nbytes; /* Number of bytes to reverse */
+
+{
+ char *sbyte, *slast;
+ char temp[8];
+
+ slast = string + nbytes;
+ sbyte = string;
+ while (sbyte < slast) {
+ temp[7] = sbyte[0];
+ temp[6] = sbyte[1];
+ temp[5] = sbyte[2];
+ temp[4] = sbyte[3];
+ temp[3] = sbyte[4];
+ temp[2] = sbyte[5];
+ temp[1] = sbyte[6];
+ temp[0] = sbyte[7];
+ sbyte[0] = temp[0];
+ sbyte[1] = temp[1];
+ sbyte[2] = temp[2];
+ sbyte[3] = temp[3];
+ sbyte[4] = temp[4];
+ sbyte[5] = temp[5];
+ sbyte[6] = temp[6];
+ sbyte[7] = temp[7];
+ sbyte = sbyte + 8;
+ }
+ return;
+}
+
+/* IMSWAPPED -- Returns 0 if big-endian (Sun,Mac),
+ 1 if little-endian(PC,Alpha) */
+
+int
+imswapped ()
+
+{
+ char *ctest;
+ int itest;
+
+ itest = 1;
+ ctest = (char *)&itest;
+ if (*ctest)
+ return (1);
+ else
+ return (0);
+}
+
+/* Apr 17 1996 New file
+ * May 22 1996 Add H so that PUTPIX and GETPIX can check coordinates
+ * Jun 11 1996 Simplify NEWIMAGE subroutine
+ * Jun 12 1996 Add byte-swapping subroutines
+ *
+ * Jul 24 1997 Add 8-bit option to subroutines
+ *
+ * May 27 1998 Include imio.h instead of fitshead.h
+ * Jun 17 1998 Fix bug, changing all unsigned int's to unsigned short's
+ *
+ * Apr 29 1999 Add scaling to getpix, putpix, getvec, and putvec
+ * Apr 29 1999 Fix bug in getvec in dealing with 1-byte data
+ * Sep 14 1999 Change dp incrementing so it works on Alpha compiler
+ * Sep 27 1999 Add interface for 1-based (FITS) image access
+ * Sep 27 1999 Add addpix() and addpix1()
+ * Dec 14 1999 In putpix(), addpix(), putvec(), round when output is integer
+ *
+ * Sep 20 2000 In getvec(), scale only if necessary
+ *
+ * Nov 27 2001 In movepix(), add char to char move
+ *
+ * Jan 23 2002 Add global scale switch to turn off scaling
+ * Jun 4 2002 In getvec() and putvec(), change dpix to dvec
+ * Jun 4 2002 Add addvec() to add to a vector
+ * Jul 19 2002 Fix getvec() bug rescaling scaled numbers
+ *
+ * May 20 2003 Declare scale0 in setscale()
+ *
+ * Jan 28 2004 Add image limit check to movepix()
+ * Feb 27 2004 Add fillvec() and fillvec1() to set vector to a constant
+ *
+ * Jun 27 2005 Fix major bug in fillvec(); pass value dpix in fillvec1(), too
+ * Aug 18 2005 Add maxvec(), addvec(), and multvec()
+ *
+ * Mar 1 2006 Fix bug of occasional double application of bscale in getvec()
+ * Apr 3 2006 Fix bad cast in unisigned int section of addvec()
+ * May 3 2006 Code fixes in addpix and multpix suggested by Robert Lupton
+ * Jun 8 2006 Drop erroneous second im2 assignment without offset in addvec()
+ * Jun 20 2006 Fix typos masquerading as unitialized variables
+ *
+ * Jan 8 2007 Include fitsfile.h instead of imio.h
+ * Jun 11 2007 Add minvec() and speed up maxvec()
+ *
+ * Apr 12 2012 Fix 8-bit variables to be unsigned char
+ * Oct 19 2012 Fix errors with character images in minvec() and maxvec()
+ * Oct 30 2012 Fix errors with short images in minvec() and maxvec()
+ */
diff --git a/funtools/wcs/imio.h b/funtools/wcs/imio.h
new file mode 100644
index 0000000..a12d8e8
--- /dev/null
+++ b/funtools/wcs/imio.h
@@ -0,0 +1,64 @@
+/*** imio.h memory access subroutines
+ *** September 27, 1999
+ *** By Jessica Mink, jmink@cfa.harvard.edu
+ *** Harvard-Smithsonian Center for Astrophysics
+ *** Copyright (C) 1996-2002
+ *** Smithsonian Astrophysical Observatory, Cambridge, MA, USA
+
+ This library 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 2 of the License, or (at your option) any later version.
+
+ This library 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 this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Correspondence concerning WCSTools should be addressed as follows:
+ Internet email: jmink@cfa.harvard.edu
+ Postal address: Jessica Mink
+ Smithsonian Astrophysical Observatory
+ 60 Garden St.
+ Cambridge, MA 02138 USA
+ */
+
+#ifndef imio_h_
+#define imio_h_
+
+/* Image pixel access subroutines in imio.c */
+extern double getpix(); /* Read one pixel from any data type 2-D array (0,0)*/
+extern double getpix1(); /* Read one pixel from any data type 2-D array (1,1)*/
+extern void putpix(); /* Write one pixel to any data type 2-D array (0,0)*/
+extern void putpix1(); /* Write one pixel to any data type 2-D array (1,1) */
+extern void addpix(); /* Add to one pixel in any data type 2-D array (0,0)*/
+extern void addpix1(); /* Add to one pixel in any data type 2-D array (1,1)*/
+extern void movepix(); /* Move one pixel value between two 2-D arrays (0,0) */
+extern void movepix1(); /* Move one pixel value between two 2-D arrays (1,1) */
+extern void getvec(); /* Read vector from a 2-D array */
+extern void putvec(); /* Write vector into a 2-D array */
+extern void fillvec(); /* Write constant into a vector */
+extern void fillvec1(); /* Write constant into a vector */
+extern void imswap(); /* Swap alternating bytes in a vector */
+extern void imswap2(); /* Swap bytes in a vector of 2-byte (short) integers */
+extern void imswap4(); /* Reverse bytes in a vector of 4-byte numbers */
+extern void imswap8(); /* Reverse bytes in a vector of 8-byte numbers */
+extern int imswapped(); /* Return 1 if machine byte order is not FITS order */
+
+#endif /* imio_h_ */
+
+/* May 31 1996 Use stream I/O for reading as well as writing
+ * Jun 12 1996 Add byte-swapping subroutines
+ * Aug 6 1996 Add MOVEPIX, HDEL and HCHANGE declarations
+ *
+ * May 27 1998 Split off imio subroutines to imio.h
+
+ * Sep 27 1999 Add Fortran-indexed (1,1), not (0,0) image access *1()
+ * Sep 28 1999 Add addpix()
+ *
+ * Feb 27 2004 Add fillvec()
+ */
diff --git a/funtools/wcs/install-sh b/funtools/wcs/install-sh
new file mode 100755
index 0000000..36f96f3
--- /dev/null
+++ b/funtools/wcs/install-sh
@@ -0,0 +1,276 @@
+#!/bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5 (mit/util/scripts/install.sh).
+#
+# Copyright 1991 by the Massachusetts Institute of Technology
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, provided that
+# the above copyright notice appear in all copies and that both that
+# copyright notice and this permission notice appear in supporting
+# documentation, and that the name of M.I.T. not be used in advertising or
+# publicity pertaining to distribution of the software without specific,
+# written prior permission. M.I.T. makes no representations about the
+# suitability of this software for any purpose. It is provided "as is"
+# without express or implied warranty.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch. It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+ case $1 in
+ -c) instcmd=$cpprog
+ shift
+ continue;;
+
+ -d) dir_arg=true
+ shift
+ continue;;
+
+ -m) chmodcmd="$chmodprog $2"
+ shift
+ shift
+ continue;;
+
+ -o) chowncmd="$chownprog $2"
+ shift
+ shift
+ continue;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift
+ shift
+ continue;;
+
+ -s) stripcmd=$stripprog
+ shift
+ continue;;
+
+ -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+ shift
+ continue;;
+
+ -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+ shift
+ continue;;
+
+ *) if [ x"$src" = x ]
+ then
+ src=$1
+ else
+ # this colon is to work around a 386BSD /bin/sh bug
+ :
+ dst=$1
+ fi
+ shift
+ continue;;
+ esac
+done
+
+if [ x"$src" = x ]
+then
+ echo "$0: no input file specified" >&2
+ exit 1
+else
+ :
+fi
+
+if [ x"$dir_arg" != x ]; then
+ dst=$src
+ src=""
+
+ if [ -d "$dst" ]; then
+ instcmd=:
+ chmodcmd=""
+ else
+ instcmd=$mkdirprog
+ fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad
+# if $src (and thus $dsttmp) contains '*'.
+
+ if [ -f "$src" ] || [ -d "$src" ]
+ then
+ :
+ else
+ echo "$0: $src does not exist" >&2
+ exit 1
+ fi
+
+ if [ x"$dst" = x ]
+ then
+ echo "$0: no destination specified" >&2
+ exit 1
+ else
+ :
+ fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+ if [ -d "$dst" ]
+ then
+ dst=$dst/`basename "$src"`
+ else
+ :
+ fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo "$dst" | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+# this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='
+ '
+IFS="${IFS-$defaultIFS}"
+
+oIFS=$IFS
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS=$oIFS
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+ pathcomp=$pathcomp$1
+ shift
+
+ if [ ! -d "$pathcomp" ] ;
+ then
+ $mkdirprog "$pathcomp"
+ else
+ :
+ fi
+
+ pathcomp=$pathcomp/
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+ $doit $instcmd "$dst" &&
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd "$dst"; else : ; fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd "$dst"; else : ; fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd "$dst"; else : ; fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd "$dst"; else : ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+ if [ x"$transformarg" = x ]
+ then
+ dstfile=`basename "$dst"`
+ else
+ dstfile=`basename "$dst" $transformbasename |
+ sed $transformarg`$transformbasename
+ fi
+
+# don't allow the sed command to completely eliminate the filename
+
+ if [ x"$dstfile" = x ]
+ then
+ dstfile=`basename "$dst"`
+ else
+ :
+ fi
+
+# Make a couple of temp file names in the proper directory.
+
+ dsttmp=$dstdir/#inst.$$#
+ rmtmp=$dstdir/#rm.$$#
+
+# Trap to clean up temp files at exit.
+
+ trap 'status=$?; rm -f "$dsttmp" "$rmtmp" && exit $status' 0
+ trap '(exit $?); exit' 1 2 13 15
+
+# Move or copy the file name to the temp name
+
+ $doit $instcmd "$src" "$dsttmp" &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing. If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd "$dsttmp"; else :;fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd "$dsttmp"; else :;fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd "$dsttmp"; else :;fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd "$dsttmp"; else :;fi &&
+
+# Now remove or move aside any old file at destination location. We try this
+# two ways since rm can't unlink itself on some systems and the destination
+# file might be busy for other reasons. In this case, the final cleanup
+# might fail but the new file should still install successfully.
+
+{
+ if [ -f "$dstdir/$dstfile" ]
+ then
+ $doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null ||
+ $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null ||
+ {
+ echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2
+ (exit 1); exit
+ }
+ else
+ :
+ fi
+} &&
+
+# Now rename the file to the real destination.
+
+ $doit $mvcmd "$dsttmp" "$dstdir/$dstfile"
+
+fi &&
+
+# The final little trick to "correctly" pass the exit status to the exit trap.
+
+{
+ (exit 0); exit
+}
diff --git a/funtools/wcs/lin.c b/funtools/wcs/lin.c
new file mode 100644
index 0000000..999a9d0
--- /dev/null
+++ b/funtools/wcs/lin.c
@@ -0,0 +1,448 @@
+/*=============================================================================
+*
+* WCSLIB - an implementation of the FITS WCS proposal.
+* Copyright (C) 1995-2002, Mark Calabretta
+*
+* This library 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 2 of the License, or (at your option) any later version.
+*
+* This library 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 this library; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*
+* Correspondence concerning WCSLIB may be directed to:
+* Internet email: mcalabre@atnf.csiro.au
+* Postal address: Dr. Mark Calabretta,
+* Australia Telescope National Facility,
+* P.O. Box 76,
+* Epping, NSW, 2121,
+* AUSTRALIA
+*
+*=============================================================================
+*
+* C routines which implement the FITS World Coordinate System (WCS)
+* convention.
+*
+* Summary of routines
+* -------------------
+* These utility routines apply the linear transformation defined by the WCS
+* FITS header cards. There are separate routines for the image-to-pixel,
+* linfwd(), and pixel-to-image, linrev(), transformations.
+*
+* An initialization routine, linset(), computes intermediate values from
+* the transformation parameters but need not be called explicitly - see the
+* explanation of lin.flag below.
+*
+* An auxiliary matrix inversion routine, matinv(), is included. It uses
+* LU-triangular factorization with scaled partial pivoting.
+*
+*
+* Initialization routine; linset()
+* --------------------------------
+* Initializes members of a linprm data structure which hold intermediate
+* values. Note that this routine need not be called directly; it will be
+* invoked by linfwd() and linrev() if the "flag" structure member is
+* anything other than a predefined magic value.
+*
+* Given and/or returned:
+* lin linprm* Linear transformation parameters (see below).
+*
+* Function return value:
+* int Error status
+* 0: Success.
+* 1: Memory allocation error.
+* 2: PC matrix is singular.
+*
+* Forward transformation; linfwd()
+* --------------------------------
+* Compute pixel coordinates from image coordinates. Note that where
+* celestial coordinate systems are concerned the image coordinates
+* correspond to (x,y) in the plane of projection, not celestial (lng,lat).
+*
+* Given:
+* imgcrd const double[]
+* Image (world) coordinate.
+*
+* Given and returned:
+* lin linprm* Linear transformation parameters (see below).
+*
+* Returned:
+* pixcrd d[] Pixel coordinate.
+*
+* Function return value:
+* int Error status
+* 0: Success.
+* 1: The transformation is not invertible.
+*
+* Reverse transformation; linrev()
+* --------------------------------
+* Compute image coordinates from pixel coordinates. Note that where
+* celestial coordinate systems are concerned the image coordinates
+* correspond to (x,y) in the plane of projection, not celestial (lng,lat).
+*
+* Given:
+* pixcrd const double[]
+* Pixel coordinate.
+*
+* Given and/or returned:
+* lin linprm* Linear transformation parameters (see below).
+*
+* Returned:
+* imgcrd d[] Image (world) coordinate.
+*
+* Function return value:
+* int Error status
+* 0: Success.
+* 1: Error.
+*
+* Linear transformation parameters
+* --------------------------------
+* The linprm struct consists of the following:
+*
+* int flag
+* This flag must be set to zero whenever any of the following members
+* are set or modified. This signals the initialization routine,
+* linset(), to recompute intermediaries.
+* int naxis
+* Number of image axes.
+* double *crpix
+* Pointer to the first element of an array of double containing the
+* coordinate reference pixel, CRPIXn.
+* double *pc
+* Pointer to the first element of the PC (pixel coordinate)
+* transformation matrix. The expected order is
+*
+* lin.pc = {PC1_1, PC1_2, PC2_1, PC2_2};
+*
+* This may be conveniently constructed from a two-dimensional array
+* via
+*
+* double m[2][2] = {{PC1_1, PC1_2},
+* {PC2_1, PC2_2}};
+*
+* which is equivalent to,
+*
+* double m[2][2];
+* m[0][0] = PC1_1;
+* m[0][1] = PC1_2;
+* m[1][0] = PC2_1;
+* m[1][1] = PC2_2;
+*
+* for which the storage order is
+*
+* PC1_1, PC1_2, PC2_1, PC2_2
+*
+* so it would be legitimate to set lin.pc = *m.
+* double *cdelt
+* Pointer to the first element of an array of double containing the
+* coordinate increments, CDELTn.
+*
+* The remaining members of the linprm struct are maintained by the
+* initialization routine and should not be modified.
+*
+* double *piximg
+* Pointer to the first element of the matrix containing the product
+* of the CDELTn diagonal matrix and the PC matrix.
+* double *imgpix
+* Pointer to the first element of the inverse of the piximg matrix.
+*
+* linset allocates storage for the above arrays using malloc(). Note,
+* however, that these routines do not free this storage so if a linprm
+* variable has itself been malloc'd then these structure members must be
+* explicitly freed before the linprm variable is free'd otherwise a memory
+* leak will result.
+*
+* Author: Mark Calabretta, Australia Telescope National Facility
+* $Id: lin.c,v 2.8 2002/01/30 06:04:03 mcalabre Exp $
+*===========================================================================*/
+
+#include <stdlib.h>
+#include <math.h>
+#include "wcslib.h"
+
+/* Map error number to error message for each function. */
+const char *linset_errmsg[] = {
+ 0,
+ "Memory allocation error",
+ "PC matrix is singular"};
+
+const char *linfwd_errmsg[] = {
+ 0,
+ "Memory allocation error",
+ "PC matrix is singular"};
+
+const char *linrev_errmsg[] = {
+ 0,
+ "Memory allocation error",
+ "PC matrix is singular"};
+
+int linset(lin)
+
+struct linprm *lin;
+
+{
+ int i, ij, j, mem, n;
+
+ n = lin->naxis;
+
+ /* Allocate memory for internal arrays. */
+ mem = n * n * sizeof(double);
+ lin->piximg = (double*)malloc(mem);
+ if (lin->piximg == (double*)0) return 1;
+
+ lin->imgpix = (double*)malloc(mem);
+ if (lin->imgpix == (double*)0) {
+ free(lin->piximg);
+ return 1;
+ }
+
+ /* Compute the pixel-to-image transformation matrix. */
+ for (i = 0, ij = 0; i < n; i++) {
+ for (j = 0; j < n; j++, ij++) {
+ lin->piximg[ij] = lin->cdelt[i] * lin->pc[ij];
+ }
+ }
+
+ /* Compute the image-to-pixel transformation matrix. */
+ if (matinv(n, lin->piximg, lin->imgpix)) return 2;
+
+ lin->flag = LINSET;
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int linfwd(imgcrd, lin, pixcrd)
+
+const double imgcrd[];
+struct linprm *lin;
+double pixcrd[];
+
+{
+ int i, ij, j, n;
+
+ n = lin->naxis;
+
+ if (lin->flag != LINSET) {
+ if (linset(lin)) return 1;
+ }
+
+ for (i = 0, ij = 0; i < n; i++) {
+ pixcrd[i] = 0.0;
+ for (j = 0; j < n; j++, ij++) {
+ pixcrd[i] += lin->imgpix[ij] * imgcrd[j];
+ }
+ }
+
+ for (j = 0; j < n; j++) {
+ pixcrd[j] += lin->crpix[j];
+ }
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int linrev(pixcrd, lin, imgcrd)
+
+const double pixcrd[];
+struct linprm *lin;
+double imgcrd[];
+
+{
+ int i, ij, j, n;
+ double temp;
+
+ n = lin->naxis;
+
+ if (lin->flag != LINSET) {
+ if (linset(lin)) return 1;
+ }
+
+ for (i = 0; i < n; i++) {
+ imgcrd[i] = 0.0;
+ }
+
+ for (j = 0; j < n; j++) {
+ temp = pixcrd[j] - lin->crpix[j];
+ for (i = 0, ij = j; i < n; i++, ij+=n) {
+ imgcrd[i] += lin->piximg[ij] * temp;
+ }
+ }
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int matinv(n, mat, inv)
+
+const int n;
+const double mat[];
+double inv[];
+
+{
+ register int i, ij, ik, j, k, kj, pj;
+ int itemp, mem, *mxl, *lxm, pivot;
+ double colmax, *lu, *rowmax, dtemp;
+
+
+ /* Allocate memory for internal arrays. */
+ mem = n * sizeof(int);
+ if ((mxl = (int*)malloc(mem)) == (int*)0) return 1;
+ if ((lxm = (int*)malloc(mem)) == (int*)0) {
+ free(mxl);
+ return 1;
+ }
+
+ mem = n * sizeof(double);
+ if ((rowmax = (double*)malloc(mem)) == (double*)0) {
+ free(mxl);
+ free(lxm);
+ return 1;
+ }
+
+ mem *= n;
+ if ((lu = (double*)malloc(mem)) == (double*)0) {
+ free(mxl);
+ free(lxm);
+ free(rowmax);
+ return 1;
+ }
+
+
+ /* Initialize arrays. */
+ for (i = 0, ij = 0; i < n; i++) {
+ /* Vector which records row interchanges. */
+ mxl[i] = i;
+
+ rowmax[i] = 0.0;
+
+ for (j = 0; j < n; j++, ij++) {
+ dtemp = fabs(mat[ij]);
+ if (dtemp > rowmax[i]) rowmax[i] = dtemp;
+
+ lu[ij] = mat[ij];
+ }
+
+ /* A row of zeroes indicates a singular matrix. */
+ if (rowmax[i] == 0.0) {
+ free(mxl);
+ free(lxm);
+ free(rowmax);
+ free(lu);
+ return 2;
+ }
+ }
+
+
+ /* Form the LU triangular factorization using scaled partial pivoting. */
+ for (k = 0; k < n; k++) {
+ /* Decide whether to pivot. */
+ colmax = fabs(lu[k*n+k]) / rowmax[k];
+ pivot = k;
+
+ for (i = k+1; i < n; i++) {
+ ik = i*n + k;
+ dtemp = fabs(lu[ik]) / rowmax[i];
+ if (dtemp > colmax) {
+ colmax = dtemp;
+ pivot = i;
+ }
+ }
+
+ if (pivot > k) {
+ /* We must pivot, interchange the rows of the design matrix. */
+ for (j = 0, pj = pivot*n, kj = k*n; j < n; j++, pj++, kj++) {
+ dtemp = lu[pj];
+ lu[pj] = lu[kj];
+ lu[kj] = dtemp;
+ }
+
+ /* Amend the vector of row maxima. */
+ dtemp = rowmax[pivot];
+ rowmax[pivot] = rowmax[k];
+ rowmax[k] = dtemp;
+
+ /* Record the interchange for later use. */
+ itemp = mxl[pivot];
+ mxl[pivot] = mxl[k];
+ mxl[k] = itemp;
+ }
+
+ /* Gaussian elimination. */
+ for (i = k+1; i < n; i++) {
+ ik = i*n + k;
+
+ /* Nothing to do if lu[ik] is zero. */
+ if (lu[ik] != 0.0) {
+ /* Save the scaling factor. */
+ lu[ik] /= lu[k*n+k];
+
+ /* Subtract rows. */
+ for (j = k+1; j < n; j++) {
+ lu[i*n+j] -= lu[ik]*lu[k*n+j];
+ }
+ }
+ }
+ }
+
+
+ /* mxl[i] records which row of mat corresponds to row i of lu. */
+ /* lxm[i] records which row of lu corresponds to row i of mat. */
+ for (i = 0; i < n; i++) {
+ lxm[mxl[i]] = i;
+ }
+
+
+ /* Determine the inverse matrix. */
+ for (i = 0, ij = 0; i < n; i++) {
+ for (j = 0; j < n; j++, ij++) {
+ inv[ij] = 0.0;
+ }
+ }
+
+ for (k = 0; k < n; k++) {
+ inv[lxm[k]*n+k] = 1.0;
+
+ /* Forward substitution. */
+ for (i = lxm[k]+1; i < n; i++) {
+ for (j = lxm[k]; j < i; j++) {
+ inv[i*n+k] -= lu[i*n+j]*inv[j*n+k];
+ }
+ }
+
+ /* Backward substitution. */
+ for (i = n-1; i >= 0; i--) {
+ for (j = i+1; j < n; j++) {
+ inv[i*n+k] -= lu[i*n+j]*inv[j*n+k];
+ }
+ inv[i*n+k] /= lu[i*n+i];
+ }
+ }
+
+ free(mxl);
+ free(lxm);
+ free(rowmax);
+ free(lu);
+
+ return 0;
+}
+/* Dec 20 1999 Doug Mink - Include wcslib.h, which includes lin.h
+ *
+ * Feb 15 2001 Doug Mink - Add comments for WCSLIB 2.6; no code changes
+ * Sep 19 2001 Doug Mink - Add above change to WCSLIB 2.7 code
+ * Nov 20 2001 Doug Mink - Always include stdlib.h
+ *
+ * Jan 15 2002 Bill Joye - Add ifdef so this compiles on MacOS/X
+ *
+ * Nov 18 2003 Doug Mink - Include stdlib.h instead of malloc.h
+ */
diff --git a/funtools/wcs/platepos.c b/funtools/wcs/platepos.c
new file mode 100644
index 0000000..8479350
--- /dev/null
+++ b/funtools/wcs/platepos.c
@@ -0,0 +1,391 @@
+/*** File saoimage/wcslib/platepos.c
+ *** February 29, 2000
+ *** By Jessica Mink, jmink@cfa.harvard.edu
+ *** Harvard-Smithsonian Center for Astrophysics
+ *** Copyright (C) 1998-2002
+ *** Smithsonian Astrophysical Observatory, Cambridge, MA, USA
+
+ This library 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 2 of the License, or (at your option) any later version.
+
+ This library 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 this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Correspondence concerning WCSTools should be addressed as follows:
+ Internet email: jmink@cfa.harvard.edu
+ Postal address: Jessica Mink
+ Smithsonian Astrophysical Observatory
+ 60 Garden St.
+ Cambridge, MA 02138 USA
+
+ * Module: platepos.c (Plate solution WCS conversion
+ * Purpose: Compute WCS from plate fit
+ * Subroutine: platepos() converts from pixel location to RA,Dec
+ * Subroutine: platepix() converts from RA,Dec to pixel location
+
+ These functions are based on the astrmcal.c portion of GETIMAGE by
+ J. Doggett and the documentation distributed with the Digital Sky Survey.
+
+*/
+
+#include <math.h>
+#include <string.h>
+#include <stdio.h>
+#include "wcs.h"
+
+int
+platepos (xpix, ypix, wcs, xpos, ypos)
+
+/* Routine to determine accurate position for pixel coordinates */
+/* returns 0 if successful otherwise 1 = angle too large for projection; */
+/* based on amdpos() from getimage */
+
+/* Input: */
+double xpix; /* x pixel number (RA or long without rotation) */
+double ypix; /* y pixel number (dec or lat without rotation) */
+struct WorldCoor *wcs; /* WCS parameter structure */
+
+/* Output: */
+double *xpos; /* Right ascension or longitude in degrees */
+double *ypos; /* Declination or latitude in degrees */
+
+{
+ double x, y, x2, y2, x3, y3, r2;
+ double xi, xir, eta, etar, raoff, ra, dec, ra0, dec0;
+ double twopi = 6.28318530717959;
+ double ctan, ccos;
+ int ncoeff1 = wcs->ncoeff1;
+ int ncoeff2 = wcs->ncoeff2;
+
+ /* Ignore magnitude and color terms
+ double mag = 0.0;
+ double color = 0.0; */
+
+ /* Convert from pixels to millimeters */
+ x = xpix - wcs->crpix[0];
+ y = ypix - wcs->crpix[1];
+ x2 = x * x;
+ y2 = y * y;
+ x3 = x * x2;
+ y3 = y * y2;
+ r2 = x2 + y2;
+
+ /* Compute xi,eta coordinates in degrees from x,y and plate model */
+ xi = wcs->x_coeff[ 0] + wcs->x_coeff[ 1]*x +
+ wcs->x_coeff[ 2]*y + wcs->x_coeff[ 3]*x2 +
+ wcs->x_coeff[ 4]*y2 + wcs->x_coeff[ 5]*x*y;
+
+ if (ncoeff1 > 6)
+ xi = xi + wcs->x_coeff[ 6]*x3 + wcs->x_coeff[ 7]*y3;
+
+ if (ncoeff1 > 8) {
+ xi = xi + wcs->x_coeff[ 8]*x2*y + wcs->x_coeff[ 9]*x*y2 +
+ wcs->x_coeff[10]*(r2) + wcs->x_coeff[11]*x*r2 +
+ wcs->x_coeff[12]*y*r2;
+ }
+
+ eta = wcs->y_coeff[ 0] + wcs->y_coeff[ 1]*x +
+ wcs->y_coeff[ 2]*y + wcs->y_coeff[ 3]*x2 +
+ wcs->y_coeff[ 4]*y2 + wcs->y_coeff[ 5]*x*y;
+
+ if (ncoeff2 > 6)
+ eta = eta + wcs->y_coeff[ 6]*x3 + wcs->y_coeff[ 7]*y3;
+
+ if (ncoeff2 > 8) {
+ eta = eta + wcs->y_coeff[ 8]*x2*y + wcs->y_coeff[ 9]*y2*x +
+ wcs->y_coeff[10]*r2 + wcs->y_coeff[11]*x*r2 +
+ wcs->y_coeff[12]*y*r2;
+ }
+
+ /* Convert to radians */
+ xir = degrad (xi);
+ etar = degrad (eta);
+
+ /* Convert to RA and Dec */
+ ra0 = degrad (wcs->crval[0]);
+ dec0 = degrad (wcs->crval[1]);
+ ctan = tan (dec0);
+ ccos = cos (dec0);
+ raoff = atan2 (xir / ccos, 1.0 - etar * ctan);
+ ra = raoff + ra0;
+ if (ra < 0.0) ra = ra + twopi;
+ *xpos = raddeg (ra);
+
+ dec = atan (cos (raoff) / ((1.0 - (etar * ctan)) / (etar + ctan)));
+ *ypos = raddeg (dec);
+ return 0;
+}
+
+
+int
+platepix (xpos, ypos, wcs, xpix, ypix)
+
+/* Routine to determine pixel coordinates for sky position */
+/* returns 0 if successful otherwise 1 = angle too large for projection; */
+/* based on amdinv() from getimage */
+
+/* Input: */
+double xpos; /* Right ascension or longitude in degrees */
+double ypos; /* Declination or latitude in degrees */
+struct WorldCoor *wcs; /* WCS parameter structure */
+
+/* Output: */
+double *xpix; /* x pixel number (RA or long without rotation) */
+double *ypix; /* y pixel number (dec or lat without rotation) */
+
+{
+ double xi,eta,x,y,xy,x2,y2,x2y,y2x,x3,y3,r2,dx,dy;
+ double tdec,ctan,ccos,traoff, craoff, etar, xir;
+ double f,fx,fy,g,gx,gy;
+ double ra0, dec0, ra, dec;
+ double tolerance = 0.0000005;
+ int max_iterations = 50;
+ int i;
+ int ncoeff1 = wcs->ncoeff1;
+ int ncoeff2 = wcs->ncoeff2;
+
+ /* Convert RA and Dec in radians to standard coordinates on a plate */
+ ra = degrad (xpos);
+ dec = degrad (ypos);
+ tdec = tan (dec);
+ ra0 = degrad (wcs->crval[0]);
+ dec0 = degrad (wcs->crval[1]);
+ ctan = tan (dec0);
+ ccos = cos (dec0);
+ traoff = tan (ra - ra0);
+ craoff = cos (ra - ra0);
+ etar = (1.0 - ctan * craoff / tdec) / (ctan + (craoff / tdec));
+ xir = traoff * ccos * (1.0 - (etar * ctan));
+ xi = raddeg (xir);
+ eta = raddeg (etar);
+
+ /* Set initial value for x,y */
+ x = xi * wcs->dc[0] + eta * wcs->dc[1];
+ y = xi * wcs->dc[2] + eta * wcs->dc[3];
+
+ /* if (wcs->x_coeff[1] == 0.0)
+ x = xi - wcs->x_coeff[0];
+ else
+ x = (xi - wcs->x_coeff[0]) / wcs->x_coeff[1];
+ if (wcs->y_coeff[2] == 0.0)
+ y = eta - wcs->y_coeff[0];
+ else
+ y = (eta - wcs->y_coeff[0]) / wcs->y_coeff[2]; */
+
+ /* Iterate by Newton's method */
+ for (i = 0; i < max_iterations; i++) {
+
+ /* X plate model */
+ xy = x * y;
+ x2 = x * x;
+ y2 = y * y;
+ x3 = x2 * x;
+ y3 = y2 * y;
+ x2y = x2 * y;
+ y2x = y2 * x;
+ r2 = x2 + y2;
+
+ f = wcs->x_coeff[0] + wcs->x_coeff[1]*x +
+ wcs->x_coeff[2]*y + wcs->x_coeff[3]*x2 +
+ wcs->x_coeff[4]*y2 + wcs->x_coeff[5]*xy;
+
+ /* Derivative of X model wrt x */
+ fx = wcs->x_coeff[1] + wcs->x_coeff[3]*2.0*x +
+ wcs->x_coeff[5]*y;
+
+ /* Derivative of X model wrt y */
+ fy = wcs->x_coeff[2] + wcs->x_coeff[4]*2.0*y +
+ wcs->x_coeff[5]*x;
+
+ if (ncoeff1 > 6) {
+ f = f + wcs->x_coeff[6]*x3 + wcs->x_coeff[7]*y3;
+ fx = fx + wcs->x_coeff[6]*3.0*x2;
+ fy = fy + wcs->x_coeff[7]*3.0*y2;
+ }
+
+ if (ncoeff1 > 8) {
+ f = f +
+ wcs->x_coeff[8]*x2y + wcs->x_coeff[9]*y2x +
+ wcs->x_coeff[10]*r2 + wcs->x_coeff[11]*x*r2 +
+ wcs->x_coeff[12]*y*r2;
+
+ fx = fx + wcs->x_coeff[8]*2.0*xy +
+ wcs->x_coeff[9]*y2 +
+ wcs->x_coeff[10]*2.0*x +
+ wcs->x_coeff[11]*(3.0*x2+y2) +
+ wcs->x_coeff[12]*2.0*xy;
+
+ fy = fy + wcs->x_coeff[8]*x2 +
+ wcs->x_coeff[9]*2.0*xy +
+ wcs->x_coeff[10]*2.0*y +
+ wcs->x_coeff[11]*2.0*xy +
+ wcs->x_coeff[12]*(3.0*y2+x2);
+ }
+
+ /* Y plate model */
+ g = wcs->y_coeff[0] + wcs->y_coeff[1]*x +
+ wcs->y_coeff[2]*y + wcs->y_coeff[3]*x2 +
+ wcs->y_coeff[4]*y2 + wcs->y_coeff[5]*xy;
+
+ /* Derivative of Y model wrt x */
+ gx = wcs->y_coeff[1] + wcs->y_coeff[3]*2.0*x +
+ wcs->y_coeff[5]*y;
+
+ /* Derivative of Y model wrt y */
+ gy = wcs->y_coeff[2] + wcs->y_coeff[4]*2.0*y +
+ wcs->y_coeff[5]*x;
+
+ if (ncoeff2 > 6) {
+ g = g + wcs->y_coeff[6]*x3 + wcs->y_coeff[7]*y3;
+ gx = gx + wcs->y_coeff[6]*3.0*x2;
+ gy = gy + wcs->y_coeff[7]*3.0*y2;
+ }
+
+ if (ncoeff2 > 8) {
+ g = g +
+ wcs->y_coeff[8]*x2y + wcs->y_coeff[9]*y2x +
+ wcs->y_coeff[10]*r2 + wcs->y_coeff[11]*x*r2 +
+ wcs->y_coeff[12]*y*r2;
+
+ gx = gx + wcs->y_coeff[8]*2.0*xy +
+ wcs->y_coeff[9]*y2 +
+ wcs->y_coeff[10]*2.0*x +
+ wcs->y_coeff[11]*(3.0*x2+y2) +
+ wcs->y_coeff[12]*2.0*xy;
+
+ gy = gy + wcs->y_coeff[8]*x2 +
+ wcs->y_coeff[9]*2.0*xy +
+ wcs->y_coeff[10]*2.0*y +
+ wcs->y_coeff[11]*2.0*xy +
+ wcs->y_coeff[12]*(3.0*y2+x2);
+ }
+
+ f = f - xi;
+ g = g - eta;
+ dx = ((-f * gy) + (g * fy)) / ((fx * gy) - (fy * gx));
+ dy = ((-g * fx) + (f * gx)) / ((fx * gy) - (fy * gx));
+ x = x + dx;
+ y = y + dy;
+ if ((fabs(dx) < tolerance) && (fabs(dy) < tolerance)) break;
+ }
+
+ /* Convert from plate pixels to image pixels */
+ *xpix = x + wcs->crpix[0];
+ *ypix = y + wcs->crpix[1];
+
+ /* If position is off of the image, return offscale code */
+ if (*xpix < 0.5 || *xpix > wcs->nxpix+0.5)
+ return -1;
+ if (*ypix < 0.5 || *ypix > wcs->nypix+0.5)
+ return -1;
+
+ return 0;
+}
+
+
+/* Set plate fit coefficients in structure from arguments */
+int
+SetPlate (wcs, ncoeff1, ncoeff2, coeff)
+
+struct WorldCoor *wcs; /* World coordinate system structure */
+int ncoeff1; /* Number of coefficients for x */
+int ncoeff2; /* Number of coefficients for y */
+double *coeff; /* Plate fit coefficients */
+
+{
+ int i;
+
+ if (nowcs (wcs) || (ncoeff1 < 1 && ncoeff2 < 1))
+ return 1;
+
+ wcs->ncoeff1 = ncoeff1;
+ wcs->ncoeff2 = ncoeff2;
+ wcs->prjcode = WCS_PLT;
+
+ for (i = 0; i < 20; i++) {
+ if (i < ncoeff1)
+ wcs->x_coeff[i] = coeff[i];
+ else
+ wcs->x_coeff[i] = 0.0;
+ }
+
+ for (i = 0; i < 20; i++) {
+ if (i < ncoeff2)
+ wcs->y_coeff[i] = coeff[ncoeff1+i];
+ else
+ wcs->y_coeff[i] = 0.0;
+ }
+ return 0;
+}
+
+
+/* Return plate fit coefficients from structure in arguments */
+int
+GetPlate (wcs, ncoeff1, ncoeff2, coeff)
+
+struct WorldCoor *wcs; /* World coordinate system structure */
+int *ncoeff1; /* Number of coefficients for x */
+int *ncoeff2; /* Number of coefficients for y) */
+double *coeff; /* Plate fit coefficients */
+
+{
+ int i;
+
+ if (nowcs (wcs))
+ return 1;
+
+ *ncoeff1 = wcs->ncoeff1;
+ *ncoeff2 = wcs->ncoeff2;
+
+ for (i = 0; i < *ncoeff1; i++)
+ coeff[i] = wcs->x_coeff[i];
+
+ for (i = 0; i < *ncoeff2; i++)
+ coeff[*ncoeff1+i] = wcs->y_coeff[i];
+
+ return 0;
+}
+
+
+/* Set FITS header plate fit coefficients from structure */
+void
+SetFITSPlate (header, wcs)
+
+char *header; /* Image FITS header */
+struct WorldCoor *wcs; /* WCS structure */
+
+{
+ char keyword[16];
+ int i;
+
+ for (i = 0; i < wcs->ncoeff1; i++) {
+ sprintf (keyword,"CO1_%d",i+1);
+ hputnr8 (header, keyword, -15, wcs->x_coeff[i]);
+ }
+ for (i = 0; i < wcs->ncoeff2; i++) {
+ sprintf (keyword,"CO2_%d",i+1);
+ hputnr8 (header, keyword, -15, wcs->y_coeff[i]);
+ }
+ return;
+}
+
+/* Mar 27 1998 New subroutines for direct image pixel <-> sky polynomials
+ * Apr 10 1998 Make terms identical for both x and y polynomials
+ * Apr 10 1998 Allow different numbers of coefficients for x and y
+ * Apr 16 1998 Drom NCOEFF header parameter
+ * Apr 28 1998 Change projection flags to WCS_*
+ * Sep 10 1998 Check for xc1 and yc2 divide by zero after Allen Harris, SAO
+ *
+ * Oct 21 1999 Drop unused variables after lint
+ *
+ * Feb 29 2000 Use inverse CD matrix to get initial X,Y in platepix()
+ * as suggested by Paolo Montegriffo from Bologna Ast. Obs.
+ */
diff --git a/funtools/wcs/poly.c b/funtools/wcs/poly.c
new file mode 100644
index 0000000..7e88d95
--- /dev/null
+++ b/funtools/wcs/poly.c
@@ -0,0 +1,914 @@
+ /*
+ poly.c
+
+*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+*
+* Part of: A program using Polynomials
+*
+* Author: E.BERTIN (IAP)
+*
+* Contents: Polynomial fitting
+*
+* Last modify: 08/03/2005
+*
+*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+*/
+
+#if HAVE_CONFIG_H
+#include "conf.h"
+#endif
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "wcslib.h"
+
+
+#define QCALLOC(ptr, typ, nel) \
+ {if (!(ptr = (typ *)calloc((size_t)(nel),sizeof(typ)))) \
+ qerror("Not enough memory for ", \
+ #ptr " (" #nel " elements) !");;}
+
+#define QMALLOC(ptr, typ, nel) \
+ {if (!(ptr = (typ *)malloc((size_t)(nel)*sizeof(typ)))) \
+ qerror("Not enough memory for ", \
+ #ptr " (" #nel " elements) !");;}
+
+/********************************* qerror ************************************/
+/*
+I hope it will never be used!
+*/
+void qerror(char *msg1, char *msg2)
+ {
+ fprintf(stderr, "\n> %s%s\n\n",msg1,msg2);
+ exit(-1);
+ }
+
+
+/****** poly_init ************************************************************
+PROTO polystruct *poly_init(int *group, int ndim, int *degree, int ngroup)
+PURPOSE Allocate and initialize a polynom structure.
+INPUT 1D array containing the group for each parameter,
+ number of dimensions (parameters),
+ 1D array with the polynomial degree for each group,
+ number of groups.
+OUTPUT polystruct pointer.
+NOTES -.
+AUTHOR E. Bertin (IAP)
+VERSION 08/03/2003
+ ***/
+polystruct *poly_init(int *group, int ndim, int *degree, int ngroup)
+ {
+ void qerror(char *msg1, char *msg2);
+ polystruct *poly;
+ char str[512];
+ int nd[POLY_MAXDIM];
+ int *groupt,
+ d,g,n,num,den;
+
+ QCALLOC(poly, polystruct, 1);
+ if ((poly->ndim=ndim) > POLY_MAXDIM)
+ {
+ sprintf(str, "The dimensionality of the polynom (%d) exceeds the maximum\n"
+ "allowed one (%d)", ndim, POLY_MAXDIM);
+ qerror("*Error*: ", str);
+ }
+
+ if (ndim)
+ QMALLOC(poly->group, int, poly->ndim);
+ for (groupt=poly->group, d=ndim; d--;)
+ *(groupt++) = *(group++)-1;
+
+ poly->ngroup = ngroup;
+ if (ngroup)
+ {
+ group = poly->group; /* Forget the original *group */
+
+ QMALLOC(poly->degree, int, poly->ngroup);
+
+/*-- Compute the number of context parameters for each group */
+ memset(nd, 0, ngroup*sizeof(int));
+ for (d=0; d<ndim; d++)
+ {
+ if ((g=group[d])>=ngroup)
+ qerror("*Error*: polynomial GROUP out of range", "");
+ nd[g]++;
+ }
+ }
+
+/* Compute the total number of coefficients */
+ poly->ncoeff = 1;
+ for (g=0; g<ngroup; g++)
+ {
+ if ((d=poly->degree[g]=*(degree++))>POLY_MAXDEGREE)
+ {
+ sprintf(str, "The degree of the polynom (%d) exceeds the maximum\n"
+ "allowed one (%d)", poly->degree[g], POLY_MAXDEGREE);
+ qerror("*Error*: ", str);
+ }
+
+/*-- There are (n+d)!/(n!d!) coeffs per group, that is Prod_(i<=d) (n+i)/i */
+ for (num=den=1, n=nd[g]; d; num*=(n+d), den*=d--);
+ poly->ncoeff *= num/den;
+ }
+
+ QMALLOC(poly->basis, double, poly->ncoeff);
+ QCALLOC(poly->coeff, double, poly->ncoeff);
+
+ return poly;
+ }
+
+
+/****** poly_end *************************************************************
+PROTO void poly_end(polystruct *poly)
+PURPOSE Free a polynom structure and everything it contains.
+INPUT polystruct pointer.
+OUTPUT -.
+NOTES -.
+AUTHOR E. Bertin (IAP, Leiden observatory & ESO)
+VERSION 09/04/2000
+ ***/
+void poly_end(polystruct *poly)
+ {
+ if (poly)
+ {
+ free(poly->coeff);
+ free(poly->basis);
+ free(poly->degree);
+ free(poly->group);
+ free(poly);
+ }
+ }
+
+
+/****** poly_func ************************************************************
+PROTO double poly_func(polystruct *poly, double *pos)
+PURPOSE Evaluate a multidimensional polynom.
+INPUT polystruct pointer,
+ pointer to the 1D array of input vector data.
+OUTPUT Polynom value.
+NOTES Values of the basis functions are updated in poly->basis.
+AUTHOR E. Bertin (IAP)
+VERSION 03/03/2004
+ ***/
+double poly_func(polystruct *poly, double *pos)
+ {
+ double xpol[POLY_MAXDIM+1];
+ double *post, *xpolt, *basis, *coeff, xval;
+ long double val;
+ int expo[POLY_MAXDIM+1], gexpo[POLY_MAXDIM+1];
+ int *expot, *degree,*degreet, *group,*groupt, *gexpot,
+ d,g,t, ndim;
+
+/* Prepare the vectors and counters */
+ ndim = poly->ndim;
+ basis = poly->basis;
+ coeff = poly->coeff;
+ group = poly->group;
+ degree = poly->degree;
+ if (ndim)
+ {
+ for (xpolt=xpol, expot=expo, post=pos, d=ndim; --d;)
+ {
+ *(++xpolt) = 1.0;
+ *(++expot) = 0;
+ }
+ for (gexpot=gexpo, degreet=degree, g=poly->ngroup; g--;)
+ *(gexpot++) = *(degreet++);
+ if (gexpo[*group])
+ gexpo[*group]--;
+ }
+
+/* The constant term is handled separately */
+ val = *(coeff++);
+ *(basis++) = 1.0;
+ *expo = 1;
+ *xpol = *pos;
+
+/* Compute the rest of the polynom */
+ for (t=poly->ncoeff; --t; )
+ {
+/*-- xpol[0] contains the current product of the x^n's */
+ val += (*(basis++)=*xpol)**(coeff++);
+/*-- A complex recursion between terms of the polynom speeds up computations */
+/*-- Not too good for roundoff errors (prefer Horner's), but much easier for */
+/*-- multivariate polynomials: this is why we use a long double accumulator */
+ post = pos;
+ groupt = group;
+ expot = expo;
+ xpolt = xpol;
+ for (d=0; d<ndim; d++, groupt++)
+ if (gexpo[*groupt]--)
+ {
+ ++*(expot++);
+ xval = (*(xpolt--) *= *post);
+ while (d--)
+ *(xpolt--) = xval;
+ break;
+ }
+ else
+ {
+ gexpo[*groupt] = *expot;
+ *(expot++) = 0;
+ *(xpolt++) = 1.0;
+ post++;
+ }
+ }
+
+ return (double)val;
+ }
+
+
+/****** poly_fit *************************************************************
+PROTO double poly_fit(polystruct *poly, double *x, double *y, double *w,
+ int ndata, double *extbasis)
+PURPOSE Least-Square fit of a multidimensional polynom to weighted data.
+INPUT polystruct pointer,
+ pointer to the (pseudo)2D array of inputs to basis functions,
+ pointer to the 1D array of data values,
+ pointer to the 1D array of data weights,
+ number of data points,
+ pointer to a (pseudo)2D array of computed basis function values.
+OUTPUT Chi2 of the fit.
+NOTES If different from NULL, extbasis can be provided to store the
+ values of the basis functions. If x==NULL and extbasis!=NULL, the
+ precomputed basis functions stored in extbasis are used (which saves
+ CPU). If w is NULL, all points are given identical weight.
+AUTHOR E. Bertin (IAP, Leiden observatory & ESO)
+VERSION 08/03/2005
+ ***/
+void poly_fit(polystruct *poly, double *x, double *y, double *w, int ndata,
+ double *extbasis)
+ {
+ void qerror(char *msg1, char *msg2);
+ double /*offset[POLY_MAXDIM],*/x2[POLY_MAXDIM],
+ *alpha,*alphat, *beta,*betat, *basis,*basis1,*basis2, *coeff,
+ *extbasist,*xt,
+ val,wval,yval;
+ int ncoeff, ndim, matsize,
+ d,i,j,n;
+
+ if (!x && !extbasis)
+ qerror("*Internal Error*: One of x or extbasis should be "
+ "different from NULL\nin ", "poly_func()");
+ ncoeff = poly->ncoeff;
+ ndim = poly->ndim;
+ matsize = ncoeff*ncoeff;
+ basis = poly->basis;
+ extbasist = extbasis;
+ QCALLOC(alpha, double, matsize);
+ QCALLOC(beta, double, ncoeff);
+
+/* Subtract an average offset to maintain precision (droped for now ) */
+/*
+ if (x)
+ {
+ for (d=0; d<ndim; d++)
+ offset[d] = 0.0;
+ xt = x;
+ for (n=ndata; n--;)
+ for (d=0; d<ndim; d++)
+ offset[d] += *(xt++);
+ for (d=0; d<ndim; d++)
+ offset[d] /= (double)ndata;
+ }
+*/
+/* Build the covariance matrix */
+ xt = x;
+ for (n=ndata; n--;)
+ {
+ if (x)
+ {
+/*---- If x!=NULL, compute the basis functions */
+ for (d=0; d<ndim; d++)
+ x2[d] = *(xt++)/* - offset[d]*/;
+ poly_func(poly, x2);
+/*---- If, in addition, extbasis is provided, then fill it */
+ if (extbasis)
+ for (basis1=basis,j=ncoeff; j--;)
+ *(extbasist++) = *(basis1++);
+ }
+ else
+/*---- If x==NULL, then rely on pre-computed basis functions */
+ for (basis1=basis,j=ncoeff; j--;)
+ *(basis1++) = *(extbasist++);
+
+ basis1 = basis;
+ wval = w? *(w++) : 1.0;
+ yval = *(y++);
+ betat = beta;
+ alphat = alpha;
+ for (j=ncoeff; j--;)
+ {
+ val = *(basis1++)*wval;
+ *(betat++) += val*yval;
+ for (basis2=basis,i=ncoeff; i--;)
+ *(alphat++) += val**(basis2++);
+ }
+ }
+
+/* Solve the system */
+ poly_solve(alpha,beta,ncoeff);
+
+ free(alpha);
+
+/* Now fill the coeff array with the result of the fit */
+ betat = beta;
+ coeff = poly->coeff;
+ for (j=ncoeff; j--;)
+ *(coeff++) = *(betat++);
+/*
+ poly_addcste(poly, offset);
+*/
+ free(beta);
+
+ return;
+ }
+
+
+/****** poly_addcste *********************************************************
+PROTO void poly_addcste(polystruct *poly, double *cste)
+PURPOSE Modify matrix coefficients to mimick the effect of adding a cst to
+ the input of a polynomial.
+INPUT Pointer to the polynomial structure,
+ Pointer to the vector of cst.
+OUTPUT -.
+NOTES Requires quadruple-precision. **For the time beeing, this function
+ returns completely wrong results!!**
+AUTHOR E. Bertin (IAP)
+VERSION 03/03/2004
+ ***/
+void poly_addcste(polystruct *poly, double *cste)
+ {
+ long double *acoeff;
+ double *coeff,*mcoeff,*mcoefft,
+ val;
+ int *mpowers,*powers,*powerst,*powerst2,
+ i,j,n,p, denum, flag, maxdegree, ncoeff, ndim;
+
+ ncoeff = poly->ncoeff;
+ ndim = poly->ndim;
+ maxdegree = 0;
+ for (j=0; j<poly->ngroup; j++)
+ if (maxdegree < poly->degree[j])
+ maxdegree = poly->degree[j];
+ maxdegree++; /* Actually we need maxdegree+1 terms */
+ QCALLOC(acoeff, long double, ncoeff);
+ QCALLOC(mcoeff, double, ndim*maxdegree);
+ QCALLOC(mpowers, int, ndim);
+ mcoefft = mcoeff; /* To avoid gcc -Wall warnings */
+ powerst = powers = poly_powers(poly);
+ coeff = poly->coeff;
+ for (i=0; i<ncoeff; i++)
+ {
+ for (j=0; j<ndim; j++)
+ {
+ mpowers[j] = n = *(powerst++);
+ mcoefft = mcoeff+j*maxdegree+n;
+ denum = 1;
+ val = 1.0;
+ for (p=n+1; p--;)
+ {
+ *(mcoefft--) = val;
+ val *= (cste[j]*(n--))/(denum++); /* This is C_n^p X^(n-p) */
+ }
+ }
+/*-- Update all valid coefficients */
+ powerst2 = powers;
+ for (p=0; p<ncoeff; p++)
+ {
+/*---- Check that this combination of powers is included in the series above */
+ flag = 0;
+ for (j=0; j<ndim; j++)
+ if (mpowers[j] < powerst2[j])
+ {
+ flag = 1;
+ powerst2 += ndim;
+ break;
+ }
+ if (flag == 1)
+ continue;
+ val = 1.0;
+ mcoefft = mcoeff;
+ for (j=ndim; j--; mcoefft += maxdegree)
+ val *= mcoefft[*(powerst2++)];
+ acoeff[i] += val*coeff[p];
+/*
+printf("%g \n", val);
+*/
+ }
+ }
+
+/* Add the new coefficients to the previous ones */
+
+ for (i=0; i<ncoeff; i++)
+{
+/*
+printf("%g %g\n", coeff[i], (double)acoeff[i]);
+*/
+ coeff[i] = (double)acoeff[i];
+}
+
+ free(acoeff);
+ free(mcoeff);
+ free(mpowers);
+ free(powers);
+
+ return;
+ }
+
+/****** poly_solve ************************************************************
+PROTO void poly_solve(double *a, double *b, int n)
+PURPOSE Solve a system of linear equations, using Cholesky decomposition or
+ SVD (if the former fails due to hidden correlation between variables).
+INPUT Pointer to the (pseudo 2D) matrix of coefficients,
+ pointer to the 1D column vector,
+ matrix size.
+OUTPUT -.
+NOTES -.
+AUTHOR E. Bertin (IAP, Leiden observatory & ESO)
+VERSION 21/09/2004
+ ***/
+void poly_solve(double *a, double *b, int n)
+ {
+ double *vmat,*wmat;
+
+ if (cholsolve(a,b,n))
+ {
+ QMALLOC(vmat, double, n*n);
+ QMALLOC(wmat, double, n);
+ svdsolve(a, b, n,n, vmat,wmat);
+ free(vmat);
+ free(wmat);
+ }
+
+ return;
+ }
+
+/****** cholsolve *************************************************************
+PROTO void cholsolve(double *a, double *b, int n)
+PURPOSE Solve a system of linear equations, using Cholesky decomposition.
+INPUT Pointer to the (pseudo 2D) matrix of coefficients,
+ pointer to the 1D column vector,
+ matrix size.
+OUTPUT -1 if the matrix is not positive-definite, 0 otherwise.
+NOTES Based on Numerical Recipes, 2nd ed. (Chap 2.9). The matrix of
+ coefficients must be symmetric and positive definite.
+AUTHOR E. Bertin (IAP, Leiden observatory & ESO)
+VERSION 28/10/2003
+ ***/
+int cholsolve(double *a, double *b, int n)
+ {
+ void qerror(char *msg1, char *msg2);
+ double *p, *x, sum;
+ int i,j,k;
+
+/* Allocate memory to store the diagonal elements */
+ QMALLOC(p, double, n);
+
+/* Cholesky decomposition */
+ for (i=0; i<n; i++)
+ for (j=i; j<n; j++)
+ {
+ for (sum=a[i*n+j],k=i-1; k>=0; k--)
+ sum -= a[i*n+k]*a[j*n+k];
+ if (i==j)
+ {
+ if (sum <= 0.0)
+ {
+ free(p);
+ return -1;
+ }
+ p[i] = sqrt(sum);
+ }
+ else
+ a[j*n+i] = sum/p[i];
+ }
+
+/* Solve the system */
+ x = b; /* Just to save memory: the solution replaces b */
+ for (i=0; i<n; i++)
+ {
+ for (sum=b[i],k=i-1; k>=0; k--)
+ sum -= a[i*n+k]*x[k];
+ x[i] = sum/p[i];
+ }
+
+ for (i=n-1; i>=0; i--)
+ {
+ for (sum=x[i],k=i+1; k<n; k++)
+ sum -= a[k*n+i]*x[k];
+ x[i] = sum/p[i];
+ }
+
+ free(p);
+
+ return 0;
+ }
+
+
+/****** svdsolve *************************************************************
+PROTO void svdsolve(double *a, double *b, int m, int n, double *vmat,
+ double *wmat)
+PURPOSE General least-square fit A.x = b, based on Singular Value
+ Decomposition (SVD).
+ Loosely adapted from Numerical Recipes in C, 2nd Ed. (p. 671).
+INPUT Pointer to the (pseudo 2D) matrix of coefficients,
+ pointer to the 1D column vector (replaced by solution in output),
+ number of matrix rows,
+ number of matrix columns,
+ pointer to the (pseudo 2D) SVD matrix,
+ pointer to the diagonal (1D) matrix of singular values.
+OUTPUT -.
+NOTES Loosely adapted from Numerical Recipes in C, 2nd Ed. (p. 671). The a
+ and v matrices are transposed with respect to the N.R. convention.
+AUTHOR E. Bertin (IAP)
+VERSION 26/12/2003
+ ***/
+void svdsolve(double *a, double *b, int m, int n, double *vmat, double *wmat)
+ {
+#define MAX(a,b) (maxarg1=(a),maxarg2=(b),(maxarg1) > (maxarg2) ?\
+ (maxarg1) : (maxarg2))
+#define PYTHAG(a,b) ((at=fabs(a)) > (bt=fabs(b)) ? \
+ (ct=bt/at,at*sqrt(1.0+ct*ct)) \
+ : (bt ? (ct=at/bt,bt*sqrt(1.0+ct*ct)): 0.0))
+#define SIGN(a,b) ((b) >= 0.0 ? fabs(a) : -fabs(a))
+#define TOL 1.0e-11
+ void qerror(char *msg1, char *msg2);
+
+ int flag,i,its,j,jj,k,l,mmi,nm, nml;
+ double *w,*ap,*ap0,*ap1,*ap10,*rv1p,*vp,*vp0,*vp1,*vp10,
+ *bp,*tmpp, *rv1,*tmp, *sol,
+ c,f,h,s,x,y,z,
+ anorm, g, scale,
+ at,bt,ct,maxarg1,maxarg2,
+ thresh, wmax;
+
+ anorm = g = scale = 0.0;
+ if (m < n)
+ qerror("*Error*: Not enough rows for solving the system ", "in svdfit()");
+
+ sol = b; /* The solution overwrites the input column matrix */
+ QMALLOC(rv1, double, n);
+ QMALLOC(tmp, double, n);
+ l = nm = nml = 0; /* To avoid gcc -Wall warnings */
+ for (i=0;i<n;i++)
+ {
+ l = i+1;
+ nml = n-l;
+ rv1[i] = scale*g;
+ g = s = scale = 0.0;
+ if ((mmi = m - i) > 0)
+ {
+ ap = ap0 = a+i*(m+1);
+ for (k=mmi;k--;)
+ scale += fabs(*(ap++));
+ if (scale)
+ {
+ for (ap=ap0,k=mmi; k--; ap++)
+ {
+ *ap /= scale;
+ s += *ap**ap;
+ }
+ f = *ap0;
+ g = -SIGN(sqrt(s),f);
+ h = f*g-s;
+ *ap0 = f-g;
+ ap10 = a+l*m+i;
+ for (j=nml;j--; ap10+=m)
+ {
+ for (s=0.0,ap=ap0,ap1=ap10,k=mmi; k--;)
+ s += *(ap1++)**(ap++);
+ f = s/h;
+ for (ap=ap0,ap1=ap10,k=mmi; k--;)
+ *(ap1++) += f**(ap++);
+ }
+ for (ap=ap0,k=mmi; k--;)
+ *(ap++) *= scale;
+ }
+ }
+ wmat[i] = scale*g;
+ g = s = scale = 0.0;
+ if (i < m && i+1 != n)
+ {
+ ap = ap0 = a+i+m*l;
+ for (k=nml;k--; ap+=m)
+ scale += fabs(*ap);
+ if (scale)
+ {
+ for (ap=ap0,k=nml;k--; ap+=m)
+ {
+ *ap /= scale;
+ s += *ap**ap;
+ }
+ f=*ap0;
+ g = -SIGN(sqrt(s),f);
+ h=f*g-s;
+ *ap0=f-g;
+ rv1p = rv1+l;
+ for (ap=ap0,k=nml;k--; ap+=m)
+ *(rv1p++) = *ap/h;
+ ap10 = a+l+m*l;
+ for (j=m-l; j--; ap10++)
+ {
+ for (s=0.0,ap=ap0,ap1=ap10,k=nml; k--; ap+=m,ap1+=m)
+ s += *ap1**ap;
+ rv1p = rv1+l;
+ for (ap1=ap10,k=nml;k--; ap1+=m)
+ *ap1 += s**(rv1p++);
+ }
+ for (ap=ap0,k=nml;k--; ap+=m)
+ *ap *= scale;
+ }
+ }
+ anorm=MAX(anorm,(fabs(wmat[i])+fabs(rv1[i])));
+ }
+
+ for (i=n-1;i>=0;i--)
+ {
+ if (i < n-1)
+ {
+ if (g)
+ {
+ ap0 = a+l*m+i;
+ vp0 = vmat+i*n+l;
+ vp10 = vmat+l*n+l;
+ g *= *ap0;
+ for (ap=ap0,vp=vp0,j=nml; j--; ap+=m)
+ *(vp++) = *ap/g;
+ for (j=nml; j--; vp10+=n)
+ {
+ for (s=0.0,ap=ap0,vp1=vp10,k=nml; k--; ap+=m)
+ s += *ap**(vp1++);
+ for (vp=vp0,vp1=vp10,k=nml; k--;)
+ *(vp1++) += s**(vp++);
+ }
+ }
+ vp = vmat+l*n+i;
+ vp1 = vmat+i*n+l;
+ for (j=nml; j--; vp+=n)
+ *vp = *(vp1++) = 0.0;
+ }
+ vmat[i*n+i]=1.0;
+ g=rv1[i];
+ l=i;
+ nml = n-l;
+ }
+
+ for (i=(m<n?m:n); --i>=0;)
+ {
+ l=i+1;
+ nml = n-l;
+ mmi=m-i;
+ g=wmat[i];
+ ap0 = a+i*m+i;
+ ap10 = ap0 + m;
+ for (ap=ap10,j=nml;j--;ap+=m)
+ *ap=0.0;
+ if (g)
+ {
+ g=1.0/g;
+ for (j=nml;j--; ap10+=m)
+ {
+ for (s=0.0,ap=ap0,ap1=ap10,k=mmi; --k;)
+ s += *(++ap)**(++ap1);
+ f = (s/(*ap0))*g;
+ for (ap=ap0,ap1=ap10,k=mmi;k--;)
+ *(ap1++) += f**(ap++);
+ }
+ for (ap=ap0,j=mmi;j--;)
+ *(ap++) *= g;
+ }
+ else
+ for (ap=ap0,j=mmi;j--;)
+ *(ap++)=0.0;
+ ++(*ap0);
+ }
+
+ for (k=n; --k>=0;)
+ {
+ for (its=0;its<100;its++)
+ {
+ flag=1;
+ for (l=k;l>=0;l--)
+ {
+ nm=l-1;
+ if (fabs(rv1[l])+anorm == anorm)
+ {
+ flag=0;
+ break;
+ }
+ if (fabs(wmat[nm])+anorm == anorm)
+ break;
+ }
+ if (flag)
+ {
+ c=0.0;
+ s=1.0;
+ ap0 = a+nm*m;
+ ap10 = a+l*m;
+ for (i=l; i<=k; i++,ap10+=m)
+ {
+ f=s*rv1[i];
+ if (fabs(f)+anorm == anorm)
+ break;
+ g=wmat[i];
+ h=PYTHAG(f,g);
+ wmat[i]=h;
+ h=1.0/h;
+ c=g*h;
+ s=(-f*h);
+ for (ap=ap0,ap1=ap10,j=m; j--;)
+ {
+ z = *ap1;
+ y = *ap;
+ *(ap++) = y*c+z*s;
+ *(ap1++) = z*c-y*s;
+ }
+ }
+ }
+ z=wmat[k];
+ if (l == k)
+ {
+ if (z < 0.0)
+ {
+ wmat[k] = -z;
+ vp = vmat+k*n;
+ for (j=n; j--; vp++)
+ *vp = (-*vp);
+ }
+ break;
+ }
+ if (its == 99)
+ qerror("*Error*: No convergence in 100 SVD iterations ",
+ "in svdfit()");
+ x=wmat[l];
+ nm=k-1;
+ y=wmat[nm];
+ g=rv1[nm];
+ h=rv1[k];
+ f=((y-z)*(y+z)+(g-h)*(g+h))/(2.0*h*y);
+ g=PYTHAG(f,1.0);
+ f=((x-z)*(x+z)+h*((y/(f+SIGN(g,f)))-h))/x;
+ c=s=1.0;
+ ap10 = a+l*m;
+ vp10 = vmat+l*n;
+ for (j=l;j<=nm;j++,ap10+=m,vp10+=n)
+ {
+ i=j+1;
+ g=rv1[i];
+ y=wmat[i];
+ h=s*g;
+ g=c*g;
+ z=PYTHAG(f,h);
+ rv1[j]=z;
+ c=f/z;
+ s=h/z;
+ f=x*c+g*s;
+ g=g*c-x*s;
+ h=y*s;
+ y=y*c;
+ for (vp=(vp1=vp10)+n,jj=n; jj--;)
+ {
+ z = *vp;
+ x = *vp1;
+ *(vp1++) = x*c+z*s;
+ *(vp++) = z*c-x*s;
+ }
+ z=PYTHAG(f,h);
+ wmat[j]=z;
+ if (z)
+ {
+ z=1.0/z;
+ c=f*z;
+ s=h*z;
+ }
+ f=c*g+s*y;
+ x=c*y-s*g;
+ for (ap=(ap1=ap10)+m,jj=m; jj--;)
+ {
+ z = *ap;
+ y = *ap1;
+ *(ap1++) = y*c+z*s;
+ *(ap++) = z*c-y*s;
+ }
+ }
+ rv1[l]=0.0;
+ rv1[k]=f;
+ wmat[k]=x;
+ }
+ }
+
+ wmax=0.0;
+ w = wmat;
+ for (j=n;j--; w++)
+ if (*w > wmax)
+ wmax=*w;
+ thresh=TOL*wmax;
+ w = wmat;
+ for (j=n;j--; w++)
+ if (*w < thresh)
+ *w = 0.0;
+
+ w = wmat;
+ ap = a;
+ tmpp = tmp;
+ for (j=n; j--; w++)
+ {
+ s=0.0;
+ if (*w)
+ {
+ bp = b;
+ for (i=m; i--;)
+ s += *(ap++)**(bp++);
+ s /= *w;
+ }
+ else
+ ap += m;
+ *(tmpp++) = s;
+ }
+
+ vp0 = vmat;
+ for (j=0; j<n; j++,vp0++)
+ {
+ s=0.0;
+ tmpp = tmp;
+ for (vp=vp0,jj=n; jj--; vp+=n)
+ s += *vp**(tmpp++);
+ sol[j]=s;
+ }
+/* Free temporary arrays */
+ free(tmp);
+ free(rv1);
+
+ return;
+ }
+
+#undef SIGN
+#undef MAX
+#undef PYTHAG
+#undef TOL
+
+/****** poly_powers ***********************************************************
+PROTO int *poly_powers(polystruct *poly)
+PURPOSE Return an array of powers of polynom terms
+INPUT polystruct pointer,
+OUTPUT Pointer to an array of polynom powers (int *), (ncoeff*ndim numbers).
+NOTES The returned pointer is mallocated.
+AUTHOR E. Bertin (IAP)
+VERSION 23/10/2003
+ ***/
+int *poly_powers(polystruct *poly)
+ {
+ int expo[POLY_MAXDIM+1], gexpo[POLY_MAXDIM+1];
+ int *expot, *degree,*degreet, *group,*groupt, *gexpot,
+ *powers, *powerst,
+ d,g,t, ndim;
+
+/* Prepare the vectors and counters */
+ ndim = poly->ndim;
+ group = poly->group;
+ degree = poly->degree;
+ QMALLOC(powers, int, ndim*poly->ncoeff);
+ if (ndim)
+ {
+ for (expot=expo, d=ndim; --d;)
+ *(++expot) = 0;
+ for (gexpot=gexpo, degreet=degree, g=poly->ngroup; g--;)
+ *(gexpot++) = *(degreet++);
+ if (gexpo[*group])
+ gexpo[*group]--;
+ }
+
+/* The constant term is handled separately */
+ powerst = powers;
+ for (d=0; d<ndim; d++)
+ *(powerst++) = 0;
+ *expo = 1;
+
+/* Compute the rest of the polynom */
+ for (t=poly->ncoeff; --t; )
+ {
+ for (d=0; d<ndim; d++)
+ *(powerst++) = expo[d];
+/*-- A complex recursion between terms of the polynom speeds up computations */
+ groupt = group;
+ expot = expo;
+ for (d=0; d<ndim; d++, groupt++)
+ if (gexpo[*groupt]--)
+ {
+ ++*(expot++);
+ break;
+ }
+ else
+ {
+ gexpo[*groupt] = *expot;
+ *(expot++) = 0;
+ }
+ }
+
+ return powers;
+ }
+
diff --git a/funtools/wcs/proj.c b/funtools/wcs/proj.c
new file mode 100644
index 0000000..c0264b8
--- /dev/null
+++ b/funtools/wcs/proj.c
@@ -0,0 +1,4527 @@
+/*============================================================================
+*
+* WCSLIB - an implementation of the FITS WCS proposal.
+* Copyright (C) 1995-2002, Mark Calabretta
+*
+* This library 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 2 of the License, or (at your option) any later version.
+*
+* This library 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 this library; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*
+* Correspondence concerning WCSLIB may be directed to:
+* Internet email: mcalabre@atnf.csiro.au
+* Postal address: Dr. Mark Calabretta,
+* Australia Telescope National Facility,
+* P.O. Box 76,
+* Epping, NSW, 2121,
+* AUSTRALIA
+*
+*=============================================================================
+*
+* C implementation of the spherical map projections recognized by the FITS
+* "World Coordinate System" (WCS) convention.
+*
+* Summary of routines
+* -------------------
+* Each projection is implemented via separate functions for the forward,
+* *fwd(), and reverse, *rev(), transformation.
+*
+* Initialization routines, *set(), compute intermediate values from the
+* projection parameters but need not be called explicitly - see the
+* explanation of prj.flag below.
+*
+* prjset prjfwd prjrev Driver routines (see below).
+*
+* azpset azpfwd azprev AZP: zenithal/azimuthal perspective
+* szpset szpfwd szprev SZP: slant zenithal perspective
+* tanset tanfwd tanrev TAN: gnomonic
+* stgset stgfwd stgrev STG: stereographic
+* sinset sinfwd sinrev SIN: orthographic/synthesis
+* arcset arcfwd arcrev ARC: zenithal/azimuthal equidistant
+* zpnset zpnfwd zpnrev ZPN: zenithal/azimuthal polynomial
+* zeaset zeafwd zearev ZEA: zenithal/azimuthal equal area
+* airset airfwd airrev AIR: Airy
+* cypset cypfwd cyprev CYP: cylindrical perspective
+* ceaset ceafwd cearev CEA: cylindrical equal area
+* carset carfwd carrev CAR: Cartesian
+* merset merfwd merrev MER: Mercator
+* sflset sflfwd sflrev SFL: Sanson-Flamsteed
+* parset parfwd parrev PAR: parabolic
+* molset molfwd molrev MOL: Mollweide
+* aitset aitfwd aitrev AIT: Hammer-Aitoff
+* copset copfwd coprev COP: conic perspective
+* coeset coefwd coerev COE: conic equal area
+* codset codfwd codrev COD: conic equidistant
+* cooset coofwd coorev COO: conic orthomorphic
+* bonset bonfwd bonrev BON: Bonne
+* pcoset pcofwd pcorev PCO: polyconic
+* tscset tscfwd tscrev TSC: tangential spherical cube
+* cscset cscfwd cscrev CSC: COBE quadrilateralized spherical cube
+* qscset qscfwd qscrev QSC: quadrilateralized spherical cube
+*
+*
+* Driver routines; prjset(), prjfwd() & prjrev()
+* ----------------------------------------------
+* A set of driver routines are available for use as a generic interface to
+* the specific projection routines. The interfaces to prjfwd() and prjrev()
+* are the same as those of the forward and reverse transformation routines
+* for the specific projections (see below).
+*
+* The interface to prjset() differs slightly from that of the initialization
+* routines for the specific projections and unlike them it must be invoked
+* explicitly to use prjfwd() and prjrev().
+*
+* Given:
+* pcode[4] const char
+* WCS projection code.
+*
+* Given and/or returned:
+* prj prjprm* Projection parameters (see below).
+*
+* Function return value:
+* int Error status
+* 0: Success.
+*
+*
+* Initialization routine; *set()
+* ------------------------------
+* Initializes members of a prjprm data structure which hold intermediate
+* values. Note that this routine need not be called directly; it will be
+* invoked by prjfwd() and prjrev() if the "flag" structure member is
+* anything other than a predefined magic value.
+*
+* Given and/or returned:
+* prj prjprm* Projection parameters (see below).
+*
+* Function return value:
+* int Error status
+* 0: Success.
+* 1: Invalid projection parameters.
+*
+* Forward transformation; *fwd()
+* -----------------------------
+* Compute (x,y) coordinates in the plane of projection from native spherical
+* coordinates (phi,theta).
+*
+* Given:
+* phi, const double
+* theta Longitude and latitude of the projected point in
+* native spherical coordinates, in degrees.
+*
+* Given and returned:
+* prj prjprm* Projection parameters (see below).
+*
+* Returned:
+* x,y double* Projected coordinates.
+*
+* Function return value:
+* int Error status
+* 0: Success.
+* 1: Invalid projection parameters.
+* 2: Invalid value of (phi,theta).
+*
+* Reverse transformation; *rev()
+* -----------------------------
+* Compute native spherical coordinates (phi,theta) from (x,y) coordinates in
+* the plane of projection.
+*
+* Given:
+* x,y const double
+* Projected coordinates.
+*
+* Given and returned:
+* prj prjprm* Projection parameters (see below).
+*
+* Returned:
+* phi, double* Longitude and latitude of the projected point in
+* theta native spherical coordinates, in degrees.
+*
+* Function return value:
+* int Error status
+* 0: Success.
+* 1: Invalid projection parameters.
+* 2: Invalid value of (x,y).
+* 1: Invalid projection parameters.
+*
+* Projection parameters
+* ---------------------
+* The prjprm struct consists of the following:
+*
+* int flag
+* This flag must be set to zero whenever any of p[10] or r0 are set
+* or changed. This signals the initialization routine to recompute
+* intermediaries. flag may also be set to -1 to disable strict bounds
+* checking for the AZP, SZP, TAN, SIN, ZPN, and COP projections.
+*
+* double r0
+* r0; The radius of the generating sphere for the projection, a linear
+* scaling parameter. If this is zero, it will be reset to the default
+* value of 180/pi (the value for FITS WCS).
+*
+* double p[10]
+* The first 10 elements contain projection parameters which correspond
+* to the PROJPn keywords in FITS, so p[0] is PROJP0, and p[9] is
+* PROJP9. Many projections use p[1] (PROJP1) and some also use p[2]
+* (PROJP2). ZPN is the only projection which uses any of the others.
+*
+* The remaining members of the prjprm struct are maintained by the
+* initialization routines and should not be modified. This is done for the
+* sake of efficiency and to allow an arbitrary number of contexts to be
+* maintained simultaneously.
+*
+* char code[4]
+* Three-letter projection code.
+*
+* double phi0, theta0
+* Native longitude and latitude of the reference point, in degrees.
+*
+* double w[10]
+* int n
+* Intermediate values derived from the projection parameters.
+*
+* int (*prjfwd)()
+* int (*prjrev)()
+* Pointers to the forward and reverse projection routines.
+*
+* Usage of the p[] array as it applies to each projection is described in
+* the prologue to each trio of projection routines.
+*
+* Argument checking
+* -----------------
+* Forward routines:
+*
+* The values of phi and theta (the native longitude and latitude)
+* normally lie in the range [-180,180] for phi, and [-90,90] for theta.
+* However, all forward projections will accept any value of phi and will
+* not normalize it.
+*
+* The forward projection routines do not explicitly check that theta lies
+* within the range [-90,90]. They do check for any value of theta which
+* produces an invalid argument to the projection equations (e.g. leading
+* to division by zero). The forward routines for AZP, SZP, TAN, SIN,
+* ZPN, and COP also return error 2 if (phi,theta) corresponds to the
+* overlapped (far) side of the projection but also return the
+* corresponding value of (x,y). This strict bounds checking may be
+* relaxed by setting prj->flag to -1 (rather than 0) when these
+* projections are initialized.
+*
+* Reverse routines:
+*
+* Error checking on the projected coordinates (x,y) is limited to that
+* required to ascertain whether a solution exists. Where a solution does
+* exist no check is made that the value of phi and theta obtained lie
+* within the ranges [-180,180] for phi, and [-90,90] for theta.
+*
+* Accuracy
+* --------
+* Closure to a precision of at least 1E-10 degree of longitude and latitude
+* has been verified for typical projection parameters on the 1 degree grid
+* of native longitude and latitude (to within 5 degrees of any latitude
+* where the projection may diverge).
+*
+* Author: Mark Calabretta, Australia Telescope National Facility
+* $Id: proj.c,v 2.20 2002/04/03 01:25:29 mcalabre Exp $
+*===========================================================================*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include "wcslib.h"
+
+int npcode = 26;
+char pcodes[26][4] =
+ {"AZP", "SZP", "TAN", "STG", "SIN", "ARC", "ZPN", "ZEA", "AIR", "CYP",
+ "CEA", "CAR", "MER", "COP", "COE", "COD", "COO", "SFL", "PAR", "MOL",
+ "AIT", "BON", "PCO", "TSC", "CSC", "QSC"};
+
+const int AZP = 101;
+const int SZP = 102;
+const int TAN = 103;
+const int STG = 104;
+const int SIN = 105;
+const int ARC = 106;
+const int ZPN = 107;
+const int ZEA = 108;
+const int AIR = 109;
+const int CYP = 201;
+const int CEA = 202;
+const int CAR = 203;
+const int MER = 204;
+const int SFL = 301;
+const int PAR = 302;
+const int MOL = 303;
+const int AIT = 401;
+const int COP = 501;
+const int COE = 502;
+const int COD = 503;
+const int COO = 504;
+const int BON = 601;
+const int PCO = 602;
+const int TSC = 701;
+const int CSC = 702;
+const int QSC = 703;
+
+/* Map error number to error message for each function. */
+const char *prjset_errmsg[] = {
+ 0,
+ "Invalid projection parameters"};
+
+const char *prjfwd_errmsg[] = {
+ 0,
+ "Invalid projection parameters",
+ "Invalid value of (phi,theta)"};
+
+const char *prjrev_errmsg[] = {
+ 0,
+ "Invalid projection parameters",
+ "Invalid value of (x,y)"};
+
+#define copysgn(X, Y) ((Y) < 0.0 ? -fabs(X) : fabs(X))
+#define copysgni(X, Y) ((Y) < 0 ? -abs(X) : abs(X))
+
+/*==========================================================================*/
+
+int prjset(pcode, prj)
+
+const char pcode[4];
+struct prjprm *prj;
+
+{
+ /* Set pointers to the forward and reverse projection routines. */
+ if (strcmp(pcode, "AZP") == 0) {
+ azpset(prj);
+ } else if (strcmp(pcode, "SZP") == 0) {
+ szpset(prj);
+ } else if (strcmp(pcode, "TAN") == 0) {
+ tanset(prj);
+ } else if (strcmp(pcode, "STG") == 0) {
+ stgset(prj);
+ } else if (strcmp(pcode, "SIN") == 0) {
+ sinset(prj);
+ } else if (strcmp(pcode, "ARC") == 0) {
+ arcset(prj);
+ } else if (strcmp(pcode, "ZPN") == 0) {
+ zpnset(prj);
+ } else if (strcmp(pcode, "ZEA") == 0) {
+ zeaset(prj);
+ } else if (strcmp(pcode, "AIR") == 0) {
+ airset(prj);
+ } else if (strcmp(pcode, "CYP") == 0) {
+ cypset(prj);
+ } else if (strcmp(pcode, "CEA") == 0) {
+ ceaset(prj);
+ } else if (strcmp(pcode, "CAR") == 0) {
+ carset(prj);
+ } else if (strcmp(pcode, "MER") == 0) {
+ merset(prj);
+ } else if (strcmp(pcode, "SFL") == 0) {
+ sflset(prj);
+ } else if (strcmp(pcode, "PAR") == 0) {
+ parset(prj);
+ } else if (strcmp(pcode, "MOL") == 0) {
+ molset(prj);
+ } else if (strcmp(pcode, "AIT") == 0) {
+ aitset(prj);
+ } else if (strcmp(pcode, "COP") == 0) {
+ copset(prj);
+ } else if (strcmp(pcode, "COE") == 0) {
+ coeset(prj);
+ } else if (strcmp(pcode, "COD") == 0) {
+ codset(prj);
+ } else if (strcmp(pcode, "COO") == 0) {
+ cooset(prj);
+ } else if (strcmp(pcode, "BON") == 0) {
+ bonset(prj);
+ } else if (strcmp(pcode, "PCO") == 0) {
+ pcoset(prj);
+ } else if (strcmp(pcode, "TSC") == 0) {
+ tscset(prj);
+ } else if (strcmp(pcode, "CSC") == 0) {
+ cscset(prj);
+ } else if (strcmp(pcode, "QSC") == 0) {
+ qscset(prj);
+ } else {
+ /* Unrecognized projection code. */
+ return 1;
+ }
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int prjfwd(phi, theta, prj, x, y)
+
+const double phi, theta;
+struct prjprm *prj;
+double *x, *y;
+
+{
+ return prj->prjfwd(phi, theta, prj, x, y);
+}
+
+/*--------------------------------------------------------------------------*/
+
+int prjrev(x, y, prj, phi, theta)
+
+const double x, y;
+struct prjprm *prj;
+double *phi, *theta;
+
+{
+ return prj->prjrev(x, y, prj, phi, theta);
+}
+
+/*============================================================================
+* AZP: zenithal/azimuthal perspective projection.
+*
+* Given:
+* prj->p[1] Distance parameter, mu in units of r0.
+* prj->p[2] Tilt angle, gamma in degrees.
+*
+* Given and/or returned:
+* prj->flag AZP, or -AZP if prj->flag is given < 0.
+* prj->r0 r0; reset to 180/pi if 0.
+*
+* Returned:
+* prj->code "AZP"
+* prj->phi0 0.0
+* prj->theta0 90.0
+* prj->w[0] r0*(mu+1)
+* prj->w[1] tan(gamma)
+* prj->w[2] sec(gamma)
+* prj->w[3] cos(gamma)
+* prj->w[4] sin(gamma)
+* prj->w[5] asin(-1/mu) for |mu| >= 1, -90 otherwise
+* prj->w[6] mu*cos(gamma)
+* prj->w[7] 1 if |mu*cos(gamma)| < 1, 0 otherwise
+* prj->prjfwd Pointer to azpfwd().
+* prj->prjrev Pointer to azprev().
+*===========================================================================*/
+
+int azpset(prj)
+
+struct prjprm *prj;
+
+{
+ strcpy(prj->code, "AZP");
+ prj->flag = copysgni (AZP, prj->flag);
+ prj->phi0 = 0.0;
+ prj->theta0 = 90.0;
+
+ if (prj->r0 == 0.0) prj->r0 = R2D;
+
+ prj->w[0] = prj->r0*(prj->p[1] + 1.0);
+ if (prj->w[0] == 0.0) {
+ return 1;
+ }
+
+ prj->w[3] = cosdeg (prj->p[2]);
+ if (prj->w[3] == 0.0) {
+ return 1;
+ }
+
+ prj->w[2] = 1.0/prj->w[3];
+ prj->w[4] = sindeg (prj->p[2]);
+ prj->w[1] = prj->w[4] / prj->w[3];
+
+ if (fabs(prj->p[1]) > 1.0) {
+ prj->w[5] = asindeg (-1.0/prj->p[1]);
+ } else {
+ prj->w[5] = -90.0;
+ }
+
+ prj->w[6] = prj->p[1] * prj->w[3];
+ prj->w[7] = (fabs(prj->w[6]) < 1.0) ? 1.0 : 0.0;
+
+ prj->prjfwd = azpfwd;
+ prj->prjrev = azprev;
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int azpfwd(phi, theta, prj, x, y)
+
+const double phi, theta;
+struct prjprm *prj;
+double *x, *y;
+
+{
+ double a, b, cphi, cthe, r, s, t;
+
+ if (abs(prj->flag) != AZP) {
+ if (azpset(prj)) return 1;
+ }
+
+ cphi = cosdeg (phi);
+ cthe = cosdeg (theta);
+
+ s = prj->w[1]*cphi;
+ t = (prj->p[1] + sindeg (theta)) + cthe*s;
+ if (t == 0.0) {
+ return 2;
+ }
+
+ r = prj->w[0]*cthe/t;
+ *x = r*sindeg (phi);
+ *y = -r*cphi*prj->w[2];
+
+ /* Bounds checking. */
+ if (prj->flag > 0) {
+ /* Overlap. */
+ if (theta < prj->w[5]) {
+ return 2;
+ }
+
+ /* Divergence. */
+ if (prj->w[7] > 0.0) {
+ t = prj->p[1] / sqrt(1.0 + s*s);
+
+ if (fabs(t) <= 1.0) {
+ s = atandeg (-s);
+ t = asindeg (t);
+ a = s - t;
+ b = s + t + 180.0;
+
+ if (a > 90.0) a -= 360.0;
+ if (b > 90.0) b -= 360.0;
+
+ if (theta < ((a > b) ? a : b)) {
+ return 2;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int azprev(x, y, prj, phi, theta)
+
+const double x, y;
+struct prjprm *prj;
+double *phi, *theta;
+
+{
+ double a, b, r, s, t, ycosg;
+ const double tol = 1.0e-13;
+
+ if (abs(prj->flag) != AZP) {
+ if (azpset(prj)) return 1;
+ }
+
+ ycosg = y*prj->w[3];
+
+ r = sqrt(x*x + ycosg*ycosg);
+ if (r == 0.0) {
+ *phi = 0.0;
+ *theta = 90.0;
+ } else {
+ *phi = atan2deg (x, -ycosg);
+
+ s = r / (prj->w[0] + y*prj->w[4]);
+ t = s*prj->p[1]/sqrt(s*s + 1.0);
+
+ s = atan2deg (1.0, s);
+
+ if (fabs(t) > 1.0) {
+ t = copysgn (90.0,t);
+ if (fabs(t) > 1.0+tol) {
+ return 2;
+ }
+ } else {
+ t = asindeg (t);
+ }
+
+ a = s - t;
+ b = s + t + 180.0;
+
+ if (a > 90.0) a -= 360.0;
+ if (b > 90.0) b -= 360.0;
+
+ *theta = (a > b) ? a : b;
+ }
+
+ return 0;
+}
+
+/*============================================================================
+* SZP: slant zenithal perspective projection.
+*
+* Given:
+* prj->p[1] Distance of the point of projection from the centre of the
+* generating sphere, mu in units of r0.
+* prj->p[2] Native longitude, phi_c, and ...
+* prj->p[3] Native latitude, theta_c, on the planewards side of the
+* intersection of the line through the point of projection
+* and the centre of the generating sphere, phi_c in degrees.
+*
+* Given and/or returned:
+* prj->flag SZP, or -SZP if prj->flag is given < 0.
+* prj->r0 r0; reset to 180/pi if 0.
+*
+* Returned:
+* prj->code "SZP"
+* prj->phi0 0.0
+* prj->theta0 90.0
+* prj->w[0] 1/r0
+* prj->w[1] xp = -mu*cos(theta_c)*sin(phi_c)
+* prj->w[2] yp = mu*cos(theta_c)*cos(phi_c)
+* prj->w[3] zp = mu*sin(theta_c) + 1
+* prj->w[4] r0*xp
+* prj->w[5] r0*yp
+* prj->w[6] r0*zp
+* prj->w[7] (zp - 1)^2
+* prj->w[8] asin(1-zp) if |1 - zp| < 1, -90 otherwise
+* prj->prjfwd Pointer to szpfwd().
+* prj->prjrev Pointer to szprev().
+*===========================================================================*/
+
+int szpset(prj)
+
+struct prjprm *prj;
+
+{
+ strcpy(prj->code, "SZP");
+ prj->flag = copysgni (SZP, prj->flag);
+ prj->phi0 = 0.0;
+ prj->theta0 = 90.0;
+
+ if (prj->r0 == 0.0) prj->r0 = R2D;
+
+ prj->w[0] = 1.0/prj->r0;
+
+ prj->w[3] = prj->p[1] * sindeg (prj->p[3]) + 1.0;
+ if (prj->w[3] == 0.0) {
+ return 1;
+ }
+
+ prj->w[1] = -prj->p[1] * cosdeg (prj->p[3]) * sindeg (prj->p[2]);
+ prj->w[2] = prj->p[1] * cosdeg (prj->p[3]) * cosdeg (prj->p[2]);
+ prj->w[4] = prj->r0 * prj->w[1];
+ prj->w[5] = prj->r0 * prj->w[2];
+ prj->w[6] = prj->r0 * prj->w[3];
+ prj->w[7] = (prj->w[3] - 1.0) * prj->w[3] - 1.0;
+
+ if (fabs(prj->w[3] - 1.0) < 1.0) {
+ prj->w[8] = asindeg (1.0 - prj->w[3]);
+ } else {
+ prj->w[8] = -90.0;
+ }
+
+ prj->prjfwd = szpfwd;
+ prj->prjrev = szprev;
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int szpfwd(phi, theta, prj, x, y)
+
+const double phi, theta;
+struct prjprm *prj;
+double *x, *y;
+
+{
+ double a, b, cphi, cthe, s, sphi, t;
+
+ if (abs(prj->flag) != SZP) {
+ if (szpset(prj)) return 1;
+ }
+
+ cphi = cosdeg (phi);
+ sphi = sindeg (phi);
+ cthe = cosdeg (theta);
+ s = 1.0 - sindeg (theta);
+
+ t = prj->w[3] - s;
+ if (t == 0.0) {
+ return 2;
+ }
+
+ *x = (prj->w[6]*cthe*sphi - prj->w[4]*s)/t;
+ *y = -(prj->w[6]*cthe*cphi + prj->w[5]*s)/t;
+
+ /* Bounds checking. */
+ if (prj->flag > 0) {
+ /* Divergence. */
+ if (theta < prj->w[8]) {
+ return 2;
+ }
+
+ /* Overlap. */
+ if (fabs(prj->p[1]) > 1.0) {
+ s = prj->w[1]*sphi - prj->w[2]*cphi;
+ t = 1.0/sqrt(prj->w[7] + s*s);
+
+ if (fabs(t) <= 1.0) {
+ s = atan2deg (s, prj->w[3] - 1.0);
+ t = asindeg (t);
+ a = s - t;
+ b = s + t + 180.0;
+
+ if (a > 90.0) a -= 360.0;
+ if (b > 90.0) b -= 360.0;
+
+ if (theta < ((a > b) ? a : b)) {
+ return 2;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int szprev(x, y, prj, phi, theta)
+
+const double x, y;
+struct prjprm *prj;
+double *phi, *theta;
+
+{
+ double a, b, c, d, r2, sth1, sth2, sthe, sxy, t, x1, xp, y1, yp, z;
+ const double tol = 1.0e-13;
+
+ if (abs(prj->flag) != SZP) {
+ if (szpset(prj)) return 1;
+ }
+
+ xp = x*prj->w[0];
+ yp = y*prj->w[0];
+ r2 = xp*xp + yp*yp;
+
+ x1 = (xp - prj->w[1])/prj->w[3];
+ y1 = (yp - prj->w[2])/prj->w[3];
+ sxy = xp*x1 + yp*y1;
+
+ if (r2 < 1.0e-10) {
+ /* Use small angle formula. */
+ z = r2/2.0;
+ *theta = 90.0 - R2D*sqrt(r2/(1.0 + sxy));
+
+ } else {
+ t = x1*x1 + y1*y1;
+ a = t + 1.0;
+ b = sxy - t;
+ c = r2 - sxy - sxy + t - 1.0;
+ d = b*b - a*c;
+
+ /* Check for a solution. */
+ if (d < 0.0) {
+ return 2;
+ }
+ d = sqrt(d);
+
+ /* Choose solution closest to pole. */
+ sth1 = (-b + d)/a;
+ sth2 = (-b - d)/a;
+ sthe = (sth1 > sth2) ? sth1 : sth2;
+ if (sthe > 1.0) {
+ if (sthe-1.0 < tol) {
+ sthe = 1.0;
+ } else {
+ sthe = (sth1 < sth2) ? sth1 : sth2;
+ }
+ }
+
+ if (sthe < -1.0) {
+ if (sthe+1.0 > -tol) {
+ sthe = -1.0;
+ }
+ }
+
+ if (sthe > 1.0 || sthe < -1.0) {
+ return 2;
+ }
+
+ *theta = asindeg (sthe);
+
+ z = 1.0 - sthe;
+ }
+
+ *phi = atan2deg (xp - x1*z, -(yp - y1*z));
+
+ return 0;
+}
+
+/*============================================================================
+* TAN: gnomonic projection.
+*
+* Given and/or returned:
+* prj->flag TAN, or -TAN if prj->flag is given < 0.
+* prj->r0 r0; reset to 180/pi if 0.
+*
+* Returned:
+* prj->code "TAN"
+* prj->phi0 0.0
+* prj->theta0 90.0
+* prj->prjfwd Pointer to tanfwd().
+* prj->prjrev Pointer to tanrev().
+*===========================================================================*/
+
+int tanset(prj)
+
+struct prjprm *prj;
+
+{
+ int k;
+
+ strcpy(prj->code, "TAN");
+ prj->flag = copysgni (TAN, prj->flag);
+ prj->phi0 = 0.0;
+ prj->theta0 = 90.0;
+
+ if (prj->r0 == 0.0) prj->r0 = R2D;
+
+ prj->prjfwd = tanfwd;
+ prj->prjrev = tanrev;
+
+ for (k = (MAXPV-1); k >= 0 && prj->ppv[k] == 0.0 && prj->ppv[k+MAXPV] == 0.0; k--);
+ if (k < 0)
+ k = 0;
+ prj->npv = k;
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int tanfwd(phi, theta, prj, x, y)
+
+const double phi, theta;
+struct prjprm *prj;
+double *x, *y;
+
+{
+ double r, s;
+ double xp[2];
+
+ if (abs(prj->flag) != TAN) {
+ if(tanset(prj)) return 1;
+ }
+
+ s = sindeg (theta);
+ if (s <= 0.0) {
+ return 2;
+ }
+
+ r = prj->r0*cosdeg (theta)/s;
+ xp[0] = r*sindeg (phi);
+ xp[1] = -r*cosdeg (phi);
+ *x = prj->inv_x? poly_func(prj->inv_x, xp) : xp[0];
+ *y = prj->inv_y? poly_func(prj->inv_y, xp) : xp[1];
+
+ if (prj->flag > 0 && s < 0.0) {
+ return 2;
+ }
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int tanrev(x, y, prj, phi, theta)
+
+const double x, y;
+struct prjprm *prj;
+double *phi, *theta;
+
+{
+ double r;
+ double xp;
+ double yp;
+
+ if (abs(prj->flag) != TAN) {
+ if (tanset(prj)) return 1;
+ }
+
+ if (prj->npv) {
+ raw_to_pv(prj, x,y, &xp, &yp);
+ } else {
+ xp = x;
+ yp = y;
+ }
+
+ r = sqrt(xp*xp + yp*yp);
+ if (r == 0.0) {
+ *phi = 0.0;
+ } else {
+ *phi = atan2deg (xp, -yp);
+ }
+
+ *theta = atan2deg (prj->r0, r);
+
+ return 0;
+}
+
+/*============================================================================
+* STG: stereographic projection.
+*
+* Given and/or returned:
+* prj->r0 r0; reset to 180/pi if 0.
+*
+* Returned:
+* prj->code "STG"
+* prj->flag STG
+* prj->phi0 0.0
+* prj->theta0 90.0
+* prj->w[0] 2*r0
+* prj->w[1] 1/(2*r0)
+* prj->prjfwd Pointer to stgfwd().
+* prj->prjrev Pointer to stgrev().
+*===========================================================================*/
+
+int stgset(prj)
+
+struct prjprm *prj;
+
+{
+ strcpy(prj->code, "STG");
+ prj->flag = STG;
+ prj->phi0 = 0.0;
+ prj->theta0 = 90.0;
+
+ if (prj->r0 == 0.0) {
+ prj->r0 = R2D;
+ prj->w[0] = 360.0/PI;
+ prj->w[1] = PI/360.0;
+ } else {
+ prj->w[0] = 2.0*prj->r0;
+ prj->w[1] = 1.0/prj->w[0];
+ }
+
+ prj->prjfwd = stgfwd;
+ prj->prjrev = stgrev;
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int stgfwd(phi, theta, prj, x, y)
+
+const double phi, theta;
+struct prjprm *prj;
+double *x, *y;
+
+{
+ double r, s;
+
+ if (prj->flag != STG) {
+ if (stgset(prj)) return 1;
+ }
+
+ s = 1.0 + sindeg (theta);
+ if (s == 0.0) {
+ return 2;
+ }
+
+ r = prj->w[0]*cosdeg (theta)/s;
+ *x = r*sindeg (phi);
+ *y = -r*cosdeg (phi);
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int stgrev(x, y, prj, phi, theta)
+
+const double x, y;
+struct prjprm *prj;
+double *phi, *theta;
+
+{
+ double r;
+
+ if (prj->flag != STG) {
+ if (stgset(prj)) return 1;
+ }
+
+ r = sqrt(x*x + y*y);
+ if (r == 0.0) {
+ *phi = 0.0;
+ } else {
+ *phi = atan2deg (x, -y);
+ }
+ *theta = 90.0 - 2.0*atandeg (r*prj->w[1]);
+
+ return 0;
+}
+
+/*============================================================================
+* SIN: orthographic/synthesis projection.
+*
+* Given:
+* prj->p[1:2] Obliqueness parameters, xi and eta.
+*
+* Given and/or returned:
+* prj->flag SIN, or -SIN if prj->flag is given < 0.
+* prj->r0 r0; reset to 180/pi if 0.
+*
+* Returned:
+* prj->code "SIN"
+* prj->phi0 0.0
+* prj->theta0 90.0
+* prj->w[0] 1/r0
+* prj->w[1] xi**2 + eta**2
+* prj->w[2] xi**2 + eta**2 + 1
+* prj->w[3] xi**2 + eta**2 - 1
+* prj->prjfwd Pointer to sinfwd().
+* prj->prjrev Pointer to sinrev().
+*===========================================================================*/
+
+int sinset(prj)
+
+struct prjprm *prj;
+
+{
+ strcpy(prj->code, "SIN");
+ prj->flag = copysgni (SIN, prj->flag);
+ prj->phi0 = 0.0;
+ prj->theta0 = 90.0;
+
+ if (prj->r0 == 0.0) prj->r0 = R2D;
+
+ prj->w[0] = 1.0/prj->r0;
+ prj->w[1] = prj->p[1]*prj->p[1] + prj->p[2]*prj->p[2];
+ prj->w[2] = prj->w[1] + 1.0;
+ prj->w[3] = prj->w[1] - 1.0;
+
+ prj->prjfwd = sinfwd;
+ prj->prjrev = sinrev;
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int sinfwd(phi, theta, prj, x, y)
+
+const double phi, theta;
+struct prjprm *prj;
+double *x, *y;
+
+{
+ double cphi, cthe, sphi, t, z;
+
+ if (abs(prj->flag) != SIN) {
+ if (sinset(prj)) return 1;
+ }
+
+ t = (90.0 - fabs(theta))*D2R;
+ if (t < 1.0e-5) {
+ if (theta > 0.0) {
+ z = t*t/2.0;
+ } else {
+ z = 2.0 - t*t/2.0;
+ }
+ cthe = t;
+ } else {
+ z = 1.0 - sindeg (theta);
+ cthe = cosdeg (theta);
+ }
+
+ cphi = cosdeg (phi);
+ sphi = sindeg (phi);
+ *x = prj->r0*(cthe*sphi + prj->p[1]*z);
+ *y = -prj->r0*(cthe*cphi - prj->p[2]*z);
+
+ /* Validate this solution. */
+ if (prj->flag > 0) {
+ if (prj->w[1] == 0.0) {
+ /* Orthographic projection. */
+ if (theta < 0.0) {
+ return 2;
+ }
+ } else {
+ /* "Synthesis" projection. */
+ t = -atandeg (prj->p[1]*sphi - prj->p[2]*cphi);
+ if (theta < t) {
+ return 2;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int sinrev (x, y, prj, phi, theta)
+
+const double x, y;
+struct prjprm *prj;
+double *phi, *theta;
+
+{
+ const double tol = 1.0e-13;
+ double a, b, c, d, r2, sth1, sth2, sthe, sxy, x0, x1, xp, y0, y1, yp, z;
+
+ if (abs(prj->flag) != SIN) {
+ if (sinset(prj)) return 1;
+ }
+
+ /* Compute intermediaries. */
+ x0 = x*prj->w[0];
+ y0 = y*prj->w[0];
+ r2 = x0*x0 + y0*y0;
+
+ if (prj->w[1] == 0.0) {
+ /* Orthographic projection. */
+ if (r2 != 0.0) {
+ *phi = atan2deg (x0, -y0);
+ } else {
+ *phi = 0.0;
+ }
+
+ if (r2 < 0.5) {
+ *theta = acosdeg (sqrt(r2));
+ } else if (r2 <= 1.0) {
+ *theta = asindeg (sqrt(1.0 - r2));
+ } else {
+ return 2;
+ }
+
+ } else {
+ /* "Synthesis" projection. */
+ x1 = prj->p[1];
+ y1 = prj->p[2];
+ sxy = x0*x1 + y0*y1;
+
+ if (r2 < 1.0e-10) {
+ /* Use small angle formula. */
+ z = r2/2.0;
+ *theta = 90.0 - R2D*sqrt(r2/(1.0 + sxy));
+
+ } else {
+ a = prj->w[2];
+ b = sxy - prj->w[1];
+ c = r2 - sxy - sxy + prj->w[3];
+ d = b*b - a*c;
+
+ /* Check for a solution. */
+ if (d < 0.0) {
+ return 2;
+ }
+ d = sqrt(d);
+
+ /* Choose solution closest to pole. */
+ sth1 = (-b + d)/a;
+ sth2 = (-b - d)/a;
+ sthe = (sth1 > sth2) ? sth1 : sth2;
+ if (sthe > 1.0) {
+ if (sthe-1.0 < tol) {
+ sthe = 1.0;
+ } else {
+ sthe = (sth1 < sth2) ? sth1 : sth2;
+ }
+ }
+
+ if (sthe < -1.0) {
+ if (sthe+1.0 > -tol) {
+ sthe = -1.0;
+ }
+ }
+
+ if (sthe > 1.0 || sthe < -1.0) {
+ return 2;
+ }
+
+ *theta = asindeg (sthe);
+ z = 1.0 - sthe;
+ }
+
+ xp = -y0 + prj->p[2]*z;
+ yp = x0 - prj->p[1]*z;
+ if (xp == 0.0 && yp == 0.0) {
+ *phi = 0.0;
+ } else {
+ *phi = atan2deg (yp,xp);
+ }
+ }
+
+ return 0;
+}
+
+/*============================================================================
+* ARC: zenithal/azimuthal equidistant projection.
+*
+* Given and/or returned:
+* prj->r0 r0; reset to 180/pi if 0.
+*
+* Returned:
+* prj->code "ARC"
+* prj->flag ARC
+* prj->phi0 0.0
+* prj->theta0 90.0
+* prj->w[0] r0*(pi/180)
+* prj->w[1] (180/pi)/r0
+* prj->prjfwd Pointer to arcfwd().
+* prj->prjrev Pointer to arcrev().
+*===========================================================================*/
+
+int arcset(prj)
+
+struct prjprm *prj;
+
+{
+ strcpy(prj->code, "ARC");
+ prj->flag = ARC;
+ prj->phi0 = 0.0;
+ prj->theta0 = 90.0;
+
+ if (prj->r0 == 0.0) {
+ prj->r0 = R2D;
+ prj->w[0] = 1.0;
+ prj->w[1] = 1.0;
+ } else {
+ prj->w[0] = prj->r0*D2R;
+ prj->w[1] = 1.0/prj->w[0];
+ }
+
+ prj->prjfwd = arcfwd;
+ prj->prjrev = arcrev;
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int arcfwd(phi, theta, prj, x, y)
+
+const double phi, theta;
+struct prjprm *prj;
+double *x, *y;
+
+{
+ double r;
+
+ if (prj->flag != ARC) {
+ if (arcset(prj)) return 1;
+ }
+
+ r = prj->w[0]*(90.0 - theta);
+ *x = r*sindeg (phi);
+ *y = -r*cosdeg (phi);
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int arcrev(x, y, prj, phi, theta)
+
+const double x, y;
+struct prjprm *prj;
+double *phi, *theta;
+
+{
+ double r;
+
+ if (prj->flag != ARC) {
+ if (arcset(prj)) return 1;
+ }
+
+ r = sqrt(x*x + y*y);
+ if (r == 0.0) {
+ *phi = 0.0;
+ } else {
+ *phi = atan2deg (x, -y);
+ }
+ *theta = 90.0 - r*prj->w[1];
+
+ return 0;
+}
+
+/*============================================================================
+* ZPN: zenithal/azimuthal polynomial projection.
+*
+* Given:
+* prj->p[0:9] Polynomial coefficients.
+*
+* Given and/or returned:
+* prj->flag ZPN, or -ZPN if prj->flag is given < 0.
+* prj->r0 r0; reset to 180/pi if 0.
+*
+* Returned:
+* prj->code "ZPN"
+* prj->phi0 0.0
+* prj->theta0 90.0
+* prj->n Degree of the polynomial, N.
+* prj->w[0] Co-latitude of the first point of inflection (N > 2).
+* prj->w[1] Radius of the first point of inflection (N > 2).
+* prj->prjfwd Pointer to zpnfwd().
+* prj->prjrev Pointer to zpnrev().
+*===========================================================================*/
+
+int zpnset(prj)
+
+struct prjprm *prj;
+
+{
+ int i, j, k;
+ double d, d1, d2, r, zd, zd1, zd2;
+ const double tol = 1.0e-13;
+
+ strcpy(prj->code, "ZPN");
+ prj->flag = copysgni (ZPN, prj->flag);
+ prj->phi0 = 0.0;
+ prj->theta0 = 90.0;
+
+ if (prj->r0 == 0.0) prj->r0 = R2D;
+
+ /* Find the highest non-zero coefficient. */
+ for (k = 9; k >= 0 && prj->p[k] == 0.0; k--){
+ i = 0; }
+ /* if (k < 0) return 1; */
+
+ /* if (k < 0 switch to ARC projection */
+ if (k < 0) {
+ return (arcset (prj));
+ }
+
+ prj->n = k;
+
+ /* No negative derivative -> no point of inflection. */
+ zd = PI;
+
+ /* Processing subroutines */
+ prj->prjfwd = zpnfwd;
+ prj->prjrev = zpnrev;
+
+ if (k >= 3) {
+ /* Find the point of inflection closest to the pole. */
+ zd1 = 0.0;
+ d1 = prj->p[1];
+ if (d1 <= 0.0) {
+ return 1;
+ }
+
+ /* Find the point where the derivative first goes negative. */
+ for (i = 0; i < 180; i++) {
+ zd2 = i*D2R;
+ d2 = 0.0;
+ for (j = k; j > 0; j--) {
+ d2 = d2*zd2 + j*prj->p[j];
+ }
+
+ if (d2 <= 0.0) break;
+ zd1 = zd2;
+ d1 = d2;
+ }
+
+ if (i == 180) {
+ /* No negative derivative -> no point of inflection. */
+ zd = PI;
+ } else {
+ /* Find where the derivative is zero. */
+ for (i = 1; i <= 10; i++) {
+ zd = zd1 - d1*(zd2-zd1)/(d2-d1);
+
+ d = 0.0;
+ for (j = k; j > 0; j--) {
+ d = d*zd + j*prj->p[j];
+ }
+
+ if (fabs(d) < tol) break;
+
+ if (d < 0.0) {
+ zd2 = zd;
+ d2 = d;
+ } else {
+ zd1 = zd;
+ d1 = d;
+ }
+ }
+ }
+
+ r = 0.0;
+ for (j = k; j >= 0; j--) {
+ r = r*zd + prj->p[j];
+ }
+ prj->w[0] = zd;
+ prj->w[1] = r;
+ }
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int zpnfwd(phi, theta, prj, x, y)
+
+const double phi, theta;
+struct prjprm *prj;
+double *x, *y;
+
+{
+ int j;
+ double r, s;
+
+ if (abs(prj->flag) != ZPN) {
+ if (zpnset(prj)) return 1;
+ }
+
+ s = (90.0 - theta)*D2R;
+
+ r = 0.0;
+ for (j = 9; j >= 0; j--) {
+ r = r*s + prj->p[j];
+ }
+ r = prj->r0*r;
+
+ *x = r*sindeg (phi);
+ *y = -r*cosdeg (phi);
+
+ if (prj->flag > 0 && s > prj->w[0]) {
+ return 2;
+ }
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int zpnrev(x, y, prj, phi, theta)
+
+const double x, y;
+struct prjprm *prj;
+double *phi, *theta;
+
+{
+ int i, j, k;
+ double a, b, c, d, lambda, r, r1, r2, rt, zd, zd1, zd2;
+ const double tol = 1.0e-13;
+
+ if (abs(prj->flag) != ZPN) {
+ if (zpnset(prj)) return 1;
+ }
+
+ k = prj->n;
+
+ r = sqrt(x*x + y*y)/prj->r0;
+
+ if (k < 1) {
+ /* Constant - no solution. */
+ return 1;
+ } else if (k == 1) {
+ /* Linear. */
+ zd = (r - prj->p[0])/prj->p[1];
+ } else if (k == 2) {
+ /* Quadratic. */
+ a = prj->p[2];
+ b = prj->p[1];
+ c = prj->p[0] - r;
+
+ d = b*b - 4.0*a*c;
+ if (d < 0.0) {
+ return 2;
+ }
+ d = sqrt(d);
+
+ /* Choose solution closest to pole. */
+ zd1 = (-b + d)/(2.0*a);
+ zd2 = (-b - d)/(2.0*a);
+ zd = (zd1<zd2) ? zd1 : zd2;
+ if (zd < -tol) zd = (zd1>zd2) ? zd1 : zd2;
+ if (zd < 0.0) {
+ if (zd < -tol) {
+ return 2;
+ }
+ zd = 0.0;
+ } else if (zd > PI) {
+ if (zd > PI+tol) {
+ return 2;
+ }
+ zd = PI;
+ }
+ } else {
+ /* Higher order - solve iteratively. */
+ zd1 = 0.0;
+ r1 = prj->p[0];
+ zd2 = prj->w[0];
+ r2 = prj->w[1];
+
+ if (r < r1) {
+ if (r < r1-tol) {
+ return 2;
+ }
+ zd = zd1;
+ } else if (r > r2) {
+ if (r > r2+tol) {
+ return 2;
+ }
+ zd = zd2;
+ } else {
+ /* Disect the interval. */
+ for (j = 0; j < 100; j++) {
+ lambda = (r2 - r)/(r2 - r1);
+ if (lambda < 0.1) {
+ lambda = 0.1;
+ } else if (lambda > 0.9) {
+ lambda = 0.9;
+ }
+
+ zd = zd2 - lambda*(zd2 - zd1);
+
+ rt = 0.0;
+ for (i = k; i >= 0; i--) {
+ rt = (rt * zd) + prj->p[i];
+ }
+
+ if (rt < r) {
+ if (r-rt < tol) break;
+ r1 = rt;
+ zd1 = zd;
+ } else {
+ if (rt-r < tol) break;
+ r2 = rt;
+ zd2 = zd;
+ }
+
+ if (fabs(zd2-zd1) < tol) break;
+ }
+ }
+ }
+
+ if (r == 0.0) {
+ *phi = 0.0;
+ } else {
+ *phi = atan2deg (x, -y);
+ }
+ *theta = 90.0 - zd*R2D;
+
+ return 0;
+}
+
+/*============================================================================
+* ZEA: zenithal/azimuthal equal area projection.
+*
+* Given and/or returned:
+* prj->r0 r0; reset to 180/pi if 0.
+*
+* Returned:
+* prj->code "ZEA"
+* prj->flag ZEA
+* prj->phi0 0.0
+* prj->theta0 90.0
+* prj->w[0] 2*r0
+* prj->w[1] 1/(2*r0)
+* prj->prjfwd Pointer to zeafwd().
+* prj->prjrev Pointer to zearev().
+*===========================================================================*/
+
+int zeaset(prj)
+
+struct prjprm *prj;
+
+{
+ strcpy(prj->code, "ZEA");
+ prj->flag = ZEA;
+ prj->phi0 = 0.0;
+ prj->theta0 = 90.0;
+
+ if (prj->r0 == 0.0) {
+ prj->r0 = R2D;
+ prj->w[0] = 360.0/PI;
+ prj->w[1] = PI/360.0;
+ } else {
+ prj->w[0] = 2.0*prj->r0;
+ prj->w[1] = 1.0/prj->w[0];
+ }
+
+ prj->prjfwd = zeafwd;
+ prj->prjrev = zearev;
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int zeafwd(phi, theta, prj, x, y)
+
+const double phi, theta;
+struct prjprm *prj;
+double *x, *y;
+
+{
+ double r;
+
+ if (prj->flag != ZEA) {
+ if (zeaset(prj)) return 1;
+ }
+
+ r = prj->w[0]*sindeg ((90.0 - theta)/2.0);
+ *x = r*sindeg (phi);
+ *y = -r*cosdeg (phi);
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int zearev(x, y, prj, phi, theta)
+
+const double x, y;
+struct prjprm *prj;
+double *phi, *theta;
+
+{
+ double r, s;
+ const double tol = 1.0e-12;
+
+ if (prj->flag != ZEA) {
+ if (zeaset(prj)) return 1;
+ }
+
+ r = sqrt(x*x + y*y);
+ if (r == 0.0) {
+ *phi = 0.0;
+ } else {
+ *phi = atan2deg (x, -y);
+ }
+
+ s = r*prj->w[1];
+ if (fabs(s) > 1.0) {
+ if (fabs(r - prj->w[0]) < tol) {
+ *theta = -90.0;
+ } else {
+ return 2;
+ }
+ } else {
+ *theta = 90.0 - 2.0*asindeg (s);
+ }
+
+ return 0;
+}
+
+/*============================================================================
+* AIR: Airy's projection.
+*
+* Given:
+* prj->p[1] Latitude theta_b within which the error is minimized, in
+* degrees.
+*
+* Given and/or returned:
+* prj->r0 r0; reset to 180/pi if 0.
+*
+* Returned:
+* prj->code "AIR"
+* prj->flag AIR
+* prj->phi0 0.0
+* prj->theta0 90.0
+* prj->w[0] 2*r0
+* prj->w[1] ln(cos(xi_b))/tan(xi_b)**2, where xi_b = (90-theta_b)/2
+* prj->w[2] 1/2 - prj->w[1]
+* prj->w[3] 2*r0*prj->w[2]
+* prj->w[4] tol, cutoff for using small angle approximation, in
+* radians.
+* prj->w[5] prj->w[2]*tol
+* prj->w[6] (180/pi)/prj->w[2]
+* prj->prjfwd Pointer to airfwd().
+* prj->prjrev Pointer to airrev().
+*===========================================================================*/
+
+int airset(prj)
+
+struct prjprm *prj;
+
+{
+ const double tol = 1.0e-4;
+ double cxi;
+
+ strcpy(prj->code, "AIR");
+ prj->flag = AIR;
+ prj->phi0 = 0.0;
+ prj->theta0 = 90.0;
+
+ if (prj->r0 == 0.0) prj->r0 = R2D;
+
+ prj->w[0] = 2.0*prj->r0;
+ if (prj->p[1] == 90.0) {
+ prj->w[1] = -0.5;
+ prj->w[2] = 1.0;
+ } else if (prj->p[1] > -90.0) {
+ cxi = cosdeg ((90.0 - prj->p[1])/2.0);
+ prj->w[1] = log(cxi)*(cxi*cxi)/(1.0-cxi*cxi);
+ prj->w[2] = 0.5 - prj->w[1];
+ } else {
+ return 1;
+ }
+
+ prj->w[3] = prj->w[0] * prj->w[2];
+ prj->w[4] = tol;
+ prj->w[5] = prj->w[2]*tol;
+ prj->w[6] = R2D/prj->w[2];
+
+ prj->prjfwd = airfwd;
+ prj->prjrev = airrev;
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int airfwd(phi, theta, prj, x, y)
+
+const double phi, theta;
+struct prjprm *prj;
+double *x, *y;
+
+{
+ double cxi, r, txi, xi;
+
+ if (prj->flag != AIR) {
+ if (airset(prj)) return 1;
+ }
+
+ if (theta == 90.0) {
+ r = 0.0;
+ } else if (theta > -90.0) {
+ xi = D2R*(90.0 - theta)/2.0;
+ if (xi < prj->w[4]) {
+ r = xi*prj->w[3];
+ } else {
+ cxi = cosdeg ((90.0 - theta)/2.0);
+ txi = sqrt(1.0-cxi*cxi)/cxi;
+ r = -prj->w[0]*(log(cxi)/txi + prj->w[1]*txi);
+ }
+ } else {
+ return 2;
+ }
+
+ *x = r*sindeg (phi);
+ *y = -r*cosdeg (phi);
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int airrev(x, y, prj, phi, theta)
+
+const double x, y;
+struct prjprm *prj;
+double *phi, *theta;
+
+{
+ int j;
+ double cxi, lambda, r, r1, r2, rt, txi, x1, x2, xi;
+ const double tol = 1.0e-12;
+
+ if (prj->flag != AIR) {
+ if (airset(prj)) return 1;
+ }
+
+ r = sqrt(x*x + y*y)/prj->w[0];
+
+ if (r == 0.0) {
+ xi = 0.0;
+ } else if (r < prj->w[5]) {
+ xi = r*prj->w[6];
+ } else {
+ /* Find a solution interval. */
+ x1 = 1.0;
+ r1 = 0.0;
+ for (j = 0; j < 30; j++) {
+ x2 = x1/2.0;
+ txi = sqrt(1.0-x2*x2)/x2;
+ r2 = -(log(x2)/txi + prj->w[1]*txi);
+
+ if (r2 >= r) break;
+ x1 = x2;
+ r1 = r2;
+ }
+ if (j == 30) return 2;
+
+ for (j = 0; j < 100; j++) {
+ /* Weighted division of the interval. */
+ lambda = (r2-r)/(r2-r1);
+ if (lambda < 0.1) {
+ lambda = 0.1;
+ } else if (lambda > 0.9) {
+ lambda = 0.9;
+ }
+ cxi = x2 - lambda*(x2-x1);
+
+ txi = sqrt(1.0-cxi*cxi)/cxi;
+ rt = -(log(cxi)/txi + prj->w[1]*txi);
+
+ if (rt < r) {
+ if (r-rt < tol) break;
+ r1 = rt;
+ x1 = cxi;
+ } else {
+ if (rt-r < tol) break;
+ r2 = rt;
+ x2 = cxi;
+ }
+ }
+ if (j == 100) return 2;
+
+ xi = acosdeg (cxi);
+ }
+
+ if (r == 0.0) {
+ *phi = 0.0;
+ } else {
+ *phi = atan2deg (x, -y);
+ }
+ *theta = 90.0 - 2.0*xi;
+
+ return 0;
+}
+
+/*============================================================================
+* CYP: cylindrical perspective projection.
+*
+* Given:
+* prj->p[1] Distance of point of projection from the centre of the
+* generating sphere, mu, in units of r0.
+* prj->p[2] Radius of the cylinder of projection, lambda, in units of
+* r0.
+*
+* Given and/or returned:
+* prj->r0 r0; reset to 180/pi if 0.
+*
+* Returned:
+* prj->code "CYP"
+* prj->flag CYP
+* prj->phi0 0.0
+* prj->theta0 0.0
+* prj->w[0] r0*lambda*(pi/180)
+* prj->w[1] (180/pi)/(r0*lambda)
+* prj->w[2] r0*(mu + lambda)
+* prj->w[3] 1/(r0*(mu + lambda))
+* prj->prjfwd Pointer to cypfwd().
+* prj->prjrev Pointer to cyprev().
+*===========================================================================*/
+
+int cypset(prj)
+
+struct prjprm *prj;
+
+{
+ strcpy(prj->code, "CYP");
+ prj->flag = CYP;
+ prj->phi0 = 0.0;
+ prj->theta0 = 0.0;
+
+ if (prj->r0 == 0.0) {
+ prj->r0 = R2D;
+
+ prj->w[0] = prj->p[2];
+ if (prj->w[0] == 0.0) {
+ return 1;
+ }
+
+ prj->w[1] = 1.0/prj->w[0];
+
+ prj->w[2] = R2D*(prj->p[1] + prj->p[2]);
+ if (prj->w[2] == 0.0) {
+ return 1;
+ }
+
+ prj->w[3] = 1.0/prj->w[2];
+ } else {
+ prj->w[0] = prj->r0*prj->p[2]*D2R;
+ if (prj->w[0] == 0.0) {
+ return 1;
+ }
+
+ prj->w[1] = 1.0/prj->w[0];
+
+ prj->w[2] = prj->r0*(prj->p[1] + prj->p[2]);
+ if (prj->w[2] == 0.0) {
+ return 1;
+ }
+
+ prj->w[3] = 1.0/prj->w[2];
+ }
+
+ prj->prjfwd = cypfwd;
+ prj->prjrev = cyprev;
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int cypfwd(phi, theta, prj, x, y)
+
+const double phi, theta;
+struct prjprm *prj;
+double *x, *y;
+
+{
+ double s;
+
+ if (prj->flag != CYP) {
+ if (cypset(prj)) return 1;
+ }
+
+ s = prj->p[1] + cosdeg (theta);
+ if (s == 0.0) {
+ return 2;
+ }
+
+ *x = prj->w[0]*phi;
+ *y = prj->w[2]*sindeg (theta)/s;
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int cyprev(x, y, prj, phi, theta)
+
+const double x, y;
+struct prjprm *prj;
+double *phi, *theta;
+
+{
+ double eta;
+
+ if (prj->flag != CYP) {
+ if (cypset(prj)) return 1;
+ }
+
+ *phi = x*prj->w[1];
+ eta = y*prj->w[3];
+ *theta = atan2deg (eta,1.0) + asindeg (eta*prj->p[1]/sqrt(eta*eta+1.0));
+
+ return 0;
+}
+
+/*============================================================================
+* CEA: cylindrical equal area projection.
+*
+* Given:
+* prj->p[1] Square of the cosine of the latitude at which the
+* projection is conformal, lambda.
+*
+* Given and/or returned:
+* prj->r0 r0; reset to 180/pi if 0.
+*
+* Returned:
+* prj->code "CEA"
+* prj->flag CEA
+* prj->phi0 0.0
+* prj->theta0 0.0
+* prj->w[0] r0*(pi/180)
+* prj->w[1] (180/pi)/r0
+* prj->w[2] r0/lambda
+* prj->w[3] lambda/r0
+* prj->prjfwd Pointer to ceafwd().
+* prj->prjrev Pointer to cearev().
+*===========================================================================*/
+
+int ceaset(prj)
+
+struct prjprm *prj;
+
+{
+ strcpy(prj->code, "CEA");
+ prj->flag = CEA;
+ prj->phi0 = 0.0;
+ prj->theta0 = 0.0;
+
+ if (prj->r0 == 0.0) {
+ prj->r0 = R2D;
+ prj->w[0] = 1.0;
+ prj->w[1] = 1.0;
+ if (prj->p[1] <= 0.0 || prj->p[1] > 1.0) {
+ return 1;
+ }
+ prj->w[2] = prj->r0/prj->p[1];
+ prj->w[3] = prj->p[1]/prj->r0;
+ } else {
+ prj->w[0] = prj->r0*D2R;
+ prj->w[1] = R2D/prj->r0;
+ if (prj->p[1] <= 0.0 || prj->p[1] > 1.0) {
+ return 1;
+ }
+ prj->w[2] = prj->r0/prj->p[1];
+ prj->w[3] = prj->p[1]/prj->r0;
+ }
+
+ prj->prjfwd = ceafwd;
+ prj->prjrev = cearev;
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int ceafwd(phi, theta, prj, x, y)
+
+const double phi, theta;
+struct prjprm *prj;
+double *x, *y;
+
+{
+ if (prj->flag != CEA) {
+ if (ceaset(prj)) return 1;
+ }
+
+ *x = prj->w[0]*phi;
+ *y = prj->w[2]*sindeg (theta);
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int cearev(x, y, prj, phi, theta)
+
+const double x, y;
+struct prjprm *prj;
+double *phi, *theta;
+
+{
+ double s;
+ const double tol = 1.0e-13;
+
+ if (prj->flag != CEA) {
+ if (ceaset(prj)) return 1;
+ }
+
+ s = y*prj->w[3];
+ if (fabs(s) > 1.0) {
+ if (fabs(s) > 1.0+tol) {
+ return 2;
+ }
+ s = copysgn (1.0,s);
+ }
+
+ *phi = x*prj->w[1];
+ *theta = asindeg (s);
+
+ return 0;
+}
+
+/*============================================================================
+* CAR: Cartesian projection.
+*
+* Given and/or returned:
+* prj->r0 r0; reset to 180/pi if 0.
+*
+* Returned:
+* prj->code "CAR"
+* prj->flag CAR
+* prj->phi0 0.0
+* prj->theta0 0.0
+* prj->w[0] r0*(pi/180)
+* prj->w[1] (180/pi)/r0
+* prj->prjfwd Pointer to carfwd().
+* prj->prjrev Pointer to carrev().
+*===========================================================================*/
+
+int carset(prj)
+
+struct prjprm *prj;
+
+{
+ strcpy(prj->code, "CAR");
+ prj->flag = CAR;
+ prj->phi0 = 0.0;
+ prj->theta0 = 0.0;
+
+ if (prj->r0 == 0.0) {
+ prj->r0 = R2D;
+ prj->w[0] = 1.0;
+ prj->w[1] = 1.0;
+ } else {
+ prj->w[0] = prj->r0*D2R;
+ prj->w[1] = 1.0/prj->w[0];
+ }
+
+ prj->prjfwd = carfwd;
+ prj->prjrev = carrev;
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int carfwd(phi, theta, prj, x, y)
+
+const double phi, theta;
+struct prjprm *prj;
+double *x, *y;
+
+{
+ if (prj->flag != CAR) {
+ if (carset(prj)) return 1;
+ }
+
+ *x = prj->w[0]*phi;
+ *y = prj->w[0]*theta;
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int carrev(x, y, prj, phi, theta)
+
+const double x, y;
+struct prjprm *prj;
+double *phi, *theta;
+
+{
+ if (prj->flag != CAR) {
+ if (carset(prj)) return 1;
+ }
+
+ *phi = prj->w[1]*x;
+ *theta = prj->w[1]*y;
+
+ return 0;
+}
+
+/*============================================================================
+* MER: Mercator's projection.
+*
+* Given and/or returned:
+* prj->r0 r0; reset to 180/pi if 0.
+*
+* Returned:
+* prj->code "MER"
+* prj->flag MER
+* prj->phi0 0.0
+* prj->theta0 0.0
+* prj->w[0] r0*(pi/180)
+* prj->w[1] (180/pi)/r0
+* prj->prjfwd Pointer to merfwd().
+* prj->prjrev Pointer to merrev().
+*===========================================================================*/
+
+int merset(prj)
+
+struct prjprm *prj;
+
+{
+ strcpy(prj->code, "MER");
+ prj->flag = MER;
+ prj->phi0 = 0.0;
+ prj->theta0 = 0.0;
+
+ if (prj->r0 == 0.0) {
+ prj->r0 = R2D;
+ prj->w[0] = 1.0;
+ prj->w[1] = 1.0;
+ } else {
+ prj->w[0] = prj->r0*D2R;
+ prj->w[1] = 1.0/prj->w[0];
+ }
+
+ prj->prjfwd = merfwd;
+ prj->prjrev = merrev;
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int merfwd(phi, theta, prj, x, y)
+
+const double phi, theta;
+struct prjprm *prj;
+double *x, *y;
+
+{
+ if (prj->flag != MER) {
+ if (merset(prj)) return 1;
+ }
+
+ if (theta <= -90.0 || theta >= 90.0) {
+ return 2;
+ }
+
+ *x = prj->w[0]*phi;
+ *y = prj->r0*log(tandeg ((90.0+theta)/2.0));
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int merrev(x, y, prj, phi, theta)
+
+const double x, y;
+struct prjprm *prj;
+double *phi, *theta;
+
+{
+ if (prj->flag != MER) {
+ if (merset(prj)) return 1;
+ }
+
+ *phi = x*prj->w[1];
+ *theta = 2.0*atandeg (exp(y/prj->r0)) - 90.0;
+
+ return 0;
+}
+
+/*============================================================================
+* SFL: Sanson-Flamsteed ("global sinusoid") projection.
+*
+* Given and/or returned:
+* prj->r0 r0; reset to 180/pi if 0.
+*
+* Returned:
+* prj->code "SFL"
+* prj->flag SFL
+* prj->phi0 0.0
+* prj->theta0 0.0
+* prj->w[0] r0*(pi/180)
+* prj->w[1] (180/pi)/r0
+* prj->prjfwd Pointer to sflfwd().
+* prj->prjrev Pointer to sflrev().
+*===========================================================================*/
+
+int sflset(prj)
+
+struct prjprm *prj;
+
+{
+ strcpy(prj->code, "SFL");
+ prj->flag = SFL;
+ prj->phi0 = 0.0;
+ prj->theta0 = 0.0;
+
+ if (prj->r0 == 0.0) {
+ prj->r0 = R2D;
+ prj->w[0] = 1.0;
+ prj->w[1] = 1.0;
+ } else {
+ prj->w[0] = prj->r0*D2R;
+ prj->w[1] = 1.0/prj->w[0];
+ }
+
+ prj->prjfwd = sflfwd;
+ prj->prjrev = sflrev;
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int sflfwd(phi, theta, prj, x, y)
+
+const double phi, theta;
+struct prjprm *prj;
+double *x, *y;
+
+{
+ if (prj->flag != SFL) {
+ if (sflset(prj)) return 1;
+ }
+
+ *x = prj->w[0]*phi*cosdeg (theta);
+ *y = prj->w[0]*theta;
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int sflrev(x, y, prj, phi, theta)
+
+const double x, y;
+struct prjprm *prj;
+double *phi, *theta;
+
+{
+ double w;
+
+ if (prj->flag != SFL) {
+ if (sflset(prj)) return 1;
+ }
+
+ w = cos(y/prj->r0);
+ if (w == 0.0) {
+ *phi = 0.0;
+ } else {
+ *phi = x*prj->w[1]/cos(y/prj->r0);
+ }
+ *theta = y*prj->w[1];
+
+ return 0;
+}
+
+/*============================================================================
+* PAR: parabolic projection.
+*
+* Given and/or returned:
+* prj->r0 r0; reset to 180/pi if 0.
+*
+* Returned:
+* prj->code "PAR"
+* prj->flag PAR
+* prj->phi0 0.0
+* prj->theta0 0.0
+* prj->w[0] r0*(pi/180)
+* prj->w[1] (180/pi)/r0
+* prj->w[2] pi*r0
+* prj->w[3] 1/(pi*r0)
+* prj->prjfwd Pointer to parfwd().
+* prj->prjrev Pointer to parrev().
+*===========================================================================*/
+
+int parset(prj)
+
+struct prjprm *prj;
+
+{
+ strcpy(prj->code, "PAR");
+ prj->flag = PAR;
+ prj->phi0 = 0.0;
+ prj->theta0 = 0.0;
+
+ if (prj->r0 == 0.0) {
+ prj->r0 = R2D;
+ prj->w[0] = 1.0;
+ prj->w[1] = 1.0;
+ prj->w[2] = 180.0;
+ prj->w[3] = 1.0/prj->w[2];
+ } else {
+ prj->w[0] = prj->r0*D2R;
+ prj->w[1] = 1.0/prj->w[0];
+ prj->w[2] = PI*prj->r0;
+ prj->w[3] = 1.0/prj->w[2];
+ }
+
+ prj->prjfwd = parfwd;
+ prj->prjrev = parrev;
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int parfwd(phi, theta, prj, x, y)
+
+const double phi, theta;
+struct prjprm *prj;
+double *x, *y;
+
+{
+ double s;
+
+ if (prj->flag != PAR) {
+ if (parset(prj)) return 1;
+ }
+
+ s = sindeg (theta/3.0);
+ *x = prj->w[0]*phi*(1.0 - 4.0*s*s);
+ *y = prj->w[2]*s;
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int parrev(x, y, prj, phi, theta)
+
+const double x, y;
+struct prjprm *prj;
+double *phi, *theta;
+
+{
+ double s, t;
+
+ if (prj->flag != PAR) {
+ if (parset(prj)) return 1;
+ }
+
+ s = y*prj->w[3];
+ if (s > 1.0 || s < -1.0) {
+ return 2;
+ }
+
+ t = 1.0 - 4.0*s*s;
+ if (t == 0.0) {
+ if (x == 0.0) {
+ *phi = 0.0;
+ } else {
+ return 2;
+ }
+ } else {
+ *phi = prj->w[1]*x/t;
+ }
+
+ *theta = 3.0*asindeg (s);
+
+ return 0;
+}
+
+/*============================================================================
+* MOL: Mollweide's projection.
+*
+* Given and/or returned:
+* prj->r0 r0; reset to 180/pi if 0.
+*
+* Returned:
+* prj->code "MOL"
+* prj->flag MOL
+* prj->phi0 0.0
+* prj->theta0 0.0
+* prj->w[0] sqrt(2)*r0
+* prj->w[1] sqrt(2)*r0/90
+* prj->w[2] 1/(sqrt(2)*r0)
+* prj->w[3] 90/r0
+* prj->prjfwd Pointer to molfwd().
+* prj->prjrev Pointer to molrev().
+*===========================================================================*/
+
+int molset(prj)
+
+struct prjprm *prj;
+
+{
+ strcpy(prj->code, "MOL");
+ prj->flag = MOL;
+ prj->phi0 = 0.0;
+ prj->theta0 = 0.0;
+
+ if (prj->r0 == 0.0) prj->r0 = R2D;
+
+ prj->w[0] = SQRT2*prj->r0;
+ prj->w[1] = prj->w[0]/90.0;
+ prj->w[2] = 1.0/prj->w[0];
+ prj->w[3] = 90.0/prj->r0;
+ prj->w[4] = 2.0/PI;
+
+ prj->prjfwd = molfwd;
+ prj->prjrev = molrev;
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int molfwd(phi, theta, prj, x, y)
+
+const double phi, theta;
+struct prjprm *prj;
+double *x, *y;
+
+{
+ int j;
+ double gamma, resid, u, v, v0, v1;
+ const double tol = 1.0e-13;
+
+ if (prj->flag != MOL) {
+ if (molset(prj)) return 1;
+ }
+
+ if (fabs(theta) == 90.0) {
+ *x = 0.0;
+ *y = copysgn (prj->w[0],theta);
+ } else if (theta == 0.0) {
+ *x = prj->w[1]*phi;
+ *y = 0.0;
+ } else {
+ u = PI*sindeg (theta);
+ v0 = -PI;
+ v1 = PI;
+ v = u;
+ for (j = 0; j < 100; j++) {
+ resid = (v - u) + sin(v);
+ if (resid < 0.0) {
+ if (resid > -tol) break;
+ v0 = v;
+ } else {
+ if (resid < tol) break;
+ v1 = v;
+ }
+ v = (v0 + v1)/2.0;
+ }
+
+ gamma = v/2.0;
+ *x = prj->w[1]*phi*cos(gamma);
+ *y = prj->w[0]*sin(gamma);
+ }
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int molrev(x, y, prj, phi, theta)
+
+const double x, y;
+struct prjprm *prj;
+double *phi, *theta;
+
+{
+ double s, y0, z;
+ const double tol = 1.0e-12;
+
+ if (prj->flag != MOL) {
+ if (molset(prj)) return 1;
+ }
+
+ y0 = y/prj->r0;
+ s = 2.0 - y0*y0;
+ if (s <= tol) {
+ if (s < -tol) {
+ return 2;
+ }
+ s = 0.0;
+
+ if (fabs(x) > tol) {
+ return 2;
+ }
+ *phi = 0.0;
+ } else {
+ s = sqrt(s);
+ *phi = prj->w[3]*x/s;
+ }
+
+ z = y*prj->w[2];
+ if (fabs(z) > 1.0) {
+ if (fabs(z) > 1.0+tol) {
+ return 2;
+ }
+ z = copysgn (1.0,z) + y0*s/PI;
+ } else {
+ z = asin(z)*prj->w[4] + y0*s/PI;
+ }
+
+ if (fabs(z) > 1.0) {
+ if (fabs(z) > 1.0+tol) {
+ return 2;
+ }
+ z = copysgn (1.0,z);
+ }
+
+ *theta = asindeg (z);
+
+ return 0;
+}
+
+/*============================================================================
+* AIT: Hammer-Aitoff projection.
+*
+* Given and/or returned:
+* prj->r0 r0; reset to 180/pi if 0.
+*
+* Returned:
+* prj->code "AIT"
+* prj->flag AIT
+* prj->phi0 0.0
+* prj->theta0 0.0
+* prj->w[0] 2*r0**2
+* prj->w[1] 1/(2*r0)**2
+* prj->w[2] 1/(4*r0)**2
+* prj->w[3] 1/(2*r0)
+* prj->prjfwd Pointer to aitfwd().
+* prj->prjrev Pointer to aitrev().
+*===========================================================================*/
+
+int aitset(prj)
+
+struct prjprm *prj;
+
+{
+ strcpy(prj->code, "AIT");
+ prj->flag = AIT;
+ prj->phi0 = 0.0;
+ prj->theta0 = 0.0;
+
+ if (prj->r0 == 0.0) prj->r0 = R2D;
+
+ prj->w[0] = 2.0*prj->r0*prj->r0;
+ prj->w[1] = 1.0/(2.0*prj->w[0]);
+ prj->w[2] = prj->w[1]/4.0;
+ prj->w[3] = 1.0/(2.0*prj->r0);
+
+ prj->prjfwd = aitfwd;
+ prj->prjrev = aitrev;
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int aitfwd(phi, theta, prj, x, y)
+
+const double phi, theta;
+struct prjprm *prj;
+double *x, *y;
+
+{
+ double cthe, w;
+
+ if (prj->flag != AIT) {
+ if (aitset(prj)) return 1;
+ }
+
+ cthe = cosdeg (theta);
+ w = sqrt(prj->w[0]/(1.0 + cthe*cosdeg (phi/2.0)));
+ *x = 2.0*w*cthe*sindeg (phi/2.0);
+ *y = w*sindeg (theta);
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int aitrev(x, y, prj, phi, theta)
+
+const double x, y;
+struct prjprm *prj;
+double *phi, *theta;
+
+{
+ double s, u, xp, yp, z;
+ const double tol = 1.0e-13;
+
+ if (prj->flag != AIT) {
+ if (aitset(prj)) return 1;
+ }
+
+ u = 1.0 - x*x*prj->w[2] - y*y*prj->w[1];
+ if (u < 0.0) {
+ if (u < -tol) {
+ return 2;
+ }
+
+ u = 0.0;
+ }
+
+ z = sqrt(u);
+ s = z*y/prj->r0;
+ if (fabs(s) > 1.0) {
+ if (fabs(s) > 1.0+tol) {
+ return 2;
+ }
+ s = copysgn (1.0,s);
+ }
+
+ xp = 2.0*z*z - 1.0;
+ yp = z*x*prj->w[3];
+ if (xp == 0.0 && yp == 0.0) {
+ *phi = 0.0;
+ } else {
+ *phi = 2.0*atan2deg (yp, xp);
+ }
+ *theta = asindeg (s);
+
+ return 0;
+}
+
+/*============================================================================
+* COP: conic perspective projection.
+*
+* Given:
+* prj->p[1] sigma = (theta2+theta1)/2
+* prj->p[2] delta = (theta2-theta1)/2, where theta1 and theta2 are the
+* latitudes of the standard parallels, in degrees.
+*
+* Given and/or returned:
+* prj->flag COP, or -COP if prj->flag is given < 0.
+* prj->r0 r0; reset to 180/pi if 0.
+*
+* Returned:
+* prj->code "COP"
+* prj->phi0 0.0
+* prj->theta0 sigma
+* prj->w[0] C = sin(sigma)
+* prj->w[1] 1/C
+* prj->w[2] Y0 = r0*cos(delta)*cot(sigma)
+* prj->w[3] r0*cos(delta)
+* prj->w[4] 1/(r0*cos(delta)
+* prj->w[5] cot(sigma)
+* prj->prjfwd Pointer to copfwd().
+* prj->prjrev Pointer to coprev().
+*===========================================================================*/
+
+int copset(prj)
+
+struct prjprm *prj;
+
+{
+ strcpy(prj->code, "COP");
+ prj->flag = copysgni (COP, prj->flag);
+ prj->phi0 = 0.0;
+ prj->theta0 = prj->p[1];
+
+ if (prj->r0 == 0.0) prj->r0 = R2D;
+
+ prj->w[0] = sindeg (prj->p[1]);
+ if (prj->w[0] == 0.0) {
+ return 1;
+ }
+
+ prj->w[1] = 1.0/prj->w[0];
+
+ prj->w[3] = prj->r0*cosdeg (prj->p[2]);
+ if (prj->w[3] == 0.0) {
+ return 1;
+ }
+
+ prj->w[4] = 1.0/prj->w[3];
+ prj->w[5] = 1.0/tandeg (prj->p[1]);
+
+ prj->w[2] = prj->w[3]*prj->w[5];
+
+ prj->prjfwd = copfwd;
+ prj->prjrev = coprev;
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int copfwd(phi, theta, prj, x, y)
+
+const double phi, theta;
+struct prjprm *prj;
+double *x, *y;
+
+{
+ double a, r, s, t;
+
+ if (abs(prj->flag) != COP) {
+ if (copset(prj)) return 1;
+ }
+
+ t = theta - prj->p[1];
+ s = cosdeg (t);
+ if (s == 0.0) {
+ return 2;
+ }
+
+ a = prj->w[0]*phi;
+ r = prj->w[2] - prj->w[3]*sindeg (t)/s;
+
+ *x = r*sindeg (a);
+ *y = prj->w[2] - r*cosdeg (a);
+
+ if (prj->flag > 0 && r*prj->w[0] < 0.0) {
+ return 2;
+ }
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int coprev(x, y, prj, phi, theta)
+
+const double x, y;
+struct prjprm *prj;
+double *phi, *theta;
+
+{
+ double a, dy, r;
+
+ if (abs(prj->flag) != COP) {
+ if (copset(prj)) return 1;
+ }
+
+ dy = prj->w[2] - y;
+ r = sqrt(x*x + dy*dy);
+ if (prj->p[1] < 0.0) r = -r;
+
+ if (r == 0.0) {
+ a = 0.0;
+ } else {
+ a = atan2deg (x/r, dy/r);
+ }
+
+ *phi = a*prj->w[1];
+ *theta = prj->p[1] + atandeg (prj->w[5] - r*prj->w[4]);
+
+ return 0;
+}
+
+/*============================================================================
+* COE: conic equal area projection.
+*
+* Given:
+* prj->p[1] sigma = (theta2+theta1)/2
+* prj->p[2] delta = (theta2-theta1)/2, where theta1 and theta2 are the
+* latitudes of the standard parallels, in degrees.
+*
+* Given and/or returned:
+* prj->r0 r0; reset to 180/pi if 0.
+*
+* Returned:
+* prj->code "COE"
+* prj->flag COE
+* prj->phi0 0.0
+* prj->theta0 sigma
+* prj->w[0] C = (sin(theta1) + sin(theta2))/2
+* prj->w[1] 1/C
+* prj->w[2] Y0 = chi*sqrt(psi - 2C*sindeg (sigma))
+* prj->w[3] chi = r0/C
+* prj->w[4] psi = 1 + sin(theta1)*sin(theta2)
+* prj->w[5] 2C
+* prj->w[6] (1 + sin(theta1)*sin(theta2))*(r0/C)**2
+* prj->w[7] C/(2*r0**2)
+* prj->w[8] chi*sqrt(psi + 2C)
+* prj->prjfwd Pointer to coefwd().
+* prj->prjrev Pointer to coerev().
+*===========================================================================*/
+
+int coeset(prj)
+
+struct prjprm *prj;
+
+{
+ double theta1, theta2;
+
+ strcpy(prj->code, "COE");
+ prj->flag = COE;
+ prj->phi0 = 0.0;
+ prj->theta0 = prj->p[1];
+
+ if (prj->r0 == 0.0) prj->r0 = R2D;
+
+ theta1 = prj->p[1] - prj->p[2];
+ theta2 = prj->p[1] + prj->p[2];
+
+ prj->w[0] = (sindeg (theta1) + sindeg (theta2))/2.0;
+ if (prj->w[0] == 0.0) {
+ return 1;
+ }
+
+ prj->w[1] = 1.0/prj->w[0];
+
+ prj->w[3] = prj->r0/prj->w[0];
+ prj->w[4] = 1.0 + sindeg (theta1)*sindeg (theta2);
+ prj->w[5] = 2.0*prj->w[0];
+ prj->w[6] = prj->w[3]*prj->w[3]*prj->w[4];
+ prj->w[7] = 1.0/(2.0*prj->r0*prj->w[3]);
+ prj->w[8] = prj->w[3]*sqrt(prj->w[4] + prj->w[5]);
+
+ prj->w[2] = prj->w[3]*sqrt(prj->w[4] - prj->w[5]*sindeg (prj->p[1]));
+
+ prj->prjfwd = coefwd;
+ prj->prjrev = coerev;
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int coefwd(phi, theta, prj, x, y)
+
+const double phi, theta;
+struct prjprm *prj;
+double *x, *y;
+
+{
+ double a, r;
+
+ if (prj->flag != COE) {
+ if (coeset(prj)) return 1;
+ }
+
+ a = phi*prj->w[0];
+ if (theta == -90.0) {
+ r = prj->w[8];
+ } else {
+ r = prj->w[3]*sqrt(prj->w[4] - prj->w[5]*sindeg (theta));
+ }
+
+ *x = r*sindeg (a);
+ *y = prj->w[2] - r*cosdeg (a);
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int coerev(x, y, prj, phi, theta)
+
+const double x, y;
+struct prjprm *prj;
+double *phi, *theta;
+
+{
+ double a, dy, r, w;
+ const double tol = 1.0e-12;
+
+ if (prj->flag != COE) {
+ if (coeset(prj)) return 1;
+ }
+
+ dy = prj->w[2] - y;
+ r = sqrt(x*x + dy*dy);
+ if (prj->p[1] < 0.0) r = -r;
+
+ if (r == 0.0) {
+ a = 0.0;
+ } else {
+ a = atan2deg (x/r, dy/r);
+ }
+
+ *phi = a*prj->w[1];
+ if (fabs(r - prj->w[8]) < tol) {
+ *theta = -90.0;
+ } else {
+ w = (prj->w[6] - r*r)*prj->w[7];
+ if (fabs(w) > 1.0) {
+ if (fabs(w-1.0) < tol) {
+ *theta = 90.0;
+ } else if (fabs(w+1.0) < tol) {
+ *theta = -90.0;
+ } else {
+ return 2;
+ }
+ } else {
+ *theta = asindeg (w);
+ }
+ }
+
+ return 0;
+}
+
+/*============================================================================
+* COD: conic equidistant projection.
+*
+* Given:
+* prj->p[1] sigma = (theta2+theta1)/2
+* prj->p[2] delta = (theta2-theta1)/2, where theta1 and theta2 are the
+* latitudes of the standard parallels, in degrees.
+*
+* Given and/or returned:
+* prj->r0 r0; reset to 180/pi if 0.
+*
+* Returned:
+* prj->code "COD"
+* prj->flag COD
+* prj->phi0 0.0
+* prj->theta0 sigma
+* prj->w[0] C = r0*sin(sigma)*sin(delta)/delta
+* prj->w[1] 1/C
+* prj->w[2] Y0 = delta*cot(delta)*cot(sigma)
+* prj->w[3] Y0 + sigma
+* prj->prjfwd Pointer to codfwd().
+* prj->prjrev Pointer to codrev().
+*===========================================================================*/
+
+int codset(prj)
+
+struct prjprm *prj;
+
+{
+ strcpy(prj->code, "COD");
+ prj->flag = COD;
+ prj->phi0 = 0.0;
+ prj->theta0 = prj->p[1];
+
+ if (prj->r0 == 0.0) prj->r0 = R2D;
+
+ if (prj->p[2] == 0.0) {
+ prj->w[0] = prj->r0*sindeg (prj->p[1])*D2R;
+ } else {
+ prj->w[0] = prj->r0*sindeg (prj->p[1])*sindeg (prj->p[2])/prj->p[2];
+ }
+
+ if (prj->w[0] == 0.0) {
+ return 1;
+ }
+
+ prj->w[1] = 1.0/prj->w[0];
+ prj->w[2] = prj->r0*cosdeg (prj->p[2])*cosdeg (prj->p[1])/prj->w[0];
+ prj->w[3] = prj->w[2] + prj->p[1];
+
+ prj->prjfwd = codfwd;
+ prj->prjrev = codrev;
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int codfwd(phi, theta, prj, x, y)
+
+const double phi, theta;
+struct prjprm *prj;
+double *x, *y;
+
+{
+ double a, r;
+
+ if (prj->flag != COD) {
+ if (codset(prj)) return 1;
+ }
+
+ a = prj->w[0]*phi;
+ r = prj->w[3] - theta;
+
+ *x = r*sindeg (a);
+ *y = prj->w[2] - r*cosdeg (a);
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int codrev(x, y, prj, phi, theta)
+
+const double x, y;
+struct prjprm *prj;
+double *phi, *theta;
+
+{
+ double a, dy, r;
+
+ if (prj->flag != COD) {
+ if (codset(prj)) return 1;
+ }
+
+ dy = prj->w[2] - y;
+ r = sqrt(x*x + dy*dy);
+ if (prj->p[1] < 0.0) r = -r;
+
+ if (r == 0.0) {
+ a = 0.0;
+ } else {
+ a = atan2deg (x/r, dy/r);
+ }
+
+ *phi = a*prj->w[1];
+ *theta = prj->w[3] - r;
+
+ return 0;
+}
+
+/*============================================================================
+* COO: conic orthomorphic projection.
+*
+* Given:
+* prj->p[1] sigma = (theta2+theta1)/2
+* prj->p[2] delta = (theta2-theta1)/2, where theta1 and theta2 are the
+* latitudes of the standard parallels, in degrees.
+*
+* Given and/or returned:
+* prj->r0 r0; reset to 180/pi if 0.
+*
+* Returned:
+* prj->code "COO"
+* prj->flag COO
+* prj->phi0 0.0
+* prj->theta0 sigma
+* prj->w[0] C = ln(cos(theta2)/cos(theta1))/ln(tan(tau2)/tan(tau1))
+* where tau1 = (90 - theta1)/2
+* tau2 = (90 - theta2)/2
+* prj->w[1] 1/C
+* prj->w[2] Y0 = psi*tan((90-sigma)/2)**C
+* prj->w[3] psi = (r0*cos(theta1)/C)/tan(tau1)**C
+* prj->w[4] 1/psi
+* prj->prjfwd Pointer to coofwd().
+* prj->prjrev Pointer to coorev().
+*===========================================================================*/
+
+int cooset(prj)
+
+struct prjprm *prj;
+
+{
+ double cos1, cos2, tan1, tan2, theta1, theta2;
+
+ strcpy(prj->code, "COO");
+ prj->flag = COO;
+ prj->phi0 = 0.0;
+ prj->theta0 = prj->p[1];
+
+ if (prj->r0 == 0.0) prj->r0 = R2D;
+
+ theta1 = prj->p[1] - prj->p[2];
+ theta2 = prj->p[1] + prj->p[2];
+
+ tan1 = tandeg ((90.0 - theta1)/2.0);
+ cos1 = cosdeg (theta1);
+
+ if (theta1 == theta2) {
+ prj->w[0] = sindeg (theta1);
+ } else {
+ tan2 = tandeg ((90.0 - theta2)/2.0);
+ cos2 = cosdeg (theta2);
+ prj->w[0] = log(cos2/cos1)/log(tan2/tan1);
+ }
+ if (prj->w[0] == 0.0) {
+ return 1;
+ }
+
+ prj->w[1] = 1.0/prj->w[0];
+
+ prj->w[3] = prj->r0*(cos1/prj->w[0])/pow(tan1,prj->w[0]);
+ if (prj->w[3] == 0.0) {
+ return 1;
+ }
+ prj->w[2] = prj->w[3]*pow(tandeg ((90.0 - prj->p[1])/2.0),prj->w[0]);
+ prj->w[4] = 1.0/prj->w[3];
+
+ prj->prjfwd = coofwd;
+ prj->prjrev = coorev;
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int coofwd(phi, theta, prj, x, y)
+
+const double phi, theta;
+struct prjprm *prj;
+double *x, *y;
+
+{
+ double a, r;
+
+ if (prj->flag != COO) {
+ if (cooset(prj)) return 1;
+ }
+
+ a = prj->w[0]*phi;
+ if (theta == -90.0) {
+ if (prj->w[0] < 0.0) {
+ r = 0.0;
+ } else {
+ return 2;
+ }
+ } else {
+ r = prj->w[3]*pow(tandeg ((90.0 - theta)/2.0),prj->w[0]);
+ }
+
+ *x = r*sindeg (a);
+ *y = prj->w[2] - r*cosdeg (a);
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int coorev(x, y, prj, phi, theta)
+
+const double x, y;
+struct prjprm *prj;
+double *phi, *theta;
+
+{
+ double a, dy, r;
+
+ if (prj->flag != COO) {
+ if (cooset(prj)) return 1;
+ }
+
+ dy = prj->w[2] - y;
+ r = sqrt(x*x + dy*dy);
+ if (prj->p[1] < 0.0) r = -r;
+
+ if (r == 0.0) {
+ a = 0.0;
+ } else {
+ a = atan2deg (x/r, dy/r);
+ }
+
+ *phi = a*prj->w[1];
+ if (r == 0.0) {
+ if (prj->w[0] < 0.0) {
+ *theta = -90.0;
+ } else {
+ return 2;
+ }
+ } else {
+ *theta = 90.0 - 2.0*atandeg (pow(r*prj->w[4],prj->w[1]));
+ }
+
+ return 0;
+}
+
+/*============================================================================
+* BON: Bonne's projection.
+*
+* Given:
+* prj->p[1] Bonne conformal latitude, theta1, in degrees.
+*
+* Given and/or returned:
+* prj->r0 r0; reset to 180/pi if 0.
+*
+* Returned:
+* prj->code "BON"
+* prj->flag BON
+* prj->phi0 0.0
+* prj->theta0 0.0
+* prj->w[1] r0*pi/180
+* prj->w[2] Y0 = r0*(cot(theta1) + theta1*pi/180)
+* prj->prjfwd Pointer to bonfwd().
+* prj->prjrev Pointer to bonrev().
+*===========================================================================*/
+
+int bonset(prj)
+
+struct prjprm *prj;
+
+{
+ strcpy(prj->code, "BON");
+ prj->flag = BON;
+ prj->phi0 = 0.0;
+ prj->theta0 = 0.0;
+
+ if (prj->r0 == 0.0) {
+ prj->r0 = R2D;
+ prj->w[1] = 1.0;
+ prj->w[2] = prj->r0*cosdeg (prj->p[1])/sindeg (prj->p[1]) + prj->p[1];
+ } else {
+ prj->w[1] = prj->r0*D2R;
+ prj->w[2] = prj->r0*(cosdeg (prj->p[1])/sindeg (prj->p[1]) + prj->p[1]*D2R);
+ }
+
+ prj->prjfwd = bonfwd;
+ prj->prjrev = bonrev;
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int bonfwd(phi, theta, prj, x, y)
+
+const double phi, theta;
+struct prjprm *prj;
+double *x, *y;
+
+{
+ double a, r;
+
+ if (prj->p[1] == 0.0) {
+ /* Sanson-Flamsteed. */
+ return sflfwd(phi, theta, prj, x, y);
+ }
+
+ if (prj->flag != BON) {
+ if (bonset(prj)) return 1;
+ }
+
+ r = prj->w[2] - theta*prj->w[1];
+ a = prj->r0*phi*cosdeg (theta)/r;
+
+ *x = r*sindeg (a);
+ *y = prj->w[2] - r*cosdeg (a);
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int bonrev(x, y, prj, phi, theta)
+
+const double x, y;
+struct prjprm *prj;
+double *phi, *theta;
+
+{
+ double a, cthe, dy, r;
+
+ if (prj->p[1] == 0.0) {
+ /* Sanson-Flamsteed. */
+ return sflrev(x, y, prj, phi, theta);
+ }
+
+ if (prj->flag != BON) {
+ if (bonset(prj)) return 1;
+ }
+
+ dy = prj->w[2] - y;
+ r = sqrt(x*x + dy*dy);
+ if (prj->p[1] < 0.0) r = -r;
+
+ if (r == 0.0) {
+ a = 0.0;
+ } else {
+ a = atan2deg (x/r, dy/r);
+ }
+
+ *theta = (prj->w[2] - r)/prj->w[1];
+ cthe = cosdeg (*theta);
+ if (cthe == 0.0) {
+ *phi = 0.0;
+ } else {
+ *phi = a*(r/prj->r0)/cthe;
+ }
+
+ return 0;
+}
+
+/*============================================================================
+* PCO: polyconic projection.
+*
+* Given and/or returned:
+* prj->r0 r0; reset to 180/pi if 0.
+*
+* Returned:
+* prj->code "PCO"
+* prj->flag PCO
+* prj->phi0 0.0
+* prj->theta0 0.0
+* prj->w[0] r0*(pi/180)
+* prj->w[1] 1/r0
+* prj->w[2] 2*r0
+* prj->prjfwd Pointer to pcofwd().
+* prj->prjrev Pointer to pcorev().
+*===========================================================================*/
+
+int pcoset(prj)
+
+struct prjprm *prj;
+
+{
+ strcpy(prj->code, "PCO");
+ prj->flag = PCO;
+ prj->phi0 = 0.0;
+ prj->theta0 = 0.0;
+
+ if (prj->r0 == 0.0) {
+ prj->r0 = R2D;
+ prj->w[0] = 1.0;
+ prj->w[1] = 1.0;
+ prj->w[2] = 360.0/PI;
+ } else {
+ prj->w[0] = prj->r0*D2R;
+ prj->w[1] = 1.0/prj->w[0];
+ prj->w[2] = 2.0*prj->r0;
+ }
+
+ prj->prjfwd = pcofwd;
+ prj->prjrev = pcorev;
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int pcofwd(phi, theta, prj, x, y)
+
+const double phi, theta;
+struct prjprm *prj;
+double *x, *y;
+
+{
+ double a, cthe, cotthe, sthe;
+
+ if (prj->flag != PCO) {
+ if (pcoset(prj)) return 1;
+ }
+
+ cthe = cosdeg (theta);
+ sthe = sindeg (theta);
+ a = phi*sthe;
+
+ if (sthe == 0.0) {
+ *x = prj->w[0]*phi;
+ *y = 0.0;
+ } else {
+ cotthe = cthe/sthe;
+ *x = prj->r0*cotthe*sindeg (a);
+ *y = prj->r0*(cotthe*(1.0 - cosdeg (a)) + theta*D2R);
+ }
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int pcorev(x, y, prj, phi, theta)
+
+const double x, y;
+struct prjprm *prj;
+double *phi, *theta;
+
+{
+ int j;
+ double f, fneg, fpos, lambda, tanthe, theneg, thepos, w, xp, xx, ymthe, yp;
+ const double tol = 1.0e-12;
+
+ if (prj->flag != PCO) {
+ if (pcoset(prj)) return 1;
+ }
+
+ w = fabs(y*prj->w[1]);
+ if (w < tol) {
+ *phi = x*prj->w[1];
+ *theta = 0.0;
+ } else if (fabs(w-90.0) < tol) {
+ *phi = 0.0;
+ *theta = copysgn (90.0,y);
+ } else {
+ /* Iterative solution using weighted division of the interval. */
+ if (y > 0.0) {
+ thepos = 90.0;
+ } else {
+ thepos = -90.0;
+ }
+ theneg = 0.0;
+
+ xx = x*x;
+ ymthe = y - prj->w[0]*thepos;
+ fpos = xx + ymthe*ymthe;
+ fneg = -999.0;
+
+ for (j = 0; j < 64; j++) {
+ if (fneg < -100.0) {
+ /* Equal division of the interval. */
+ *theta = (thepos+theneg)/2.0;
+ } else {
+ /* Weighted division of the interval. */
+ lambda = fpos/(fpos-fneg);
+ if (lambda < 0.1) {
+ lambda = 0.1;
+ } else if (lambda > 0.9) {
+ lambda = 0.9;
+ }
+ *theta = thepos - lambda*(thepos-theneg);
+ }
+
+ /* Compute the residue. */
+ ymthe = y - prj->w[0]*(*theta);
+ tanthe = tandeg (*theta);
+ f = xx + ymthe*(ymthe - prj->w[2]/tanthe);
+
+ /* Check for convergence. */
+ if (fabs(f) < tol) break;
+ if (fabs(thepos-theneg) < tol) break;
+
+ /* Redefine the interval. */
+ if (f > 0.0) {
+ thepos = *theta;
+ fpos = f;
+ } else {
+ theneg = *theta;
+ fneg = f;
+ }
+ }
+
+ xp = prj->r0 - ymthe*tanthe;
+ yp = x*tanthe;
+ if (xp == 0.0 && yp == 0.0) {
+ *phi = 0.0;
+ } else {
+ *phi = atan2deg (yp, xp)/sindeg (*theta);
+ }
+ }
+
+ return 0;
+}
+
+/*============================================================================
+* TSC: tangential spherical cube projection.
+*
+* Given and/or returned:
+* prj->r0 r0; reset to 180/pi if 0.
+*
+* Returned:
+* prj->code "TSC"
+* prj->flag TSC
+* prj->phi0 0.0
+* prj->theta0 0.0
+* prj->w[0] r0*(pi/4)
+* prj->w[1] (4/pi)/r0
+* prj->prjfwd Pointer to tscfwd().
+* prj->prjrev Pointer to tscrev().
+*===========================================================================*/
+
+int tscset(prj)
+
+struct prjprm *prj;
+
+{
+ strcpy(prj->code, "TSC");
+ prj->flag = TSC;
+ prj->phi0 = 0.0;
+ prj->theta0 = 0.0;
+
+ if (prj->r0 == 0.0) {
+ prj->r0 = R2D;
+ prj->w[0] = 45.0;
+ prj->w[1] = 1.0/45.0;
+ } else {
+ prj->w[0] = prj->r0*PI/4.0;
+ prj->w[1] = 1.0/prj->w[0];
+ }
+
+ prj->prjfwd = tscfwd;
+ prj->prjrev = tscrev;
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int tscfwd(phi, theta, prj, x, y)
+
+const double phi, theta;
+struct prjprm *prj;
+double *x, *y;
+
+{
+ int face;
+ double cthe, l, m, n, rho;
+ double x0 = 0.0;
+ double y0 = 0.0;
+ double xf = 0.0;
+ double yf = 0.0;
+ const double tol = 1.0e-12;
+
+ if (prj->flag != TSC) {
+ if (tscset(prj)) return 1;
+ }
+
+ cthe = cosdeg (theta);
+ l = cthe*cosdeg (phi);
+ m = cthe*sindeg (phi);
+ n = sindeg (theta);
+
+ face = 0;
+ rho = n;
+ if (l > rho) {
+ face = 1;
+ rho = l;
+ }
+ if (m > rho) {
+ face = 2;
+ rho = m;
+ }
+ if (-l > rho) {
+ face = 3;
+ rho = -l;
+ }
+ if (-m > rho) {
+ face = 4;
+ rho = -m;
+ }
+ if (-n > rho) {
+ face = 5;
+ rho = -n;
+ }
+
+ if (face == 0) {
+ xf = m/rho;
+ yf = -l/rho;
+ x0 = 0.0;
+ y0 = 2.0;
+ } else if (face == 1) {
+ xf = m/rho;
+ yf = n/rho;
+ x0 = 0.0;
+ y0 = 0.0;
+ } else if (face == 2) {
+ xf = -l/rho;
+ yf = n/rho;
+ x0 = 2.0;
+ y0 = 0.0;
+ } else if (face == 3) {
+ xf = -m/rho;
+ yf = n/rho;
+ x0 = 4.0;
+ y0 = 0.0;
+ } else if (face == 4) {
+ xf = l/rho;
+ yf = n/rho;
+ x0 = 6.0;
+ y0 = 0.0;
+ } else if (face == 5) {
+ xf = m/rho;
+ yf = l/rho;
+ x0 = 0.0;
+ y0 = -2.0;
+ }
+
+ if (fabs(xf) > 1.0) {
+ if (fabs(xf) > 1.0+tol) {
+ return 2;
+ }
+ xf = copysgn (1.0,xf);
+ }
+ if (fabs(yf) > 1.0) {
+ if (fabs(yf) > 1.0+tol) {
+ return 2;
+ }
+ yf = copysgn (1.0,yf);
+ }
+
+ *x = prj->w[0]*(xf + x0);
+ *y = prj->w[0]*(yf + y0);
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int tscrev(x, y, prj, phi, theta)
+
+const double x, y;
+struct prjprm *prj;
+double *phi, *theta;
+
+{
+ double l, m, n, xf, yf;
+
+ if (prj->flag != TSC) {
+ if (tscset(prj)) return 1;
+ }
+
+ xf = x*prj->w[1];
+ yf = y*prj->w[1];
+
+ /* Check bounds. */
+ if (fabs(xf) <= 1.0) {
+ if (fabs(yf) > 3.0) return 2;
+ } else {
+ if (fabs(xf) > 7.0) return 2;
+ if (fabs(yf) > 1.0) return 2;
+ }
+
+ /* Map negative faces to the other side. */
+ if (xf < -1.0) xf += 8.0;
+
+ /* Determine the face. */
+ if (xf > 5.0) {
+ /* face = 4 */
+ xf = xf - 6.0;
+ m = -1.0/sqrt(1.0 + xf*xf + yf*yf);
+ l = -m*xf;
+ n = -m*yf;
+ } else if (xf > 3.0) {
+ /* face = 3 */
+ xf = xf - 4.0;
+ l = -1.0/sqrt(1.0 + xf*xf + yf*yf);
+ m = l*xf;
+ n = -l*yf;
+ } else if (xf > 1.0) {
+ /* face = 2 */
+ xf = xf - 2.0;
+ m = 1.0/sqrt(1.0 + xf*xf + yf*yf);
+ l = -m*xf;
+ n = m*yf;
+ } else if (yf > 1.0) {
+ /* face = 0 */
+ yf = yf - 2.0;
+ n = 1.0/sqrt(1.0 + xf*xf + yf*yf);
+ l = -n*yf;
+ m = n*xf;
+ } else if (yf < -1.0) {
+ /* face = 5 */
+ yf = yf + 2.0;
+ n = -1.0/sqrt(1.0 + xf*xf + yf*yf);
+ l = -n*yf;
+ m = -n*xf;
+ } else {
+ /* face = 1 */
+ l = 1.0/sqrt(1.0 + xf*xf + yf*yf);
+ m = l*xf;
+ n = l*yf;
+ }
+
+ if (l == 0.0 && m == 0.0) {
+ *phi = 0.0;
+ } else {
+ *phi = atan2deg (m, l);
+ }
+ *theta = asindeg (n);
+
+ return 0;
+}
+
+/*============================================================================
+* CSC: COBE quadrilateralized spherical cube projection.
+*
+* Given and/or returned:
+* prj->r0 r0; reset to 180/pi if 0.
+*
+* Returned:
+* prj->code "CSC"
+* prj->flag CSC
+* prj->phi0 0.0
+* prj->theta0 0.0
+* prj->w[0] r0*(pi/4)
+* prj->w[1] (4/pi)/r0
+* prj->prjfwd Pointer to cscfwd().
+* prj->prjrev Pointer to cscrev().
+*===========================================================================*/
+
+int cscset(prj)
+
+struct prjprm *prj;
+
+{
+ strcpy(prj->code, "CSC");
+ prj->flag = CSC;
+ prj->phi0 = 0.0;
+ prj->theta0 = 0.0;
+
+ if (prj->r0 == 0.0) {
+ prj->r0 = R2D;
+ prj->w[0] = 45.0;
+ prj->w[1] = 1.0/45.0;
+ } else {
+ prj->w[0] = prj->r0*PI/4.0;
+ prj->w[1] = 1.0/prj->w[0];
+ }
+
+ prj->prjfwd = cscfwd;
+ prj->prjrev = cscrev;
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int cscfwd(phi, theta, prj, x, y)
+
+const double phi, theta;
+struct prjprm *prj;
+double *x, *y;
+
+{
+ int face;
+ double cthe, eta=0.0, l, m, n, rho, xi=0.0;
+ const float tol = 1.0e-7;
+
+ float a, a2, a2b2, a4, ab, b, b2, b4, ca2, cb2;
+ float x0 = 0.0;
+ float y0 = 0.0;
+ float xf = 0.0;
+ float yf = 0.0;
+ const float gstar = 1.37484847732;
+ const float mm = 0.004869491981;
+ const float gamma = -0.13161671474;
+ const float omega1 = -0.159596235474;
+ const float d0 = 0.0759196200467;
+ const float d1 = -0.0217762490699;
+ const float c00 = 0.141189631152;
+ const float c10 = 0.0809701286525;
+ const float c01 = -0.281528535557;
+ const float c11 = 0.15384112876;
+ const float c20 = -0.178251207466;
+ const float c02 = 0.106959469314;
+
+ if (prj->flag != CSC) {
+ if (cscset(prj)) return 1;
+ }
+
+ cthe = cosdeg (theta);
+ l = cthe*cosdeg (phi);
+ m = cthe*sindeg (phi);
+ n = sindeg (theta);
+
+ face = 0;
+ rho = n;
+ if (l > rho) {
+ face = 1;
+ rho = l;
+ }
+ if (m > rho) {
+ face = 2;
+ rho = m;
+ }
+ if (-l > rho) {
+ face = 3;
+ rho = -l;
+ }
+ if (-m > rho) {
+ face = 4;
+ rho = -m;
+ }
+ if (-n > rho) {
+ face = 5;
+ rho = -n;
+ }
+
+ if (face == 0) {
+ xi = m;
+ eta = -l;
+ x0 = 0.0;
+ y0 = 2.0;
+ } else if (face == 1) {
+ xi = m;
+ eta = n;
+ x0 = 0.0;
+ y0 = 0.0;
+ } else if (face == 2) {
+ xi = -l;
+ eta = n;
+ x0 = 2.0;
+ y0 = 0.0;
+ } else if (face == 3) {
+ xi = -m;
+ eta = n;
+ x0 = 4.0;
+ y0 = 0.0;
+ } else if (face == 4) {
+ xi = l;
+ eta = n;
+ x0 = 6.0;
+ y0 = 0.0;
+ } else if (face == 5) {
+ xi = m;
+ eta = l;
+ x0 = 0.0;
+ y0 = -2.0;
+ }
+
+ a = xi/rho;
+ b = eta/rho;
+
+ a2 = a*a;
+ b2 = b*b;
+ ca2 = 1.0 - a2;
+ cb2 = 1.0 - b2;
+
+ /* Avoid floating underflows. */
+ ab = fabs(a*b);
+ a4 = (a2 > 1.0e-16) ? a2*a2 : 0.0;
+ b4 = (b2 > 1.0e-16) ? b2*b2 : 0.0;
+ a2b2 = (ab > 1.0e-16) ? a2*b2 : 0.0;
+
+ xf = a*(a2 + ca2*(gstar + b2*(gamma*ca2 + mm*a2 +
+ cb2*(c00 + c10*a2 + c01*b2 + c11*a2b2 + c20*a4 + c02*b4)) +
+ a2*(omega1 - ca2*(d0 + d1*a2))));
+ yf = b*(b2 + cb2*(gstar + a2*(gamma*cb2 + mm*b2 +
+ ca2*(c00 + c10*b2 + c01*a2 + c11*a2b2 + c20*b4 + c02*a4)) +
+ b2*(omega1 - cb2*(d0 + d1*b2))));
+
+ if (fabs(xf) > 1.0) {
+ if (fabs(xf) > 1.0+tol) {
+ return 2;
+ }
+ xf = copysgn (1.0,xf);
+ }
+ if (fabs(yf) > 1.0) {
+ if (fabs(yf) > 1.0+tol) {
+ return 2;
+ }
+ yf = copysgn (1.0,yf);
+ }
+
+ *x = prj->w[0]*(x0 + xf);
+ *y = prj->w[0]*(y0 + yf);
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int cscrev(x, y, prj, phi, theta)
+
+const double x, y;
+struct prjprm *prj;
+double *phi, *theta;
+
+{
+ int face;
+ double l = 0.0;
+ double m = 0.0;
+ double n = 0.0;
+
+ float a, b, xf, xx, yf, yy, z0, z1, z2, z3, z4, z5, z6;
+ const float p00 = -0.27292696;
+ const float p10 = -0.07629969;
+ const float p20 = -0.22797056;
+ const float p30 = 0.54852384;
+ const float p40 = -0.62930065;
+ const float p50 = 0.25795794;
+ const float p60 = 0.02584375;
+ const float p01 = -0.02819452;
+ const float p11 = -0.01471565;
+ const float p21 = 0.48051509;
+ const float p31 = -1.74114454;
+ const float p41 = 1.71547508;
+ const float p51 = -0.53022337;
+ const float p02 = 0.27058160;
+ const float p12 = -0.56800938;
+ const float p22 = 0.30803317;
+ const float p32 = 0.98938102;
+ const float p42 = -0.83180469;
+ const float p03 = -0.60441560;
+ const float p13 = 1.50880086;
+ const float p23 = -0.93678576;
+ const float p33 = 0.08693841;
+ const float p04 = 0.93412077;
+ const float p14 = -1.41601920;
+ const float p24 = 0.33887446;
+ const float p05 = -0.63915306;
+ const float p15 = 0.52032238;
+ const float p06 = 0.14381585;
+
+ if (prj->flag != CSC) {
+ if (cscset(prj)) return 1;
+ }
+
+ xf = x*prj->w[1];
+ yf = y*prj->w[1];
+
+ /* Check bounds. */
+ if (fabs(xf) <= 1.0) {
+ if (fabs(yf) > 3.0) return 2;
+ } else {
+ if (fabs(xf) > 7.0) return 2;
+ if (fabs(yf) > 1.0) return 2;
+ }
+
+ /* Map negative faces to the other side. */
+ if (xf < -1.0) xf += 8.0;
+
+ /* Determine the face. */
+ if (xf > 5.0) {
+ face = 4;
+ xf = xf - 6.0;
+ } else if (xf > 3.0) {
+ face = 3;
+ xf = xf - 4.0;
+ } else if (xf > 1.0) {
+ face = 2;
+ xf = xf - 2.0;
+ } else if (yf > 1.0) {
+ face = 0;
+ yf = yf - 2.0;
+ } else if (yf < -1.0) {
+ face = 5;
+ yf = yf + 2.0;
+ } else {
+ face = 1;
+ }
+
+ xx = xf*xf;
+ yy = yf*yf;
+
+ z0 = p00 + xx*(p10 + xx*(p20 + xx*(p30 + xx*(p40 + xx*(p50 + xx*(p60))))));
+ z1 = p01 + xx*(p11 + xx*(p21 + xx*(p31 + xx*(p41 + xx*(p51)))));
+ z2 = p02 + xx*(p12 + xx*(p22 + xx*(p32 + xx*(p42))));
+ z3 = p03 + xx*(p13 + xx*(p23 + xx*(p33)));
+ z4 = p04 + xx*(p14 + xx*(p24));
+ z5 = p05 + xx*(p15);
+ z6 = p06;
+
+ a = z0 + yy*(z1 + yy*(z2 + yy*(z3 + yy*(z4 + yy*(z5 + yy*z6)))));
+ a = xf + xf*(1.0 - xx)*a;
+
+ z0 = p00 + yy*(p10 + yy*(p20 + yy*(p30 + yy*(p40 + yy*(p50 + yy*(p60))))));
+ z1 = p01 + yy*(p11 + yy*(p21 + yy*(p31 + yy*(p41 + yy*(p51)))));
+ z2 = p02 + yy*(p12 + yy*(p22 + yy*(p32 + yy*(p42))));
+ z3 = p03 + yy*(p13 + yy*(p23 + yy*(p33)));
+ z4 = p04 + yy*(p14 + yy*(p24));
+ z5 = p05 + yy*(p15);
+ z6 = p06;
+
+ b = z0 + xx*(z1 + xx*(z2 + xx*(z3 + xx*(z4 + xx*(z5 + xx*z6)))));
+ b = yf + yf*(1.0 - yy)*b;
+
+ if (face == 0) {
+ n = 1.0/sqrt(a*a + b*b + 1.0);
+ l = -b*n;
+ m = a*n;
+ } else if (face == 1) {
+ l = 1.0/sqrt(a*a + b*b + 1.0);
+ m = a*l;
+ n = b*l;
+ } else if (face == 2) {
+ m = 1.0/sqrt(a*a + b*b + 1.0);
+ l = -a*m;
+ n = b*m;
+ } else if (face == 3) {
+ l = -1.0/sqrt(a*a + b*b + 1.0);
+ m = a*l;
+ n = -b*l;
+ } else if (face == 4) {
+ m = -1.0/sqrt(a*a + b*b + 1.0);
+ l = -a*m;
+ n = -b*m;
+ } else if (face == 5) {
+ n = -1.0/sqrt(a*a + b*b + 1.0);
+ l = -b*n;
+ m = -a*n;
+ }
+
+ if (l == 0.0 && m == 0.0) {
+ *phi = 0.0;
+ } else {
+ *phi = atan2deg (m, l);
+ }
+ *theta = asindeg (n);
+
+ return 0;
+}
+
+/*============================================================================
+* QSC: quadrilaterilized spherical cube projection.
+*
+* Given and/or returned:
+* prj->r0 r0; reset to 180/pi if 0.
+*
+* Returned:
+* prj->code "QSC"
+* prj->flag QSC
+* prj->phi0 0.0
+* prj->theta0 0.0
+* prj->w[0] r0*(pi/4)
+* prj->w[1] (4/pi)/r0
+* prj->prjfwd Pointer to qscfwd().
+* prj->prjrev Pointer to qscrev().
+*===========================================================================*/
+
+int qscset(prj)
+
+struct prjprm *prj;
+
+{
+ strcpy(prj->code, "QSC");
+ prj->flag = QSC;
+ prj->phi0 = 0.0;
+ prj->theta0 = 0.0;
+
+ if (prj->r0 == 0.0) {
+ prj->r0 = R2D;
+ prj->w[0] = 45.0;
+ prj->w[1] = 1.0/45.0;
+ } else {
+ prj->w[0] = prj->r0*PI/4.0;
+ prj->w[1] = 1.0/prj->w[0];
+ }
+
+ prj->prjfwd = qscfwd;
+ prj->prjrev = qscrev;
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int qscfwd(phi, theta, prj, x, y)
+
+const double phi, theta;
+struct prjprm *prj;
+double *x, *y;
+
+{
+ int face;
+ double cthe, l, m, n, omega, p, rho, rhu, t, tau;
+ double xi = 0.0;
+ double eta = 0.0;
+ double x0 = 0.0;
+ double y0 = 0.0;
+ double xf = 0.0;
+ double yf = 0.0;
+ const double tol = 1.0e-12;
+
+ if (prj->flag != QSC) {
+ if (qscset(prj)) return 1;
+ }
+
+ if (fabs(theta) == 90.0) {
+ *x = 0.0;
+ *y = copysgn (2.0*prj->w[0],theta);
+ return 0;
+ }
+
+ cthe = cosdeg (theta);
+ l = cthe*cosdeg (phi);
+ m = cthe*sindeg (phi);
+ n = sindeg (theta);
+
+ face = 0;
+ rho = n;
+ if (l > rho) {
+ face = 1;
+ rho = l;
+ }
+ if (m > rho) {
+ face = 2;
+ rho = m;
+ }
+ if (-l > rho) {
+ face = 3;
+ rho = -l;
+ }
+ if (-m > rho) {
+ face = 4;
+ rho = -m;
+ }
+ if (-n > rho) {
+ face = 5;
+ rho = -n;
+ }
+
+ rhu = 1.0 - rho;
+
+ if (face == 0) {
+ xi = m;
+ eta = -l;
+ if (rhu < 1.0e-8) {
+ /* Small angle formula. */
+ t = (90.0 - theta)*D2R;
+ rhu = t*t/2.0;
+ }
+ x0 = 0.0;
+ y0 = 2.0;
+ } else if (face == 1) {
+ xi = m;
+ eta = n;
+ if (rhu < 1.0e-8) {
+ /* Small angle formula. */
+ t = theta*D2R;
+ p = fmod(phi,360.0);
+ if (p < -180.0) p += 360.0;
+ if (p > 180.0) p -= 360.0;
+ p *= D2R;
+ rhu = (p*p + t*t)/2.0;
+ }
+ x0 = 0.0;
+ y0 = 0.0;
+ } else if (face == 2) {
+ xi = -l;
+ eta = n;
+ if (rhu < 1.0e-8) {
+ /* Small angle formula. */
+ t = theta*D2R;
+ p = fmod(phi,360.0);
+ if (p < -180.0) p += 360.0;
+ p = (90.0 - p)*D2R;
+ rhu = (p*p + t*t)/2.0;
+ }
+ x0 = 2.0;
+ y0 = 0.0;
+ } else if (face == 3) {
+ xi = -m;
+ eta = n;
+ if (rhu < 1.0e-8) {
+ /* Small angle formula. */
+ t = theta*D2R;
+ p = fmod(phi,360.0);
+ if (p < 0.0) p += 360.0;
+ p = (180.0 - p)*D2R;
+ rhu = (p*p + t*t)/2.0;
+ }
+ x0 = 4.0;
+ y0 = 0.0;
+ } else if (face == 4) {
+ xi = l;
+ eta = n;
+ if (rhu < 1.0e-8) {
+ /* Small angle formula. */
+ t = theta*D2R;
+ p = fmod(phi,360.0);
+ if (p > 180.0) p -= 360.0;
+ p *= (90.0 + p)*D2R;
+ rhu = (p*p + t*t)/2.0;
+ }
+ x0 = 6;
+ y0 = 0.0;
+ } else if (face == 5) {
+ xi = m;
+ eta = l;
+ if (rhu < 1.0e-8) {
+ /* Small angle formula. */
+ t = (90.0 + theta)*D2R;
+ rhu = t*t/2.0;
+ }
+ x0 = 0.0;
+ y0 = -2;
+ }
+
+ if (xi == 0.0 && eta == 0.0) {
+ xf = 0.0;
+ yf = 0.0;
+ } else if (-xi >= fabs(eta)) {
+ omega = eta/xi;
+ tau = 1.0 + omega*omega;
+ xf = -sqrt(rhu/(1.0-1.0/sqrt(1.0+tau)));
+ yf = (xf/15.0)*(atandeg (omega) - asindeg (omega/sqrt(tau+tau)));
+ } else if (xi >= fabs(eta)) {
+ omega = eta/xi;
+ tau = 1.0 + omega*omega;
+ xf = sqrt(rhu/(1.0-1.0/sqrt(1.0+tau)));
+ yf = (xf/15.0)*(atandeg (omega) - asindeg (omega/sqrt(tau+tau)));
+ } else if (-eta > fabs(xi)) {
+ omega = xi/eta;
+ tau = 1.0 + omega*omega;
+ yf = -sqrt(rhu/(1.0-1.0/sqrt(1.0+tau)));
+ xf = (yf/15.0)*(atandeg (omega) - asindeg (omega/sqrt(tau+tau)));
+ } else if (eta > fabs(xi)) {
+ omega = xi/eta;
+ tau = 1.0 + omega*omega;
+ yf = sqrt(rhu/(1.0-1.0/sqrt(1.0+tau)));
+ xf = (yf/15.0)*(atandeg (omega) - asindeg (omega/sqrt(tau+tau)));
+ }
+
+ if (fabs(xf) > 1.0) {
+ if (fabs(xf) > 1.0+tol) {
+ return 2;
+ }
+ xf = copysgn (1.0,xf);
+ }
+ if (fabs(yf) > 1.0) {
+ if (fabs(yf) > 1.0+tol) {
+ return 2;
+ }
+ yf = copysgn (1.0,yf);
+ }
+
+ *x = prj->w[0]*(xf + x0);
+ *y = prj->w[0]*(yf + y0);
+
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int qscrev(x, y, prj, phi, theta)
+
+const double x, y;
+struct prjprm *prj;
+double *phi, *theta;
+
+{
+ int direct, face;
+ double omega, rho, rhu, tau, xf, yf, w;
+ double l = 0.0;
+ double m = 0.0;
+ double n = 0.0;
+ const double tol = 1.0e-12;
+
+ if (prj->flag != QSC) {
+ if (qscset(prj)) return 1;
+ }
+
+ xf = x*prj->w[1];
+ yf = y*prj->w[1];
+
+ /* Check bounds. */
+ if (fabs(xf) <= 1.0) {
+ if (fabs(yf) > 3.0) return 2;
+ } else {
+ if (fabs(xf) > 7.0) return 2;
+ if (fabs(yf) > 1.0) return 2;
+ }
+
+ /* Map negative faces to the other side. */
+ if (xf < -1.0) xf += 8.0;
+
+ /* Determine the face. */
+ if (xf > 5.0) {
+ face = 4;
+ xf = xf - 6.0;
+ } else if (xf > 3.0) {
+ face = 3;
+ xf = xf - 4.0;
+ } else if (xf > 1.0) {
+ face = 2;
+ xf = xf - 2.0;
+ } else if (yf > 1.0) {
+ face = 0;
+ yf = yf - 2.0;
+ } else if (yf < -1.0) {
+ face = 5;
+ yf = yf + 2.0;
+ } else {
+ face = 1;
+ }
+
+ direct = (fabs(xf) > fabs(yf));
+ if (direct) {
+ if (xf == 0.0) {
+ omega = 0.0;
+ tau = 1.0;
+ rho = 1.0;
+ rhu = 0.0;
+ } else {
+ w = 15.0*yf/xf;
+ omega = sindeg (w)/(cosdeg (w) - SQRT2INV);
+ tau = 1.0 + omega*omega;
+ rhu = xf*xf*(1.0 - 1.0/sqrt(1.0 + tau));
+ rho = 1.0 - rhu;
+ }
+ } else {
+ if (yf == 0.0) {
+ omega = 0.0;
+ tau = 1.0;
+ rho = 1.0;
+ rhu = 0.0;
+ } else {
+ w = 15.0*xf/yf;
+ omega = sindeg (w)/(cosdeg (w) - SQRT2INV);
+ tau = 1.0 + omega*omega;
+ rhu = yf*yf*(1.0 - 1.0/sqrt(1.0 + tau));
+ rho = 1.0 - rhu;
+ }
+ }
+
+ if (rho < -1.0) {
+ if (rho < -1.0-tol) {
+ return 2;
+ }
+
+ rho = -1.0;
+ rhu = 2.0;
+ w = 0.0;
+ } else {
+ w = sqrt(rhu*(2.0-rhu)/tau);
+ }
+
+ if (face == 0) {
+ n = rho;
+ if (direct) {
+ m = w;
+ if (xf < 0.0) m = -m;
+ l = -m*omega;
+ } else {
+ l = w;
+ if (yf > 0.0) l = -l;
+ m = -l*omega;
+ }
+ } else if (face == 1) {
+ l = rho;
+ if (direct) {
+ m = w;
+ if (xf < 0.0) m = -m;
+ n = m*omega;
+ } else {
+ n = w;
+ if (yf < 0.0) n = -n;
+ m = n*omega;
+ }
+ } else if (face == 2) {
+ m = rho;
+ if (direct) {
+ l = w;
+ if (xf > 0.0) l = -l;
+ n = -l*omega;
+ } else {
+ n = w;
+ if (yf < 0.0) n = -n;
+ l = -n*omega;
+ }
+ } else if (face == 3) {
+ l = -rho;
+ if (direct) {
+ m = w;
+ if (xf > 0.0) m = -m;
+ n = -m*omega;
+ } else {
+ n = w;
+ if (yf < 0.0) n = -n;
+ m = -n*omega;
+ }
+ } else if (face == 4) {
+ m = -rho;
+ if (direct) {
+ l = w;
+ if (xf < 0.0) l = -l;
+ n = l*omega;
+ } else {
+ n = w;
+ if (yf < 0.0) n = -n;
+ l = n*omega;
+ }
+ } else if (face == 5) {
+ n = -rho;
+ if (direct) {
+ m = w;
+ if (xf < 0.0) m = -m;
+ l = m*omega;
+ } else {
+ l = w;
+ if (yf < 0.0) l = -l;
+ m = l*omega;
+ }
+ }
+
+ if (l == 0.0 && m == 0.0) {
+ *phi = 0.0;
+ } else {
+ *phi = atan2deg (m, l);
+ }
+ *theta = asindeg (n);
+
+ return 0;
+}
+
+/* This routine comes from E. Bertin sextractor-2.8.6 */
+
+int
+raw_to_pv(struct prjprm *prj, double x, double y, double *xo, double *yo)
+
+{
+ int k;
+ double *a,*b,
+ r,r3,r5,r7,xy,x2,x3,x4,x5,x6,x7,y2,y3,y4,y5,y6,y7,xp,yp;
+
+
+ k=prj->npv;
+ a = prj->ppv+MAXPV; /* Latitude comes first for compatibility */
+ b = prj->ppv; /* Longitude */
+ xp = *(a++);
+ xp += *(a++)*x;
+ yp = *(b++);
+ yp += *(b++)*y;
+ if (!--k) goto poly_end;
+ xp += *(a++)*y;
+ yp += *(b++)*x;
+ if (!--k) goto poly_end;
+ r = sqrt(x*x + y*y);
+ xp += *(a++)*r;
+ yp += *(b++)*r;
+ if (!--k) goto poly_end;
+ xp += *(a++)*(x2=x*x);
+ yp += *(b++)*(y2=y*y);
+ if (!--k) goto poly_end;
+ xp += *(a++)*(xy=x*y);
+ yp += *(b++)*xy;
+ if (!--k) goto poly_end;
+ xp += *(a++)*y2;
+ yp += *(b++)*x2;
+ if (!--k) goto poly_end;
+ xp += *(a++)*(x3=x*x2);
+ yp += *(b++)*(y3=y*y2);
+ if (!--k) goto poly_end;
+ xp += *(a++)*x2*y;
+ yp += *(b++)*y2*x;
+ if (!--k) goto poly_end;
+ xp += *(a++)*x*y2;
+ yp += *(b++)*y*x2;
+ if (!--k) goto poly_end;
+ xp += *(a++)*y3;
+ yp += *(b++)*x3;
+ if (!--k) goto poly_end;
+ xp += *(a++)*(r3=r*r*r);
+ yp += *(b++)*r3;
+ if (!--k) goto poly_end;
+ xp += *(a++)*(x4=x2*x2);
+ yp += *(b++)*(y4=y2*y2);
+ if (!--k) goto poly_end;
+ xp += *(a++)*x3*y;
+ yp += *(b++)*y3*x;
+ if (!--k) goto poly_end;
+ xp += *(a++)*x2*y2;
+ yp += *(b++)*x2*y2;
+ if (!--k) goto poly_end;
+ xp += *(a++)*x*y3;
+ yp += *(b++)*y*x3;
+ if (!--k) goto poly_end;
+ xp += *(a++)*y4;
+ yp += *(b++)*x4;
+ if (!--k) goto poly_end;
+ xp += *(a++)*(x5=x4*x);
+ yp += *(b++)*(y5=y4*y);
+ if (!--k) goto poly_end;
+ xp += *(a++)*x4*y;
+ yp += *(b++)*y4*x;
+ if (!--k) goto poly_end;
+ xp += *(a++)*x3*y2;
+ yp += *(b++)*y3*x2;
+ if (!--k) goto poly_end;
+ xp += *(a++)*x2*y3;
+ yp += *(b++)*y2*x3;
+ if (!--k) goto poly_end;
+ xp += *(a++)*x*y4;
+ yp += *(b++)*y*x4;
+ if (!--k) goto poly_end;
+ xp += *(a++)*y5;
+ yp += *(b++)*x5;
+ if (!--k) goto poly_end;
+ xp += *(a++)*(r5=r3*r*r);
+ yp += *(b++)*r5;
+ if (!--k) goto poly_end;
+ xp += *(a++)*(x6=x5*x);
+ yp += *(b++)*(y6=y5*y);
+ if (!--k) goto poly_end;
+ xp += *(a++)*x5*y;
+ yp += *(b++)*y5*x;
+ if (!--k) goto poly_end;
+ xp += *(a++)*x4*y2;
+ yp += *(b++)*y4*x2;
+ if (!--k) goto poly_end;
+ xp += *(a++)*x3*y3;
+ yp += *(b++)*y3*x3;
+ if (!--k) goto poly_end;
+ xp += *(a++)*x2*y4;
+ yp += *(b++)*y2*x4;
+ if (!--k) goto poly_end;
+ xp += *(a++)*x*y5;
+ yp += *(b++)*y*x5;
+ if (!--k) goto poly_end;
+ xp += *(a++)*y6;
+ yp += *(b++)*x6;
+ if (!--k) goto poly_end;
+ xp += *(a++)*(x7=x6*x);
+ yp += *(b++)*(y7=y6*y);
+ if (!--k) goto poly_end;
+ xp += *(a++)*x6*y;
+ yp += *(b++)*y6*x;
+ if (!--k) goto poly_end;
+ xp += *(a++)*x5*y2;
+ yp += *(b++)*y5*x2;
+ if (!--k) goto poly_end;
+ xp += *(a++)*x4*y3;
+ yp += *(b++)*y4*x3;
+ if (!--k) goto poly_end;
+ xp += *(a++)*x3*y4;
+ yp += *(b++)*y3*x4;
+ if (!--k) goto poly_end;
+ xp += *(a++)*x2*y5;
+ yp += *(b++)*y2*x5;
+ if (!--k) goto poly_end;
+ xp += *(a++)*x*y6;
+ yp += *(b++)*y*x6;
+ if (!--k) goto poly_end;
+ xp += *(a++)*y7;
+ yp += *(b++)*x7;
+ if (!--k) goto poly_end;
+ xp += *a*(r7=r5*r*r);
+ yp += *b*r7;
+
+poly_end:
+
+ *xo = xp;
+ *yo = yp;
+
+ return 0;
+}
+
+/* Dec 20 1999 Doug Mink - Change cosd() and sind() to cosdeg() and sindeg()
+ * Dec 20 1999 Doug Mink - Include wcslib.h, which includes proj.h, wcsmath.h
+ * Dec 20 1999 Doug Mink - Define copysign only if it is not defined
+ * Dec 20 1999 Doug Mink - tanfwd() returns error if s<=0.0, not only if s==0.0
+ *
+ * Jun 2 2000 Doug Mink - include stdlib.h to get abs()
+ *
+ * Feb 15 2001 Doug Mink - update zearev() for WCSLIB 2.6
+ * Sep 19 2001 Doug Mink - Make above changes for WCSLIB 2.7
+ *
+ * Mar 15 2002 Doug Mink - Make above changes for WCSLIB 2.8.2
+ *
+ * Feb 3 2003 Doug Mink - Use locally defined copysgn() and copysgni(),
+ * not copysign()
+ * Apr 1 2003 Doug Mink - include string.h for strcpy() and strcmp()
+ *
+ * Mar 14 2011 Doug Mink - If no coefficients in ZPN, make ARC
+ * Mar 14 2011 Doug Mink - Add Emmanuel Bertin's TAN polynomial from Ed Los
+ */
diff --git a/funtools/wcs/slasubs.c b/funtools/wcs/slasubs.c
new file mode 100644
index 0000000..74ddb88
--- /dev/null
+++ b/funtools/wcs/slasubs.c
@@ -0,0 +1,364 @@
+/* File slasubs.c
+ *** Starlink subroutines by Patrick Wallace used by wcscon.c subroutines
+ *** April 13, 1998
+ */
+
+#include <math.h>
+#include <string.h>
+
+/* slaDcs2c (a, b, v): Spherical coordinates to direction cosines.
+ * slaDcc2s (v, a, b): Direction cosines to spherical coordinates.
+ * slaDmxv (dm, va, vb): vector vb = matrix dm * vector va
+ * slaImxv (rm, va, vb): vector vb = (inverse of matrix rm) * vector va
+ * slaDranrm (angle): Normalize angle into range 0-2 pi.
+ * slaDrange (angle): Normalize angle into range +/- pi.
+ * slaDeuler (order, phi, theta, psi, rmat)
+ * Form a rotation matrix from the Euler angles - three successive
+ * rotations about specified Cartesian axes.
+ */
+
+void
+slaDcs2c (a, b, v)
+
+double a; /* Right ascension in radians */
+double b; /* Declination in radians */
+double *v; /* x,y,z unit vector (returned) */
+
+/*
+** slaDcs2c: Spherical coordinates to direction cosines.
+**
+** The spherical coordinates are longitude (+ve anticlockwise
+** looking from the +ve latitude pole) and latitude. The
+** Cartesian coordinates are right handed, with the x axis
+** at zero longitude and latitude, and the z axis at the
+** +ve latitude pole.
+**
+** P.T.Wallace Starlink 31 October 1993
+*/
+{
+ double cosb;
+
+ cosb = cos ( b );
+ v[0] = cos ( a ) * cosb;
+ v[1] = sin ( a ) * cosb;
+ v[2] = sin ( b );
+}
+
+
+void
+slaDcc2s (v, a, b)
+
+double *v; /* x,y,z vector */
+double *a; /* Right ascension in radians */
+double *b; /* Declination in radians */
+
+/*
+** slaDcc2s:
+** Direction cosines to spherical coordinates.
+**
+** Returned:
+** *a,*b double spherical coordinates in radians
+**
+** The spherical coordinates are longitude (+ve anticlockwise
+** looking from the +ve latitude pole) and latitude. The
+** Cartesian coordinates are right handed, with the x axis
+** at zero longitude and latitude, and the z axis at the
+** +ve latitude pole.
+**
+** If v is null, zero a and b are returned.
+** At either pole, zero a is returned.
+**
+** P.T.Wallace Starlink 31 October 1993
+*/
+{
+ double x, y, z, r;
+
+ x = v[0];
+ y = v[1];
+ z = v[2];
+ r = sqrt ( x * x + y * y );
+
+ *a = ( r != 0.0 ) ? atan2 ( y, x ) : 0.0;
+ *b = ( z != 0.0 ) ? atan2 ( z, r ) : 0.0;
+}
+
+
+void
+slaDmxv (dm, va, vb)
+
+double (*dm)[3]; /* 3x3 Matrix */
+double *va; /* Vector */
+double *vb; /* Result vector (returned) */
+
+/*
+** slaDmxv:
+** Performs the 3-d forward unitary transformation:
+** vector vb = matrix dm * vector va
+**
+** P.T.Wallace Starlink 31 October 1993
+*/
+{
+ int i, j;
+ double w, vw[3];
+
+ /* Matrix dm * vector va -> vector vw */
+ for ( j = 0; j < 3; j++ ) {
+ w = 0.0;
+ for ( i = 0; i < 3; i++ ) {
+ w += dm[j][i] * va[i];
+ }
+ vw[j] = w;
+ }
+
+ /* Vector vw -> vector vb */
+ for ( j = 0; j < 3; j++ ) {
+ vb[j] = vw[j];
+ }
+}
+
+
+void slaDimxv (dm, va, vb)
+ double (*dm)[3];
+ double *va;
+ double *vb;
+/*
+** - - - - - - - - -
+** s l a D i m x v
+** - - - - - - - - -
+**
+** Performs the 3-d backward unitary transformation:
+**
+** vector vb = (inverse of matrix dm) * vector va
+**
+** (double precision)
+**
+** (n.b. The matrix must be unitary, as this routine assumes that
+** the inverse and transpose are identical)
+**
+**
+** Given:
+** dm double[3][3] matrix
+** va double[3] vector
+**
+** Returned:
+** vb double[3] result vector
+**
+** P.T.Wallace Starlink 31 October 1993
+*/
+{
+ long i, j;
+ double w, vw[3];
+
+/* Inverse of matrix dm * vector va -> vector vw */
+ for ( j = 0; j < 3; j++ ) {
+ w = 0.0;
+ for ( i = 0; i < 3; i++ ) {
+ w += dm[i][j] * va[i];
+ }
+ vw[j] = w;
+ }
+
+/* Vector vw -> vector vb */
+ for ( j = 0; j < 3; j++ ) {
+ vb[j] = vw[j];
+ }
+}
+
+
+/* 2pi */
+#define D2PI 6.2831853071795864769252867665590057683943387987502
+
+/* pi */
+#define DPI 3.1415926535897932384626433832795028841971693993751
+
+double slaDranrm (angle)
+
+double angle; /* angle in radians */
+
+/*
+** slaDranrm:
+** Normalize angle into range 0-2 pi.
+** The result is angle expressed in the range 0-2 pi (double).
+** Defined in slamac.h: D2PI
+**
+** P.T.Wallace Starlink 30 October 1993
+*/
+{
+ double w;
+
+ w = fmod ( angle, D2PI );
+ return ( w >= 0.0 ) ? w : w + D2PI;
+}
+
+#ifndef dsign
+#define dsign(A,B) ((B)<0.0?-(A):(A))
+#endif
+
+double
+slaDrange (angle)
+ double angle;
+/*
+** - - - - - - - - - -
+** s l a D r a n g e
+** - - - - - - - - - -
+**
+** Normalize angle into range +/- pi.
+**
+** (double precision)
+**
+** Given:
+** angle double the angle in radians
+**
+** The result is angle expressed in the +/- pi (double precision).
+**
+** Defined in slamac.h: DPI, D2PI
+**
+** P.T.Wallace Starlink 31 October 1993
+*/
+{
+ double w;
+
+ w = fmod ( angle, D2PI );
+ return ( fabs ( w ) < DPI ) ? w : w - dsign ( D2PI, angle );
+}
+
+
+void
+slaDeuler (order, phi, theta, psi, rmat)
+
+char *order; /* specifies about which axes the rotations occur */
+double phi; /* 1st rotation (radians) */
+double theta; /* 2nd rotation (radians) */
+double psi; /* 3rd rotation (radians) */
+double (*rmat)[3]; /* 3x3 Rotation matrix (returned) */
+
+/*
+** slaDeuler:
+** Form a rotation matrix from the Euler angles - three successive
+** rotations about specified Cartesian axes.
+**
+** A rotation is positive when the reference frame rotates
+** anticlockwise as seen looking towards the origin from the
+** positive region of the specified axis.
+**
+** The characters of order define which axes the three successive
+** rotations are about. A typical value is 'zxz', indicating that
+** rmat is to become the direction cosine matrix corresponding to
+** rotations of the reference frame through phi radians about the
+** old z-axis, followed by theta radians about the resulting x-axis,
+** then psi radians about the resulting z-axis.
+**
+** The axis names can be any of the following, in any order or
+** combination: x, y, z, uppercase or lowercase, 1, 2, 3. Normal
+** axis labelling/numbering conventions apply; the xyz (=123)
+** triad is right-handed. Thus, the 'zxz' example given above
+** could be written 'zxz' or '313' (or even 'zxz' or '3xz'). Order
+** is terminated by length or by the first unrecognised character.
+**
+** Fewer than three rotations are acceptable, in which case the later
+** angle arguments are ignored. Zero rotations produces a unit rmat.
+**
+** P.T.Wallace Starlink 17 November 1993
+*/
+{
+ int j, i, l, n, k;
+ double result[3][3], rotn[3][3], angle, s, c , w, wm[3][3];
+ char axis;
+
+/* Initialize result matrix */
+ for ( j = 0; j < 3; j++ ) {
+ for ( i = 0; i < 3; i++ ) {
+ result[i][j] = ( i == j ) ? 1.0 : 0.0;
+ }
+ }
+
+/* Establish length of axis string */
+ l = strlen ( order );
+
+/* Look at each character of axis string until finished */
+ for ( n = 0; n < 3; n++ ) {
+ if ( n <= l ) {
+
+ /* Initialize rotation matrix for the current rotation */
+ for ( j = 0; j < 3; j++ ) {
+ for ( i = 0; i < 3; i++ ) {
+ rotn[i][j] = ( i == j ) ? 1.0 : 0.0;
+ }
+ }
+
+ /* Pick up the appropriate Euler angle and take sine & cosine */
+ switch ( n ) {
+ case 0 :
+ angle = phi;
+ break;
+ case 1 :
+ angle = theta;
+ break;
+ case 2 :
+ angle = psi;
+ break;
+ }
+ s = sin ( angle );
+ c = cos ( angle );
+
+ /* Identify the axis */
+ axis = order[n];
+ if ( ( axis == 'X' ) || ( axis == 'x' ) || ( axis == '1' ) ) {
+
+ /* Matrix for x-rotation */
+ rotn[1][1] = c;
+ rotn[1][2] = s;
+ rotn[2][1] = -s;
+ rotn[2][2] = c;
+ }
+ else if ( ( axis == 'Y' ) || ( axis == 'y' ) || ( axis == '2' ) ) {
+
+ /* Matrix for y-rotation */
+ rotn[0][0] = c;
+ rotn[0][2] = -s;
+ rotn[2][0] = s;
+ rotn[2][2] = c;
+ }
+ else if ( ( axis == 'Z' ) || ( axis == 'z' ) || ( axis == '3' ) ) {
+
+ /* Matrix for z-rotation */
+ rotn[0][0] = c;
+ rotn[0][1] = s;
+ rotn[1][0] = -s;
+ rotn[1][1] = c;
+ } else {
+
+ /* Unrecognized character - fake end of string */
+ l = 0;
+ }
+
+ /* Apply the current rotation (matrix rotn x matrix result) */
+ for ( i = 0; i < 3; i++ ) {
+ for ( j = 0; j < 3; j++ ) {
+ w = 0.0;
+ for ( k = 0; k < 3; k++ ) {
+ w += rotn[i][k] * result[k][j];
+ }
+ wm[i][j] = w;
+ }
+ }
+ for ( j = 0; j < 3; j++ ) {
+ for ( i= 0; i < 3; i++ ) {
+ result[i][j] = wm[i][j];
+ }
+ }
+ }
+ }
+
+/* Copy the result */
+ for ( j = 0; j < 3; j++ ) {
+ for ( i = 0; i < 3; i++ ) {
+ rmat[i][j] = result[i][j];
+ }
+ }
+}
+/*
+ * Nov 4 1996 New file
+ *
+ * Apr 13 1998 Add list of subroutines to start of file
+ */
diff --git a/funtools/wcs/sph.c b/funtools/wcs/sph.c
new file mode 100644
index 0000000..b8ba23d
--- /dev/null
+++ b/funtools/wcs/sph.c
@@ -0,0 +1,234 @@
+/*============================================================================
+*
+* WCSLIB - an implementation of the FITS WCS proposal.
+* Copyright (C) 1995-2002, Mark Calabretta
+*
+* This library 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 2 of the License, or (at your option) any later version.
+*
+* This library 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 this library; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*
+* Correspondence concerning WCSLIB may be directed to:
+* Internet email: mcalabre@atnf.csiro.au
+* Postal address: Dr. Mark Calabretta,
+* Australia Telescope National Facility,
+* P.O. Box 76,
+* Epping, NSW, 2121,
+* AUSTRALIA
+*
+*=============================================================================
+*
+* C routines for the spherical coordinate transformations used by the FITS
+* "World Coordinate System" (WCS) convention.
+*
+* Summary of routines
+* -------------------
+* The spherical coordinate transformations are implemented via separate
+* functions for the transformation in each direction.
+*
+* Forward transformation; sphfwd()
+* --------------------------------
+* Transform celestial coordinates to the native coordinates of a projection.
+*
+* Given:
+* lng,lat double Celestial longitude and latitude, in degrees.
+* eul[5] double Euler angles for the transformation:
+* 0: Celestial longitude of the native pole, in
+* degrees.
+* 1: Celestial colatitude of the native pole, or
+* native colatitude of the celestial pole, in
+* degrees.
+* 2: Native longitude of the celestial pole, in
+* degrees.
+* 3: cos(eul[1])
+* 4: sin(eul[1])
+*
+* Returned:
+* phi, double Longitude and latitude in the native coordinate
+* theta system of the projection, in degrees.
+*
+* Function return value:
+* int Error status
+* 0: Success.
+*
+* Reverse transformation; sphrev()
+* --------------------------------
+* Transform native coordinates of a projection to celestial coordinates.
+*
+* Given:
+* phi, double Longitude and latitude in the native coordinate
+* theta system of the projection, in degrees.
+* eul[5] double Euler angles for the transformation:
+* 0: Celestial longitude of the native pole, in
+* degrees.
+* 1: Celestial colatitude of the native pole, or
+* native colatitude of the celestial pole, in
+* degrees.
+* 2: Native longitude of the celestial pole, in
+* degrees.
+* 3: cos(eul[1])
+* 4: sin(eul[1])
+*
+* Returned:
+* lng,lat double Celestial longitude and latitude, in degrees.
+*
+* Function return value:
+* int Error status
+* 0: Success.
+*
+* Author: Mark Calabretta, Australia Telescope National Facility
+* $Id: sph.c,v 2.7 2002/04/03 01:25:29 mcalabre Exp $
+*===========================================================================*/
+
+#include <math.h>
+#include "wcslib.h"
+
+#ifndef __STDC__
+#ifndef const
+#define const
+#endif
+#endif
+
+const double tol = 1.0e-5;
+
+int sphfwd (lng, lat, eul, phi, theta)
+
+const double lat, lng, eul[5];
+double *phi, *theta;
+
+{
+ double coslat, coslng, dlng, dphi, sinlat, sinlng, x, y, z;
+
+ coslat = cosdeg (lat);
+ sinlat = sindeg (lat);
+
+ dlng = lng - eul[0];
+ coslng = cosdeg (dlng);
+ sinlng = sindeg (dlng);
+
+ /* Compute the native longitude. */
+ x = sinlat*eul[4] - coslat*eul[3]*coslng;
+ if (fabs(x) < tol) {
+ /* Rearrange formula to reduce roundoff errors. */
+ x = -cosdeg (lat+eul[1]) + coslat*eul[3]*(1.0 - coslng);
+ }
+ y = -coslat*sinlng;
+ if (x != 0.0 || y != 0.0) {
+ dphi = atan2deg (y, x);
+ } else {
+ /* Change of origin of longitude. */
+ dphi = dlng - 180.0;
+ }
+ *phi = eul[2] + dphi;
+
+ /* Normalize the native longitude. */
+ if (*phi > 180.0) {
+ *phi -= 360.0;
+ } else if (*phi < -180.0) {
+ *phi += 360.0;
+ }
+
+ /* Compute the native latitude. */
+ if (fmod(dlng,180.0) == 0.0) {
+ *theta = lat + coslng*eul[1];
+ if (*theta > 90.0) *theta = 180.0 - *theta;
+ if (*theta < -90.0) *theta = -180.0 - *theta;
+ } else {
+ z = sinlat*eul[3] + coslat*eul[4]*coslng;
+ /* Use an alternative formula for greater numerical accuracy. */
+ if (fabs(z) > 0.99) {
+ if (z < 0)
+ *theta = -acosdeg (sqrt(x*x+y*y));
+ else
+ *theta = acosdeg (sqrt(x*x+y*y));
+ } else {
+ *theta = asindeg (z);
+ }
+ }
+
+ return 0;
+}
+
+/*-----------------------------------------------------------------------*/
+
+int sphrev (phi, theta, eul, lng, lat)
+
+const double phi, theta, eul[5];
+double *lng, *lat;
+
+{
+ double cosphi, costhe, dlng, dphi, sinphi, sinthe, x, y, z;
+
+ costhe = cosdeg (theta);
+ sinthe = sindeg (theta);
+
+ dphi = phi - eul[2];
+ cosphi = cosdeg (dphi);
+ sinphi = sindeg (dphi);
+
+ /* Compute the celestial longitude. */
+ x = sinthe*eul[4] - costhe*eul[3]*cosphi;
+ if (fabs(x) < tol) {
+ /* Rearrange formula to reduce roundoff errors. */
+ x = -cosdeg (theta+eul[1]) + costhe*eul[3]*(1.0 - cosphi);
+ }
+ y = -costhe*sinphi;
+ if (x != 0.0 || y != 0.0) {
+ dlng = atan2deg (y, x);
+ } else {
+ /* Change of origin of longitude. */
+ dlng = dphi + 180.0;
+ }
+ *lng = eul[0] + dlng;
+
+ /* Normalize the celestial longitude. */
+ if (eul[0] >= 0.0) {
+ if (*lng < 0.0) *lng += 360.0;
+ } else {
+ if (*lng > 0.0) *lng -= 360.0;
+ }
+
+ if (*lng > 360.0) {
+ *lng -= 360.0;
+ } else if (*lng < -360.0) {
+ *lng += 360.0;
+ }
+
+ /* Compute the celestial latitude. */
+ if (fmod(dphi,180.0) == 0.0) {
+ *lat = theta + cosphi*eul[1];
+ if (*lat > 90.0) *lat = 180.0 - *lat;
+ if (*lat < -90.0) *lat = -180.0 - *lat;
+ } else {
+ z = sinthe*eul[3] + costhe*eul[4]*cosphi;
+
+ /* Use an alternative formula for greater numerical accuracy. */
+ if (fabs(z) > 0.99) {
+ if (z < 0)
+ *lat = -acosdeg (sqrt(x*x+y*y));
+ else
+ *lat = acosdeg (sqrt(x*x+y*y));
+ } else {
+ *lat = asindeg (z);
+ }
+ }
+
+ return 0;
+}
+/* Dec 20 1999 Doug Mink - Change cosd() and sind() to cosdeg() and sindeg()
+ * Dec 20 1999 Doug Mink - Include wcslib.h, which includes wcstrig.h, sph.h
+ * Dec 20 1999 Doug Mink - Define copysign only if it is not already defined
+ *
+ * Jan 5 2000 Doug Mink - Drop copysign
+ *
+ * Sep 19 2001 Doug Mink - No change for WCSLIB 2.7
+ */
diff --git a/funtools/wcs/tnxpos.c b/funtools/wcs/tnxpos.c
new file mode 100644
index 0000000..e13d78e
--- /dev/null
+++ b/funtools/wcs/tnxpos.c
@@ -0,0 +1,1234 @@
+/*** File wcslib/tnxpos.c
+ *** September 17, 2008
+ *** By Jessica Mink, jmink@cfa.harvard.edu
+ *** Harvard-Smithsonian Center for Astrophysics
+ *** After IRAF mwcs/wftnx.x and mwcs/wfgsurfit.x
+ *** Copyright (C) 1998-2008
+ *** Smithsonian Astrophysical Observatory, Cambridge, MA, USA
+
+ This library 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 2 of the License, or (at your option) any later version.
+
+ This library 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 this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Correspondence concerning WCSTools should be addressed as follows:
+ Internet email: jmink@cfa.harvard.edu
+ Postal address: Jessica Mink
+ Smithsonian Astrophysical Observatory
+ 60 Garden St.
+ Cambridge, MA 02138 USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include "wcs.h"
+
+#define SPHTOL 0.00001
+#define BADCVAL 0.0
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+
+/* wftnx -- wcs function driver for the gnomonic projection with correction.
+ * tnxinit (header, wcs)
+ * tnxclose (wcs)
+ * tnxfwd (xpix, ypix, wcs, xpos, ypos) Pixels to WCS
+ * tnxrev (xpos, ypos, wcs, xpix, ypix) WCS to pixels
+ */
+
+#define max_niter 500
+#define SZ_ATSTRING 2000
+static void wf_gsclose();
+static void wf_gsb1pol();
+static void wf_gsb1leg();
+static void wf_gsb1cheb();
+
+/* tnxinit -- initialize the gnomonic forward or inverse transform.
+ * initialization for this transformation consists of, determining which
+ * axis is ra / lon and which is dec / lat, computing the celestial longitude
+ * and colatitude of the native pole, reading in the the native longitude
+ * of the pole of the celestial coordinate system longpole from the attribute
+ * list, precomputing euler angles and various intermediaries derived from the
+ * coordinate reference values, and reading in the projection parameter ro
+ * from the attribute list. if longpole is undefined then a value of 180.0
+ * degrees is assumed. if ro is undefined a value of 180.0 / pi is assumed.
+ * the tan projection is equivalent to the azp projection with mu set to 0.0.
+ * in order to determine the axis order, the parameter "axtype={ra|dec}
+ * {xlon|glat}{xlon|elat}" must have been set in the attribute list for the
+ * function. the longpole and ro parameters may be set in either or both of
+ * the axes attribute lists, but the value in the ra axis attribute list takes
+ * precedence.
+ */
+
+int
+tnxinit (header, wcs)
+
+const char *header; /* FITS header */
+struct WorldCoor *wcs; /* pointer to WCS structure */
+{
+ struct IRAFsurface *wf_gsopen();
+ char *str1, *str2, *lngstr, *latstr;
+ extern void wcsrotset();
+
+ /* allocate space for the attribute strings */
+ str1 = malloc (SZ_ATSTRING);
+ str2 = malloc (SZ_ATSTRING);
+ hgetm (header, "WAT1", SZ_ATSTRING, str1);
+ hgetm (header, "WAT2", SZ_ATSTRING, str2);
+
+ lngstr = malloc (SZ_ATSTRING);
+ latstr = malloc (SZ_ATSTRING);
+
+ /* determine the native longitude of the pole of the celestial
+ coordinate system corresponding to the FITS keyword longpole.
+ this number has no default and should normally be set to 180
+ degrees. search both axes for this quantity. */
+
+ if (wcs->longpole > 360.0) {
+ if (!igetr8 (str1, "longpole", &wcs->longpole)) {
+ if (!igetr8 (str2, "longpole", &wcs->longpole))
+ wcs->longpole = 180.0;
+ }
+ }
+
+ /* Fetch the ro projection parameter which is the radius of the
+ generating sphere for the projection. if ro is absent which
+ is the usual case set it to 180 / pi. search both axes for
+ this quantity. */
+
+ if (!igetr8 (str1, "ro", &wcs->rodeg)) {
+ if (!igetr8 (str2, "ro", &wcs->rodeg))
+ wcs->rodeg = 180.0 / PI;
+ }
+
+ /* Fetch the longitude correction surface. note that the attribute
+ string may be of any length so the length of atvalue may have
+ to be adjusted. */
+
+ if (!igets (str1, "lngcor", SZ_ATSTRING, lngstr)) {
+ if (!igets (str2, "lngcor", SZ_ATSTRING, lngstr))
+ wcs->lngcor = NULL;
+ else
+ wcs->lngcor = wf_gsopen (lngstr);
+ }
+ else
+ wcs->lngcor = wf_gsopen (lngstr);
+
+ /* Fetch the latitude correction surface. note that the attribute
+ string may be of any length so the length of atvalue may have
+ to be adjusted. */
+
+ if (!igets (str2, "latcor", SZ_ATSTRING, latstr)) {
+ if (!igets (str1, "latcor", SZ_ATSTRING, latstr))
+ wcs->latcor = NULL;
+ else
+ wcs->latcor = wf_gsopen (latstr);
+ }
+ else
+ wcs->latcor = wf_gsopen (latstr);
+
+ /* Compute image rotation */
+ wcsrotset (wcs);
+
+ /* free working space. */
+ free (str1);
+ free (str2);
+ free (lngstr);
+ free (latstr);
+
+ /* Return 1 if there are no correction coefficients */
+ if (wcs->latcor == NULL && wcs->lngcor == NULL)
+ return (1);
+ else
+ return (0);
+}
+
+
+/* tnxpos -- forward transform (physical to world) gnomonic projection. */
+
+int
+tnxpos (xpix, ypix, wcs, xpos, ypos)
+
+double xpix, ypix; /*i physical coordinates (x, y) */
+struct WorldCoor *wcs; /*i pointer to WCS descriptor */
+double *xpos, *ypos; /*o world coordinates (ra, dec) */
+{
+ int ira, idec;
+ double x, y, r, phi, theta, costhe, sinthe, dphi, cosphi, sinphi, dlng, z;
+ double colatp, coslatp, sinlatp, longp;
+ double xs, ys, ra, dec, xp, yp;
+ double wf_gseval();
+
+ /* Convert from pixels to image coordinates */
+ xpix = xpix - wcs->crpix[0];
+ ypix = ypix - wcs->crpix[1];
+
+ /* Scale and rotate using CD matrix */
+ if (wcs->rotmat) {
+ x = xpix * wcs->cd[0] + ypix * wcs->cd[1];
+ y = xpix * wcs->cd[2] + ypix * wcs->cd[3];
+ }
+
+ else {
+
+ /* Check axis increments - bail out if either 0 */
+ if (wcs->cdelt[0] == 0.0 || wcs->cdelt[1] == 0.0) {
+ *xpos = 0.0;
+ *ypos = 0.0;
+ return 2;
+ }
+
+ /* Scale using CDELT */
+ xs = xpix * wcs->cdelt[0];
+ ys = ypix * wcs->cdelt[1];
+
+ /* Take out rotation from CROTA */
+ if (wcs->rot != 0.0) {
+ double cosr = cos (degrad (wcs->rot));
+ double sinr = sin (degrad (wcs->rot));
+ x = xs * cosr - ys * sinr;
+ y = xs * sinr + ys * cosr;
+ }
+ else {
+ x = xs;
+ y = ys;
+ }
+ }
+
+ /* get the axis numbers */
+ if (wcs->coorflip) {
+ ira = 1;
+ idec = 0;
+ }
+ else {
+ ira = 0;
+ idec = 1;
+ }
+ colatp = degrad (90.0 - wcs->crval[idec]);
+ coslatp = cos(colatp);
+ sinlatp = sin(colatp);
+ longp = degrad(wcs->longpole);
+
+ /* Compute native spherical coordinates phi and theta in degrees from the
+ projected coordinates. this is the projection part of the computation */
+ if (wcs->lngcor != NULL)
+ xp = x + wf_gseval (wcs->lngcor, x, y);
+ else
+ xp = x;
+ if (wcs->latcor != NULL)
+ yp = y + wf_gseval (wcs->latcor, x, y);
+ else
+ yp = y;
+ x = xp;
+ y = yp;
+ r = sqrt (x * x + y * y);
+
+ /* Compute phi */
+ if (r == 0.0)
+ phi = 0.0;
+ else
+ phi = atan2 (x, -y);
+
+ /* Compute theta */
+ theta = atan2 (wcs->rodeg, r);
+
+ /* Compute the celestial coordinates ra and dec from the native
+ coordinates phi and theta. this is the spherical geometry part
+ of the computation */
+
+ costhe = cos (theta);
+ sinthe = sin (theta);
+ dphi = phi - longp;
+ cosphi = cos (dphi);
+ sinphi = sin (dphi);
+
+ /* Compute the ra */
+ x = sinthe * sinlatp - costhe * coslatp * cosphi;
+ if (fabs (x) < SPHTOL)
+ x = -cos (theta + colatp) + costhe * coslatp * (1.0 - cosphi);
+ y = -costhe * sinphi;
+ if (x != 0.0 || y != 0.0)
+ dlng = atan2 (y, x);
+ else
+ dlng = dphi + PI ;
+ ra = wcs->crval[ira] + raddeg(dlng);
+
+ /* normalize ra */
+ if (wcs->crval[ira] >= 0.0) {
+ if (ra < 0.0)
+ ra = ra + 360.0;
+ }
+ else {
+ if (ra > 0.0)
+ ra = ra - 360.0;
+ }
+ if (ra > 360.0)
+ ra = ra - 360.0;
+ else if (ra < -360.0)
+ ra = ra + 360.0;
+
+ /* compute the dec */
+ if (fmod (dphi, PI) == 0.0) {
+ dec = raddeg(theta + cosphi * colatp);
+ if (dec > 90.0)
+ dec = 180.0 - dec;
+ if (dec < -90.0)
+ dec = -180.0 - dec;
+ }
+ else {
+ z = sinthe * coslatp + costhe * sinlatp * cosphi;
+ if (fabs(z) > 0.99) {
+ if (z >= 0.0)
+ dec = raddeg(acos (sqrt(x * x + y * y)));
+ else
+ dec = raddeg(-acos (sqrt(x * x + y * y)));
+ }
+ else
+ dec = raddeg(asin (z));
+ }
+
+ /* store the results */
+ *xpos = ra;
+ *ypos = dec;
+ return (0);
+}
+
+
+/* tnxpix -- inverse transform (world to physical) gnomonic projection */
+
+int
+tnxpix (xpos, ypos, wcs, xpix, ypix)
+
+double xpos, ypos; /*i world coordinates (ra, dec) */
+struct WorldCoor *wcs; /*i pointer to WCS descriptor */
+double *xpix, *ypix; /*o physical coordinates (x, y) */
+{
+ int ira, idec, niter;
+ double ra, dec, cosdec, sindec, cosra, sinra, x, y, phi, theta;
+ double s, r, dphi, z, dpi, dhalfpi, twopi, tx;
+ double xm, ym, f, fx, fy, g, gx, gy, denom, dx, dy;
+ double colatp, coslatp, sinlatp, longp, sphtol;
+ double wf_gseval(), wf_gsder();
+
+ /* get the axis numbers */
+ if (wcs->coorflip) {
+ ira = 1;
+ idec = 0;
+ }
+ else {
+ ira = 0;
+ idec = 1;
+ }
+
+ /* Compute the transformation from celestial coordinates ra and
+ dec to native coordinates phi and theta. this is the spherical
+ geometry part of the transformation */
+
+ ra = degrad (xpos - wcs->crval[ira]);
+ dec = degrad (ypos);
+ cosra = cos (ra);
+ sinra = sin (ra);
+ cosdec = cos (dec);
+ sindec = sin (dec);
+ colatp = degrad (90.0 - wcs->crval[idec]);
+ coslatp = cos (colatp);
+ sinlatp = sin (colatp);
+ if (wcs->longpole == 999.0)
+ longp = degrad (180.0);
+ else
+ longp = degrad(wcs->longpole);
+ dpi = PI;
+ dhalfpi = dpi * 0.5;
+ twopi = PI + PI;
+ sphtol = SPHTOL;
+
+ /* Compute phi */
+ x = sindec * sinlatp - cosdec * coslatp * cosra;
+ if (fabs(x) < sphtol)
+ x = -cos (dec + colatp) + cosdec * coslatp * (1.0 - cosra);
+ y = -cosdec * sinra;
+ if (x != 0.0 || y != 0.0)
+ dphi = atan2 (y, x);
+ else
+ dphi = ra - dpi;
+ phi = longp + dphi;
+ if (phi > dpi)
+ phi = phi - twopi;
+ else if (phi < -dpi)
+ phi = phi + twopi;
+
+ /* Compute theta */
+ if (fmod (ra, dpi) == 0.0) {
+ theta = dec + cosra * colatp;
+ if (theta > dhalfpi)
+ theta = dpi - theta;
+ if (theta < -dhalfpi)
+ theta = -dpi - theta;
+ }
+ else {
+ z = sindec * coslatp + cosdec * sinlatp * cosra;
+ if (fabs (z) > 0.99) {
+ if (z >= 0.0)
+ theta = acos (sqrt(x * x + y * y));
+ else
+ theta = -acos (sqrt(x * x + y * y));
+ }
+ else
+ theta = asin (z);
+ }
+
+ /* Compute the transformation from native coordinates phi and theta
+ to projected coordinates x and y */
+
+ s = sin (theta);
+ if (s == 0.0) {
+ x = BADCVAL;
+ y = BADCVAL;
+ }
+ else {
+ r = wcs->rodeg * cos (theta) / s;
+ if (wcs->lngcor == NULL && wcs->latcor == NULL) {
+ if (wcs->coorflip) {
+ y = r * sin (phi);
+ x = -r * cos (phi);
+ }
+ else {
+ x = r * sin (phi);
+ y = -r * cos (phi);
+ }
+ }
+ else {
+ xm = r * sin (phi);
+ ym = -r * cos (phi);
+ x = xm;
+ y = ym;
+ niter = 0;
+ while (niter < max_niter) {
+ if (wcs->lngcor != NULL) {
+ f = x + wf_gseval (wcs->lngcor, x, y) - xm;
+ fx = wf_gsder (wcs->lngcor, x, y, 1, 0);
+ fx = 1.0 + fx;
+ fy = wf_gsder (wcs->lngcor, x, y, 0, 1);
+ }
+ else {
+ f = x - xm;
+ fx = 1.0 ;
+ fy = 0.0;
+ }
+ if (wcs->latcor != NULL) {
+ g = y + wf_gseval (wcs->latcor, x, y) - ym;
+ gx = wf_gsder (wcs->latcor, x, y, 1, 0);
+ gy = wf_gsder (wcs->latcor, x, y, 0, 1);
+ gy = 1.0 + gy;
+ }
+ else {
+ g = y - ym;
+ gx = 0.0 ;
+ gy = 1.0;
+ }
+
+ denom = fx * gy - fy * gx;
+ if (denom == 0.0)
+ break;
+ dx = (-f * gy + g * fy) / denom;
+ dy = (-g * fx + f * gx) / denom;
+ x = x + dx;
+ y = y + dy;
+ if (MAX(MAX(fabs(dx),fabs(dy)),MAX(fabs(f),fabs(g))) < 2.80e-8)
+ break;
+
+ niter = niter + 1;
+ }
+
+ /* Reverse x and y if axes flipped */
+ if (wcs->coorflip) {
+ tx = x;
+ x = y;
+ y = tx;
+ }
+ }
+ }
+
+ /* Scale and rotate using CD matrix */
+ if (wcs->rotmat) {
+ *xpix = x * wcs->dc[0] + y * wcs->dc[1];
+ *ypix = x * wcs->dc[2] + y * wcs->dc[3];
+ }
+
+ else {
+
+ /* Correct for rotation */
+ if (wcs->rot!=0.0) {
+ double cosr = cos (degrad (wcs->rot));
+ double sinr = sin (degrad (wcs->rot));
+ *xpix = x * cosr + y * sinr;
+ *ypix = y * cosr - x * sinr;
+ }
+ else {
+ *xpix = x;
+ *ypix = y;
+ }
+
+ /* Scale using CDELT */
+ if (wcs->xinc != 0.)
+ *xpix = *xpix / wcs->xinc;
+ if (wcs->yinc != 0.)
+ *ypix = *ypix / wcs->yinc;
+ }
+
+ /* Convert to pixels */
+ *xpix = *xpix + wcs->xrefpix;
+ *ypix = *ypix + wcs->yrefpix;
+
+ return (0);
+}
+
+
+/* TNXCLOSE -- free up the distortion surface pointers */
+
+void
+tnxclose (wcs)
+
+struct WorldCoor *wcs; /* pointer to the WCS descriptor */
+
+{
+ if (wcs->lngcor != NULL)
+ wf_gsclose (wcs->lngcor);
+ if (wcs->latcor != NULL)
+ wf_gsclose (wcs->latcor);
+ return;
+}
+
+/* copyright(c) 1986 association of universities for research in astronomy inc.
+ * wfgsurfit.x -- surface fitting package used by wcs function drivers.
+ * Translated to C from SPP by Jessica Mink, SAO, May 26, 1998
+ *
+ * the following routines are used by the experimental function drivers tnx
+ * and zpx to decode polynomial fits stored in the image header in the form
+ * of a list of parameters and coefficients into surface descriptors in
+ * ra / dec or longitude latitude. the polynomial surfaces so encoded consist
+ * of corrections to function drivers tan and zpn. the package routines are
+ * modelled after the equivalent gsurfit routines and are consistent with them.
+ * the routines are:
+ *
+ * sf = wf_gsopen (wattstr)
+ * wf_gsclose (sf)
+ *
+ * z = wf_gseval (sf, x, y)
+ * ncoeff = wf_gscoeff (sf, coeff)
+ * zder = wf_gsder (sf, x, y, nxder, nyder)
+ *
+ * wf_gsopen is used to open a surface fit encoded in a wcs attribute, returning
+ * the sf surface fitting descriptor. wf_gsclose should be called later to free
+ * the descriptor. wf_gseval is called to evaluate the surface at a point.
+ */
+
+
+#define SZ_GSCOEFFBUF 20
+
+/* define the structure elements for the wf_gsrestore task */
+#define TNX_SAVETYPE 0
+#define TNX_SAVEXORDER 1
+#define TNX_SAVEYORDER 2
+#define TNX_SAVEXTERMS 3
+#define TNX_SAVEXMIN 4
+#define TNX_SAVEXMAX 5
+#define TNX_SAVEYMIN 6
+#define TNX_SAVEYMAX 7
+#define TNX_SAVECOEFF 8
+
+
+/* wf_gsopen -- decode the longitude / latitude or ra / dec mwcs attribute
+ * and return a gsurfit compatible surface descriptor.
+ */
+
+struct IRAFsurface *
+wf_gsopen (astr)
+
+char *astr; /* the input mwcs attribute string */
+
+{
+ double dval;
+ char *estr;
+ int npar, szcoeff;
+ double *coeff;
+ struct IRAFsurface *gs;
+ struct IRAFsurface *wf_gsrestore();
+
+ if (astr[1] == 0)
+ return (NULL);
+
+ gs = NULL;
+ npar = 0;
+ szcoeff = SZ_GSCOEFFBUF;
+ coeff = (double *) malloc (szcoeff * sizeof (double));
+
+ estr = astr;
+ while (*estr != (char) 0) {
+ dval = strtod (astr, &estr);
+ if (*estr == '.')
+ estr++;
+ if (*estr != (char) 0) {
+ npar++;
+ if (npar >= szcoeff) {
+ szcoeff = szcoeff + SZ_GSCOEFFBUF;
+ coeff = (double *) realloc (coeff, (szcoeff * sizeof (double)));
+ }
+ coeff[npar-1] = dval;
+ astr = estr;
+ while (*astr == ' ') astr++;
+ }
+ }
+
+ gs = wf_gsrestore (coeff);
+
+ free (coeff);
+
+ if (npar == 0)
+ return (NULL);
+ else
+ return (gs);
+}
+
+
+/* wf_gsclose -- procedure to free the surface descriptor */
+
+static void
+wf_gsclose (sf)
+
+struct IRAFsurface *sf; /* the surface descriptor */
+
+{
+ if (sf != NULL) {
+ if (sf->xbasis != NULL)
+ free (sf->xbasis);
+ if (sf->ybasis != NULL)
+ free (sf->ybasis);
+ if (sf->coeff != NULL)
+ free (sf->coeff);
+ free (sf);
+ }
+ return;
+}
+
+
+/* wf_gseval -- procedure to evaluate the fitted surface at a single point.
+ * the wf->ncoeff coefficients are stored in the vector pointed to by sf->coeff.
+ */
+
+double
+wf_gseval (sf, x, y)
+
+struct IRAFsurface *sf; /* pointer to surface descriptor structure */
+double x; /* x value */
+double y; /* y value */
+{
+ double sum, accum;
+ int i, ii, k, maxorder, xorder;
+
+ /* Calculate the basis functions */
+ switch (sf->type) {
+ case TNX_CHEBYSHEV:
+ wf_gsb1cheb (x, sf->xorder, sf->xmaxmin, sf->xrange, sf->xbasis);
+ wf_gsb1cheb (y, sf->yorder, sf->ymaxmin, sf->yrange, sf->ybasis);
+ break;
+ case TNX_LEGENDRE:
+ wf_gsb1leg (x, sf->xorder, sf->xmaxmin, sf->xrange, sf->xbasis);
+ wf_gsb1leg (y, sf->yorder, sf->ymaxmin, sf->yrange, sf->ybasis);
+ break;
+ case TNX_POLYNOMIAL:
+ wf_gsb1pol (x, sf->xorder, sf->xbasis);
+ wf_gsb1pol (y, sf->yorder, sf->ybasis);
+ break;
+ default:
+ fprintf (stderr,"TNX_GSEVAL: unknown surface type\n");
+ return (0.0);
+ }
+
+ /* Initialize accumulator basis functions */
+ sum = 0.0;
+
+ /* Loop over y basis functions */
+ if (sf->xorder > sf->yorder)
+ maxorder = sf->xorder + 1;
+ else
+ maxorder = sf->yorder + 1;
+ xorder = sf->xorder;
+ ii = 0;
+
+ for (i = 0; i < sf->yorder; i++) {
+
+ /* Loop over the x basis functions */
+ accum = 0.0;
+ for (k = 0; k < xorder; k++) {
+ accum = accum + sf->coeff[ii] * sf->xbasis[k];
+ ii = ii + 1;
+ }
+ accum = accum * sf->ybasis[i];
+ sum = sum + accum;
+
+ /* Elements of the coefficient vector where neither k = 1 or i = 1
+ are not calculated if sf->xterms = no. */
+ if (sf->xterms == TNX_XNONE)
+ xorder = 1;
+ else if (sf->xterms == TNX_XHALF) {
+ if ((i + 1 + sf->xorder + 1) > maxorder)
+ xorder = xorder - 1;
+ }
+ }
+
+ return (sum);
+}
+
+
+/* TNX_GSCOEFF -- procedure to fetch the number and magnitude of the coefficients
+ * if the sf->xterms = wf_xbi (yes) then the number of coefficients will be
+ * (sf->xorder * sf->yorder); if wf_xterms is wf_xtri then the number
+ * of coefficients will be (sf->xorder * sf->yorder - order *
+ * (order - 1) / 2) where order is the minimum of the x and yorders; if
+ * sf->xterms = TNX_XNONE then the number of coefficients will be
+ * (sf->xorder + sf->yorder - 1).
+ */
+
+int
+wf_gscoeff (sf, coeff)
+
+struct IRAFsurface *sf; /* pointer to the surface fitting descriptor */
+double *coeff; /* the coefficients of the fit */
+
+{
+ int ncoeff; /* the number of coefficients */
+ int i;
+
+ /* Exctract coefficients from data structure and calculate their number */
+ ncoeff = sf->ncoeff;
+ for (i = 0; i < ncoeff; i++)
+ coeff[i] = sf->coeff[i];
+ return (ncoeff);
+}
+
+
+static double *coeff = NULL;
+static int nbcoeff = 0;
+
+/* wf_gsder -- procedure to calculate a new surface which is a derivative of
+ * the input surface.
+ */
+
+double
+wf_gsder (sf1, x, y, nxd, nyd)
+
+struct IRAFsurface *sf1; /* pointer to the previous surface */
+double x; /* x values */
+double y; /* y values */
+int nxd, nyd; /* order of the derivatives in x and y */
+{
+ int nxder, nyder, i, j, k, nbytes;
+ int order, maxorder1, maxorder2, nmove1, nmove2;
+ struct IRAFsurface *sf2 = 0;
+ double *ptr1, *ptr2;
+ double zfit, norm;
+ double wf_gseval();
+
+ if (sf1 == NULL)
+ return (0.0);
+
+ if (nxd < 0 || nyd < 0) {
+ fprintf (stderr, "TNX_GSDER: order of derivatives cannot be < 0\n");
+ return (0.0);
+ }
+
+ if (nxd == 0 && nyd == 0) {
+ zfit = wf_gseval (sf1, x, y);
+ return (zfit);
+ }
+
+ /* Allocate space for new surface */
+ sf2 = (struct IRAFsurface *) malloc (sizeof (struct IRAFsurface));
+
+ /* Check the order of the derivatives */
+ nxder = MIN (nxd, sf1->xorder - 1);
+ nyder = MIN (nyd, sf1->yorder - 1);
+
+ /* Set up new surface */
+ sf2->type = sf1->type;
+
+ /* Set the derivative surface parameters */
+ if (sf2->type == TNX_LEGENDRE ||
+ sf2->type == TNX_CHEBYSHEV ||
+ sf2->type == TNX_POLYNOMIAL) {
+
+ sf2->xterms = sf1->xterms;
+
+ /* Find the order of the new surface */
+ switch (sf2->xterms) {
+ case TNX_XNONE:
+ if (nxder > 0 && nyder > 0) {
+ sf2->xorder = 1;
+ sf2->yorder = 1;
+ sf2->ncoeff = 1;
+ }
+ else if (nxder > 0) {
+ sf2->xorder = MAX (1, sf1->xorder - nxder);
+ sf2->yorder = 1;
+ sf2->ncoeff = sf2->xorder;
+ }
+ else if (nyder > 0) {
+ sf2->xorder = 1;
+ sf2->yorder = MAX (1, sf1->yorder - nyder);
+ sf2->ncoeff = sf2->yorder;
+ }
+ break;
+
+ case TNX_XHALF:
+ maxorder1 = MAX (sf1->xorder+1, sf1->yorder+1);
+ order = MAX(1, MIN(maxorder1-1-nyder-nxder,sf1->xorder-nxder));
+ sf2->xorder = order;
+ order = MAX(1, MIN(maxorder1-1-nyder-nxder,sf1->yorder-nyder));
+ sf2->yorder = order;
+ order = MIN (sf2->xorder, sf2->yorder);
+ sf2->ncoeff = sf2->xorder * sf2->yorder - (order*(order-1)/2);
+ break;
+
+ default:
+ sf2->xorder = MAX (1, sf1->xorder - nxder);
+ sf2->yorder = MAX (1, sf1->yorder - nyder);
+ sf2->ncoeff = sf2->xorder * sf2->yorder;
+ }
+
+ /* define the data limits */
+ sf2->xrange = sf1->xrange;
+ sf2->xmaxmin = sf1->xmaxmin;
+ sf2->yrange = sf1->yrange;
+ sf2->ymaxmin = sf1->ymaxmin;
+ }
+
+ else {
+ fprintf (stderr, "TNX_GSDER: unknown surface type %d\n", sf2->type);
+ return (0.0);
+ }
+
+ /* Allocate space for coefficients and basis functions */
+ nbytes = sf2->ncoeff * sizeof(double);
+ sf2->coeff = (double *) malloc (nbytes);
+ nbytes = sf2->xorder * sizeof(double);
+ sf2->xbasis = (double *) malloc (nbytes);
+ nbytes = sf2->yorder * sizeof(double);
+ sf2->ybasis = (double *) malloc (nbytes);
+
+ /* Get coefficients */
+ nbytes = sf1->ncoeff * sizeof(double);
+ if (nbytes > nbcoeff) {
+ if (nbcoeff > 0)
+ coeff = (double *) realloc (coeff, nbytes);
+ else
+ coeff = (double *) malloc (nbytes);
+ nbcoeff = nbytes;
+ }
+ (void) wf_gscoeff (sf1, coeff);
+
+ /* Compute the new coefficients */
+ switch (sf2->xterms) {
+ case TNX_XFULL:
+ ptr2 = sf2->coeff + (sf2->yorder - 1) * sf2->xorder;
+ ptr1 = coeff + (sf1->yorder - 1) * sf1->xorder;
+ for (i = sf1->yorder - 1; i >= nyder; i--) {
+ for (j = i; j >= i-nyder+1; j--) {
+ for (k = 0; k < sf2->xorder; k++)
+ ptr1[nxder+k] = ptr1[nxder+k] * (double)(j);
+ }
+ for (j = sf1->xorder; j >= nxder+1; j--) {
+ for (k = j; k >= j-nxder+1; k--)
+ ptr1[j-1] = ptr1[j-1] * (double)(k - 1);
+ }
+ for (j = 0; j < sf2->xorder; j++)
+ ptr2[j] = ptr1[nxder+j];
+ ptr2 = ptr2 - sf2->xorder;
+ ptr1 = ptr1 - sf1->xorder;
+ }
+ break;
+
+ case TNX_XHALF:
+ maxorder1 = MAX (sf1->xorder + 1, sf1->yorder + 1);
+ maxorder2 = MAX (sf2->xorder + 1, sf2->yorder + 1);
+ ptr2 = sf2->coeff + sf2->ncoeff;
+ ptr1 = coeff + sf1->ncoeff;
+ for (i = sf1->yorder; i >= nyder+1; i--) {
+ nmove1 = MAX (0, MIN (maxorder1 - i, sf1->xorder));
+ nmove2 = MAX (0, MIN (maxorder2 - i + nyder, sf2->xorder));
+ ptr1 = ptr1 - nmove1;
+ ptr2 = ptr2 - nmove2;
+ for (j = i; j > i - nyder + 1; j--) {
+ for (k = 0; k < nmove2; k++)
+ ptr1[nxder+k] = ptr1[nxder+k] * (double)(j-1);
+ }
+ for (j = nmove1; j >= nxder+1; j--) {
+ for (k = j; k >= j-nxder+1; k--)
+ ptr1[j-1] = ptr1[j-1] * (double)(k - 1);
+ }
+ for (j = 0; j < nmove2; j++)
+ ptr2[j] = ptr1[nxder+j];
+ }
+ break;
+
+ default:
+ if (nxder > 0 && nyder > 0)
+ sf2->coeff[0] = 0.0;
+
+ else if (nxder > 0) {
+ ptr1 = coeff;
+ ptr2 = sf2->coeff + sf2->ncoeff - 1;
+ for (j = sf1->xorder; j >= nxder+1; j--) {
+ for (k = j; k >= j - nxder + 1; k--)
+ ptr1[j-1] = ptr1[j-1] * (double)(k - 1);
+ ptr2[0] = ptr1[j-1];
+ ptr2 = ptr2 - 1;
+ }
+ }
+
+ else if (nyder > 0) {
+ ptr1 = coeff + sf1->ncoeff - 1;
+ ptr2 = sf2->coeff;
+ for (i = sf1->yorder; i >= nyder + 1; i--) {
+ for (j = i; j >= i - nyder + 1; j--)
+ *ptr1 = *ptr1 * (double)(j - 1);
+ ptr1 = ptr1 - 1;
+ }
+ for (i = 0; i < sf2->ncoeff; i++)
+ ptr2[i] = ptr1[i+1];
+ }
+ }
+
+ /* evaluate the derivatives */
+ zfit = wf_gseval (sf2, x, y);
+
+ /* normalize */
+ if (sf2->type != TNX_POLYNOMIAL) {
+ norm = pow (sf2->xrange, (double)nxder) *
+ pow (sf2->yrange, (double)nyder);
+ zfit = norm * zfit;
+ }
+
+ /* free the space */
+ wf_gsclose (sf2);
+
+ return (zfit);
+}
+
+
+/* wf_gsrestore -- procedure to restore the surface fit encoded in the
+ image header as a list of double precision parameters and coefficients
+ to the surface descriptor for use by the evaluating routines. the
+ surface parameters, surface type, xorder (or number of polynomial
+ terms in x), yorder (or number of polynomial terms in y), xterms,
+ xmin, xmax and ymin and ymax, are stored in the first eight elements
+ of the double array fit, followed by the wf->ncoeff surface coefficients.
+ */
+
+struct IRAFsurface *
+wf_gsrestore (fit)
+
+double *fit; /* array containing the surface parameters
+ and coefficients */
+{
+ struct IRAFsurface *sf; /* surface descriptor */
+ int surface_type, xorder, yorder, order, i;
+ double xmin, xmax, ymin, ymax;
+
+ xorder = (int) (fit[TNX_SAVEXORDER] + 0.5);
+ if (xorder < 1) {
+ fprintf (stderr, "wf_gsrestore: illegal x order %d\n", xorder);
+ return (NULL);
+ }
+
+ yorder = (int) (fit[TNX_SAVEYORDER] + 0.5);
+ if (yorder < 1) {
+ fprintf (stderr, "wf_gsrestore: illegal y order %d\n", yorder);
+ return (NULL);
+ }
+
+ xmin = fit[TNX_SAVEXMIN];
+ xmax = fit[TNX_SAVEXMAX];
+ if (xmax <= xmin) {
+ fprintf (stderr, "wf_gsrestore: illegal x range %f-%f\n",xmin,xmax);
+ return (NULL);
+ }
+ ymin = fit[TNX_SAVEYMIN];
+ ymax = fit[TNX_SAVEYMAX];
+ if (ymax <= ymin) {
+ fprintf (stderr, "wf_gsrestore: illegal y range %f-%f\n",ymin,ymax);
+ return (NULL);
+ }
+
+ /* Set surface type dependent surface descriptor parameters */
+ surface_type = (int) (fit[TNX_SAVETYPE] + 0.5);
+
+ if (surface_type == TNX_LEGENDRE ||
+ surface_type == TNX_CHEBYSHEV ||
+ surface_type == TNX_POLYNOMIAL) {
+
+ /* allocate space for the surface descriptor */
+ sf = (struct IRAFsurface *) malloc (sizeof (struct IRAFsurface));
+ sf->xorder = xorder;
+ sf->xrange = 2.0 / (xmax - xmin);
+ sf->xmaxmin = - (xmax + xmin) / 2.0;
+ sf->yorder = yorder;
+ sf->yrange = 2.0 / (ymax - ymin);
+ sf->ymaxmin = - (ymax + ymin) / 2.0;
+ sf->xterms = fit[TNX_SAVEXTERMS];
+ switch (sf->xterms) {
+ case TNX_XNONE:
+ sf->ncoeff = sf->xorder + sf->yorder - 1;
+ break;
+ case TNX_XHALF:
+ order = MIN (xorder, yorder);
+ sf->ncoeff = sf->xorder * sf->yorder - order * (order-1) / 2;
+ break;
+ case TNX_XFULL:
+ sf->ncoeff = sf->xorder * sf->yorder;
+ break;
+ }
+ }
+ else {
+ fprintf (stderr, "wf_gsrestore: unknown surface type %d\n", surface_type);
+ return (NULL);
+ }
+
+ /* Set remaining curve parameters */
+ sf->type = surface_type;
+
+ /* Restore coefficient array */
+ sf->coeff = (double *) malloc (sf->ncoeff*sizeof (double));
+ for (i = 0; i < sf->ncoeff; i++)
+ sf->coeff[i] = fit[TNX_SAVECOEFF+i];
+
+ /* Allocate space for basis vectors */
+ sf->xbasis = (double *) malloc (sf->xorder*sizeof (double));
+ sf->ybasis = (double *) malloc (sf->yorder*sizeof (double));
+
+ return (sf);
+}
+
+
+/* wf_gsb1pol -- procedure to evaluate all the non-zero polynomial functions
+ for a single point and given order. */
+
+static void
+wf_gsb1pol (x, order, basis)
+
+double x; /*i data point */
+int order; /*i order of polynomial, order = 1, constant */
+double *basis; /*o basis functions */
+{
+ int i;
+
+ basis[0] = 1.0;
+ if (order == 1)
+ return;
+
+ basis[1] = x;
+ if (order == 2)
+ return;
+
+ for (i = 2; i < order; i++)
+ basis[i] = x * basis[i-1];
+
+ return;
+}
+
+
+/* wf_gsb1leg -- procedure to evaluate all the non-zero legendre functions for
+ a single point and given order. */
+
+static void
+wf_gsb1leg (x, order, k1, k2, basis)
+
+double x; /*i data point */
+int order; /*i order of polynomial, order = 1, constant */
+double k1, k2; /*i normalizing constants */
+double *basis; /*o basis functions */
+{
+ int i;
+ double ri, xnorm;
+
+ basis[0] = 1.0;
+ if (order == 1)
+ return;
+
+ xnorm = (x + k1) * k2 ;
+ basis[1] = xnorm;
+ if (order == 2)
+ return;
+
+ for (i = 2; i < order; i++) {
+ ri = i;
+ basis[i] = ((2.0 * ri - 1.0) * xnorm * basis[i-1] -
+ (ri - 1.0) * basis[i-2]) / ri;
+ }
+
+ return;
+}
+
+
+/* wf_gsb1cheb -- procedure to evaluate all the non-zero chebyshev function
+ coefficients for a given x and order. */
+
+static void
+wf_gsb1cheb (x, order, k1, k2, basis)
+
+double x; /*i number of data points */
+int order; /*i order of polynomial, 1 is a constant */
+double k1, k2; /*i normalizing constants */
+double *basis; /*o array of basis functions */
+{
+ int i;
+ double xnorm;
+
+ basis[0] = 1.0;
+ if (order == 1)
+ return;
+
+ xnorm = (x + k1) * k2;
+ basis[1] = xnorm;
+ if (order == 2)
+ return;
+
+ for (i = 2; i < order; i++)
+ basis[i] = 2. * xnorm * basis[i-1] - basis[i-2];
+
+ return;
+}
+
+/* Set surface polynomial from arguments */
+
+int
+tnxpset (wcs, xorder, yorder, xterms, coeff)
+
+struct WorldCoor *wcs; /* World coordinate system structure */
+int xorder; /* Number of x coefficients (same for x and y) */
+int yorder; /* Number of y coefficients (same for x and y) */
+int xterms; /* Number of xy coefficients (same for x and y) */
+double *coeff; /* Plate fit coefficients */
+
+{
+ double *ycoeff;
+ struct IRAFsurface *wf_gspset ();
+
+ wcs->prjcode = WCS_TNX;
+
+ wcs->lngcor = wf_gspset (xorder, yorder, xterms, coeff);
+ ycoeff = coeff + wcs->lngcor->ncoeff;
+ wcs->latcor = wf_gspset (xorder, yorder, xterms, ycoeff);
+
+ return 0;
+}
+
+
+/* wf_gspset -- procedure to set the surface descriptor for use by the
+ evaluating routines. from arguments. The surface parameters are
+ surface type, xorder (number of polynomial terms in x), yorder (number
+ of polynomial terms in y), xterms, and the surface coefficients.
+ */
+
+struct IRAFsurface *
+wf_gspset (xorder, yorder, xterms, coeff)
+
+int xorder;
+int yorder;
+int xterms;
+double *coeff;
+{
+ struct IRAFsurface *sf; /* surface descriptor */
+ int surface_type, order, i;
+ double xmin, xmax;
+ double ymin, ymax;
+
+ surface_type = TNX_POLYNOMIAL;
+ xmin = 0.0;
+ xmax = 0.0;
+ ymin = 0.0;
+ ymax = 0.0;
+
+ if (surface_type == TNX_LEGENDRE ||
+ surface_type == TNX_CHEBYSHEV ||
+ surface_type == TNX_POLYNOMIAL) {
+
+ /* allocate space for the surface descriptor */
+ sf = (struct IRAFsurface *) malloc (sizeof (struct IRAFsurface));
+ sf->xorder = xorder;
+ sf->xrange = 2.0 / (xmax - xmin);
+ sf->xmaxmin = -(xmax + xmin) / 2.0;
+ sf->yorder = yorder;
+ sf->yrange = 2.0 / (ymax - ymin);
+ sf->ymaxmin = - (ymax + ymin) / 2.0;
+ sf->xterms = xterms;
+ switch (sf->xterms) {
+ case TNX_XNONE:
+ sf->ncoeff = sf->xorder + sf->yorder - 1;
+ break;
+ case TNX_XHALF:
+ order = MIN (xorder, yorder);
+ sf->ncoeff = sf->xorder * sf->yorder - order * (order-1) / 2;
+ break;
+ case TNX_XFULL:
+ sf->ncoeff = sf->xorder * sf->yorder;
+ break;
+ }
+ }
+ else {
+ fprintf (stderr, "TNX_GSSET: unknown surface type %d\n", surface_type);
+ return (NULL);
+ }
+
+ /* Set remaining curve parameters */
+ sf->type = surface_type;
+
+ /* Restore coefficient array */
+ sf->coeff = (double *) malloc (sf->ncoeff*sizeof (double));
+ for (i = 0; i < sf->ncoeff; i++)
+ sf->coeff[i] = coeff[i];
+
+ /* Allocate space for basis vectors */
+ sf->xbasis = (double *) malloc (sf->xorder*sizeof (double));
+ sf->ybasis = (double *) malloc (sf->yorder*sizeof (double));
+
+ return (sf);
+}
+
+/* Mar 26 1998 New subroutines, translated from SPP
+ * Apr 28 1998 Change all local flags to TNX_* and projection flag to WCS_TNX
+ * May 11 1998 Fix use of pole longitude default
+ * Sep 4 1998 Fix missed assignment in tnxpos from Allen Harris, SAO
+ * Sep 10 1998 Fix bugs in tnxpix()
+ * Sep 10 1998 Fix missed assignment in tnxpix from Allen Harris, SAO
+ *
+ * Oct 22 1999 Drop unused variables, fix case statements after lint
+ * Dec 10 1999 Fix bug in gsder() which failed to allocate enough memory
+ * Dec 10 1999 Compute wcs->rot using wcsrotset() in tnxinit()
+ *
+ * Feb 14 2001 Fixed off-by-one bug in legendre evaluation (Mike Jarvis)
+ *
+ * Apr 11 2002 Fix bug when .-terminated substring in wf_gsopen()
+ * Apr 29 2002 Clean up code
+ * Jun 26 2002 Increase size of WAT strings from 500 to 2000
+ *
+ * Jun 27 2005 Drop unused arguments k1 and k2 from wf_gsb1pol()
+ *
+ * Jan 8 2007 Drop unused variable ncoeff in wf_gsder()
+ * Jan 9 2007 Declare header const char in tnxinit()
+ * Apr 3 2007 Fix offsets to hit last cooefficient in wf_gsder()
+ *
+ * Sep 5 2008 Fix wf_gseval() call in tnxpos() so unmodified x and y are used
+ * Sep 9 2008 Fix loop in TNX_XFULL section of wf_gsder()
+ * (last two bugs found by Ed Los)
+ * Sep 17 2008 Fix tnxpos for null correction case (fix by Ed Los)
+ */
diff --git a/funtools/wcs/wcs.c b/funtools/wcs/wcs.c
new file mode 100644
index 0000000..32ea3f7
--- /dev/null
+++ b/funtools/wcs/wcs.c
@@ -0,0 +1,2994 @@
+/*** File libwcs/wcs.c
+ *** October 19, 2012
+ *** By Jessica Mink, jmink@cfa.harvard.edu
+ *** Harvard-Smithsonian Center for Astrophysics
+ *** Copyright (C) 1994-2012
+ *** Smithsonian Astrophysical Observatory, Cambridge, MA, USA
+
+ This library 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 2 of the License, or (at your option) any later version.
+
+ This library 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 this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Correspondence concerning WCSTools should be addressed as follows:
+ Internet email: jmink@cfa.harvard.edu
+ Postal address: Jessica Mink
+ Smithsonian Astrophysical Observatory
+ 60 Garden St.
+ Cambridge, MA 02138 USA
+
+ * Module: wcs.c (World Coordinate Systems)
+ * Purpose: Convert FITS WCS to pixels and vice versa:
+ * Subroutine: wcsxinit (cra,cdec,secpix,xrpix,yrpix,nxpix,nypix,rotate,equinox,epoch,proj)
+ * sets a WCS structure from arguments
+ * Subroutine: wcskinit (nxpix,nypix,ctype1,ctype2,crpix1,crpix2,crval1,crval2,
+ cd,cdelt1,cdelt2,crota,equinox,epoch)
+ * sets a WCS structure from keyword-based arguments
+ * Subroutine: wcsreset (wcs,crpix1,crpix2,crval1,crval2,cdelt1,cdelt2,crota,cd, equinox)
+ * resets an existing WCS structure from arguments
+ * Subroutine: wcsdeltset (wcs,cdelt1,cdelt2,crota) sets rotation and scaling
+ * Subroutine: wcscdset (wcs, cd) sets rotation and scaling from a CD matrix
+ * Subroutine: wcspcset (wcs,cdelt1,cdelt2,pc) sets rotation and scaling
+ * Subroutine: wcseqset (wcs, equinox) resets an existing WCS structure to new equinox
+ * Subroutine: iswcs(wcs) returns 1 if WCS structure is filled, else 0
+ * Subroutine: nowcs(wcs) returns 0 if WCS structure is filled, else 1
+ * Subroutine: wcscent (wcs) prints the image center and size in WCS units
+ * Subroutine: wcssize (wcs, cra, cdec, dra, ddec) returns image center and size
+ * Subroutine: wcsfull (wcs, cra, cdec, width, height) returns image center and size
+ * Subroutine: wcsrange (wcs, ra1, ra2, dec1, dec2) returns image coordinate limits
+
+ * Subroutine: wcsshift (wcs,cra,cdec) resets the center of a WCS structure
+ * Subroutine: wcsdist (x1,y1,x2,y2) compute angular distance between ra/dec or lat/long
+ * Subroutine: wcsdiff (x1,y1,x2,y2) compute angular distance between ra/dec or lat/long
+ * Subroutine: wcscominit (wcs,command) sets up a command format for execution by wcscom
+ * Subroutine: wcsoutinit (wcs,coor) sets up the coordinate system used by pix2wcs
+ * Subroutine: getwcsout (wcs) returns current output coordinate system used by pix2wcs
+ * Subroutine: wcsininit (wcs,coor) sets up the coordinate system used by wcs2pix
+ * Subroutine: getwcsin (wcs) returns current input coordinate system used by wcs2pix
+ * Subroutine: setwcsdeg(wcs, new) sets WCS output in degrees or hh:mm:ss
+ * Subroutine: getradecsys(wcs) returns current coordinate system type
+ * Subroutine: wcscom (wcs,file,x,y,wcstr) executes a command using the current world coordinates
+ * Subroutine: setwcslin (wcs, mode) sets output string mode for LINEAR
+ * Subroutine: pix2wcst (wcs,xpix,ypix,wcstring,lstr) pixels -> sky coordinate string
+ * Subroutine: pix2wcs (wcs,xpix,ypix,xpos,ypos) pixel coordinates -> sky coordinates
+ * Subroutine: wcsc2pix (wcs,xpos,ypos,coorsys,xpix,ypix,offscl) sky coordinates -> pixel coordinates
+ * Subroutine: wcs2pix (wcs,xpos,ypos,xpix,ypix,offscl) sky coordinates -> pixel coordinates
+ * Subroutine: wcszin (izpix) sets third dimension for pix2wcs() and pix2wcst()
+ * Subroutine: wcszout (wcs) returns third dimension from wcs2pix()
+ * Subroutine: setwcsfile (filename) Set file name for error messages
+ * Subroutine: setwcserr (errmsg) Set error message
+ * Subroutine: wcserr() Print error message
+ * Subroutine: setdefwcs (wcsproj) Set flag to choose AIPS or WCSLIB WCS subroutines
+ * Subroutine: getdefwcs() Get flag to switch between AIPS and WCSLIB subroutines
+ * Subroutine: savewcscoor (wcscoor)
+ * Subroutine: getwcscoor() Return preset output default coordinate system
+ * Subroutine: savewcscom (i, wcscom) Save specified WCS command
+ * Subroutine: setwcscom (wcs) Initialize WCS commands
+ * Subroutine: getwcscom (i) Return specified WCS command
+ * Subroutine: wcsfree (wcs) Free storage used by WCS structure
+ * Subroutine: freewcscom (wcs) Free storage used by WCS commands
+ * Subroutine: cpwcs (&header, cwcs)
+ */
+
+#include <string.h> /* strstr, NULL */
+#include <stdio.h> /* stderr */
+#include <math.h>
+#include "wcs.h"
+#ifndef VMS
+#include <stdlib.h>
+#endif
+
+static char wcserrmsg[80];
+static char wcsfile[256]={""};
+static void wcslibrot();
+void wcsrotset();
+static int wcsproj0 = 0;
+static int izpix = 0;
+static double zpix = 0.0;
+
+void
+wcsfree (wcs)
+struct WorldCoor *wcs; /* WCS structure */
+{
+ if (nowcs (wcs)) {
+
+ /* Free WCS structure if allocated but not filled */
+ if (wcs)
+ free (wcs);
+
+ return;
+ }
+
+ /* Free WCS on which this WCS depends */
+ if (wcs->wcs) {
+ wcsfree (wcs->wcs);
+ wcs->wcs = NULL;
+ }
+
+ freewcscom (wcs);
+ if (wcs->wcsname != NULL)
+ free (wcs->wcsname);
+ if (wcs->lin.imgpix != NULL)
+ free (wcs->lin.imgpix);
+ if (wcs->lin.piximg != NULL)
+ free (wcs->lin.piximg);
+ if (wcs->inv_x != NULL)
+ poly_end (wcs->inv_x);
+ if (wcs->inv_y != NULL)
+ poly_end (wcs->inv_y);
+ free (wcs);
+ return;
+}
+
+/* Set up a WCS structure from subroutine arguments */
+
+struct WorldCoor *
+wcsxinit (cra,cdec,secpix,xrpix,yrpix,nxpix,nypix,rotate,equinox,epoch,proj)
+
+double cra; /* Center right ascension in degrees */
+double cdec; /* Center declination in degrees */
+double secpix; /* Number of arcseconds per pixel */
+double xrpix; /* Reference pixel X coordinate */
+double yrpix; /* Reference pixel X coordinate */
+int nxpix; /* Number of pixels along x-axis */
+int nypix; /* Number of pixels along y-axis */
+double rotate; /* Rotation angle (clockwise positive) in degrees */
+int equinox; /* Equinox of coordinates, 1950 and 2000 supported */
+double epoch; /* Epoch of coordinates, used for FK4/FK5 conversion
+ * no effect if 0 */
+char *proj; /* Projection */
+
+{
+ struct WorldCoor *wcs;
+ double cdelt1, cdelt2;
+
+ wcs = (struct WorldCoor *) calloc (1, sizeof(struct WorldCoor));
+
+ /* Set WCSLIB flags so that structures will be reinitialized */
+ wcs->cel.flag = 0;
+ wcs->lin.flag = 0;
+ wcs->wcsl.flag = 0;
+
+ /* Image dimensions */
+ wcs->naxis = 2;
+ wcs->naxes = 2;
+ wcs->lin.naxis = 2;
+ wcs->nxpix = nxpix;
+ wcs->nypix = nypix;
+
+ wcs->wcsproj = wcsproj0;
+
+ wcs->crpix[0] = xrpix;
+ wcs->crpix[1] = yrpix;
+ wcs->xrefpix = wcs->crpix[0];
+ wcs->yrefpix = wcs->crpix[1];
+ wcs->lin.crpix = wcs->crpix;
+
+ wcs->crval[0] = cra;
+ wcs->crval[1] = cdec;
+ wcs->xref = wcs->crval[0];
+ wcs->yref = wcs->crval[1];
+ wcs->cel.ref[0] = wcs->crval[0];
+ wcs->cel.ref[1] = wcs->crval[1];
+ wcs->cel.ref[2] = 999.0;
+
+ strcpy (wcs->c1type,"RA");
+ strcpy (wcs->c2type,"DEC");
+
+/* Allan Brighton: 28.4.98: for backward compat., remove leading "--" */
+ while (proj && *proj == '-')
+ proj++;
+ strcpy (wcs->ptype,proj);
+ strcpy (wcs->ctype[0],"RA---");
+ strcpy (wcs->ctype[1],"DEC--");
+ strcat (wcs->ctype[0],proj);
+ strcat (wcs->ctype[1],proj);
+
+ if (wcstype (wcs, wcs->ctype[0], wcs->ctype[1])) {
+ wcsfree (wcs);
+ return (NULL);
+ }
+
+ /* Approximate world coordinate system from a known plate scale */
+ cdelt1 = -secpix / 3600.0;
+ cdelt2 = secpix / 3600.0;
+ wcsdeltset (wcs, cdelt1, cdelt2, rotate);
+ wcs->lin.cdelt = wcs->cdelt;
+ wcs->lin.pc = wcs->pc;
+
+ /* Coordinate reference frame and equinox */
+ wcs->equinox = (double) equinox;
+ if (equinox > 1980)
+ strcpy (wcs->radecsys,"FK5");
+ else
+ strcpy (wcs->radecsys,"FK4");
+ if (epoch > 0)
+ wcs->epoch = epoch;
+ else
+ wcs->epoch = 0.0;
+ wcs->wcson = 1;
+
+ wcs->syswcs = wcscsys (wcs->radecsys);
+ wcsoutinit (wcs, wcs->radecsys);
+ wcsininit (wcs, wcs->radecsys);
+ wcs->eqout = 0.0;
+ wcs->printsys = 1;
+ wcs->tabsys = 0;
+
+ /* Initialize special WCS commands */
+ setwcscom (wcs);
+
+ return (wcs);
+}
+
+
+/* Set up a WCS structure from subroutine arguments based on FITS keywords */
+
+struct WorldCoor *
+wcskinit (naxis1, naxis2, ctype1, ctype2, crpix1, crpix2, crval1, crval2,
+ cd, cdelt1, cdelt2, crota, equinox, epoch)
+
+int naxis1; /* Number of pixels along x-axis */
+int naxis2; /* Number of pixels along y-axis */
+char *ctype1; /* FITS WCS projection for axis 1 */
+char *ctype2; /* FITS WCS projection for axis 2 */
+double crpix1, crpix2; /* Reference pixel coordinates */
+double crval1, crval2; /* Coordinates at reference pixel in degrees */
+double *cd; /* Rotation matrix, used if not NULL */
+double cdelt1, cdelt2; /* scale in degrees/pixel, ignored if cd is not NULL */
+double crota; /* Rotation angle in degrees, ignored if cd is not NULL */
+int equinox; /* Equinox of coordinates, 1950 and 2000 supported */
+double epoch; /* Epoch of coordinates, used for FK4/FK5 conversion
+ * no effect if 0 */
+{
+ struct WorldCoor *wcs;
+
+ wcs = (struct WorldCoor *) calloc (1, sizeof(struct WorldCoor));
+
+ /* Set WCSLIB flags so that structures will be reinitialized */
+ wcs->cel.flag = 0;
+ wcs->lin.flag = 0;
+ wcs->wcsl.flag = 0;
+
+ /* Image dimensions */
+ wcs->naxis = 2;
+ wcs->naxes = 2;
+ wcs->lin.naxis = 2;
+ wcs->nxpix = naxis1;
+ wcs->nypix = naxis2;
+
+ wcs->wcsproj = wcsproj0;
+
+ wcs->crpix[0] = crpix1;
+ wcs->crpix[1] = crpix2;
+ wcs->xrefpix = wcs->crpix[0];
+ wcs->yrefpix = wcs->crpix[1];
+ wcs->lin.crpix = wcs->crpix;
+
+ if (wcstype (wcs, ctype1, ctype2)) {
+ wcsfree (wcs);
+ return (NULL);
+ }
+ if (wcs->latbase == 90)
+ crval2 = 90.0 - crval2;
+ else if (wcs->latbase == -90)
+ crval2 = crval2 - 90.0;
+
+ wcs->crval[0] = crval1;
+ wcs->crval[1] = crval2;
+ wcs->xref = wcs->crval[0];
+ wcs->yref = wcs->crval[1];
+ wcs->cel.ref[0] = wcs->crval[0];
+ wcs->cel.ref[1] = wcs->crval[1];
+ wcs->cel.ref[2] = 999.0;
+
+ if (cd != NULL)
+ wcscdset (wcs, cd);
+
+ else if (cdelt1 != 0.0)
+ wcsdeltset (wcs, cdelt1, cdelt2, crota);
+
+ else {
+ wcsdeltset (wcs, 1.0, 1.0, crota);
+ setwcserr ("WCSRESET: setting CDELT to 1");
+ }
+ wcs->lin.cdelt = wcs->cdelt;
+ wcs->lin.pc = wcs->pc;
+
+ /* Coordinate reference frame and equinox */
+ wcs->equinox = (double) equinox;
+ if (equinox > 1980)
+ strcpy (wcs->radecsys,"FK5");
+ else
+ strcpy (wcs->radecsys,"FK4");
+ if (epoch > 0)
+ wcs->epoch = epoch;
+ else
+ wcs->epoch = 0.0;
+ wcs->wcson = 1;
+
+ strcpy (wcs->radecout, wcs->radecsys);
+ wcs->syswcs = wcscsys (wcs->radecsys);
+ wcsoutinit (wcs, wcs->radecsys);
+ wcsininit (wcs, wcs->radecsys);
+ wcs->eqout = 0.0;
+ wcs->printsys = 1;
+ wcs->tabsys = 0;
+
+ /* Initialize special WCS commands */
+ setwcscom (wcs);
+
+ return (wcs);
+}
+
+
+/* Set projection in WCS structure from FITS keyword values */
+
+int
+wcstype (wcs, ctype1, ctype2)
+
+struct WorldCoor *wcs; /* World coordinate system structure */
+char *ctype1; /* FITS WCS projection for axis 1 */
+char *ctype2; /* FITS WCS projection for axis 2 */
+
+{
+ int i, iproj;
+ int nctype = NWCSTYPE;
+ char ctypes[NWCSTYPE][4];
+ char dtypes[10][4];
+
+ /* Initialize projection types */
+ strcpy (ctypes[0], "LIN");
+ strcpy (ctypes[1], "AZP");
+ strcpy (ctypes[2], "SZP");
+ strcpy (ctypes[3], "TAN");
+ strcpy (ctypes[4], "SIN");
+ strcpy (ctypes[5], "STG");
+ strcpy (ctypes[6], "ARC");
+ strcpy (ctypes[7], "ZPN");
+ strcpy (ctypes[8], "ZEA");
+ strcpy (ctypes[9], "AIR");
+ strcpy (ctypes[10], "CYP");
+ strcpy (ctypes[11], "CAR");
+ strcpy (ctypes[12], "MER");
+ strcpy (ctypes[13], "CEA");
+ strcpy (ctypes[14], "COP");
+ strcpy (ctypes[15], "COD");
+ strcpy (ctypes[16], "COE");
+ strcpy (ctypes[17], "COO");
+ strcpy (ctypes[18], "BON");
+ strcpy (ctypes[19], "PCO");
+ strcpy (ctypes[20], "SFL");
+ strcpy (ctypes[21], "PAR");
+ strcpy (ctypes[22], "AIT");
+ strcpy (ctypes[23], "MOL");
+ strcpy (ctypes[24], "CSC");
+ strcpy (ctypes[25], "QSC");
+ strcpy (ctypes[26], "TSC");
+ strcpy (ctypes[27], "NCP");
+ strcpy (ctypes[28], "GLS");
+ strcpy (ctypes[29], "DSS");
+ strcpy (ctypes[30], "PLT");
+ strcpy (ctypes[31], "TNX");
+ strcpy (ctypes[32], "ZPX");
+ strcpy (ctypes[33], "TPV");
+
+ /* Initialize distortion types */
+ strcpy (dtypes[1], "SIP");
+
+ if (!strncmp (ctype1, "LONG",4))
+ strncpy (ctype1, "XLON",4);
+
+ strcpy (wcs->ctype[0], ctype1);
+ strcpy (wcs->c1type, ctype1);
+ strcpy (wcs->ptype, ctype1);
+
+ /* Linear coordinates */
+ if (!strncmp (ctype1,"LINEAR",6))
+ wcs->prjcode = WCS_LIN;
+
+ /* Pixel coordinates */
+ else if (!strncmp (ctype1,"PIXEL",6))
+ wcs->prjcode = WCS_PIX;
+
+ /*Detector pixel coordinates */
+ else if (strsrch (ctype1,"DET"))
+ wcs->prjcode = WCS_PIX;
+
+ /* Set up right ascension, declination, latitude, or longitude */
+ else if (ctype1[0] == 'R' || ctype1[0] == 'D' ||
+ ctype1[0] == 'A' || ctype1[1] == 'L') {
+ wcs->c1type[0] = ctype1[0];
+ wcs->c1type[1] = ctype1[1];
+ if (ctype1[2] == '-') {
+ wcs->c1type[2] = 0;
+ iproj = 3;
+ }
+ else {
+ wcs->c1type[2] = ctype1[2];
+ iproj = 4;
+ if (ctype1[3] == '-') {
+ wcs->c1type[3] = 0;
+ }
+ else {
+ wcs->c1type[3] = ctype1[3];
+ wcs->c1type[4] = 0;
+ }
+ }
+ if (ctype1[iproj] == '-') iproj = iproj + 1;
+ if (ctype1[iproj] == '-') iproj = iproj + 1;
+ if (ctype1[iproj] == '-') iproj = iproj + 1;
+ if (ctype1[iproj] == '-') iproj = iproj + 1;
+ wcs->ptype[0] = ctype1[iproj];
+ wcs->ptype[1] = ctype1[iproj+1];
+ wcs->ptype[2] = ctype1[iproj+2];
+ wcs->ptype[3] = 0;
+ sprintf (wcs->ctype[0],"%-4s%4s",wcs->c1type,wcs->ptype);
+ for (i = 0; i < 8; i++)
+ if (wcs->ctype[0][i] == ' ') wcs->ctype[0][i] = '-';
+
+ /* Find projection type */
+ wcs->prjcode = 0; /* default type is linear */
+ for (i = 1; i < nctype; i++) {
+ if (!strncmp(wcs->ptype, ctypes[i], 3))
+ wcs->prjcode = i;
+ }
+
+ /* Handle "obsolete" NCP projection (now WCSLIB should be OK)
+ if (wcs->prjcode == WCS_NCP) {
+ if (wcs->wcsproj == WCS_BEST)
+ wcs->wcsproj = WCS_OLD;
+ else if (wcs->wcsproj == WCS_ALT)
+ wcs->wcsproj = WCS_NEW;
+ } */
+
+ /* Work around bug in WCSLIB handling of CAR projection
+ else if (wcs->prjcode == WCS_CAR) {
+ if (wcs->wcsproj == WCS_BEST)
+ wcs->wcsproj = WCS_OLD;
+ else if (wcs->wcsproj == WCS_ALT)
+ wcs->wcsproj = WCS_NEW;
+ } */
+
+ /* Work around bug in WCSLIB handling of COE projection
+ else if (wcs->prjcode == WCS_COE) {
+ if (wcs->wcsproj == WCS_BEST)
+ wcs->wcsproj = WCS_OLD;
+ else if (wcs->wcsproj == WCS_ALT)
+ wcs->wcsproj = WCS_NEW;
+ }
+
+ else if (wcs->wcsproj == WCS_BEST) */
+ if (wcs->wcsproj == WCS_BEST)
+ wcs->wcsproj = WCS_NEW;
+
+ else if (wcs->wcsproj == WCS_ALT)
+ wcs->wcsproj = WCS_OLD;
+
+ /* if (wcs->wcsproj == WCS_OLD && (
+ wcs->prjcode != WCS_STG && wcs->prjcode != WCS_AIT &&
+ wcs->prjcode != WCS_MER && wcs->prjcode != WCS_GLS &&
+ wcs->prjcode != WCS_ARC && wcs->prjcode != WCS_TAN &&
+ wcs->prjcode != WCS_TNX && wcs->prjcode != WCS_SIN &&
+ wcs->prjcode != WCS_PIX && wcs->prjcode != WCS_LIN &&
+ wcs->prjcode != WCS_CAR && wcs->prjcode != WCS_COE &&
+ wcs->prjcode != WCS_NCP && wcs->prjcode != WCS_ZPX))
+ wcs->wcsproj = WCS_NEW; */
+
+ /* Handle NOAO corrected TNX as uncorrected TAN if oldwcs is set */
+ if (wcs->wcsproj == WCS_OLD && wcs->prjcode == WCS_TNX) {
+ wcs->ctype[0][6] = 'A';
+ wcs->ctype[0][7] = 'N';
+ wcs->prjcode = WCS_TAN;
+ }
+
+ /* Handle NOAO corrected ZPX as uncorrected ZPN if oldwcs is set */
+ if (wcs->wcsproj == WCS_OLD && wcs->prjcode == WCS_ZPX) {
+ wcs->ctype[0][6] = 'P';
+ wcs->ctype[0][7] = 'N';
+ wcs->prjcode = WCS_ZPN;
+ }
+ }
+
+ /* If not sky coordinates, assume linear */
+ else {
+ wcs->prjcode = WCS_LIN;
+ return (0);
+ }
+
+ /* Second coordinate type */
+ if (!strncmp (ctype2, "NPOL",4)) {
+ ctype2[0] = ctype1[0];
+ strncpy (ctype2+1, "LAT",3);
+ wcs->latbase = 90;
+ strcpy (wcs->radecsys,"NPOLE");
+ wcs->syswcs = WCS_NPOLE;
+ }
+ else if (!strncmp (ctype2, "SPA-",4)) {
+ ctype2[0] = ctype1[0];
+ strncpy (ctype2+1, "LAT",3);
+ wcs->latbase = -90;
+ strcpy (wcs->radecsys,"SPA");
+ wcs->syswcs = WCS_SPA;
+ }
+ else
+ wcs->latbase = 0;
+ strcpy (wcs->ctype[1], ctype2);
+ strcpy (wcs->c2type, ctype2);
+
+ /* Linear coordinates */
+ if (!strncmp (ctype2,"LINEAR",6))
+ wcs->prjcode = WCS_LIN;
+
+ /* Pixel coordinates */
+ else if (!strncmp (ctype2,"PIXEL",6))
+ wcs->prjcode = WCS_PIX;
+
+ /* Set up right ascension, declination, latitude, or longitude */
+ else if (ctype2[0] == 'R' || ctype2[0] == 'D' ||
+ ctype2[0] == 'A' || ctype2[1] == 'L') {
+ wcs->c2type[0] = ctype2[0];
+ wcs->c2type[1] = ctype2[1];
+ if (ctype2[2] == '-') {
+ wcs->c2type[2] = 0;
+ iproj = 3;
+ }
+ else {
+ wcs->c2type[2] = ctype2[2];
+ iproj = 4;
+ if (ctype2[3] == '-') {
+ wcs->c2type[3] = 0;
+ }
+ else {
+ wcs->c2type[3] = ctype2[3];
+ wcs->c2type[4] = 0;
+ }
+ }
+ if (ctype2[iproj] == '-') iproj = iproj + 1;
+ if (ctype2[iproj] == '-') iproj = iproj + 1;
+ if (ctype2[iproj] == '-') iproj = iproj + 1;
+ if (ctype2[iproj] == '-') iproj = iproj + 1;
+ wcs->ptype[0] = ctype2[iproj];
+ wcs->ptype[1] = ctype2[iproj+1];
+ wcs->ptype[2] = ctype2[iproj+2];
+ wcs->ptype[3] = 0;
+
+ if (!strncmp (ctype1, "DEC", 3) ||
+ !strncmp (ctype1+1, "LAT", 3))
+ wcs->coorflip = 1;
+ else
+ wcs->coorflip = 0;
+ if (ctype2[1] == 'L' || ctype2[0] == 'A') {
+ wcs->degout = 1;
+ wcs->ndec = 5;
+ }
+ else {
+ wcs->degout = 0;
+ wcs->ndec = 3;
+ }
+ sprintf (wcs->ctype[1],"%-4s%4s",wcs->c2type,wcs->ptype);
+ for (i = 0; i < 8; i++)
+ if (wcs->ctype[1][i] == ' ') wcs->ctype[1][i] = '-';
+ }
+
+ /* If not sky coordinates, assume linear */
+ else {
+ wcs->prjcode = WCS_LIN;
+ }
+
+ /* Set distortion code from CTYPE1 extension */
+ setdistcode (wcs, ctype1);
+
+ return (0);
+}
+
+
+int
+wcsreset (wcs, crpix1, crpix2, crval1, crval2, cdelt1, cdelt2, crota, cd)
+
+struct WorldCoor *wcs; /* World coordinate system data structure */
+double crpix1, crpix2; /* Reference pixel coordinates */
+double crval1, crval2; /* Coordinates at reference pixel in degrees */
+double cdelt1, cdelt2; /* scale in degrees/pixel, ignored if cd is not NULL */
+double crota; /* Rotation angle in degrees, ignored if cd is not NULL */
+double *cd; /* Rotation matrix, used if not NULL */
+{
+
+ if (nowcs (wcs))
+ return (-1);
+
+ /* Set WCSLIB flags so that structures will be reinitialized */
+ wcs->cel.flag = 0;
+ wcs->lin.flag = 0;
+ wcs->wcsl.flag = 0;
+
+ /* Reference pixel coordinates and WCS value */
+ wcs->crpix[0] = crpix1;
+ wcs->crpix[1] = crpix2;
+ wcs->xrefpix = wcs->crpix[0];
+ wcs->yrefpix = wcs->crpix[1];
+ wcs->lin.crpix = wcs->crpix;
+
+ wcs->crval[0] = crval1;
+ wcs->crval[1] = crval2;
+ wcs->xref = wcs->crval[0];
+ wcs->yref = wcs->crval[1];
+ if (wcs->coorflip) {
+ wcs->cel.ref[1] = wcs->crval[0];
+ wcs->cel.ref[0] = wcs->crval[1];
+ }
+ else {
+ wcs->cel.ref[0] = wcs->crval[0];
+ wcs->cel.ref[1] = wcs->crval[1];
+ }
+ /* Keep ref[2] and ref[3] from input */
+
+ /* Initialize to no plate fit */
+ wcs->ncoeff1 = 0;
+ wcs->ncoeff2 = 0;
+
+ if (cd != NULL)
+ wcscdset (wcs, cd);
+
+ else if (cdelt1 != 0.0)
+ wcsdeltset (wcs, cdelt1, cdelt2, crota);
+
+ else {
+ wcs->xinc = 1.0;
+ wcs->yinc = 1.0;
+ setwcserr ("WCSRESET: setting CDELT to 1");
+ }
+
+ /* Coordinate reference frame, equinox, and epoch */
+ if (!strncmp (wcs->ptype,"LINEAR",6) ||
+ !strncmp (wcs->ptype,"PIXEL",5))
+ wcs->degout = -1;
+
+ wcs->wcson = 1;
+ return (0);
+}
+
+void
+wcseqset (wcs, equinox)
+
+struct WorldCoor *wcs; /* World coordinate system data structure */
+double equinox; /* Desired equinox as fractional year */
+{
+
+ if (nowcs (wcs))
+ return;
+
+ /* Leave WCS alone if already at desired equinox */
+ if (wcs->equinox == equinox)
+ return;
+
+ /* Convert center from B1950 (FK4) to J2000 (FK5) */
+ if (equinox == 2000.0 && wcs->equinox == 1950.0) {
+ if (wcs->coorflip) {
+ fk425e (&wcs->crval[1], &wcs->crval[0], wcs->epoch);
+ wcs->cel.ref[1] = wcs->crval[0];
+ wcs->cel.ref[0] = wcs->crval[1];
+ }
+ else {
+ fk425e (&wcs->crval[0], &wcs->crval[1], wcs->epoch);
+ wcs->cel.ref[0] = wcs->crval[0];
+ wcs->cel.ref[1] = wcs->crval[1];
+ }
+ wcs->xref = wcs->crval[0];
+ wcs->yref = wcs->crval[1];
+ wcs->equinox = 2000.0;
+ strcpy (wcs->radecsys, "FK5");
+ wcs->syswcs = WCS_J2000;
+ wcs->cel.flag = 0;
+ wcs->wcsl.flag = 0;
+ }
+
+ /* Convert center from J2000 (FK5) to B1950 (FK4) */
+ else if (equinox == 1950.0 && wcs->equinox == 2000.0) {
+ if (wcs->coorflip) {
+ fk524e (&wcs->crval[1], &wcs->crval[0], wcs->epoch);
+ wcs->cel.ref[1] = wcs->crval[0];
+ wcs->cel.ref[0] = wcs->crval[1];
+ }
+ else {
+ fk524e (&wcs->crval[0], &wcs->crval[1], wcs->epoch);
+ wcs->cel.ref[0] = wcs->crval[0];
+ wcs->cel.ref[1] = wcs->crval[1];
+ }
+ wcs->xref = wcs->crval[0];
+ wcs->yref = wcs->crval[1];
+ wcs->equinox = 1950.0;
+ strcpy (wcs->radecsys, "FK4");
+ wcs->syswcs = WCS_B1950;
+ wcs->cel.flag = 0;
+ wcs->wcsl.flag = 0;
+ }
+ wcsoutinit (wcs, wcs->radecsys);
+ wcsininit (wcs, wcs->radecsys);
+ return;
+}
+
+
+/* Set scale and rotation in WCS structure */
+
+void
+wcscdset (wcs, cd)
+
+struct WorldCoor *wcs; /* World coordinate system structure */
+double *cd; /* CD matrix, ignored if NULL */
+{
+ double tcd;
+
+ if (cd == NULL)
+ return;
+
+ wcs->rotmat = 1;
+ wcs->cd[0] = cd[0];
+ wcs->cd[1] = cd[1];
+ wcs->cd[2] = cd[2];
+ wcs->cd[3] = cd[3];
+ (void) matinv (2, wcs->cd, wcs->dc);
+
+ /* Compute scale */
+ wcs->xinc = sqrt (cd[0]*cd[0] + cd[2]*cd[2]);
+ wcs->yinc = sqrt (cd[1]*cd[1] + cd[3]*cd[3]);
+
+ /* Deal with x=Dec/y=RA case */
+ if (wcs->coorflip) {
+ tcd = cd[1];
+ cd[1] = -cd[2];
+ cd[2] = -tcd;
+ }
+ wcslibrot (wcs);
+ wcs->wcson = 1;
+
+ /* Compute image rotation */
+ wcsrotset (wcs);
+
+ wcs->cdelt[0] = wcs->xinc;
+ wcs->cdelt[1] = wcs->yinc;
+
+ return;
+}
+
+
+/* Set scale and rotation in WCS structure from axis scale and rotation */
+
+void
+wcsdeltset (wcs, cdelt1, cdelt2, crota)
+
+struct WorldCoor *wcs; /* World coordinate system structure */
+double cdelt1; /* degrees/pixel in first axis (or both axes) */
+double cdelt2; /* degrees/pixel in second axis if nonzero */
+double crota; /* Rotation counterclockwise in degrees */
+{
+ double *pci;
+ double crot, srot;
+ int i, j, naxes;
+
+ naxes = wcs->naxis;
+ if (naxes > 2)
+ naxes = 2;
+ wcs->cdelt[0] = cdelt1;
+ if (cdelt2 != 0.0)
+ wcs->cdelt[1] = cdelt2;
+ else
+ wcs->cdelt[1] = cdelt1;
+ wcs->xinc = wcs->cdelt[0];
+ wcs->yinc = wcs->cdelt[1];
+ pci = wcs->pc;
+ for (i = 0; i < naxes; i++) {
+ for (j = 0; j < naxes; j++) {
+ if (i ==j)
+ *pci = 1.0;
+ else
+ *pci = 0.0;
+ pci++;
+ }
+ }
+ wcs->rotmat = 0;
+
+ /* If image is reversed, value of CROTA is flipped, too */
+ wcs->rot = crota;
+ if (wcs->rot < 0.0)
+ wcs->rot = wcs->rot + 360.0;
+ if (wcs->rot >= 360.0)
+ wcs->rot = wcs->rot - 360.0;
+ crot = cos (degrad(wcs->rot));
+ if (cdelt1 * cdelt2 > 0)
+ srot = sin (-degrad(wcs->rot));
+ else
+ srot = sin (degrad(wcs->rot));
+
+ /* Set CD matrix */
+ wcs->cd[0] = wcs->cdelt[0] * crot;
+ if (wcs->cdelt[0] < 0)
+ wcs->cd[1] = -fabs (wcs->cdelt[1]) * srot;
+ else
+ wcs->cd[1] = fabs (wcs->cdelt[1]) * srot;
+ if (wcs->cdelt[1] < 0)
+ wcs->cd[2] = fabs (wcs->cdelt[0]) * srot;
+ else
+ wcs->cd[2] = -fabs (wcs->cdelt[0]) * srot;
+ wcs->cd[3] = wcs->cdelt[1] * crot;
+ (void) matinv (2, wcs->cd, wcs->dc);
+
+ /* Set rotation matrix */
+ wcslibrot (wcs);
+
+ /* Set image rotation and mirroring */
+ if (wcs->coorflip) {
+ if (wcs->cdelt[0] < 0 && wcs->cdelt[1] > 0) {
+ wcs->imflip = 1;
+ wcs->imrot = wcs->rot - 90.0;
+ if (wcs->imrot < -180.0) wcs->imrot = wcs->imrot + 360.0;
+ wcs->pa_north = wcs->rot;
+ wcs->pa_east = wcs->rot - 90.0;
+ if (wcs->pa_east < -180.0) wcs->pa_east = wcs->pa_east + 360.0;
+ }
+ else if (wcs->cdelt[0] > 0 && wcs->cdelt[1] < 0) {
+ wcs->imflip = 1;
+ wcs->imrot = wcs->rot + 90.0;
+ if (wcs->imrot > 180.0) wcs->imrot = wcs->imrot - 360.0;
+ wcs->pa_north = wcs->rot;
+ wcs->pa_east = wcs->rot - 90.0;
+ if (wcs->pa_east < -180.0) wcs->pa_east = wcs->pa_east + 360.0;
+ }
+ else if (wcs->cdelt[0] > 0 && wcs->cdelt[1] > 0) {
+ wcs->imflip = 0;
+ wcs->imrot = wcs->rot + 90.0;
+ if (wcs->imrot > 180.0) wcs->imrot = wcs->imrot - 360.0;
+ wcs->pa_north = wcs->imrot;
+ wcs->pa_east = wcs->rot + 90.0;
+ if (wcs->pa_east > 180.0) wcs->pa_east = wcs->pa_east - 360.0;
+ }
+ else if (wcs->cdelt[0] < 0 && wcs->cdelt[1] < 0) {
+ wcs->imflip = 0;
+ wcs->imrot = wcs->rot - 90.0;
+ if (wcs->imrot < -180.0) wcs->imrot = wcs->imrot + 360.0;
+ wcs->pa_north = wcs->imrot;
+ wcs->pa_east = wcs->rot + 90.0;
+ if (wcs->pa_east > 180.0) wcs->pa_east = wcs->pa_east - 360.0;
+ }
+ }
+ else {
+ if (wcs->cdelt[0] < 0 && wcs->cdelt[1] > 0) {
+ wcs->imflip = 0;
+ wcs->imrot = wcs->rot;
+ wcs->pa_north = wcs->rot + 90.0;
+ if (wcs->pa_north > 180.0) wcs->pa_north = wcs->pa_north - 360.0;
+ wcs->pa_east = wcs->rot + 180.0;
+ if (wcs->pa_east > 180.0) wcs->pa_east = wcs->pa_east - 360.0;
+ }
+ else if (wcs->cdelt[0] > 0 && wcs->cdelt[1] < 0) {
+ wcs->imflip = 0;
+ wcs->imrot = wcs->rot + 180.0;
+ if (wcs->imrot > 180.0) wcs->imrot = wcs->imrot - 360.0;
+ wcs->pa_north = wcs->imrot + 90.0;
+ if (wcs->pa_north > 180.0) wcs->pa_north = wcs->pa_north - 360.0;
+ wcs->pa_east = wcs->imrot + 180.0;
+ if (wcs->pa_east > 180.0) wcs->pa_east = wcs->pa_east - 360.0;
+ }
+ else if (wcs->cdelt[0] > 0 && wcs->cdelt[1] > 0) {
+ wcs->imflip = 1;
+ wcs->imrot = -wcs->rot;
+ wcs->pa_north = wcs->imrot + 90.0;
+ if (wcs->pa_north > 180.0) wcs->pa_north = wcs->pa_north - 360.0;
+ wcs->pa_east = wcs->rot;
+ }
+ else if (wcs->cdelt[0] < 0 && wcs->cdelt[1] < 0) {
+ wcs->imflip = 1;
+ wcs->imrot = wcs->rot + 180.0;
+ if (wcs->imrot > 180.0) wcs->imrot = wcs->imrot - 360.0;
+ wcs->pa_north = wcs->imrot + 90.0;
+ if (wcs->pa_north > 180.0) wcs->pa_north = wcs->pa_north - 360.0;
+ wcs->pa_east = wcs->rot + 90.0;
+ if (wcs->pa_east > 180.0) wcs->pa_east = wcs->pa_east - 360.0;
+ }
+ }
+
+ return;
+}
+
+
+/* Set scale and rotation in WCS structure */
+
+void
+wcspcset (wcs, cdelt1, cdelt2, pc)
+
+struct WorldCoor *wcs; /* World coordinate system structure */
+double cdelt1; /* degrees/pixel in first axis (or both axes) */
+double cdelt2; /* degrees/pixel in second axis if nonzero */
+double *pc; /* Rotation matrix, ignored if NULL */
+{
+ double *pci, *pc0i;
+ int i, j, naxes;
+
+ if (pc == NULL)
+ return;
+
+ naxes = wcs->naxis;
+/* if (naxes > 2)
+ naxes = 2; */
+ if (naxes < 1 || naxes > 9) {
+ naxes = wcs->naxes;
+ wcs->naxis = naxes;
+ }
+ wcs->cdelt[0] = cdelt1;
+ if (cdelt2 != 0.0)
+ wcs->cdelt[1] = cdelt2;
+ else
+ wcs->cdelt[1] = cdelt1;
+ wcs->xinc = wcs->cdelt[0];
+ wcs->yinc = wcs->cdelt[1];
+
+ /* Set rotation matrix */
+ pci = wcs->pc;
+ pc0i = pc;
+ for (i = 0; i < naxes; i++) {
+ for (j = 0; j < naxes; j++) {
+ *pci = *pc0i;
+ pci++;
+ pc0i++;
+ }
+ }
+
+ /* Set CD matrix */
+ if (naxes > 1) {
+ wcs->cd[0] = pc[0] * wcs->cdelt[0];
+ wcs->cd[1] = pc[1] * wcs->cdelt[0];
+ wcs->cd[2] = pc[naxes] * wcs->cdelt[1];
+ wcs->cd[3] = pc[naxes+1] * wcs->cdelt[1];
+ }
+ else {
+ wcs->cd[0] = pc[0] * wcs->cdelt[0];
+ wcs->cd[1] = 0.0;
+ wcs->cd[2] = 0.0;
+ wcs->cd[3] = 1.0;
+ }
+ (void) matinv (2, wcs->cd, wcs->dc);
+ wcs->rotmat = 1;
+
+ (void)linset (&wcs->lin);
+ wcs->wcson = 1;
+
+ wcsrotset (wcs);
+
+ return;
+}
+
+
+/* Set up rotation matrix for WCSLIB projection subroutines */
+
+static void
+wcslibrot (wcs)
+
+struct WorldCoor *wcs; /* World coordinate system structure */
+
+{
+ int i, mem, naxes;
+
+ naxes = wcs->naxis;
+ if (naxes > 2)
+ naxes = 2;
+ if (naxes < 1 || naxes > 9) {
+ naxes = wcs->naxes;
+ wcs->naxis = naxes;
+ }
+ mem = naxes * naxes * sizeof(double);
+ if (wcs->lin.piximg == NULL)
+ wcs->lin.piximg = (double*)malloc(mem);
+ if (wcs->lin.piximg != NULL) {
+ if (wcs->lin.imgpix == NULL)
+ wcs->lin.imgpix = (double*)malloc(mem);
+ if (wcs->lin.imgpix != NULL) {
+ wcs->lin.flag = LINSET;
+ if (naxes == 2) {
+ for (i = 0; i < 4; i++) {
+ wcs->lin.piximg[i] = wcs->cd[i];
+ }
+ }
+ else if (naxes == 3) {
+ for (i = 0; i < 9; i++)
+ wcs->lin.piximg[i] = 0.0;
+ wcs->lin.piximg[0] = wcs->cd[0];
+ wcs->lin.piximg[1] = wcs->cd[1];
+ wcs->lin.piximg[3] = wcs->cd[2];
+ wcs->lin.piximg[4] = wcs->cd[3];
+ wcs->lin.piximg[8] = 1.0;
+ }
+ else if (naxes == 4) {
+ for (i = 0; i < 16; i++)
+ wcs->lin.piximg[i] = 0.0;
+ wcs->lin.piximg[0] = wcs->cd[0];
+ wcs->lin.piximg[1] = wcs->cd[1];
+ wcs->lin.piximg[4] = wcs->cd[2];
+ wcs->lin.piximg[5] = wcs->cd[3];
+ wcs->lin.piximg[10] = 1.0;
+ wcs->lin.piximg[15] = 1.0;
+ }
+ (void) matinv (naxes, wcs->lin.piximg, wcs->lin.imgpix);
+ wcs->lin.crpix = wcs->crpix;
+ wcs->lin.cdelt = wcs->cdelt;
+ wcs->lin.pc = wcs->pc;
+ wcs->lin.flag = LINSET;
+ }
+ }
+ return;
+}
+
+
+/* Compute image rotation */
+
+void
+wcsrotset (wcs)
+
+struct WorldCoor *wcs; /* World coordinate system structure */
+{
+ int off;
+ double cra, cdec, xc, xn, xe, yc, yn, ye;
+
+ /* If image is one-dimensional, leave rotation angle alone */
+ if (wcs->nxpix < 1.5 || wcs->nypix < 1.5) {
+ wcs->imrot = wcs->rot;
+ wcs->pa_north = wcs->rot + 90.0;
+ wcs->pa_east = wcs->rot + 180.0;
+ return;
+ }
+
+
+ /* Do not try anything if image is LINEAR (not Cartesian projection) */
+ if (wcs->syswcs == WCS_LINEAR)
+ return;
+
+ wcs->xinc = fabs (wcs->xinc);
+ wcs->yinc = fabs (wcs->yinc);
+
+ /* Compute position angles of North and East in image */
+ xc = wcs->xrefpix;
+ yc = wcs->yrefpix;
+ pix2wcs (wcs, xc, yc, &cra, &cdec);
+ if (wcs->coorflip) {
+ wcs2pix (wcs, cra+wcs->yinc, cdec, &xe, &ye, &off);
+ wcs2pix (wcs, cra, cdec+wcs->xinc, &xn, &yn, &off);
+ }
+ else {
+ wcs2pix (wcs, cra+wcs->xinc, cdec, &xe, &ye, &off);
+ wcs2pix (wcs, cra, cdec+wcs->yinc, &xn, &yn, &off);
+ }
+ wcs->pa_north = raddeg (atan2 (yn-yc, xn-xc));
+ if (wcs->pa_north < -90.0)
+ wcs->pa_north = wcs->pa_north + 360.0;
+ wcs->pa_east = raddeg (atan2 (ye-yc, xe-xc));
+ if (wcs->pa_east < -90.0)
+ wcs->pa_east = wcs->pa_east + 360.0;
+
+ /* Compute image rotation angle from North */
+ if (wcs->pa_north < -90.0)
+ wcs->imrot = 270.0 + wcs->pa_north;
+ else
+ wcs->imrot = wcs->pa_north - 90.0;
+
+ /* Compute CROTA */
+ if (wcs->coorflip) {
+ wcs->rot = wcs->imrot + 90.0;
+ if (wcs->rot < 0.0)
+ wcs->rot = wcs->rot + 360.0;
+ }
+ else
+ wcs->rot = wcs->imrot;
+ if (wcs->rot < 0.0)
+ wcs->rot = wcs->rot + 360.0;
+ if (wcs->rot >= 360.0)
+ wcs->rot = wcs->rot - 360.0;
+
+ /* Set image mirror flag based on axis orientation */
+ wcs->imflip = 0;
+ if (wcs->pa_east - wcs->pa_north < -80.0 &&
+ wcs->pa_east - wcs->pa_north > -100.0)
+ wcs->imflip = 1;
+ if (wcs->pa_east - wcs->pa_north < 280.0 &&
+ wcs->pa_east - wcs->pa_north > 260.0)
+ wcs->imflip = 1;
+ if (wcs->pa_north - wcs->pa_east > 80.0 &&
+ wcs->pa_north - wcs->pa_east < 100.0)
+ wcs->imflip = 1;
+ if (wcs->coorflip) {
+ if (wcs->imflip)
+ wcs->yinc = -wcs->yinc;
+ }
+ else {
+ if (!wcs->imflip)
+ wcs->xinc = -wcs->xinc;
+ }
+
+ return;
+}
+
+
+/* Return 1 if WCS structure is filled, else 0 */
+
+int
+iswcs (wcs)
+
+struct WorldCoor *wcs; /* World coordinate system structure */
+
+{
+ if (wcs == NULL)
+ return (0);
+ else
+ return (wcs->wcson);
+}
+
+
+/* Return 0 if WCS structure is filled, else 1 */
+
+int
+nowcs (wcs)
+
+struct WorldCoor *wcs; /* World coordinate system structure */
+
+{
+ if (wcs == NULL)
+ return (1);
+ else
+ return (!wcs->wcson);
+}
+
+
+/* Reset the center of a WCS structure */
+
+void
+wcsshift (wcs,rra,rdec,coorsys)
+
+struct WorldCoor *wcs; /* World coordinate system structure */
+double rra; /* Reference pixel right ascension in degrees */
+double rdec; /* Reference pixel declination in degrees */
+char *coorsys; /* FK4 or FK5 coordinates (1950 or 2000) */
+
+{
+ if (nowcs (wcs))
+ return;
+
+/* Approximate world coordinate system from a known plate scale */
+ wcs->crval[0] = rra;
+ wcs->crval[1] = rdec;
+ wcs->xref = wcs->crval[0];
+ wcs->yref = wcs->crval[1];
+
+
+/* Coordinate reference frame */
+ strcpy (wcs->radecsys,coorsys);
+ wcs->syswcs = wcscsys (coorsys);
+ if (wcs->syswcs == WCS_B1950)
+ wcs->equinox = 1950.0;
+ else
+ wcs->equinox = 2000.0;
+
+ return;
+}
+
+/* Print position of WCS center, if WCS is set */
+
+void
+wcscent (wcs)
+
+struct WorldCoor *wcs; /* World coordinate system structure */
+
+{
+ double xpix,ypix, xpos1, xpos2, ypos1, ypos2;
+ char wcstring[32];
+ double width, height, secpix, secpixh, secpixw;
+ int lstr = 32;
+
+ if (nowcs (wcs))
+ (void)fprintf (stderr,"No WCS information available\n");
+ else {
+ if (wcs->prjcode == WCS_DSS)
+ (void)fprintf (stderr,"WCS plate center %s\n", wcs->center);
+ xpix = 0.5 * wcs->nxpix;
+ ypix = 0.5 * wcs->nypix;
+ (void) pix2wcst (wcs,xpix,ypix,wcstring, lstr);
+ (void)fprintf (stderr,"WCS center %s %s %s %s at pixel (%.2f,%.2f)\n",
+ wcs->ctype[0],wcs->ctype[1],wcstring,wcs->ptype,xpix,ypix);
+
+ /* Image width */
+ (void) pix2wcs (wcs,1.0,ypix,&xpos1,&ypos1);
+ (void) pix2wcs (wcs,wcs->nxpix,ypix,&xpos2,&ypos2);
+ if (wcs->syswcs == WCS_LINEAR) {
+ width = xpos2 - xpos1;
+ if (width < 100.0)
+ (void)fprintf (stderr, "WCS width = %.5f %s ",width, wcs->units[0]);
+ else
+ (void)fprintf (stderr, "WCS width = %.3f %s ",width, wcs->units[0]);
+ }
+ else {
+ width = wcsdist (xpos1,ypos1,xpos2,ypos2);
+ if (width < 1/60.0)
+ (void)fprintf (stderr, "WCS width = %.2f arcsec ",width*3600.0);
+ else if (width < 1.0)
+ (void)fprintf (stderr, "WCS width = %.2f arcmin ",width*60.0);
+ else
+ (void)fprintf (stderr, "WCS width = %.3f degrees ",width);
+ }
+ secpixw = width / (wcs->nxpix - 1.0);
+
+ /* Image height */
+ (void) pix2wcs (wcs,xpix,1.0,&xpos1,&ypos1);
+ (void) pix2wcs (wcs,xpix,wcs->nypix,&xpos2,&ypos2);
+ if (wcs->syswcs == WCS_LINEAR) {
+ height = ypos2 - ypos1;
+ if (height < 100.0)
+ (void)fprintf (stderr, " height = %.5f %s ",height, wcs->units[1]);
+ else
+ (void)fprintf (stderr, " height = %.3f %s ",height, wcs->units[1]);
+ }
+ else {
+ height = wcsdist (xpos1,ypos1,xpos2,ypos2);
+ if (height < 1/60.0)
+ (void) fprintf (stderr, " height = %.2f arcsec",height*3600.0);
+ else if (height < 1.0)
+ (void) fprintf (stderr, " height = %.2f arcmin",height*60.0);
+ else
+ (void) fprintf (stderr, " height = %.3f degrees",height);
+ }
+ secpixh = height / (wcs->nypix - 1.0);
+
+ /* Image scale */
+ if (wcs->syswcs == WCS_LINEAR) {
+ (void) fprintf (stderr,"\n");
+ (void) fprintf (stderr,"WCS %.5f %s/pixel, %.5f %s/pixel\n",
+ wcs->xinc,wcs->units[0],wcs->yinc,wcs->units[1]);
+ }
+ else {
+ if (wcs->xinc != 0.0 && wcs->yinc != 0.0)
+ secpix = (fabs(wcs->xinc) + fabs(wcs->yinc)) * 0.5 * 3600.0;
+ else if (secpixh > 0.0 && secpixw > 0.0)
+ secpix = (secpixw + secpixh) * 0.5 * 3600.0;
+ else if (wcs->xinc != 0.0 || wcs->yinc != 0.0)
+ secpix = (fabs(wcs->xinc) + fabs(wcs->yinc)) * 3600.0;
+ else
+ secpix = (secpixw + secpixh) * 3600.0;
+ if (secpix < 100.0)
+ (void) fprintf (stderr, " %.3f arcsec/pixel\n",secpix);
+ else if (secpix < 3600.0)
+ (void) fprintf (stderr, " %.3f arcmin/pixel\n",secpix/60.0);
+ else
+ (void) fprintf (stderr, " %.3f degrees/pixel\n",secpix/3600.0);
+ }
+ }
+ return;
+}
+
+/* Return RA and Dec of image center, plus size in RA and Dec */
+
+void
+wcssize (wcs, cra, cdec, dra, ddec)
+
+struct WorldCoor *wcs; /* World coordinate system structure */
+double *cra; /* Right ascension of image center (deg) (returned) */
+double *cdec; /* Declination of image center (deg) (returned) */
+double *dra; /* Half-width in right ascension (deg) (returned) */
+double *ddec; /* Half-width in declination (deg) (returned) */
+
+{
+ double width, height;
+
+ /* Find right ascension and declination of coordinates */
+ if (iswcs(wcs)) {
+ wcsfull (wcs, cra, cdec, &width, &height);
+ *dra = 0.5 * width / cos (degrad (*cdec));
+ *ddec = 0.5 * height;
+ }
+ else {
+ *cra = 0.0;
+ *cdec = 0.0;
+ *dra = 0.0;
+ *ddec = 0.0;
+ }
+ return;
+}
+
+
+/* Return RA and Dec of image center, plus size in degrees */
+
+void
+wcsfull (wcs, cra, cdec, width, height)
+
+struct WorldCoor *wcs; /* World coordinate system structure */
+double *cra; /* Right ascension of image center (deg) (returned) */
+double *cdec; /* Declination of image center (deg) (returned) */
+double *width; /* Width in degrees (returned) */
+double *height; /* Height in degrees (returned) */
+
+{
+ double xpix, ypix, xpos1, xpos2, ypos1, ypos2, xcpix, ycpix;
+ double xcent, ycent;
+
+ /* Find right ascension and declination of coordinates */
+ if (iswcs(wcs)) {
+ xcpix = (0.5 * wcs->nxpix) + 0.5;
+ ycpix = (0.5 * wcs->nypix) + 0.5;
+ (void) pix2wcs (wcs,xcpix,ycpix,&xcent, &ycent);
+ *cra = xcent;
+ *cdec = ycent;
+
+ /* Compute image width in degrees */
+ xpix = 0.500001;
+ (void) pix2wcs (wcs,xpix,ycpix,&xpos1,&ypos1);
+ xpix = wcs->nxpix + 0.499999;
+ (void) pix2wcs (wcs,xpix,ycpix,&xpos2,&ypos2);
+ if (strncmp (wcs->ptype,"LINEAR",6) &&
+ strncmp (wcs->ptype,"PIXEL",5)) {
+ *width = wcsdist (xpos1,ypos1,xpos2,ypos2);
+ }
+ else
+ *width = sqrt (((ypos2-ypos1) * (ypos2-ypos1)) +
+ ((xpos2-xpos1) * (xpos2-xpos1)));
+
+ /* Compute image height in degrees */
+ ypix = 0.5;
+ (void) pix2wcs (wcs,xcpix,ypix,&xpos1,&ypos1);
+ ypix = wcs->nypix + 0.5;
+ (void) pix2wcs (wcs,xcpix,ypix,&xpos2,&ypos2);
+ if (strncmp (wcs->ptype,"LINEAR",6) &&
+ strncmp (wcs->ptype,"PIXEL",5))
+ *height = wcsdist (xpos1,ypos1,xpos2,ypos2);
+ else
+ *height = sqrt (((ypos2-ypos1) * (ypos2-ypos1)) +
+ ((xpos2-xpos1) * (xpos2-xpos1)));
+ }
+
+ else {
+ *cra = 0.0;
+ *cdec = 0.0;
+ *width = 0.0;
+ *height = 0.0;
+ }
+
+ return;
+}
+
+
+/* Return minimum and maximum RA and Dec of image in degrees */
+
+void
+wcsrange (wcs, ra1, ra2, dec1, dec2)
+
+struct WorldCoor *wcs; /* World coordinate system structure */
+double *ra1; /* Minimum right ascension of image (deg) (returned) */
+double *ra2; /* Maximum right ascension of image (deg) (returned) */
+double *dec1; /* Minimum declination of image (deg) (returned) */
+double *dec2; /* Maximum declination of image (deg) (returned) */
+
+{
+ double xpos1, xpos2, xpos3, xpos4, ypos1, ypos2, ypos3, ypos4, temp;
+
+ if (iswcs(wcs)) {
+
+ /* Compute image corner coordinates in degrees */
+ (void) pix2wcs (wcs,1.0,1.0,&xpos1,&ypos1);
+ (void) pix2wcs (wcs,1.0,wcs->nypix,&xpos2,&ypos2);
+ (void) pix2wcs (wcs,wcs->nxpix,1.0,&xpos3,&ypos3);
+ (void) pix2wcs (wcs,wcs->nxpix,wcs->nypix,&xpos4,&ypos4);
+
+ /* Find minimum right ascension or longitude */
+ *ra1 = xpos1;
+ if (xpos2 < *ra1) *ra1 = xpos2;
+ if (xpos3 < *ra1) *ra1 = xpos3;
+ if (xpos4 < *ra1) *ra1 = xpos4;
+
+ /* Find maximum right ascension or longitude */
+ *ra2 = xpos1;
+ if (xpos2 > *ra2) *ra2 = xpos2;
+ if (xpos3 > *ra2) *ra2 = xpos3;
+ if (xpos4 > *ra2) *ra2 = xpos4;
+
+ if (wcs->syswcs != WCS_LINEAR && wcs->syswcs != WCS_XY) {
+ if (*ra2 - *ra1 > 180.0) {
+ temp = *ra1;
+ *ra1 = *ra2;
+ *ra2 = temp;
+ }
+ }
+
+ /* Find minimum declination or latitude */
+ *dec1 = ypos1;
+ if (ypos2 < *dec1) *dec1 = ypos2;
+ if (ypos3 < *dec1) *dec1 = ypos3;
+ if (ypos4 < *dec1) *dec1 = ypos4;
+
+ /* Find maximum declination or latitude */
+ *dec2 = ypos1;
+ if (ypos2 > *dec2) *dec2 = ypos2;
+ if (ypos3 > *dec2) *dec2 = ypos3;
+ if (ypos4 > *dec2) *dec2 = ypos4;
+ }
+
+ else {
+ *ra1 = 0.0;
+ *ra2 = 0.0;
+ *dec1 = 0.0;
+ *dec2 = 0.0;
+ }
+
+ return;
+}
+
+
+/* Compute distance in degrees between two sky coordinates */
+
+double
+wcsdist (x1,y1,x2,y2)
+
+double x1,y1; /* (RA,Dec) or (Long,Lat) in degrees */
+double x2,y2; /* (RA,Dec) or (Long,Lat) in degrees */
+
+{
+ double r, diffi;
+ double pos1[3], pos2[3], w, diff;
+ int i;
+
+ /* Convert two vectors to direction cosines */
+ r = 1.0;
+ d2v3 (x1, y1, r, pos1);
+ d2v3 (x2, y2, r, pos2);
+
+ /* Modulus squared of half the difference vector */
+ w = 0.0;
+ for (i = 0; i < 3; i++) {
+ diffi = pos1[i] - pos2[i];
+ w = w + (diffi * diffi);
+ }
+ w = w / 4.0;
+ if (w > 1.0) w = 1.0;
+
+ /* Angle beween the vectors */
+ diff = 2.0 * atan2 (sqrt (w), sqrt (1.0 - w));
+ diff = raddeg (diff);
+ return (diff);
+}
+
+
+
+/* Compute distance in degrees between two sky coordinates */
+
+double
+wcsdist1 (x1,y1,x2,y2)
+
+double x1,y1; /* (RA,Dec) or (Long,Lat) in degrees */
+double x2,y2; /* (RA,Dec) or (Long,Lat) in degrees */
+
+{
+ double d1, d2, r;
+ double pos1[3], pos2[3], w, diff;
+ int i;
+
+ /* Convert two vectors to direction cosines */
+ r = 1.0;
+ d2v3 (x1, y1, r, pos1);
+ d2v3 (x2, y2, r, pos2);
+
+ w = 0.0;
+ d1 = 0.0;
+ d2 = 0.0;
+ for (i = 0; i < 3; i++) {
+ w = w + (pos1[i] * pos2[i]);
+ d1 = d1 + (pos1[i] * pos1[i]);
+ d2 = d2 + (pos2[i] * pos2[i]);
+ }
+ diff = acosdeg (w / (sqrt (d1) * sqrt (d2)));
+ return (diff);
+}
+
+
+/* Compute distance in degrees between two sky coordinates away from pole */
+
+double
+wcsdiff (x1,y1,x2,y2)
+
+double x1,y1; /* (RA,Dec) or (Long,Lat) in degrees */
+double x2,y2; /* (RA,Dec) or (Long,Lat) in degrees */
+
+{
+ double xdiff, ydiff, ycos, diff;
+
+ ycos = cos (degrad ((y2 + y1) / 2.0));
+ xdiff = x2 - x1;
+ if (xdiff > 180.0)
+ xdiff = xdiff - 360.0;
+ if (xdiff < -180.0)
+ xdiff = xdiff + 360.0;
+ xdiff = xdiff / ycos;
+ ydiff = (y2 - y1);
+ diff = sqrt ((xdiff * xdiff) + (ydiff * ydiff));
+ return (diff);
+}
+
+
+/* Initialize catalog search command set by -wcscom */
+
+void
+wcscominit (wcs, i, command)
+
+struct WorldCoor *wcs; /* World coordinate system structure */
+int i; /* Number of command (0-9) to initialize */
+char *command; /* command with %s where coordinates will go */
+
+{
+ int lcom,icom;
+
+ if (iswcs(wcs)) {
+ lcom = strlen (command);
+ if (lcom > 0) {
+ if (wcs->command_format[i] != NULL)
+ free (wcs->command_format[i]);
+ wcs->command_format[i] = (char *) calloc (lcom+2, 1);
+ if (wcs->command_format[i] == NULL)
+ return;
+ for (icom = 0; icom < lcom; icom++) {
+ if (command[icom] == '_')
+ wcs->command_format[i][icom] = ' ';
+ else
+ wcs->command_format[i][icom] = command[icom];
+ }
+ wcs->command_format[i][lcom] = 0;
+ }
+ }
+ return;
+}
+
+
+/* Execute Unix command with world coordinates (from x,y) and/or filename */
+
+void
+wcscom ( wcs, i, filename, xfile, yfile, wcstring )
+
+struct WorldCoor *wcs; /* World coordinate system structure */
+int i; /* Number of command (0-9) to execute */
+char *filename; /* Image file name */
+double xfile,yfile; /* Image pixel coordinates for WCS command */
+char *wcstring; /* WCS String from pix2wcst() */
+{
+ char command[120];
+ char comform[120];
+ char xystring[32];
+ char *fileform, *posform, *imform;
+ int ier;
+
+ if (nowcs (wcs)) {
+ (void)fprintf(stderr,"WCSCOM: no WCS\n");
+ return;
+ }
+
+ if (wcs->command_format[i] != NULL)
+ strcpy (comform, wcs->command_format[i]);
+ else
+ strcpy (comform, "sgsc -ah %s");
+
+ if (comform[0] > 0) {
+
+ /* Create and execute search command */
+ fileform = strsrch (comform,"%f");
+ imform = strsrch (comform,"%x");
+ posform = strsrch (comform,"%s");
+ if (imform != NULL) {
+ *(imform+1) = 's';
+ (void)sprintf (xystring, "%.2f %.2f", xfile, yfile);
+ if (fileform != NULL) {
+ *(fileform+1) = 's';
+ if (posform == NULL) {
+ if (imform < fileform)
+ (void)sprintf(command, comform, xystring, filename);
+ else
+ (void)sprintf(command, comform, filename, xystring);
+ }
+ else if (fileform < posform) {
+ if (imform < fileform)
+ (void)sprintf(command, comform, xystring, filename,
+ wcstring);
+ else if (imform < posform)
+ (void)sprintf(command, comform, filename, xystring,
+ wcstring);
+ else
+ (void)sprintf(command, comform, filename, wcstring,
+ xystring);
+ }
+ else
+ if (imform < posform)
+ (void)sprintf(command, comform, xystring, wcstring,
+ filename);
+ else if (imform < fileform)
+ (void)sprintf(command, comform, wcstring, xystring,
+ filename);
+ else
+ (void)sprintf(command, comform, wcstring, filename,
+ xystring);
+ }
+ else if (posform == NULL)
+ (void)sprintf(command, comform, xystring);
+ else if (imform < posform)
+ (void)sprintf(command, comform, xystring, wcstring);
+ else
+ (void)sprintf(command, comform, wcstring, xystring);
+ }
+ else if (fileform != NULL) {
+ *(fileform+1) = 's';
+ if (posform == NULL)
+ (void)sprintf(command, comform, filename);
+ else if (fileform < posform)
+ (void)sprintf(command, comform, filename, wcstring);
+ else
+ (void)sprintf(command, comform, wcstring, filename);
+ }
+ else
+ (void)sprintf(command, comform, wcstring);
+ ier = system (command);
+ if (ier)
+ (void)fprintf(stderr,"WCSCOM: %s failed %d\n",command,ier);
+ }
+ return;
+}
+
+/* Initialize WCS output coordinate system for use by PIX2WCS() */
+
+void
+wcsoutinit (wcs, coorsys)
+
+struct WorldCoor *wcs; /* World coordinate system structure */
+char *coorsys; /* Input world coordinate system:
+ FK4, FK5, B1950, J2000, GALACTIC, ECLIPTIC
+ fk4, fk5, b1950, j2000, galactic, ecliptic */
+{
+ int sysout, i;
+
+ if (nowcs (wcs))
+ return;
+
+ /* If argument is null, set to image system and equinox */
+ if (coorsys == NULL || strlen (coorsys) < 1 ||
+ !strcmp(coorsys,"IMSYS") || !strcmp(coorsys,"imsys")) {
+ sysout = wcs->syswcs;
+ strcpy (wcs->radecout, wcs->radecsys);
+ wcs->eqout = wcs->equinox;
+ if (sysout == WCS_B1950) {
+ if (wcs->eqout != 1950.0) {
+ wcs->radecout[0] = 'B';
+ sprintf (wcs->radecout+1,"%.4f", wcs->equinox);
+ i = strlen(wcs->radecout) - 1;
+ if (wcs->radecout[i] == '0')
+ wcs->radecout[i] = (char)0;
+ i = strlen(wcs->radecout) - 1;
+ if (wcs->radecout[i] == '0')
+ wcs->radecout[i] = (char)0;
+ i = strlen(wcs->radecout) - 1;
+ if (wcs->radecout[i] == '0')
+ wcs->radecout[i] = (char)0;
+ }
+ else
+ strcpy (wcs->radecout, "B1950");
+ }
+ else if (sysout == WCS_J2000) {
+ if (wcs->eqout != 2000.0) {
+ wcs->radecout[0] = 'J';
+ sprintf (wcs->radecout+1,"%.4f", wcs->equinox);
+ i = strlen(wcs->radecout) - 1;
+ if (wcs->radecout[i] == '0')
+ wcs->radecout[i] = (char)0;
+ i = strlen(wcs->radecout) - 1;
+ if (wcs->radecout[i] == '0')
+ wcs->radecout[i] = (char)0;
+ i = strlen(wcs->radecout) - 1;
+ if (wcs->radecout[i] == '0')
+ wcs->radecout[i] = (char)0;
+ }
+ else
+ strcpy (wcs->radecout, "J2000");
+ }
+ }
+
+ /* Ignore new coordinate system if it is not supported */
+ else {
+ if ((sysout = wcscsys (coorsys)) < 0)
+ return;
+
+ /* Do not try to convert linear or alt-az coordinates */
+ if (sysout != wcs->syswcs &&
+ (wcs->syswcs == WCS_LINEAR || wcs->syswcs == WCS_ALTAZ))
+ return;
+
+ strcpy (wcs->radecout, coorsys);
+ wcs->eqout = wcsceq (coorsys);
+ }
+
+ wcs->sysout = sysout;
+ if (wcs->wcson) {
+
+ /* Set output in degrees flag and number of decimal places */
+ if (wcs->sysout == WCS_GALACTIC || wcs->sysout == WCS_ECLIPTIC ||
+ wcs->sysout == WCS_PLANET) {
+ wcs->degout = 1;
+ wcs->ndec = 5;
+ }
+ else if (wcs->sysout == WCS_ALTAZ) {
+ wcs->degout = 1;
+ wcs->ndec = 5;
+ }
+ else if (wcs->sysout == WCS_NPOLE || wcs->sysout == WCS_SPA) {
+ wcs->degout = 1;
+ wcs->ndec = 5;
+ }
+ else {
+ wcs->degout = 0;
+ wcs->ndec = 3;
+ }
+ }
+ return;
+}
+
+
+/* Return current value of WCS output coordinate system set by -wcsout */
+char *
+getwcsout(wcs)
+struct WorldCoor *wcs; /* World coordinate system structure */
+{
+ if (nowcs (wcs))
+ return (NULL);
+ else
+ return(wcs->radecout);
+}
+
+
+/* Initialize WCS input coordinate system for use by WCS2PIX() */
+
+void
+wcsininit (wcs, coorsys)
+
+struct WorldCoor *wcs; /* World coordinate system structure */
+char *coorsys; /* Input world coordinate system:
+ FK4, FK5, B1950, J2000, GALACTIC, ECLIPTIC
+ fk4, fk5, b1950, j2000, galactic, ecliptic */
+{
+ int sysin, i;
+
+ if (nowcs (wcs))
+ return;
+
+ /* If argument is null, set to image system and equinox */
+ if (coorsys == NULL || strlen (coorsys) < 1) {
+ wcs->sysin = wcs->syswcs;
+ strcpy (wcs->radecin, wcs->radecsys);
+ wcs->eqin = wcs->equinox;
+ if (wcs->sysin == WCS_B1950) {
+ if (wcs->eqin != 1950.0) {
+ wcs->radecin[0] = 'B';
+ sprintf (wcs->radecin+1,"%.4f", wcs->equinox);
+ i = strlen(wcs->radecin) - 1;
+ if (wcs->radecin[i] == '0')
+ wcs->radecin[i] = (char)0;
+ i = strlen(wcs->radecin) - 1;
+ if (wcs->radecin[i] == '0')
+ wcs->radecin[i] = (char)0;
+ i = strlen(wcs->radecin) - 1;
+ if (wcs->radecin[i] == '0')
+ wcs->radecin[i] = (char)0;
+ }
+ else
+ strcpy (wcs->radecin, "B1950");
+ }
+ else if (wcs->sysin == WCS_J2000) {
+ if (wcs->eqin != 2000.0) {
+ wcs->radecin[0] = 'J';
+ sprintf (wcs->radecin+1,"%.4f", wcs->equinox);
+ i = strlen(wcs->radecin) - 1;
+ if (wcs->radecin[i] == '0')
+ wcs->radecin[i] = (char)0;
+ i = strlen(wcs->radecin) - 1;
+ if (wcs->radecin[i] == '0')
+ wcs->radecin[i] = (char)0;
+ i = strlen(wcs->radecin) - 1;
+ if (wcs->radecin[i] == '0')
+ wcs->radecin[i] = (char)0;
+ }
+ else
+ strcpy (wcs->radecin, "J2000");
+ }
+ }
+
+ /* Ignore new coordinate system if it is not supported */
+ if ((sysin = wcscsys (coorsys)) < 0)
+ return;
+
+ wcs->sysin = sysin;
+ wcs->eqin = wcsceq (coorsys);
+ strcpy (wcs->radecin, coorsys);
+ return;
+}
+
+
+/* Return current value of WCS input coordinate system set by wcsininit */
+char *
+getwcsin (wcs)
+struct WorldCoor *wcs; /* World coordinate system structure */
+{
+ if (nowcs (wcs))
+ return (NULL);
+ else
+ return (wcs->radecin);
+}
+
+
+/* Set WCS output in degrees or hh:mm:ss dd:mm:ss, returning old flag value */
+int
+setwcsdeg(wcs, new)
+struct WorldCoor *wcs; /* World coordinate system structure */
+int new; /* 1: degrees, 0: h:m:s d:m:s */
+{
+ int old;
+
+ if (nowcs (wcs))
+ return (0);
+ old = wcs->degout;
+ wcs->degout = new;
+ if (new == 1 && old == 0 && wcs->ndec == 3)
+ wcs->ndec = 6;
+ if (new == 0 && old == 1 && wcs->ndec == 5)
+ wcs->ndec = 3;
+ return(old);
+}
+
+
+/* Set number of decimal places in pix2wcst output string */
+int
+wcsndec (wcs, ndec)
+struct WorldCoor *wcs; /* World coordinate system structure */
+int ndec; /* Number of decimal places in output string */
+ /* If < 0, return current unchanged value */
+{
+ if (nowcs (wcs))
+ return (0);
+ else if (ndec >= 0)
+ wcs->ndec = ndec;
+ return (wcs->ndec);
+}
+
+
+
+/* Return current value of coordinate system */
+char *
+getradecsys(wcs)
+struct WorldCoor *wcs; /* World coordinate system structure */
+{
+ if (nowcs (wcs))
+ return (NULL);
+ else
+ return (wcs->radecsys);
+}
+
+
+/* Set output string mode for LINEAR coordinates */
+
+void
+setwcslin (wcs, mode)
+struct WorldCoor *wcs; /* World coordinate system structure */
+int mode; /* mode = 0: x y linear
+ mode = 1: x units x units
+ mode = 2: x y linear units */
+{
+ if (iswcs (wcs))
+ wcs->linmode = mode;
+ return;
+}
+
+
+/* Convert pixel coordinates to World Coordinate string */
+
+int
+pix2wcst (wcs, xpix, ypix, wcstring, lstr)
+
+struct WorldCoor *wcs; /* World coordinate system structure */
+double xpix,ypix; /* Image coordinates in pixels */
+char *wcstring; /* World coordinate string (returned) */
+int lstr; /* Length of world coordinate string (returned) */
+{
+ double xpos,ypos;
+ char rastr[32], decstr[32];
+ int minlength, lunits, lstring;
+
+ if (nowcs (wcs)) {
+ if (lstr > 0)
+ wcstring[0] = 0;
+ return(0);
+ }
+
+ pix2wcs (wcs,xpix,ypix,&xpos,&ypos);
+
+ /* If point is off scale, set string accordingly */
+ if (wcs->offscl) {
+ (void)sprintf (wcstring,"Off map");
+ return (1);
+ }
+
+ /* Print coordinates in degrees */
+ else if (wcs->degout == 1) {
+ minlength = 9 + (2 * wcs->ndec);
+ if (lstr > minlength) {
+ deg2str (rastr, 32, xpos, wcs->ndec);
+ deg2str (decstr, 32, ypos, wcs->ndec);
+ if (wcs->tabsys)
+ (void)sprintf (wcstring,"%s %s", rastr, decstr);
+ else
+ (void)sprintf (wcstring,"%s %s", rastr, decstr);
+ lstr = lstr - minlength;
+ }
+ else {
+ if (wcs->tabsys)
+ strncpy (wcstring,"********* **********",lstr);
+ else
+ strncpy (wcstring,"*******************",lstr);
+ lstr = 0;
+ }
+ }
+
+ /* print coordinates in sexagesimal notation */
+ else if (wcs->degout == 0) {
+ minlength = 18 + (2 * wcs->ndec);
+ if (lstr > minlength) {
+ if (wcs->sysout == WCS_J2000 || wcs->sysout == WCS_B1950) {
+ ra2str (rastr, 32, xpos, wcs->ndec);
+ dec2str (decstr, 32, ypos, wcs->ndec-1);
+ }
+ else {
+ dec2str (rastr, 32, xpos, wcs->ndec);
+ dec2str (decstr, 32, ypos, wcs->ndec);
+ }
+ if (wcs->tabsys) {
+ (void)sprintf (wcstring,"%s %s", rastr, decstr);
+ }
+ else {
+ (void)sprintf (wcstring,"%s %s", rastr, decstr);
+ }
+ lstr = lstr - minlength;
+ }
+ else {
+ if (wcs->tabsys) {
+ strncpy (wcstring,"************* *************",lstr);
+ }
+ else {
+ strncpy (wcstring,"**************************",lstr);
+ }
+ lstr = 0;
+ }
+ }
+
+ /* Label galactic coordinates */
+ if (wcs->sysout == WCS_GALACTIC) {
+ if (lstr > 9 && wcs->printsys) {
+ if (wcs->tabsys)
+ strcat (wcstring," galactic");
+ else
+ strcat (wcstring," galactic");
+ }
+ }
+
+ /* Label ecliptic coordinates */
+ else if (wcs->sysout == WCS_ECLIPTIC) {
+ if (lstr > 9 && wcs->printsys) {
+ if (wcs->tabsys)
+ strcat (wcstring," ecliptic");
+ else
+ strcat (wcstring," ecliptic");
+ }
+ }
+
+ /* Label planet coordinates */
+ else if (wcs->sysout == WCS_PLANET) {
+ if (lstr > 9 && wcs->printsys) {
+ if (wcs->tabsys)
+ strcat (wcstring," planet");
+ else
+ strcat (wcstring," planet");
+ }
+ }
+
+ /* Label alt-az coordinates */
+ else if (wcs->sysout == WCS_ALTAZ) {
+ if (lstr > 7 && wcs->printsys) {
+ if (wcs->tabsys)
+ strcat (wcstring," alt-az");
+ else
+ strcat (wcstring," alt-az");
+ }
+ }
+
+ /* Label north pole angle coordinates */
+ else if (wcs->sysout == WCS_NPOLE) {
+ if (lstr > 7 && wcs->printsys) {
+ if (wcs->tabsys)
+ strcat (wcstring," long-npa");
+ else
+ strcat (wcstring," long-npa");
+ }
+ }
+
+ /* Label south pole angle coordinates */
+ else if (wcs->sysout == WCS_SPA) {
+ if (lstr > 7 && wcs->printsys) {
+ if (wcs->tabsys)
+ strcat (wcstring," long-spa");
+ else
+ strcat (wcstring," long-spa");
+ }
+ }
+
+ /* Label equatorial coordinates */
+ else if (wcs->sysout==WCS_B1950 || wcs->sysout==WCS_J2000) {
+ if (lstr > (int) strlen(wcs->radecout)+1 && wcs->printsys) {
+ if (wcs->tabsys)
+ strcat (wcstring," ");
+ else
+ strcat (wcstring," ");
+ strcat (wcstring, wcs->radecout);
+ }
+ }
+
+ /* Output linear coordinates */
+ else {
+ num2str (rastr, xpos, 0, wcs->ndec);
+ num2str (decstr, ypos, 0, wcs->ndec);
+ lstring = strlen (rastr) + strlen (decstr) + 1;
+ lunits = strlen (wcs->units[0]) + strlen (wcs->units[1]) + 2;
+ if (wcs->syswcs == WCS_LINEAR && wcs->linmode == 1) {
+ if (lstr > lstring + lunits) {
+ if (strlen (wcs->units[0]) > 0) {
+ strcat (rastr, " ");
+ strcat (rastr, wcs->units[0]);
+ }
+ if (strlen (wcs->units[1]) > 0) {
+ strcat (decstr, " ");
+ strcat (decstr, wcs->units[1]);
+ }
+ lstring = lstring + lunits;
+ }
+ }
+ if (lstr > lstring) {
+ if (wcs->tabsys)
+ (void)sprintf (wcstring,"%s %s", rastr, decstr);
+ else
+ (void)sprintf (wcstring,"%s %s", rastr, decstr);
+ }
+ else {
+ if (wcs->tabsys)
+ strncpy (wcstring,"********** *********",lstr);
+ else
+ strncpy (wcstring,"*******************",lstr);
+ }
+ if (wcs->syswcs == WCS_LINEAR && wcs->linmode != 1 &&
+ lstr > lstring + 7)
+ strcat (wcstring, " linear");
+ if (wcs->syswcs == WCS_LINEAR && wcs->linmode == 2 &&
+ lstr > lstring + lunits + 7) {
+ if (strlen (wcs->units[0]) > 0) {
+ strcat (wcstring, " ");
+ strcat (wcstring, wcs->units[0]);
+ }
+ if (strlen (wcs->units[1]) > 0) {
+ strcat (wcstring, " ");
+ strcat (wcstring, wcs->units[1]);
+ }
+
+ }
+ }
+ return (1);
+}
+
+
+/* Convert pixel coordinates to World Coordinates */
+
+void
+pix2wcs (wcs,xpix,ypix,xpos,ypos)
+
+struct WorldCoor *wcs; /* World coordinate system structure */
+double xpix,ypix; /* x and y image coordinates in pixels */
+double *xpos,*ypos; /* RA and Dec in degrees (returned) */
+{
+ double xpi, ypi, xp, yp;
+ double eqin, eqout;
+ int wcspos();
+
+ if (nowcs (wcs))
+ return;
+ wcs->xpix = xpix;
+ wcs->ypix = ypix;
+ wcs->zpix = zpix;
+ wcs->offscl = 0;
+
+ /* If this WCS is converted from another WCS rather than pixels, convert now */
+ if (wcs->wcs != NULL) {
+ pix2wcs (wcs->wcs, xpix, ypix, &xpi, &ypi);
+ }
+ else {
+ pix2foc (wcs, xpix, ypix, &xpi, &ypi);
+ }
+
+ /* Convert image coordinates to sky coordinates */
+
+ /* Use Digitized Sky Survey plate fit */
+ if (wcs->prjcode == WCS_DSS) {
+ if (dsspos (xpi, ypi, wcs, &xp, &yp))
+ wcs->offscl = 1;
+ }
+
+ /* Use SAO plate fit */
+ else if (wcs->prjcode == WCS_PLT) {
+ if (platepos (xpi, ypi, wcs, &xp, &yp))
+ wcs->offscl = 1;
+ }
+
+ /* Use NOAO IRAF corrected plane tangent projection */
+ else if (wcs->prjcode == WCS_TNX) {
+ if (tnxpos (xpi, ypi, wcs, &xp, &yp))
+ wcs->offscl = 1;
+ }
+
+ /* Use NOAO IRAF corrected zenithal projection */
+ else if (wcs->prjcode == WCS_ZPX) {
+ if (zpxpos (xpi, ypi, wcs, &xp, &yp))
+ wcs->offscl = 1;
+ }
+
+ /* Use Classic AIPS projections */
+ else if (wcs->wcsproj == WCS_OLD || wcs->prjcode <= 0) {
+ if (worldpos (xpi, ypi, wcs, &xp, &yp))
+ wcs->offscl = 1;
+ }
+
+ /* Use Mark Calabretta's WCSLIB projections */
+ else if (wcspos (xpi, ypi, wcs, &xp, &yp))
+ wcs->offscl = 1;
+
+
+ /* Do not change coordinates if offscale */
+ if (wcs->offscl) {
+ *xpos = 0.0;
+ *ypos = 0.0;
+ }
+ else {
+
+ /* Convert coordinates to output system, if not LINEAR */
+ if (wcs->prjcode > 0) {
+
+ /* Convert coordinates to desired output system */
+ eqin = wcs->equinox;
+ eqout = wcs->eqout;
+ wcscon (wcs->syswcs,wcs->sysout,eqin,eqout,&xp,&yp,wcs->epoch);
+ }
+ if (wcs->latbase == 90)
+ yp = 90.0 - yp;
+ else if (wcs->latbase == -90)
+ yp = yp - 90.0;
+ wcs->xpos = xp;
+ wcs->ypos = yp;
+ *xpos = xp;
+ *ypos = yp;
+ }
+
+ /* Keep RA/longitude within range if spherical coordinate output
+ (Not LINEAR or XY) */
+ if (wcs->sysout > 0 && wcs->sysout != 6 && wcs->sysout != 10) {
+ if (*xpos < 0.0)
+ *xpos = *xpos + 360.0;
+ else if (*xpos > 360.0)
+ *xpos = *xpos - 360.0;
+ }
+
+ return;
+}
+
+
+/* Convert World Coordinates to pixel coordinates */
+
+void
+wcs2pix (wcs, xpos, ypos, xpix, ypix, offscl)
+
+struct WorldCoor *wcs; /* World coordinate system structure */
+double xpos,ypos; /* World coordinates in degrees */
+double *xpix,*ypix; /* Image coordinates in pixels */
+int *offscl; /* 0 if within bounds, else off scale */
+{
+ wcsc2pix (wcs, xpos, ypos, wcs->radecin, xpix, ypix, offscl);
+ return;
+}
+
+/* Convert World Coordinates to pixel coordinates */
+
+void
+wcsc2pix (wcs, xpos, ypos, coorsys, xpix, ypix, offscl)
+
+struct WorldCoor *wcs; /* World coordinate system structure */
+double xpos,ypos; /* World coordinates in degrees */
+char *coorsys; /* Input world coordinate system:
+ FK4, FK5, B1950, J2000, GALACTIC, ECLIPTIC
+ fk4, fk5, b1950, j2000, galactic, ecliptic
+ * If NULL, use image WCS */
+double *xpix,*ypix; /* Image coordinates in pixels */
+int *offscl; /* 0 if within bounds, else off scale */
+{
+ double xp, yp, xpi, ypi;
+ double eqin, eqout;
+ int sysin;
+ int wcspix();
+
+ if (nowcs (wcs))
+ return;
+
+ *offscl = 0;
+ xp = xpos;
+ yp = ypos;
+ if (wcs->latbase == 90)
+ yp = 90.0 - yp;
+ else if (wcs->latbase == -90)
+ yp = yp - 90.0;
+ if (coorsys == NULL) {
+ sysin = wcs->syswcs;
+ eqin = wcs->equinox;
+ }
+ else {
+ sysin = wcscsys (coorsys);
+ eqin = wcsceq (coorsys);
+ }
+ wcs->zpix = 1.0;
+
+ /* Convert coordinates to same system as image */
+ if (sysin > 0 && sysin != 6 && sysin != 10) {
+ eqout = wcs->equinox;
+ wcscon (sysin, wcs->syswcs, eqin, eqout, &xp, &yp, wcs->epoch);
+ }
+
+ /* Convert sky coordinates to image coordinates */
+
+ /* Use Digitized Sky Survey plate fit */
+ if (wcs->prjcode == WCS_DSS) {
+ if (dsspix (xp, yp, wcs, &xpi, &ypi))
+ *offscl = 1;
+ }
+
+ /* Use SAO polynomial plate fit */
+ else if (wcs->prjcode == WCS_PLT) {
+ if (platepix (xp, yp, wcs, &xpi, &ypi))
+ *offscl = 1;
+ }
+
+ /* Use NOAO IRAF corrected plane tangent projection */
+ else if (wcs->prjcode == WCS_TNX) {
+ if (tnxpix (xp, yp, wcs, &xpi, &ypi))
+ *offscl = 1;
+ }
+
+ /* Use NOAO IRAF corrected zenithal projection */
+ else if (wcs->prjcode == WCS_ZPX) {
+ if (zpxpix (xp, yp, wcs, &xpi, &ypi))
+ *offscl = 1;
+ }
+
+ /* Use Classic AIPS projections */
+ else if (wcs->wcsproj == WCS_OLD || wcs->prjcode <= 0) {
+ if (worldpix (xp, yp, wcs, &xpi, &ypi))
+ *offscl = 1;
+ }
+
+ /* Use Mark Calabretta's WCSLIB projections */
+ else if (wcspix (xp, yp, wcs, &xpi, &ypi)) {
+ *offscl = 1;
+ }
+
+ /* If this WCS is converted from another WCS rather than pixels, convert now */
+ if (wcs->wcs != NULL) {
+ wcsc2pix (wcs->wcs, xpi, ypi, NULL, xpix, ypix, offscl);
+ }
+ else {
+ foc2pix (wcs, xpi, ypi, xpix, ypix);
+
+ /* Set off-scale flag to 2 if off image but within bounds of projection */
+ if (!*offscl) {
+ if (*xpix < 0.5 || *ypix < 0.5)
+ *offscl = 2;
+ else if (*xpix > wcs->nxpix + 0.5 || *ypix > wcs->nypix + 0.5)
+ *offscl = 2;
+ }
+ }
+
+ wcs->offscl = *offscl;
+ wcs->xpos = xpos;
+ wcs->ypos = ypos;
+ wcs->xpix = *xpix;
+ wcs->ypix = *ypix;
+
+ return;
+}
+
+
+int
+wcspos (xpix, ypix, wcs, xpos, ypos)
+
+/* Input: */
+double xpix; /* x pixel number (RA or long without rotation) */
+double ypix; /* y pixel number (dec or lat without rotation) */
+struct WorldCoor *wcs; /* WCS parameter structure */
+
+/* Output: */
+double *xpos; /* x (RA) coordinate (deg) */
+double *ypos; /* y (dec) coordinate (deg) */
+{
+ int offscl;
+ int i;
+ int wcsrev();
+ double wcscrd[4], imgcrd[4], pixcrd[4];
+ double phi, theta;
+
+ *xpos = 0.0;
+ *ypos = 0.0;
+
+ pixcrd[0] = xpix;
+ pixcrd[1] = ypix;
+ if (wcs->prjcode == WCS_CSC || wcs->prjcode == WCS_QSC ||
+ wcs->prjcode == WCS_TSC)
+ pixcrd[2] = (double) (izpix + 1);
+ else
+ pixcrd[2] = zpix;
+ pixcrd[3] = 1.0;
+ for (i = 0; i < 4; i++)
+ imgcrd[i] = 0.0;
+ offscl = wcsrev ((void *)&wcs->ctype, &wcs->wcsl, pixcrd, &wcs->lin, imgcrd,
+ &wcs->prj, &phi, &theta, wcs->crval, &wcs->cel, wcscrd);
+ if (offscl == 0) {
+ *xpos = wcscrd[wcs->wcsl.lng];
+ *ypos = wcscrd[wcs->wcsl.lat];
+ }
+
+ return (offscl);
+}
+
+int
+wcspix (xpos, ypos, wcs, xpix, ypix)
+
+/* Input: */
+double xpos; /* x (RA) coordinate (deg) */
+double ypos; /* y (dec) coordinate (deg) */
+struct WorldCoor *wcs; /* WCS parameter structure */
+
+/* Output: */
+double *xpix; /* x pixel number (RA or long without rotation) */
+double *ypix; /* y pixel number (dec or lat without rotation) */
+
+{
+ int offscl;
+ int wcsfwd();
+ double wcscrd[4], imgcrd[4], pixcrd[4];
+ double phi, theta;
+
+ *xpix = 0.0;
+ *ypix = 0.0;
+ if (wcs->wcsl.flag != WCSSET) {
+ if (wcsset (wcs->lin.naxis, (void *)&wcs->ctype, &wcs->wcsl) )
+ return (1);
+ }
+
+ /* Set input for WCSLIB subroutines */
+ wcscrd[0] = 0.0;
+ wcscrd[1] = 0.0;
+ wcscrd[2] = 0.0;
+ wcscrd[3] = 0.0;
+ wcscrd[wcs->wcsl.lng] = xpos;
+ wcscrd[wcs->wcsl.lat] = ypos;
+
+ /* Initialize output for WCSLIB subroutines */
+ pixcrd[0] = 0.0;
+ pixcrd[1] = 0.0;
+ pixcrd[2] = 1.0;
+ pixcrd[3] = 1.0;
+ imgcrd[0] = 0.0;
+ imgcrd[1] = 0.0;
+ imgcrd[2] = 1.0;
+ imgcrd[3] = 1.0;
+
+ /* Invoke WCSLIB subroutines for coordinate conversion */
+ offscl = wcsfwd ((void *)&wcs->ctype, &wcs->wcsl, wcscrd, wcs->crval, &wcs->cel,
+ &phi, &theta, &wcs->prj, imgcrd, &wcs->lin, pixcrd);
+
+ if (!offscl) {
+ *xpix = pixcrd[0];
+ *ypix = pixcrd[1];
+ if (wcs->prjcode == WCS_CSC || wcs->prjcode == WCS_QSC ||
+ wcs->prjcode == WCS_TSC)
+ wcs->zpix = pixcrd[2] - 1.0;
+ else
+ wcs->zpix = pixcrd[2];
+ }
+ return (offscl);
+}
+
+
+/* Set third dimension for cube projections */
+
+int
+wcszin (izpix0)
+
+int izpix0; /* coordinate in third dimension
+ (if < 0, return current value without changing it */
+{
+ if (izpix0 > -1) {
+ izpix = izpix0;
+ zpix = (double) izpix0;
+ }
+ return (izpix);
+}
+
+
+/* Return third dimension for cube projections */
+
+int
+wcszout (wcs)
+
+struct WorldCoor *wcs; /* WCS parameter structure */
+{
+ return ((int) wcs->zpix);
+}
+
+/* Set file name for error messages */
+void
+setwcsfile (filename)
+char *filename; /* FITS or IRAF file with WCS */
+{ if (strlen (filename) < 256)
+ strcpy (wcsfile, filename);
+ else
+ strncpy (wcsfile, filename, 255);
+ return; }
+
+/* Set error message */
+void
+setwcserr (errmsg)
+char *errmsg; /* Error mesage < 80 char */
+{ strcpy (wcserrmsg, errmsg); return; }
+
+/* Print error message */
+void
+wcserr ()
+{ if (strlen (wcsfile) > 0)
+ fprintf (stderr, "%s in file %s\n",wcserrmsg, wcsfile);
+ else
+ fprintf (stderr, "%s\n",wcserrmsg);
+ return; }
+
+
+/* Flag to use AIPS WCS subroutines instead of WCSLIB */
+void
+setdefwcs (wp)
+int wp;
+{ wcsproj0 = wp; return; }
+
+int
+getdefwcs ()
+{ return (wcsproj0); }
+
+/* Save output default coordinate system */
+static char wcscoor0[16];
+
+void
+savewcscoor (wcscoor)
+char *wcscoor;
+{ strcpy (wcscoor0, wcscoor); return; }
+
+/* Return preset output default coordinate system */
+char *
+getwcscoor ()
+{ return (wcscoor0); }
+
+
+/* Save default commands */
+static char *wcscom0[10];
+
+void
+savewcscom (i, wcscom)
+int i;
+char *wcscom;
+{
+ int lcom;
+ if (i < 0) i = 0;
+ else if (i > 9) i = 9;
+ lcom = strlen (wcscom) + 2;
+ wcscom0[i] = (char *) calloc (lcom, 1);
+ if (wcscom0[i] != NULL)
+ strcpy (wcscom0[i], wcscom);
+ return;
+}
+
+void
+setwcscom (wcs)
+struct WorldCoor *wcs; /* WCS parameter structure */
+{
+ char envar[16];
+ int i;
+ char *str;
+ if (nowcs(wcs))
+ return;
+ for (i = 0; i < 10; i++) {
+ if (i == 0)
+ strcpy (envar, "WCS_COMMAND");
+ else
+ sprintf (envar, "WCS_COMMAND%d", i);
+ if (wcscom0[i] != NULL)
+ wcscominit (wcs, i, wcscom0[i]);
+ else if ((str = getenv (envar)) != NULL)
+ wcscominit (wcs, i, str);
+ else if (i == 1)
+ wcscominit (wcs, i, "sua2 -ah %s"); /* F1= Search USNO-A2.0 Catalog */
+ else if (i == 2)
+ wcscominit (wcs, i, "sgsc -ah %s"); /* F2= Search HST GSC */
+ else if (i == 3)
+ wcscominit (wcs, i, "sty2 -ah %s"); /* F3= Search Tycho-2 Catalog */
+ else if (i == 4)
+ wcscominit (wcs, i, "sppm -ah %s"); /* F4= Search PPM Catalog */
+ else if (i == 5)
+ wcscominit (wcs, i, "ssao -ah %s"); /* F5= Search SAO Catalog */
+ else
+ wcs->command_format[i] = NULL;
+ }
+ return;
+}
+
+char *
+getwcscom (i)
+int i;
+{ return (wcscom0[i]); }
+
+
+void
+freewcscom (wcs)
+struct WorldCoor *wcs; /* WCS parameter structure */
+{
+ int i;
+ for (i = 0; i < 10; i++) {
+ if (wcscom0[i] != NULL) {
+ free (wcscom0[i]);
+ wcscom0[i] = NULL;
+ }
+ }
+ if (iswcs (wcs)) {
+ for (i = 0; i < 10; i++) {
+ if (wcs->command_format[i] != NULL) {
+ free (wcs->command_format[i]);
+ }
+ }
+ }
+ return;
+}
+
+int
+cpwcs (header, cwcs)
+
+char **header; /* Pointer to start of FITS header */
+char *cwcs; /* Keyword suffix character for output WCS */
+{
+ double tnum;
+ int dkwd[100];
+ int i, maxnkwd, ikwd, nleft, lbuff, lhead, nkwd, nbytes;
+ int nkwdw;
+ char **kwd;
+ char *newhead, *oldhead;
+ char kwdc[16], keyword[16];
+ char tstr[80];
+
+ /* Allocate array of keywords to be transferred */
+ maxnkwd = 100;
+ kwd = (char **)calloc (maxnkwd, sizeof(char *));
+ for (ikwd = 0; ikwd < maxnkwd; ikwd++)
+ kwd[ikwd] = (char *) calloc (16, 1);
+
+ /* Make list of all possible keywords to be transferred */
+ nkwd = 0;
+ strcpy (kwd[++nkwd], "EPOCH");
+ dkwd[nkwd] = 1;
+ strcpy (kwd[++nkwd], "EQUINOX");
+ dkwd[nkwd] = 1;
+ strcpy (kwd[++nkwd], "RADECSYS");
+ dkwd[nkwd] = 0;
+ strcpy (kwd[++nkwd], "CTYPE1");
+ dkwd[nkwd] = 0;
+ strcpy (kwd[++nkwd], "CTYPE2");
+ dkwd[nkwd] = 0;
+ strcpy (kwd[++nkwd], "CRVAL1");
+ dkwd[nkwd] = 1;
+ strcpy (kwd[++nkwd], "CRVAL2");
+ dkwd[nkwd] = 1;
+ strcpy (kwd[++nkwd], "CDELT1");
+ dkwd[nkwd] = 1;
+ strcpy (kwd[++nkwd], "CDELT2");
+ dkwd[nkwd] = 1;
+ strcpy (kwd[++nkwd], "CRPIX1");
+ dkwd[nkwd] = 1;
+ strcpy (kwd[++nkwd], "CRPIX2");
+ dkwd[nkwd] = 1;
+ strcpy (kwd[++nkwd], "CROTA1");
+ dkwd[nkwd] = 1;
+ strcpy (kwd[++nkwd], "CROTA2");
+ dkwd[nkwd] = 1;
+ strcpy (kwd[++nkwd], "CD1_1");
+ dkwd[nkwd] = 1;
+ strcpy (kwd[++nkwd], "CD1_2");
+ dkwd[nkwd] = 1;
+ strcpy (kwd[++nkwd], "CD2_1");
+ dkwd[nkwd] = 1;
+ strcpy (kwd[++nkwd], "CD2_2");
+ dkwd[nkwd] = 1;
+ strcpy (kwd[++nkwd], "PC1_1");
+ dkwd[nkwd] = 1;
+ strcpy (kwd[++nkwd], "PC1_2");
+ dkwd[nkwd] = 1;
+ strcpy (kwd[++nkwd], "PC2_1");
+ dkwd[nkwd] = 1;
+ strcpy (kwd[++nkwd], "PC2_2");
+ dkwd[nkwd] = 1;
+ strcpy (kwd[++nkwd], "PC001001");
+ dkwd[nkwd] = 1;
+ strcpy (kwd[++nkwd], "PC001002");
+ dkwd[nkwd] = 1;
+ strcpy (kwd[++nkwd], "PC002001");
+ dkwd[nkwd] = 1;
+ strcpy (kwd[++nkwd], "PC002002");
+ dkwd[nkwd] = 1;
+ strcpy (kwd[++nkwd], "LATPOLE");
+ dkwd[nkwd] = 1;
+ strcpy (kwd[++nkwd], "LONPOLE");
+ dkwd[nkwd] = 1;
+ for (i = 1; i < 13; i++) {
+ sprintf (keyword,"CO1_%d", i);
+ strcpy (kwd[++nkwd], keyword);
+ dkwd[nkwd] = 1;
+ }
+ for (i = 1; i < 13; i++) {
+ sprintf (keyword,"CO2_%d", i);
+ strcpy (kwd[++nkwd], keyword);
+ dkwd[nkwd] = 1;
+ }
+ for (i = 0; i < 10; i++) {
+ sprintf (keyword,"PROJP%d", i);
+ strcpy (kwd[++nkwd], keyword);
+ dkwd[nkwd] = 1;
+ }
+ for (i = 0; i < MAXPV; i++) {
+ sprintf (keyword,"PV1_%d", i);
+ strcpy (kwd[++nkwd], keyword);
+ dkwd[nkwd] = 1;
+ }
+ for (i = 0; i < MAXPV; i++) {
+ sprintf (keyword,"PV2_%d", i);
+ strcpy (kwd[++nkwd], keyword);
+ dkwd[nkwd] = 1;
+ }
+
+ /* Allocate new header buffer if needed */
+ lhead = (ksearch (*header, "END") - *header) + 80;
+ lbuff = gethlength (*header);
+ nleft = (lbuff - lhead) / 80;
+ if (nleft < nkwd) {
+ nbytes = lhead + (nkwd * 80) + 400;
+ newhead = (char *) calloc (1, nbytes);
+ strncpy (newhead, *header, lhead);
+ oldhead = *header;
+ header = &newhead;
+ free (oldhead);
+ }
+
+ /* Copy keywords to new WCS ID in header */
+ nkwdw = 0;
+ for (i = 0; i < nkwd; i++) {
+ if (dkwd[i]) {
+ if (hgetr8 (*header, kwd[i], &tnum)) {
+ nkwdw++;
+ if (!strncmp (kwd[i], "PC0", 3)) {
+ if (!strcmp (kwd[i], "PC001001"))
+ strcpy (kwdc, "PC1_1");
+ else if (!strcmp (kwd[i], "PC001002"))
+ strcpy (kwdc, "PC1_2");
+ else if (!strcmp (kwd[i], "PC002001"))
+ strcpy (kwdc, "PC2_1");
+ else
+ strcpy (kwdc, "PC2_2");
+ }
+ else
+ strcpy (kwdc, kwd[i]);
+ strncat (kwdc, cwcs, 1);
+ (void)hputr8 (*header, kwdc, tnum);
+ }
+ }
+ else {
+ if (hgets (*header, kwd[i], 80, tstr)) {
+ nkwdw++;
+ if (!strncmp (kwd[i], "RADECSYS", 8))
+ strcpy (kwdc, "RADECSY");
+ else
+ strcpy (kwdc, kwd[i]);
+ strncat (kwdc, cwcs, 1);
+ hputs (*header, kwdc, tstr);
+ }
+ }
+ }
+
+ /* Free keyword list array */
+ for (ikwd = 0; ikwd < maxnkwd; ikwd++)
+ free (kwd[ikwd]);
+ free (kwd);
+ kwd = NULL;
+ return (nkwdw);
+}
+
+
+/* Oct 28 1994 new program
+ * Dec 21 1994 Implement CD rotation matrix
+ * Dec 22 1994 Allow RA and DEC to be either x,y or y,x
+ *
+ * Mar 6 1995 Add Digital Sky Survey plate fit
+ * May 2 1995 Add prototype of PIX2WCST to WCSCOM
+ * May 25 1995 Print leading zero for hours and degrees
+ * Jun 21 1995 Add WCS2PIX to get pixels from WCS
+ * Jun 21 1995 Read plate scale from FITS header for plate solution
+ * Jul 6 1995 Pass WCS structure as argument; malloc it in WCSINIT
+ * Jul 6 1995 Check string lengths in PIX2WCST
+ * Aug 16 1995 Add galactic coordinate conversion to PIX2WCST
+ * Aug 17 1995 Return 0 from iswcs if wcs structure is not yet set
+ * Sep 8 1995 Do not include malloc.h if VMS
+ * Sep 8 1995 Check for legal WCS before trying anything
+ * Sep 8 1995 Do not try to set WCS if missing key keywords
+ * Oct 18 1995 Add WCSCENT and WCSDIST to print center and size of image
+ * Nov 6 1995 Include stdlib.h instead of malloc.h
+ * Dec 6 1995 Fix format statement in PIX2WCST
+ * Dec 19 1995 Change MALLOC to CALLOC to initialize array to zeroes
+ * Dec 19 1995 Explicitly initialize rotation matrix and yinc
+ * Dec 22 1995 If SECPIX is set, use approximate WCS
+ * Dec 22 1995 Always print coordinate system
+ *
+ * Jan 12 1996 Use plane-tangent, not linear, projection if SECPIX is set
+ * Jan 12 1996 Add WCSSET to set WCS without an image
+ * Feb 15 1996 Replace all calls to HGETC with HGETS
+ * Feb 20 1996 Add tab table output from PIX2WCST
+ * Apr 2 1996 Convert all equinoxes to B1950 or J2000
+ * Apr 26 1996 Get and use image epoch for accurate FK4/FK5 conversions
+ * May 16 1996 Clean up internal documentation
+ * May 17 1996 Return width in right ascension degrees, not sky degrees
+ * May 24 1996 Remove extraneous print command from WCSSIZE
+ * May 28 1996 Add NOWCS and WCSSHIFT subroutines
+ * Jun 11 1996 Drop unused variables after running lint
+ * Jun 12 1996 Set equinox as well as system in WCSSHIFT
+ * Jun 14 1996 Make DSS keyword searches more robust
+ * Jul 1 1996 Allow for SECPIX1 and SECPIX2 keywords
+ * Jul 2 1996 Test for CTYPE1 instead of CRVAL1
+ * Jul 5 1996 Declare all subroutines in wcs.h
+ * Jul 19 1996 Add subroutine WCSFULL to return real image size
+ * Aug 12 1996 Allow systemless coordinates which cannot be converted
+ * Aug 15 1996 Allow LINEAR WCS to pass numbers through transparently
+ * Aug 15 1996 Add WCSERR to print error message under calling program control
+ * Aug 16 1996 Add latitude and longitude as image coordinate types
+ * Aug 26 1996 Fix arguments to HLENGTH in WCSNINIT
+ * Aug 28 1996 Explicitly set OFFSCL in WCS2PIX if coordinates outside image
+ * Sep 3 1996 Return computed pixel values even if they are offscale
+ * Sep 6 1996 Allow filename to be passed by WCSCOM
+ * Oct 8 1996 Default to 2000 for EQUINOX and EPOCH and FK5 for RADECSYS
+ * Oct 8 1996 If EPOCH is 0 and EQUINOX is not set, default to 1950 and FK4
+ * Oct 15 1996 Add comparison when testing an assignment
+ * Oct 16 1996 Allow PIXEL CTYPE which means WCS is same as image coordinates
+ * Oct 21 1996 Add WCS_COMMAND environment variable
+ * Oct 25 1996 Add image scale to WCSCENT
+ * Oct 30 1996 Fix bugs in WCS2PIX
+ * Oct 31 1996 Fix CD matrix rotation angle computation
+ * Oct 31 1996 Use inline degree <-> radian conversion functions
+ * Nov 1 1996 Add option to change number of decimal places in PIX2WCST
+ * Nov 5 1996 Set wcs->crot to 1 if rotation matrix is used
+ * Dec 2 1996 Add altitide/azimuth coordinates
+ * Dec 13 1996 Fix search format setting from environment
+ *
+ * Jan 22 1997 Add ifdef for Eric Mandel (SAOtng)
+ * Feb 5 1997 Add wcsout for Eric Mandel
+ * Mar 20 1997 Drop unused variable STR in WCSCOM
+ * May 21 1997 Do not make pixel coordinates mod 360 in PIX2WCST
+ * May 22 1997 Add PIXEL prjcode = -1;
+ * Jul 11 1997 Get center pixel x and y from header even if no WCS
+ * Aug 7 1997 Add NOAO PIXSCALi keywords for default WCS
+ * Oct 15 1997 Do not reset reference pixel in WCSSHIFT
+ * Oct 20 1997 Set chip rotation
+ * Oct 24 1997 Keep longitudes between 0 and 360, not -180 and +180
+ * Nov 5 1997 Do no compute crot and srot; they are now computed in worldpos
+ * Dec 16 1997 Set rotation and axis increments from CD matrix
+ *
+ * Jan 6 1998 Deal with J2000 and B1950 as EQUINOX values (from ST)
+ * Jan 7 1998 Read INSTRUME and DETECTOR header keywords
+ * Jan 7 1998 Fix tab-separated output
+ * Jan 9 1998 Precess coordinates if either FITS projection or *DSS plate*
+ * Jan 16 1998 Change PTYPE to not include initial hyphen
+ * Jan 16 1998 Change WCSSET to WCSXINIT to avoid conflict with Calabretta
+ * Jan 23 1998 Change PCODE to PRJCODE to avoid conflict with Calabretta
+ * Jan 27 1998 Add LATPOLE and LONGPOLE for Calabretta projections
+ * Feb 5 1998 Make cd and dc into vectors; use matinv() to invert cd
+ * Feb 5 1998 In wcsoutinit(), check that corsys is a valid pointer
+ * Feb 18 1998 Fix bugs for Calabretta projections
+ * Feb 19 1998 Add wcs structure access subroutines from Eric Mandel
+ * Feb 19 1998 Add wcsreset() to make sure derived values are reset
+ * Feb 19 1998 Always set oldwcs to 1 if NCP projection
+ * Feb 19 1998 Add subroutine to set oldwcs default
+ * Feb 20 1998 Initialize projection types one at a time for SunOS C
+ * Feb 23 1998 Add TNX projection from NOAO; treat it as TAN
+ * Feb 23 1998 Compute size based on max and min coordinates, not sides
+ * Feb 26 1998 Add code to set center pixel if part of detector array
+ * Mar 6 1998 Write 8-character values to RADECSYS
+ * Mar 9 1998 Add naxis to WCS structure
+ * Mar 16 1998 Use separate subroutine for IRAF TNX projection
+ * Mar 20 1998 Set PC matrix if more than two axes and it's not in header
+ * Mar 20 1998 Reset lin flag in WCSRESET if CDELTn
+ * Mar 20 1998 Set CD matrix with CDELTs and CROTA in wcsinit and wcsreset
+ * Mar 20 1998 Allow initialization of rotation angle alone
+ * Mar 23 1998 Use dsspos() and dsspix() instead of platepos() and platepix()
+ * Mar 24 1998 Set up PLT/PLATE plate polynomial fit using platepos() and platepix()
+ * Mar 25 1998 Read plate fit coefficients from header in getwcscoeffs()
+ * Mar 27 1998 Check for FITS WCS before DSS WCS
+ * Mar 27 1998 Compute scale from edges if xinc and yinc not set in wcscent()
+ * Apr 6 1998 Change plate coefficient keywords from PLTij to COi_j
+ * Apr 6 1998 Read all coefficients in line instead of with subroutine
+ * Apr 7 1998 Change amd_i_coeff to i_coeff
+ * Apr 8 1998 Add wcseqset to change equinox after wcs has been set
+ * Apr 10 1998 Use separate counters for x and y polynomial coefficients
+ * Apr 13 1998 Use CD/CDELT+CDROTA if oldwcs is set
+ * Apr 14 1998 Use codes instead of strings for various coordinate systems
+ * Apr 14 1998 Separate input coordinate conversion from output conversion
+ * Apr 14 1998 Use wcscon() for most coordinate conversion
+ * Apr 17 1998 Always compute cdelt[]
+ * Apr 17 1998 Deal with reversed axis more correctly
+ * Apr 17 1998 Compute rotation angle and approximate CDELTn for polynomial
+ * Apr 23 1998 Deprecate xref/yref in favor of crval[]
+ * Apr 23 1998 Deprecate xrefpix/yrefpix in favor of crpix[]
+ * Apr 23 1998 Add LINEAR to coordinate system types
+ * Apr 23 1998 Always use AIPS subroutines for LINEAR or PIXEL
+ * Apr 24 1998 Format linear coordinates better
+ * Apr 28 1998 Change coordinate system flags to WCS_*
+ * Apr 28 1998 Change projection flags to WCS_*
+ * Apr 28 1998 Add subroutine wcsc2pix for coordinates to pixels with system
+ * Apr 28 1998 Add setlinmode() to set output string mode for LINEAR coordinates
+ * Apr 30 1998 Fix bug by setting degree flag for lat and long in wcsinit()
+ * Apr 30 1998 Allow leading "-"s in projecting in wcsxinit()
+ * May 1 1998 Assign new output coordinate system only if legitimate system
+ * May 1 1998 Do not allow oldwcs=1 unless allowed projection
+ * May 4 1998 Fix bug in units reading for LINEAR coordinates
+ * May 6 1998 Initialize to no CD matrix
+ * May 6 1998 Use TAN instead of TNX if oldwcs
+ * May 12 1998 Set 3rd and 4th coordinates in wcspos()
+ * May 12 1998 Return *xpos and *ypos = 0 in pix2wcs() if offscale
+ * May 12 1998 Declare undeclared external subroutines after lint
+ * May 13 1998 Add equinox conversion to specified output equinox
+ * May 13 1998 Set output or input system to image with null argument
+ * May 15 1998 Return reference pixel, cdelts, and rotation for DSS
+ * May 20 1998 Fix bad bug so setlinmode() is no-op if wcs not set
+ * May 20 1998 Fix bug so getwcsout() returns null pointer if wcs not set
+ * May 27 1998 Change WCS_LPR back to WCS_LIN; allow CAR in oldwcs
+ * May 28 1998 Go back to old WCSFULL, computing height and width from center
+ * May 29 1998 Add wcskinit() to initialize WCS from arguments
+ * May 29 1998 Add wcstype() to set projection from arguments
+ * May 29 1998 Add wcscdset(), and wcsdeltset() to set scale from arguments
+ * Jun 1 1998 In wcstype(), reconstruct ctype for WCS structure
+ * Jun 11 1998 Split off header-dependent subroutines to wcsinit.c
+ * Jun 18 1998 Add wcspcset() for PC matrix initialization
+ * Jun 24 1998 Add string lengths to ra2str(), dec2str, and deg2str() calls
+ * Jun 25 1998 Use AIPS software for CAR projection
+ * Jun 25 1998 Add wcsndec to set number of decimal places in output string
+ * Jul 6 1998 Add wcszin() and wcszout() to use third dimension of images
+ * Jul 7 1998 Change setlinmode() to setwcslin(); setdegout() to setwcsdeg()
+ * Jul 10 1998 Initialize matrices correctly for naxis > 2 in wcs<>set()
+ * Jul 16 1998 Initialize coordinates to be returned in wcspos()
+ * Jul 17 1998 Link lin structure arrays to wcs structure arrays
+ * Jul 20 1998 In wcscdset() compute sign of xinc and yinc from CD1_1, CD 2_2
+ * Jul 20 1998 In wcscdset() compute sign of rotation based on CD1_1, CD 1_2
+ * Jul 22 1998 Add wcslibrot() to compute lin() rotation matrix
+ * Jul 30 1998 Set wcs->naxes and lin.naxis in wcsxinit() and wcskinit()
+ * Aug 5 1998 Use old WCS subroutines to deal with COE projection (for ESO)
+ * Aug 14 1998 Add option to print image coordinates with wcscom()
+ * Aug 14 1998 Add multiple command options to wcscom*()
+ * Aug 31 1998 Declare undeclared arguments to wcspcset()
+ * Sep 3 1998 Set CD rotation and cdelts from sky axis position angles
+ * Sep 16 1998 Add option to use North Polar Angle instead of Latitude
+ * Sep 29 1998 Initialize additional WCS commands from the environment
+ * Oct 14 1998 Fix bug in wcssize() which didn't divide dra by cos(dec)
+ * Nov 12 1998 Fix sign of CROTA when either axis is reflected
+ * Dec 2 1998 Fix non-arcsecond scale factors in wcscent()
+ * Dec 2 1998 Add PLANET coordinate system to pix2wcst()
+
+ * Jan 20 1999 Free lin.imgpix and lin.piximg in wcsfree()
+ * Feb 22 1999 Fix bug setting latitude reference value of latbase != 0
+ * Feb 22 1999 Fix bug so that quad cube faces are 0-5, not 1-6
+ * Mar 16 1999 Always initialize all 4 imgcrds and pixcrds in wcspix()
+ * Mar 16 1999 Always return (0,0) from wcs2pix if offscale
+ * Apr 7 1999 Add code to put file name in error messages
+ * Apr 7 1999 Document utility subroutines at end of file
+ * May 6 1999 Fix bug printing height of LINEAR image
+ * Jun 16 1999 Add wcsrange() to return image RA and Dec limits
+ * Jul 8 1999 Always use FK5 and FK4 instead of J2000 and B1950 in RADECSYS
+ * Aug 16 1999 Print dd:mm:ss dd:mm:ss if not J2000 or B1950 output
+ * Aug 20 1999 Add WCS string argument to wcscom(); don't compute it there
+ * Aug 20 1999 Change F3 WCS command default from Tycho to ACT
+ * Oct 15 1999 Free wcs using wcsfree()
+ * Oct 21 1999 Drop declarations of unused functions after lint
+ * Oct 25 1999 Drop out of wcsfree() if wcs is null pointer
+ * Nov 17 1999 Fix bug which caused software to miss NCP projection
+ *
+ * Jan 24 2000 Default to AIPS for NCP, CAR, and COE proj.; if -z use WCSLIB
+ * Feb 24 2000 If coorsys is null in wcsc2pix, wcs->radecin is assumed
+ * May 10 2000 In wcstype(), default to WCS_LIN, not error (after Bill Joye)
+ * Jun 22 2000 In wcsrotset(), leave rotation angle alone in 1-d image
+ * Jul 3 2000 Initialize wcscrd[] to zero in wcspix()
+ *
+ * Feb 20 2001 Add recursion to wcs2pix() and pix2wcs() for dependent WCS's
+ * Mar 20 2001 Add braces to avoid ambiguity in if/else groupings
+ * Mar 22 2001 Free WCS structure in wcsfree even if it is not filled
+ * Sep 12 2001 Fix bug which omitted tab in pix2wcst() galactic coord output
+ *
+ * Mar 7 2002 Fix bug which gave wrong pa's and rotation for reflected RA
+ * (but correct WCS conversions!)
+ * Mar 28 2002 Add SZP projection
+ * Apr 3 2002 Synchronize projection types with other subroutines
+ * Apr 3 2002 Drop special cases of projections
+ * Apr 9 2002 Implement inversion of multiple WCSs in wcsc2pix()
+ * Apr 25 2002 Use Tycho-2 catalog instead of ACT in setwcscom()
+ * May 13 2002 Free WCSNAME in wcsfree()
+ *
+ * Mar 31 2003 Add distcode to wcstype()
+ * Apr 1 2003 Add calls to foc2pix() in wcs2pix() and pix2foc() in pix2wcs()
+ * May 20 2003 Declare argument i in savewcscom()
+ * Sep 29 2003 Fix bug to compute width and height correctly in wcsfull()
+ * Sep 29 2003 Fix bug to deal with all-sky images orrectly in wcsfull()
+ * Oct 1 2003 Rename wcs->naxes to wcs->naxis to match WCSLIB 3.2
+ * Nov 3 2003 Set distortion code by calling setdistcode() in wcstype()
+ * Dec 3 2003 Add back wcs->naxes for compatibility
+ * Dec 3 2003 Add braces in if...else in pix2wcst()
+ *
+ * Sep 17 2004 If spherical coordinate output, keep 0 < long/RA < 360
+ * Sep 17 2004 Fix bug in wcsfull() when wrapping around RA=0:00
+ * Nov 1 2004 Keep wcs->rot between 0 and 360
+ *
+ * Mar 9 2005 Fix bug in wcsrotset() which set rot > 360 to 360
+ * Jun 27 2005 Fix ctype in calls to wcs subroutines
+ * Jul 21 2005 Fix bug in wcsrange() at RA ~= 0.0
+ *
+ * Apr 24 2006 Always set inverse CD matrix to 2 dimensions in wcspcset()
+ * May 3 2006 (void *) pointers so arguments match type, from Robert Lupton
+ * Jun 30 2006 Set only 2-dimensional PC matrix; that is all lin* can deal with
+ * Oct 30 2006 In pix2wcs(), do not limit x to between 0 and 360 if XY or LINEAR
+ * Oct 30 2006 In wcsc2pix(), do not precess LINEAR or XY coordinates
+ * Dec 21 2006 Add cpwcs() to copy WCS keywords to new suffix
+ *
+ * Jan 4 2007 Fix pointer to header in cpwcs()
+ * Jan 5 2007 Drop declarations of wcscon(); it is in wcs.h
+ * Jan 9 2006 Drop declarations of fk425e() and fk524e(); moved to wcs.h
+ * Jan 9 2006 Drop *pix() and *pos() external declarations; moved to wcs.h
+ * Jan 9 2006 Drop matinv() external declaration; it is already in wcslib.h
+ * Feb 15 2007 If CTYPEi contains DET, set to WCS_PIX projection
+ * Feb 23 2007 Fix bug when checking for "DET" in CTYPEi
+ * Apr 2 2007 Fix PC to CD matrix conversion
+ * Jul 25 2007 Compute distance between two coordinates using d2v3()
+ *
+ * Apr 7 2010 In wcstype() set number of WCS projections from NWCSTYPE
+ *
+ * Mar 11 2011 Add NOAO ZPX projection (Frank Valdes)
+ * Mar 14 2011 Delete j<=MAXPV PVi_j parameters (for SCAMP polynomials via Ed Los)
+ * Mar 17 2011 Fix WCSDEP bug found by Ed Los
+ * May 9 2011 Free WCS structure recursively if WCSDEP is used
+ * Sep 1 2011 Add TPV projection type for SCAMP TAN with PVs
+ *
+ * Oct 19 2012 Drop d1 and d2 from wcsdist(); diffi from wcsdist1()
+ * Oct 19 2012 Drop depwcs; it's in main wcs structure
+ */
diff --git a/funtools/wcs/wcs.h b/funtools/wcs/wcs.h
new file mode 100644
index 0000000..1943c8d
--- /dev/null
+++ b/funtools/wcs/wcs.h
@@ -0,0 +1,963 @@
+/*** File libwcs/wcs.h
+ *** September 9, 2011
+ *** By Jessica Mink, jmink@cfa.harvard.edu
+ *** Harvard-Smithsonian Center for Astrophysics
+ *** Copyright (C) 1994-2011
+ *** Smithsonian Astrophysical Observatory, Cambridge, MA, USA
+
+ This library 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 2 of the License, or (at your option) any later version.
+
+ This library 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 this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Correspondence concerning WCSTools should be addressed as follows:
+ Internet email: jmink@cfa.harvard.edu
+ Postal address: Jessica Mink
+ Smithsonian Astrophysical Observatory
+ 60 Garden St.
+ Cambridge, MA 02138 USA
+ */
+
+#ifndef _wcs_h_
+#define _wcs_h_
+
+#include "wcslib.h"
+#include "fitshead.h"
+
+/* SIRTF distortion matrix coefficients */
+#define DISTMAX 10
+struct Distort {
+ int a_order; /* max power for the 1st dimension */
+ double a[DISTMAX][DISTMAX]; /* coefficient array of 1st dimension */
+ int b_order; /* max power for 1st dimension */
+ double b[DISTMAX][DISTMAX]; /* coefficient array of 2nd dimension */
+ int ap_order; /* max power for the 1st dimension */
+ double ap[DISTMAX][DISTMAX]; /* coefficient array of 1st dimension */
+ int bp_order; /* max power for 1st dimension */
+ double bp[DISTMAX][DISTMAX]; /* coefficient array of 2nd dimension */
+};
+
+struct WorldCoor {
+ double xref; /* X reference coordinate value (deg) */
+ double yref; /* Y reference coordinate value (deg) */
+ double xrefpix; /* X reference pixel */
+ double yrefpix; /* Y reference pixel */
+ double xinc; /* X coordinate increment (deg) */
+ double yinc; /* Y coordinate increment (deg) */
+ double rot; /* rotation around axis (deg) (N through E) */
+ double cd[4]; /* rotation matrix */
+ double dc[4]; /* inverse rotation matrix */
+ double equinox; /* Equinox of coordinates default to 1950.0 */
+ double epoch; /* Epoch of coordinates default to equinox */
+ double nxpix; /* Number of pixels in X-dimension of image */
+ double nypix; /* Number of pixels in Y-dimension of image */
+ double plate_ra; /* Right ascension of plate center */
+ double plate_dec; /* Declination of plate center */
+ double plate_scale; /* Plate scale in arcsec/mm */
+ double x_pixel_offset; /* X pixel offset of image lower right */
+ double y_pixel_offset; /* Y pixel offset of image lower right */
+ double x_pixel_size; /* X pixel_size */
+ double y_pixel_size; /* Y pixel_size */
+ double ppo_coeff[6]; /* pixel to plate coefficients for DSS */
+ double x_coeff[20]; /* X coefficients for plate model */
+ double y_coeff[20]; /* Y coefficients for plate model */
+ double xpix; /* X (RA) coordinate (pixels) */
+ double ypix; /* Y (dec) coordinate (pixels) */
+ double zpix; /* Z (face) coordinate (pixels) */
+ double xpos; /* X (RA) coordinate (deg) */
+ double ypos; /* Y (dec) coordinate (deg) */
+ double crpix[9]; /* Values of CRPIXn keywords */
+ double crval[9]; /* Values of CRVALn keywords */
+ double cdelt[9]; /* Values of CDELTn keywords */
+ double pc[81]; /* Values of PCiiijjj keywords */
+ double projp[10]; /* Constants for various projections */
+ int pvfail; /* If non-zero, significant inaccuracy likely to occur in projection */
+ double projppv[2*MAXPV]; /* SCAMP constants for the PV coordinates */
+ struct poly *inv_x; /* SCAMP projection correction polynom in x */
+ struct poly *inv_y; /* SCAMP projection correction polynom in y */
+ double longpole; /* Longitude of North Pole in degrees */
+ double latpole; /* Latitude of North Pole in degrees */
+ double rodeg; /* Radius of the projection generating sphere */
+ double imrot; /* Rotation angle of north pole */
+ double pa_north; /* Position angle of north (0=horizontal) */
+ double pa_east; /* Position angle of east (0=horizontal) */
+ double radvel; /* Radial velocity (km/sec away from observer)*/
+ double zvel; /* Radial velocity (v/c away from observer)*/
+ double zpzd; /* Colat of FIP (degs) */
+ double zpr; /* Radius of FIP (degs) */
+ int imflip; /* If not 0, image is reflected around axis */
+ int prjcode; /* projection code (-1-32) */
+ int latbase; /* Latitude base 90 (NPA), 0 (LAT), -90 (SPA) */
+ int ncoeff1; /* Number of x-axis plate fit coefficients */
+ int ncoeff2; /* Number of y-axis plate fit coefficients */
+ int zpnp; /* ZP polynomial order (0-9) */
+ int changesys; /* 1 for FK4->FK5, 2 for FK5->FK4 */
+ /* 3 for FK4->galactic, 4 for FK5->galactic */
+ int printsys; /* 1 to print coordinate system, else 0 */
+ int ndec; /* Number of decimal places in PIX2WCST */
+ int degout; /* 1 to always print degrees in PIX2WCST */
+ int tabsys; /* 1 to put tab between RA & Dec, else 0 */
+ int rotmat; /* 0 if CDELT, CROTA; 1 if CD */
+ int coorflip; /* 0 if x=RA, y=Dec; 1 if x=Dec, y=RA */
+ int offscl; /* 0 if OK, 1 if offscale */
+ int wcson; /* 1 if WCS is set, else 0 */
+ int naxis; /* Number of axes in image (for WCSLIB 3.0) */
+ int naxes; /* Number of axes in image */
+ int wcsproj; /* WCS_OLD: AIPS worldpos() and worldpix()
+ WCS_NEW: Mark Calabretta's WCSLIB subroutines
+ WCS_BEST: WCSLIB for all but CAR,COE,NCP
+ WCS_ALT: AIPS for all but CAR,COE,NCP */
+ int linmode; /* 0=system only, 1=units, 2=system+units */
+ int detector; /* Instrument detector number */
+ char instrument[32]; /* Instrument name */
+ char ctype[9][9]; /* Values of CTYPEn keywords */
+ char c1type[9]; /* 1st coordinate type code:
+ RA--, GLON, ELON */
+ char c2type[9]; /* 2nd coordinate type code:
+ DEC-, GLAT, ELAT */
+ char ptype[9]; /* projection type code:
+ SIN, TAN, ARC, NCP, GLS, MER, AIT, etc */
+ char units[9][32]; /* Units if LINEAR */
+ char radecsys[32]; /* Reference frame: FK4, FK4-NO-E, FK5, GAPPT*/
+ char radecout[32]; /* Output reference frame: FK4,FK5,GAL,ECL */
+ char radecin[32]; /* Input reference frame: FK4,FK5,GAL,ECL */
+ double eqin; /* Input equinox (match sysin if 0.0) */
+ double eqout; /* Output equinox (match sysout if 0.0) */
+ int sysin; /* Input coordinate system code */
+ int syswcs; /* WCS coordinate system code */
+ int sysout; /* Output coordinate system code */
+ /* WCS_B1950, WCS_J2000, WCS_ICRS, WCS_GALACTIC,
+ * WCS_ECLIPTIC, WCS_LINEAR, WCS_ALTAZ */
+ char center[32]; /* Center coordinates (with frame) */
+ struct wcsprm wcsl; /* WCSLIB main projection parameters */
+ struct linprm lin; /* WCSLIB image/pixel conversion parameters */
+ struct celprm cel; /* WCSLIB projection type */
+ struct prjprm prj; /* WCSLIB projection parameters */
+ struct IRAFsurface *lngcor; /* RA/longitude correction structure */
+ struct IRAFsurface *latcor; /* Dec/latitude correction structure */
+ int distcode; /* Distortion code 0=none 1=SIRTF */
+ struct Distort distort; /* SIRTF distortion coefficients */
+ char *command_format[10]; /* WCS command formats */
+ /* where %s is replaced by WCS coordinates */
+ /* where %f is replaced by the image filename */
+ /* where %x is replaced by image coordinates */
+ double ltm[4]; /* Image rotation matrix */
+ double ltv[2]; /* Image offset */
+ int idpix[2]; /* First pixel to use in image (x, y) */
+ int ndpix[2]; /* Number of pixels to use in image (x, y) */
+ struct WorldCoor *wcs; /* WCS upon which this WCS depends */
+ struct WorldCoor *wcsdep; /* WCS depending on this WCS */
+ char *wcsname; /* WCS name (defaults to NULL pointer) */
+ char wcschar; /* WCS character (A-Z, null, space) */
+ int logwcs; /* 1 if DC-FLAG is set for log wavelength */
+};
+
+/* Projections (1-26 are WCSLIB) (values for wcs->prjcode) */
+#define WCS_PIX -1 /* Pixel WCS */
+#define WCS_LIN 0 /* Linear projection */
+#define WCS_AZP 1 /* Zenithal/Azimuthal Perspective */
+#define WCS_SZP 2 /* Zenithal/Azimuthal Perspective */
+#define WCS_TAN 3 /* Gnomonic = Tangent Plane */
+#define WCS_SIN 4 /* Orthographic/synthesis */
+#define WCS_STG 5 /* Stereographic */
+#define WCS_ARC 6 /* Zenithal/azimuthal equidistant */
+#define WCS_ZPN 7 /* Zenithal/azimuthal PolyNomial */
+#define WCS_ZEA 8 /* Zenithal/azimuthal Equal Area */
+#define WCS_AIR 9 /* Airy */
+#define WCS_CYP 10 /* CYlindrical Perspective */
+#define WCS_CAR 11 /* Cartesian */
+#define WCS_MER 12 /* Mercator */
+#define WCS_CEA 13 /* Cylindrical Equal Area */
+#define WCS_COP 14 /* Conic PerSpective (COP) */
+#define WCS_COD 15 /* COnic equiDistant */
+#define WCS_COE 16 /* COnic Equal area */
+#define WCS_COO 17 /* COnic Orthomorphic */
+#define WCS_BON 18 /* Bonne */
+#define WCS_PCO 19 /* Polyconic */
+#define WCS_SFL 20 /* Sanson-Flamsteed (GLobal Sinusoidal) */
+#define WCS_PAR 21 /* Parabolic */
+#define WCS_AIT 22 /* Hammer-Aitoff */
+#define WCS_MOL 23 /* Mollweide */
+#define WCS_CSC 24 /* COBE quadrilateralized Spherical Cube */
+#define WCS_QSC 25 /* Quadrilateralized Spherical Cube */
+#define WCS_TSC 26 /* Tangential Spherical Cube */
+#define WCS_NCP 27 /* Special case of SIN */
+#define WCS_GLS 28 /* Same as SFL */
+#define WCS_DSS 29 /* Digitized Sky Survey plate solution */
+#define WCS_PLT 30 /* Plate fit polynomials (SAO) */
+#define WCS_TNX 31 /* Gnomonic = Tangent Plane (NOAO with corrections) */
+#define WCS_ZPX 32 /* Gnomonic = Tangent Plane (NOAO with corrections) */
+#define WCS_TPV 33 /* Gnomonic = Tangent Plane (NOAO with corrections) */
+#define NWCSTYPE 34 /* Number of WCS types (-1 really means no WCS) */
+
+/* Coordinate systems */
+#define WCS_J2000 1 /* J2000(FK5) right ascension and declination */
+#define WCS_B1950 2 /* B1950(FK4) right ascension and declination */
+#define WCS_GALACTIC 3 /* Galactic longitude and latitude */
+#define WCS_ECLIPTIC 4 /* Ecliptic longitude and latitude */
+#define WCS_ALTAZ 5 /* Azimuth and altitude/elevation */
+#define WCS_LINEAR 6 /* Linear with optional units */
+#define WCS_NPOLE 7 /* Longitude and north polar angle */
+#define WCS_SPA 8 /* Longitude and south polar angle */
+#define WCS_PLANET 9 /* Longitude and latitude on planet */
+#define WCS_XY 10 /* X-Y Cartesian coordinates */
+#define WCS_ICRS 11 /* ICRS right ascension and declination */
+
+/* Method to use */
+#define WCS_BEST 0 /* Use best WCS projections */
+#define WCS_ALT 1 /* Use not best WCS projections */
+#define WCS_OLD 2 /* Use AIPS WCS projections */
+#define WCS_NEW 3 /* Use WCSLIB 2.5 WCS projections */
+
+/* Distortion codes (values for wcs->distcode) */
+#define DISTORT_NONE 0 /* No distortion coefficients */
+#define DISTORT_SIRTF 1 /* SIRTF distortion matrix */
+
+#ifndef PI
+#define PI 3.141592653589793238462643
+#endif
+
+/* pi/(180*3600): arcseconds to radians */
+#define AS2R 4.8481368110953e-6
+
+/* Conversions among hours of RA, degrees and radians. */
+#define degrad(x) ((x)*PI/180.)
+#define raddeg(x) ((x)*180./PI)
+#define hrdeg(x) ((x)*15.)
+#define deghr(x) ((x)/15.)
+#define hrrad(x) degrad(hrdeg(x))
+#define radhr(x) deghr(raddeg(x))
+#define secrad(x) ((x)*AS2R)
+
+/* TNX/ZPX surface fitting structure and flags */
+struct IRAFsurface {
+ double xrange; /* 2. / (xmax - xmin), polynomials */
+ double xmaxmin; /* - (xmax + xmin) / 2., polynomials */
+ double yrange; /* 2. / (ymax - ymin), polynomials */
+ double ymaxmin; /* - (ymax + ymin) / 2., polynomials */
+ int type; /* type of curve to be fitted */
+ int xorder; /* order of the fit in x */
+ int yorder; /* order of the fit in y */
+ int xterms; /* cross terms for polynomials */
+ int ncoeff; /* total number of coefficients */
+ double *coeff; /* pointer to coefficient vector */
+ double *xbasis; /* pointer to basis functions (all x) */
+ double *ybasis; /* pointer to basis functions (all y) */
+};
+
+/* TNX/ZPX permitted types of surfaces */
+#define TNX_CHEBYSHEV 1
+#define TNX_LEGENDRE 2
+#define TNX_POLYNOMIAL 3
+
+/* TNX/ZPX cross-terms flags */
+#define TNX_XNONE 0 /* no x-terms (old no) */
+#define TNX_XFULL 1 /* full x-terms (new yes) */
+#define TNX_XHALF 2 /* half x-terms (new) */
+
+#ifdef __cplusplus /* C++ prototypes */
+extern "C" {
+#endif
+
+#ifdef __STDC__ /* Full ANSI prototypes */
+
+ /* WCS data structure initialization subroutines in wcsinit.c */
+ struct WorldCoor *wcsinit ( /* set up WCS structure from a FITS image header */
+ const char* hstring);
+
+ struct WorldCoor *wcsninit ( /* set up WCS structure from a FITS image header */
+ const char* hstring, /* FITS header */
+ int len); /* Length of FITS header */
+
+ struct WorldCoor *wcsinitn ( /* set up WCS structure from a FITS image header */
+ const char* hstring, /* FITS header */
+ const char* wcsname); /* WCS name */
+
+ struct WorldCoor *wcsninitn ( /* set up WCS structure from a FITS image header */
+ const char* hstring, /* FITS header */
+ int len, /* Length of FITS header */
+ const char* wcsname); /* WCS name */
+
+ struct WorldCoor *wcsinitc ( /* set up WCS structure from a FITS image header */
+ const char* hstring, /* FITS header */
+ char *wcschar); /* WCS character (A-Z) */
+
+ struct WorldCoor *wcsninitc ( /* set up WCS structure from a FITS image header */
+ const char* hstring, /* FITS header */
+ int len, /* Length of FITS header */
+ char *wcschar); /* WCS character (A-Z) */
+
+ /* WCS subroutines in wcs.c */
+ void wcsfree ( /* Free a WCS structure and its contents */
+ struct WorldCoor *wcs); /* World coordinate system structure */
+
+ int wcstype( /* Set projection type from header CTYPEs */
+ struct WorldCoor *wcs, /* World coordinate system structure */
+ char *ctype1, /* FITS WCS projection for axis 1 */
+ char *ctype2); /* FITS WCS projection for axis 2 */
+
+ int iswcs( /* Returns 1 if wcs structure set, else 0 */
+ struct WorldCoor *wcs); /* World coordinate system structure */
+ int nowcs( /* Returns 0 if wcs structure set, else 1 */
+ struct WorldCoor *wcs); /* World coordinate system structure */
+
+ int pix2wcst ( /* Convert pixel coordinates to World Coordinate string */
+ struct WorldCoor *wcs, /* World coordinate system structure */
+ double xpix, /* Image horizontal coordinate in pixels */
+ double ypix, /* Image vertical coordinate in pixels */
+ char *wcstring, /* World coordinate string (returned) */
+ int lstr); /* Length of world coordinate string (returned) */
+
+ void pix2wcs ( /* Convert pixel coordinates to World Coordinates */
+ struct WorldCoor *wcs, /* World coordinate system structure */
+ double xpix, /* Image horizontal coordinate in pixels */
+ double ypix, /* Image vertical coordinate in pixels */
+ double *xpos, /* Longitude/Right Ascension in degrees (returned) */
+ double *ypos); /* Latitude/Declination in degrees (returned) */
+
+ void wcsc2pix ( /* Convert World Coordinates to pixel coordinates */
+ struct WorldCoor *wcs, /* World coordinate system structure */
+ double xpos, /* Longitude/Right Ascension in degrees */
+ double ypos, /* Latitude/Declination in degrees */
+ char *coorsys, /* Coordinate system (B1950, J2000, etc) */
+ double *xpix, /* Image horizontal coordinate in pixels (returned) */
+ double *ypix, /* Image vertical coordinate in pixels (returned) */
+ int *offscl);
+
+ void wcs2pix ( /* Convert World Coordinates to pixel coordinates */
+ struct WorldCoor *wcs, /* World coordinate system structure */
+ double xpos, /* Longitude/Right Ascension in degrees */
+ double ypos, /* Latitude/Declination in degrees */
+ double *xpix, /* Image horizontal coordinate in pixels (returned) */
+ double *ypix, /* Image vertical coordinate in pixels (returned) */
+ int *offscl);
+
+ double wcsdist( /* Compute angular distance between 2 sky positions */
+ double ra1, /* First longitude/right ascension in degrees */
+ double dec1, /* First latitude/declination in degrees */
+ double ra2, /* Second longitude/right ascension in degrees */
+ double dec2); /* Second latitude/declination in degrees */
+
+ double wcsdist1( /* Compute angular distance between 2 sky positions */
+ double ra1, /* First longitude/right ascension in degrees */
+ double dec1, /* First latitude/declination in degrees */
+ double ra2, /* Second longitude/right ascension in degrees */
+ double dec2); /* Second latitude/declination in degrees */
+
+ double wcsdiff( /* Compute angular distance between 2 sky positions */
+ double ra1, /* First longitude/right ascension in degrees */
+ double dec1, /* First latitude/declination in degrees */
+ double ra2, /* Second longitude/right ascension in degrees */
+ double dec2); /* Second latitude/declination in degrees */
+
+ struct WorldCoor* wcsxinit( /* set up a WCS structure from arguments */
+ double cra, /* Center right ascension in degrees */
+ double cdec, /* Center declination in degrees */
+ double secpix, /* Number of arcseconds per pixel */
+ double xrpix, /* Reference pixel X coordinate */
+ double yrpix, /* Reference pixel X coordinate */
+ int nxpix, /* Number of pixels along x-axis */
+ int nypix, /* Number of pixels along y-axis */
+ double rotate, /* Rotation angle (clockwise positive) in degrees */
+ int equinox, /* Equinox of coordinates, 1950 and 2000 supported */
+ double epoch, /* Epoch of coordinates, used for FK4/FK5 conversion
+ * no effect if 0 */
+ char *proj); /* Projection */
+
+ struct WorldCoor* wcskinit( /* set up WCS structure from keyword values */
+ int naxis1, /* Number of pixels along x-axis */
+ int naxis2, /* Number of pixels along y-axis */
+ char *ctype1, /* FITS WCS projection for axis 1 */
+ char *ctype2, /* FITS WCS projection for axis 2 */
+ double crpix1, /* Reference pixel coordinates */
+ double crpix2, /* Reference pixel coordinates */
+ double crval1, /* Coordinate at reference pixel in degrees */
+ double crval2, /* Coordinate at reference pixel in degrees */
+ double *cd, /* Rotation matrix, used if not NULL */
+ double cdelt1, /* scale in degrees/pixel, if cd is NULL */
+ double cdelt2, /* scale in degrees/pixel, if cd is NULL */
+ double crota, /* Rotation angle in degrees, if cd is NULL */
+ int equinox, /* Equinox of coordinates, 1950 and 2000 supported */
+ double epoch); /* Epoch of coordinates, for FK4/FK5 conversion */
+
+ void wcsshift( /* Change center of WCS */
+ struct WorldCoor *wcs, /* World coordinate system structure */
+ double cra, /* New center right ascension in degrees */
+ double cdec, /* New center declination in degrees */
+ char *coorsys); /* FK4 or FK5 coordinates (1950 or 2000) */
+
+ void wcsfull( /* Return RA and Dec of image center, size in degrees */
+ struct WorldCoor *wcs, /* World coordinate system structure */
+ double *cra, /* Right ascension of image center (deg) (returned) */
+ double *cdec, /* Declination of image center (deg) (returned) */
+ double *width, /* Width in degrees (returned) */
+ double *height); /* Height in degrees (returned) */
+
+ void wcscent( /* Print the image center and size in WCS units */
+ struct WorldCoor *wcs); /* World coordinate system structure */
+
+ void wcssize( /* Return image center and size in RA and Dec */
+ struct WorldCoor *wcs, /* World coordinate system structure */
+ double *cra, /* Right ascension of image center (deg) (returned) */
+ double *cdec, /* Declination of image center (deg) (returned) */
+ double *dra, /* Half-width in right ascension (deg) (returned) */
+ double *ddec); /* Half-width in declination (deg) (returned) */
+
+ void wcsrange( /* Return min and max RA and Dec of image in degrees */
+ struct WorldCoor *wcs, /* World coordinate system structure */
+ double *ra1, /* Min. right ascension of image (deg) (returned) */
+ double *ra2, /* Max. right ascension of image (deg) (returned) */
+ double *dec1, /* Min. declination of image (deg) (returned) */
+ double *dec2); /* Max. declination of image (deg) (returned) */
+
+ void wcscdset( /* Set scaling and rotation from CD matrix */
+ struct WorldCoor *wcs, /* World coordinate system structure */
+ double *cd); /* CD matrix, ignored if NULL */
+
+ void wcsdeltset( /* set scaling, rotation from CDELTi, CROTA2 */
+ struct WorldCoor *wcs, /* World coordinate system structure */
+ double cdelt1, /* degrees/pixel in first axis (or both axes) */
+ double cdelt2, /* degrees/pixel in second axis if nonzero */
+ double crota); /* Rotation counterclockwise in degrees */
+
+ void wcspcset( /* set scaling, rotation from CDELTs and PC matrix */
+ struct WorldCoor *wcs, /* World coordinate system structure */
+ double cdelt1, /* degrees/pixel in first axis (or both axes) */
+ double cdelt2, /* degrees/pixel in second axis if nonzero */
+ double *pc); /* Rotation matrix, ignored if NULL */
+
+ void setwcserr( /* Set WCS error message for later printing */
+ char *errmsg); /* Error mesage < 80 char */
+ void wcserr(void); /* Print WCS error message to stderr */
+
+ void setdefwcs( /* Set flag to use AIPS WCS instead of WCSLIB */
+ int oldwcs); /* 1 for AIPS WCS subroutines, else WCSLIB */
+ int getdefwcs(void); /* Return flag for AIPS WCS set by setdefwcs */
+
+ char *getradecsys( /* Return name of image coordinate system */
+ struct WorldCoor *wcs); /* World coordinate system structure */
+
+ void wcsoutinit( /* Set output coordinate system for pix2wcs */
+ struct WorldCoor *wcs, /* World coordinate system structure */
+ char *coorsys); /* Coordinate system (B1950, J2000, etc) */
+
+ char *getwcsout( /* Return current output coordinate system */
+ struct WorldCoor *wcs); /* World coordinate system structure */
+
+ void wcsininit( /* Set input coordinate system for wcs2pix */
+ struct WorldCoor *wcs, /* World coordinate system structure */
+ char *coorsys); /* Coordinate system (B1950, J2000, etc) */
+
+ char *getwcsin( /* Return current input coordinate system */
+ struct WorldCoor *wcs); /* World coordinate system structure */
+
+ int setwcsdeg( /* Set WCS coordinate output format */
+ struct WorldCoor *wcs, /* World coordinate system structure */
+ int degout); /* 1= degrees, 0= hh:mm:ss dd:mm:ss */
+
+ int wcsndec( /* Set or get number of output decimal places */
+ struct WorldCoor *wcs, /* World coordinate system structure */
+ int ndec); /* Number of decimal places in output string
+ if < 0, return current ndec unchanged */
+
+ int wcsreset( /* Change WCS using arguments */
+ struct WorldCoor *wcs, /* World coordinate system data structure */
+ double crpix1, /* Horizontal reference pixel */
+ double crpix2, /* Vertical reference pixel */
+ double crval1, /* Reference pixel horizontal coordinate in degrees */
+ double crval2, /* Reference pixel vertical coordinate in degrees */
+ double cdelt1, /* Horizontal scale in degrees/pixel, ignored if cd is not NULL */
+ double cdelt2, /* Vertical scale in degrees/pixel, ignored if cd is not NULL */
+ double crota, /* Rotation angle in degrees, ignored if cd is not NULL */
+ double *cd); /* Rotation matrix, used if not NULL */
+
+ void wcseqset( /* Change equinox of reference pixel coordinates in WCS */
+ struct WorldCoor *wcs, /* World coordinate system data structure */
+ double equinox); /* Desired equinox as fractional year */
+
+ void setwcslin( /* Set pix2wcst() mode for LINEAR coordinates */
+ struct WorldCoor *wcs, /* World coordinate system structure */
+ int mode); /* 0: x y linear, 1: x units x units
+ 2: x y linear units */
+
+ int wcszin( /* Set third dimension for cube projections */
+ int izpix); /* Set coordinate in third dimension (face) */
+
+ int wcszout ( /* Return coordinate in third dimension */
+ struct WorldCoor *wcs); /* World coordinate system structure */
+
+ void wcscominit( /* Initialize catalog search command set by -wcscom */
+ struct WorldCoor *wcs, /* World coordinate system structure */
+ int i, /* Number of command (0-9) to initialize */
+ char *command); /* command with %s where coordinates will go */
+
+ void wcscom( /* Execute catalog search command set by -wcscom */
+ struct WorldCoor *wcs, /* World coordinate system structure */
+ int i, /* Number of command (0-9) to execute */
+ char *filename, /* Image file name */
+ double xfile, /* Horizontal image pixel coordinates for WCS command */
+ double yfile, /* Vertical image pixel coordinates for WCS command */
+ char *wcstring); /* WCS String from pix2wcst() */
+
+ void savewcscom( /* Save WCS shell command */
+ int i, /* i of 10 possible shell commands */
+ char *wcscom); /* Shell command using output WCS string */
+ char *getwcscom( /* Return WCS shell command */
+ int i); /* i of 10 possible shell commands */
+ void setwcscom( /* Set WCS shell commands from stored values */
+ struct WorldCoor *wcs); /* World coordinate system structure */
+ void freewcscom( /* Free memory storing WCS shell commands */
+ struct WorldCoor *wcs); /* World coordinate system structure */
+
+ void setwcsfile( /* Set filename for WCS error message */
+ char *filename); /* FITS or IRAF file name */
+ int cpwcs ( /* Copy WCS keywords with no suffix to ones with suffix */
+ char **header, /* Pointer to start of FITS header */
+ char *cwcs); /* Keyword suffix character for output WCS */
+
+ void savewcscoor( /* Save output coordinate system */
+ char *wcscoor); /* coordinate system (J2000, B1950, galactic) */
+ char *getwcscoor(void); /* Return output coordinate system */
+
+ /* Coordinate conversion subroutines in wcscon.c */
+ void wcsconv( /* Convert between coordinate systems and equinoxes */
+ int sys1, /* Input coordinate system (J2000, B1950, ECLIPTIC, GALACTIC */
+ int sys2, /* Output coordinate system (J2000, B1950, ECLIPTIC, G ALACTIC */
+ double eq1, /* Input equinox (default of sys1 if 0.0) */
+ double eq2, /* Output equinox (default of sys2 if 0.0) */
+ double ep1, /* Input Besselian epoch in years */
+ double ep2, /* Output Besselian epoch in years */
+ double *dtheta, /* Longitude or right ascension in degrees
+ Input in sys1, returned in sys2 */
+ double *dphi, /* Latitude or declination in degrees
+ Input in sys1, returned in sys2 */
+ double *ptheta, /* Longitude or right ascension proper motion in deg/year
+ Input in sys1, returned in sys2 */
+ double *pphi, /* Latitude or declination proper motion in deg/year */
+ double *px, /* Parallax in arcseconds */
+ double *rv); /* Radial velocity in km/sec */
+ void wcsconp( /* Convert between coordinate systems and equinoxes */
+ int sys1, /* Input coordinate system (J2000, B1950, ECLIPTIC, GALACTIC */
+ int sys2, /* Output coordinate system (J2000, B1950, ECLIPTIC, G ALACTIC */
+ double eq1, /* Input equinox (default of sys1 if 0.0) */
+ double eq2, /* Output equinox (default of sys2 if 0.0) */
+ double ep1, /* Input Besselian epoch in years */
+ double ep2, /* Output Besselian epoch in years */
+ double *dtheta, /* Longitude or right ascension in degrees
+ Input in sys1, returned in sys2 */
+ double *dphi, /* Latitude or declination in degrees
+ Input in sys1, returned in sys2 */
+ double *ptheta, /* Longitude or right ascension proper motion in degrees/year
+ Input in sys1, returned in sys2 */
+ double *pphi); /* Latitude or declination proper motion in degrees/year
+ Input in sys1, returned in sys2 */
+ void wcscon( /* Convert between coordinate systems and equinoxes */
+ int sys1, /* Input coordinate system (J2000, B1950, ECLIPTIC, GALACTIC */
+ int sys2, /* Output coordinate system (J2000, B1950, ECLIPTIC, G ALACTIC */
+ double eq1, /* Input equinox (default of sys1 if 0.0) */
+ double eq2, /* Output equinox (default of sys2 if 0.0) */
+ double *dtheta, /* Longitude or right ascension in degrees
+ Input in sys1, returned in sys2 */
+ double *dphi, /* Latitude or declination in degrees
+ Input in sys1, returned in sys2 */
+ double epoch); /* Besselian epoch in years */
+ void fk425e ( /* Convert B1950(FK4) to J2000(FK5) coordinates */
+ double *ra, /* Right ascension in degrees (B1950 in, J2000 out) */
+ double *dec, /* Declination in degrees (B1950 in, J2000 out) */
+ double epoch); /* Besselian epoch in years */
+ void fk524e ( /* Convert J2000(FK5) to B1950(FK4) coordinates */
+ double *ra, /* Right ascension in degrees (J2000 in, B1950 out) */
+ double *dec, /* Declination in degrees (J2000 in, B1950 out) */
+ double epoch); /* Besselian epoch in years */
+ int wcscsys( /* Return code for coordinate system in string */
+ char *coorsys); /* Coordinate system (B1950, J2000, etc) */
+ double wcsceq ( /* Set equinox from string (return 0.0 if not obvious) */
+ char *wcstring); /* Coordinate system (B1950, J2000, etc) */
+ void wcscstr ( /* Set coordinate system type string from system and equinox */
+ char *cstr, /* Coordinate system string (returned) */
+ int syswcs, /* Coordinate system code */
+ double equinox, /* Equinox of coordinate system */
+ double epoch); /* Epoch of coordinate system */
+ void d2v3 ( /* Convert RA and Dec in degrees and distance to vector */
+ double rra, /* Right ascension in degrees */
+ double rdec, /* Declination in degrees */
+ double r, /* Distance to object in same units as pos */
+ double pos[3]); /* x,y,z geocentric equatorial position of object (returned) */
+ void s2v3 ( /* Convert RA and Dec in radians and distance to vector */
+ double rra, /* Right ascension in radians */
+ double rdec, /* Declination in radians */
+ double r, /* Distance to object in same units as pos */
+ double pos[3]); /* x,y,z geocentric equatorial position of object (returned) */
+ void v2d3 ( /* Convert vector to RA and Dec in degrees and distance */
+ double pos[3], /* x,y,z geocentric equatorial position of object */
+ double *rra, /* Right ascension in degrees (returned) */
+ double *rdec, /* Declination in degrees (returned) */
+ double *r); /* Distance to object in same units as pos (returned) */
+ void v2s3 ( /* Convert vector to RA and Dec in radians and distance */
+ double pos[3], /* x,y,z geocentric equatorial position of object */
+ double *rra, /* Right ascension in radians (returned) */
+ double *rdec, /* Declination in radians (returned) */
+ double *r); /* Distance to object in same units as pos (returned) */
+
+/* Distortion model subroutines in distort.c */
+ void distortinit ( /* Set distortion coefficients from FITS header */
+ struct WorldCoor *wcs, /* World coordinate system structure */
+ const char* hstring); /* FITS header */
+ void setdistcode ( /* Set WCS distortion code string from CTYPEi value */
+ struct WorldCoor *wcs, /* World coordinate system structure */
+ char *ctype); /* CTYPE value from FITS header */
+ char *getdistcode ( /* Return distortion code string for CTYPEi */
+ struct WorldCoor *wcs); /* World coordinate system structure */
+ int DelDistort ( /* Delete all distortion-related fields */
+ char *header, /* FITS header */
+ int verbose); /* If !=0, print keywords as deleted */
+ void pix2foc ( /* Convert pixel to focal plane coordinates */
+ struct WorldCoor *wcs, /* World coordinate system structure */
+ double x, /* Image pixel horizontal coordinate */
+ double y, /* Image pixel vertical coordinate */
+ double *u, /* Focal plane horizontal coordinate(returned) */
+ double *v); /* Focal plane vertical coordinate (returned) */
+ void foc2pix ( /* Convert focal plane to pixel coordinates */
+ struct WorldCoor *wcs, /* World coordinate system structure */
+ double u, /* Focal plane horizontal coordinate */
+ double v, /* Focal plane vertical coordinate */
+ double *x, /* Image pixel horizontal coordinate(returned) */
+ double *y); /* Image pixel vertical coordinate (returned) */
+
+/* Other projection subroutines */
+
+/* 8 projections using AIPS algorithms (worldpos.c) */
+ int worldpos ( /* Convert from pixel location to RA,Dec */
+ double xpix, /* x pixel number (RA or long without rotation) */
+ double ypix, /* y pixel number (Dec or lat without rotation) */
+ struct WorldCoor *wcs, /* WCS parameter structure */
+ double *xpos, /* x (RA) coordinate (deg) (returned) */
+ double *ypos); /* y (dec) coordinate (deg) (returned) */
+ int worldpix ( /* Convert from RA,Dec to pixel location */
+ double xpos, /* x (RA) coordinate (deg) */
+ double ypos, /* y (dec) coordinate (deg) */
+ struct WorldCoor *wcs, /* WCS parameter structure */
+ double *xpix, /* x pixel number (RA or long without rotation) */
+ double *ypix); /* y pixel number (dec or lat without rotation) */
+
+/* Digital Sky Survey projection (dsspos.c) */
+ int dsspos ( /* Convert from pixel location to RA,Dec */
+ double xpix, /* x pixel number (RA or long without rotation) */
+ double ypix, /* y pixel number (Dec or lat without rotation) */
+ struct WorldCoor *wcs, /* WCS parameter structure */
+ double *xpos, /* x (RA) coordinate (deg) (returned) */
+ double *ypos); /* y (dec) coordinate (deg) (returned) */
+ int dsspix ( /* Convert from RA,Dec to pixel location */
+ double xpos, /* x (RA) coordinate (deg) */
+ double ypos, /* y (dec) coordinate (deg) */
+ struct WorldCoor *wcs, /* WCS parameter structure */
+ double *xpix, /* x pixel number (RA or long without rotation) */
+ double *ypix); /* y pixel number (dec or lat without rotation) */
+
+/* SAO TDC TAN projection with higher order terms (platepos.c) */
+ int platepos ( /* Convert from pixel location to RA,Dec */
+ double xpix, /* x pixel number (RA or long without rotation) */
+ double ypix, /* y pixel number (Dec or lat without rotation) */
+ struct WorldCoor *wcs, /* WCS parameter structure */
+ double *xpos, /* x (RA) coordinate (deg) (returned) */
+ double *ypos); /* y (dec) coordinate (deg) (returned) */
+ int platepix ( /* Convert from RA,Dec to pixel location */
+ double xpos, /* x (RA) coordinate (deg) */
+ double ypos, /* y (dec) coordinate (deg) */
+ struct WorldCoor *wcs, /* WCS parameter structure */
+ double *xpix, /* x pixel number (RA or long without rotation) */
+ double *ypix); /* y pixel number (dec or lat without rotation) */
+ void SetFITSPlate ( /* Set FITS header plate fit coefficients from structure */
+ char *header, /* Image FITS header */
+ struct WorldCoor *wcs); /* WCS structure */
+ int SetPlate ( /* Set plate fit coefficients in structure from arguments */
+ struct WorldCoor *wcs, /* World coordinate system structure */
+ int ncoeff1, /* Number of coefficients for x */
+ int ncoeff2, /* Number of coefficients for y */
+ double *coeff); /* Plate fit coefficients */
+ int GetPlate ( /* Return plate fit coefficients from structure in arguments */
+ struct WorldCoor *wcs, /* World coordinate system structure */
+ int *ncoeff1, /* Number of coefficients for x */
+ int *ncoeff2, /* Number of coefficients for y) */
+ double *coeff); /* Plate fit coefficients */
+
+/* IRAF TAN projection with higher order terms (tnxpos.c) */
+ int tnxinit ( /* initialize the gnomonic forward or inverse transform */
+ const char *header, /* FITS header */
+ struct WorldCoor *wcs); /* pointer to WCS structure */
+ int tnxpos ( /* forward transform (physical to world) gnomonic projection. */
+ double xpix, /* Image X coordinate */
+ double ypix, /* Image Y coordinate */
+ struct WorldCoor *wcs, /* pointer to WCS descriptor */
+ double *xpos, /* Right ascension (returned) */
+ double *ypos); /* Declination (returned) */
+ int tnxpix ( /* Inverse transform (world to physical) gnomonic projection */
+ double xpos, /* Right ascension */
+ double ypos, /* Declination */
+ struct WorldCoor *wcs, /* Pointer to WCS descriptor */
+ double *xpix, /* Image X coordinate (returned) */
+ double *ypix); /* Image Y coordinate (returned) */
+
+/* IRAF ZPN projection with higher order terms (zpxpos.c) */
+ int zpxinit ( /* initialize the zenithal forward or inverse transform */
+ const char *header, /* FITS header */
+ struct WorldCoor *wcs); /* pointer to WCS structure */
+ int zpxpos ( /* forward transform (physical to world) */
+ double xpix, /* Image X coordinate */
+ double ypix, /* Image Y coordinate */
+ struct WorldCoor *wcs, /* pointer to WCS descriptor */
+ double *xpos, /* Right ascension (returned) */
+ double *ypos); /* Declination (returned) */
+ int zpxpix ( /* Inverse transform (world to physical) */
+ double xpos, /* Right ascension */
+ double ypos, /* Declination */
+ struct WorldCoor *wcs, /* Pointer to WCS descriptor */
+ double *xpix, /* Image X coordinate (returned) */
+ double *ypix); /* Image Y coordinate (returned) */
+
+#else /* K&R prototypes */
+
+/* WCS subroutines in wcs.c */
+struct WorldCoor *wcsinit(); /* set up a WCS structure from a FITS image header */
+struct WorldCoor *wcsninit(); /* set up a WCS structure from a FITS image header */
+struct WorldCoor *wcsinitn(); /* set up a WCS structure from a FITS image header */
+struct WorldCoor *wcsninitn(); /* set up a WCS structure from a FITS image header */
+struct WorldCoor *wcsinitc(); /* set up a WCS structure from a FITS image header */
+struct WorldCoor *wcsninitc(); /* set up a WCS structure from a FITS image header */
+struct WorldCoor *wcsxinit(); /* set up a WCS structure from arguments */
+struct WorldCoor *wcskinit(); /* set up a WCS structure from keyword values */
+void wcsfree(void); /* Free a WCS structure and its contents */
+int wcstype(); /* Set projection type from header CTYPEs */
+void wcscdset(); /* Set scaling and rotation from CD matrix */
+void wcsdeltset(); /* set scaling and rotation from CDELTs and CROTA2 */
+void wcspcset(); /* set scaling and rotation from CDELTs and PC matrix */
+int iswcs(); /* Return 1 if WCS structure is filled, else 0 */
+int nowcs(); /* Return 0 if WCS structure is filled, else 1 */
+void wcsshift(); /* Reset the center of a WCS structure */
+void wcscent(); /* Print the image center and size in WCS units */
+void wcssize(); /* Return RA and Dec of image center, size in RA and Dec */
+void wcsfull(); /* Return RA and Dec of image center, size in degrees */
+void wcsrange(); /* Return min and max RA and Dec of image in degrees */
+double wcsdist(); /* Distance in degrees between two sky coordinates */
+double wcsdist1(); /* Compute angular distance between 2 sky positions */
+double wcsdiff(); /* Distance in degrees between two sky coordinates */
+void wcscominit(); /* Initialize catalog search command set by -wcscom */
+void wcscom(); /* Execute catalog search command set by -wcscom */
+char *getradecsys(); /* Return current value of coordinate system */
+void wcsoutinit(); /* Initialize WCS output coordinate system for use by pix2wcs */
+char *getwcsout(); /* Return current value of WCS output coordinate system */
+void wcsininit(); /* Initialize WCS input coordinate system for use by wcs2pix */
+char *getwcsin(); /* Return current value of WCS input coordinate system */
+int setwcsdeg(); /* Set WCS output in degrees (1) or hh:mm:ss dd:mm:ss (0) */
+int wcsndec(); /* Set or get number of output decimal places */
+int wcsreset(); /* Change WCS using arguments */
+void wcseqset(); /* Change equinox of reference pixel coordinates in WCS */
+void wcscstr(); /* Return system string from system code, equinox, epoch */
+void setwcslin(); /* Set output string mode for LINEAR coordinates */
+int pix2wcst(); /* Convert pixel coordinates to World Coordinate string */
+void pix2wcs(); /* Convert pixel coordinates to World Coordinates */
+void wcsc2pix(); /* Convert World Coordinates to pixel coordinates */
+void wcs2pix(); /* Convert World Coordinates to pixel coordinates */
+void setdefwcs(); /* Call to use AIPS classic WCS (also not PLT/TNX/ZPX */
+int getdefwcs(); /* Call to get flag for AIPS classic WCS */
+int wcszin(); /* Set coordinate in third dimension (face) */
+int wcszout(); /* Return coordinate in third dimension */
+void wcserr(); /* Print WCS error message to stderr */
+void setwcserr(); /* Set WCS error message for later printing */
+void savewcscoor(); /* Save output coordinate system */
+char *getwcscoor(); /* Return output coordinate system */
+void savewcscom(); /* Save WCS shell command */
+char *getwcscom(); /* Return WCS shell command */
+void setwcscom(); /* Set WCS shell commands from stored values */
+void freewcscom(); /* Free memory used to store WCS shell commands */
+void setwcsfile(); /* Set filename for WCS error message */
+int cpwcs(); /* Copy WCS keywords with no suffix to ones with suffix */
+
+/* Coordinate conversion subroutines in wcscon.c */
+void wcscon(); /* Convert between coordinate systems and equinoxes */
+void wcsconp(); /* Convert between coordinate systems and equinoxes */
+void wcsconv(); /* Convert between coordinate systems and equinoxes */
+void fk425e(); /* Convert B1950(FK4) to J2000(FK5) coordinates */
+void fk524e(); /* Convert J2000(FK5) to B1950(FK4) coordinates */
+int wcscsys(); /* Set coordinate system from string */
+double wcsceq(); /* Set equinox from string (return 0.0 if not obvious) */
+void d2v3(); /* Convert RA and Dec in degrees and distance to vector */
+void s2v3(); /* Convert RA and Dec in radians and distance to vector */
+void v2d3(); /* Convert vector to RA and Dec in degrees and distance */
+void v2s3(); /* Convert vector to RA and Dec in radians and distance */
+
+/* Distortion model subroutines in distort.c */
+void distortinit(); /* Set distortion coefficients from FITS header */
+void setdistcode(); /* Set WCS distortion code string from CTYPEi value */
+char *getdistcode(); /* Return distortion code string for CTYPEi */
+int DelDistort(); /* Delete all distortion-related fields */
+void pix2foc(); /* pixel coordinates -> focal plane coordinates */
+void foc2pix(); /* focal plane coordinates -> pixel coordinates */
+
+/* Other projection subroutines */
+
+/* 8 projections using AIPS algorithms (worldpos.c) */
+extern int worldpos(); /* Convert from pixel location to RA,Dec */
+extern int worldpix(); /* Convert from RA,Dec to pixel location */
+
+/* Digital Sky Survey projection (dsspos.c) */
+extern int dsspos(); /* Convert from pixel location to RA,Dec */
+extern int dsspix(); /* Convert from RA,Dec to pixel location */
+
+/* SAO TDC TAN projection with higher order terms (platepos.c) */
+extern int platepos(); /* Convert from pixel location to RA,Dec */
+extern int platepix(); /* Convert from RA,Dec to pixel location */
+extern void SetFITSPlate(); /* Set FITS header plate fit coefficients from structure */
+extern int SetPlate(); /* Set plate fit coefficients in structure from arguments */
+extern int GetPlate(); /* Return plate fit coefficients from structure in arguments */
+
+/* IRAF TAN projection with higher order terms (tnxpos.c) */
+extern int tnxinit(); /* initialize the gnomonic forward or inverse transform */
+extern int tnxpos(); /* forward transform (physical to world) gnomonic projection. */
+extern int tnxpix(); /* Inverse transform (world to physical) gnomonic projection */
+
+/* IRAF ZPN projection with higher order terms (zpxpos.c) */
+extern int zpxinit(); /* initialize the gnomonic forward or inverse transform */
+extern int zpxpos(); /* forward transform (physical to world) gnomonic projection. */
+extern int zpxpix(); /* Inverse transform (world to physical) gnomonic projection */
+
+#endif /* __STDC__ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _wcs_h_ */
+
+/* Oct 26 1994 New file
+ * Dec 21 1994 Add rotation matrix
+ * Dec 22 1994 Add flag for coordinate reversal
+
+ * Mar 6 1995 Add parameters for Digital Sky Survey plate fit
+ * Jun 8 1995 Add parameters for coordinate system change
+ * Jun 21 1995 Add parameter for plate scale
+ * Jul 6 1995 Add parameter to note whether WCS is set
+ * Aug 8 1995 Add parameter to note whether to print coordinate system
+ * Oct 16 1995 Add parameters to save image dimensions and center coordinates
+
+ * Feb 15 1996 Add coordinate conversion functions
+ * Feb 20 1996 Add flag for tab tables
+ * Apr 26 1996 Add epoch of positions (actual date of image)
+ * Jul 5 1996 Add subroutine declarations
+ * Jul 19 1996 Add WCSFULL declaration
+ * Aug 5 1996 Add WCSNINIT to initialize WCS for non-terminated header
+ * Oct 31 1996 Add DCnn inverse rotation matrix
+ * Nov 1 1996 Add NDEC number of decimal places in output
+ *
+ * May 22 1997 Change range of pcode from 1-8 to -1-8 for linear transform
+ * Sep 12 1997 Add chip rotation MROT, XMPIX, YMPIX
+ *
+ * Jan 7 1998 Add INSTRUME and DETECTOR for HST metric correction
+ * Jan 16 1998 Add Mark Calabretta's WCSLIB data structures
+ * Jan 16 1998 Add LONGPOLE, LATPOLE, and PROJP constants for Calabretta
+ * Jan 22 1998 Add ctype[], crpix[], crval[], and cdelt[] for Calabretta
+ * Jan 23 1998 Change wcsset() to wcsxinit() and pcode to prjcode
+ * Jan 23 1998 Define projection type flags
+ * Jan 26 1998 Remove chip rotation
+ * Jan 26 1998 Add chip correction polynomial
+ * Feb 3 1998 Add number of coefficients for residual fit
+ * Feb 5 1998 Make cd and dc matrices vectors, not individual elements
+ * Feb 19 1998 Add projection names
+ * Feb 23 1998 Add TNX projection from NOAO
+ * Mar 3 1998 Add NOAO plate fit and residual fit
+ * Mar 12 1998 Add variables for TNX correction surface
+ * Mar 23 1998 Add PLT plate fit polynomial projection; reassign DSS
+ * Mar 23 1998 Drop plate_fit flag from structure
+ * Mar 25 1998 Add npcoeff to wcs structure for new plate fit WCS
+ * Apr 7 1998 Change amd_i_coeff to i_coeff
+ * Apr 8 1998 Add wcseqset() and wcsreset() subroutine declarations
+ * Apr 10 1998 Rearrange order of nonstandard WCS types
+ * Apr 13 1998 Add setdefwcs() subroutine declaration
+ * Apr 14 1998 Add coordinate systems and wcscoor()
+ * Apr 24 1998 Add units
+ * Apr 28 1998 Change coordinate system flags to WCS_*
+ * Apr 28 1998 Change projection flags to WCS_*
+ * Apr 28 1998 Add wcsc2pix()
+ * May 7 1998 Add C++ declarations
+ * May 13 1998 Add eqin and eqout for conversions to and from equinoxes
+ * May 14 1998 Add declarations for coordinate conversion subroutines
+ * May 27 1998 Add blsearch()
+ * May 27 1998 Change linear projection back to WCS_LIN from WCS_LPR
+ * May 27 1998 Move hget.c and hput.c C++ declarations to fitshead.h
+ * May 27 1998 Include fitshead.h
+ * May 29 1998 Add wcskinit()
+ * Jun 1 1998 Add wcserr()
+ * Jun 11 1998 Add initialization support subroutines
+ * Jun 18 1998 Add wcspcset()
+ * Jun 25 1998 Add wcsndec()
+ * Jul 6 1998 Add wcszin() and wcszout() to use third dimension of images
+ * Jul 7 1998 Change setdegout() to setwcsdeg(); setlinmode() to setwcslin()
+ * Jul 17 1998 Add savewcscoor(), getwcscoor(), savewcscom(), and getwcscom()
+ * Aug 14 1998 Add freewcscom(), setwcscom(), and multiple WCS commands
+ * Sep 3 1998 Add pa_north, pa_east, imrot and imflip to wcs structure
+ * Sep 14 1998 Add latbase for AXAF North Polar angle (NPOL not LAT-)
+ * Sep 16 1998 Make WCS_system start at 1; add NPOLE
+ * Sep 17 1998 Add wcscstr()
+ * Sep 21 1998 Add wcsconp() to convert proper motions, too.
+ * Dec 2 1998 Add WCS type for planet surface
+
+ * Jan 20 1999 Add declaration of wcsfree()
+ * Jun 16 1999 Add declaration of wcsrange()
+ * Oct 21 1999 Add declaration of setwcsfile()
+ *
+ * Jan 28 2000 Add flags for choice of WCS projection subroutines
+ * Jun 26 2000 Add XY coordinate system
+ * Nov 2 2000 Add wcsconv() to convert coordinates when parallax or rv known
+ *
+ * Jan 17 2001 Add idpix and ndpix for trim section, ltm for readout rotation
+ * Jan 31 2001 Add wcsinitn(), wcsninitn(), wcsinitc(), and wcsninitc()
+ * Feb 20 2001 Add wcs->wcs to main data structure
+ * Mar 20 2001 Close unclosed comment in wcsconv() argument list
+ *
+ * Apr 3 2002 Add SZP and second GLS/SFL projection
+ * Apr 9 2002 Add wcs->wcsdep for pointer to WCS depending on this WCS
+ * Apr 26 2002 Add wcs->wcsname and wcs->wcschar to identify WCS structure
+ * May 9 2002 Add wcs->radvel and wcs->zvel for radial velocity in km/sec
+ *
+ * Apr 1 2003 Add wcs->distort Distort structure for distortion correction
+ * Apr 1 2003 Add foc2pix() and pix2foc() subroutines for distortion correction
+ * May 1 2003 Add missing semicolons after C++ declarations of previous two functions
+ * Oct 1 2003 Rename wcs->naxes to wcs->naxis to match WCSLIB 3.2
+ * Nov 3 2003 Add distinit(), setdistcode(), and getdistcode() to distort.c
+ * Dec 3 2003 Add back wcs->naxes for backward compatibility
+ *
+ * Aug 30 2004 Add DelDistort()
+ *
+ * Nov 1 2005 Add WCS_ICRS
+ *
+ * Jan 5 2006 Add secrad()
+ * Apr 21 2006 Increase maximum number of axes from 4 to 8
+ * Apr 24 2006 Increase maximum number of axes to 9
+ * Nov 29 2006 Drop semicolon at end of C++ ifdef
+ * Dec 21 2006 Add cpwcs()
+ *
+ * Jan 4 2007 Drop extra declaration of wcscstr()
+ * Jan 4 2007 Fix declarations so ANSI prototypes are not just for C++
+ * Jan 9 2007 Add fk425e() and fk524e() subroutines
+ * Jan 9 2007 Add worldpos.c, dsspos.c, platepos.c, and tnxpos.c subroutines
+ * Jan 10 2007 Add ANSI prototypes for all subroutines
+ * Feb 1 2007 Add wcs.wcslog for log wavelength
+ * Jul 25 2007 Add v2s3(), s2v3(), d2v3(), v2d3() for coordinate-vector conversion
+ *
+ * Mar 31 2010 Add wcsdist1(), an alternate method
+ * Apr 07 2010 Add NWCSTYPE to keep it aligned with actual number of WCS types
+ *
+ * Mar 11 2011 Add NOAO ZPX projection parameters and subroutines (Frank Valdes)
+ * Mar 14 2011 Add SCAMP polynomial projection coefficients
+ * Sep 1 2011 Add TPV TAN projectioin with SCAT PV terms
+ * Sep 9 2011 Fix comment on TPV declaration
+ */
diff --git a/funtools/wcs/wcscon.c b/funtools/wcs/wcscon.c
new file mode 100644
index 0000000..6e99bd3
--- /dev/null
+++ b/funtools/wcs/wcscon.c
@@ -0,0 +1,2328 @@
+/*** File wcscon.c
+ *** March 30, 2010
+ *** Doug Mink, Harvard-Smithsonian Center for Astrophysics
+ *** Some subroutines are based on Starlink subroutines by Patrick Wallace
+ *** Copyright (C) 1995-2010
+ *** Smithsonian Astrophysical Observatory, Cambridge, MA, USA
+
+ This library 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 2 of the License, or (at your option) any later version.
+
+ This library 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 this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Correspondence concerning WCSTools should be addressed as follows:
+ Internet email: jmink@cfa.harvard.edu
+ Postal address: Jessica Mink
+ Smithsonian Astrophysical Observatory
+ 60 Garden St.
+ Cambridge, MA 02138 USA
+
+ * Module: wcscon.c (World Coordinate System conversion)
+ * Purpose: Convert between various sky coordinate systems
+ * Subroutine: wcscon (sys1,sys2,eq1,eq2,theta,phi,epoch)
+ * convert between coordinate systems
+ * Subroutine: wcsconp (sys1,sys2,eq1,eq2,ep1,ep2,dtheta,dphi,ptheta,pphi)
+ * convert coordinates and proper motion between coordinate systems
+ * Subroutine: wcsconv (sys1,sys2,eq1,eq2,ep1,ep2,dtheta,dphi,ptheta,pphi,px,rv)
+ * convert coordinates and proper motion between coordinate systems
+ * Subroutine: wcscsys (cstring) returns code for coordinate system in string
+ * Subroutine: wcsceq (wcstring) returns equinox in years from system string
+ * Subroutine: wcscstr (sys,equinox,epoch) returns system string from equinox
+ * Subroutine: fk524 (ra,dec) Convert J2000(FK5) to B1950(FK4) coordinates
+ * Subroutine: fk524e (ra, dec, epoch) (more accurate for known position epoch)
+ * Subroutine: fk524m (ra,dec,rapm,decpm) exact
+ * Subroutine: fk524pv (ra,dec,rapm,decpm,parallax,rv) more exact
+ * Subroutine: fk425 (ra,dec) Convert B1950(FK4) to J2000(FK5) coordinates
+ * Subroutine: fk425e (ra, dec, epoch) (more accurate for known position epoch)
+ * Subroutine: fk425m (ra, dec, rapm, decpm) exact
+ * Subroutine: fk425pv (ra,dec,rapm,decpm,parallax,rv) more exact
+ * Subroutine: fk42gal (dtheta,dphi) Convert B1950(FK4) to galactic coordinates
+ * Subroutine: fk52gal (dtheta,dphi) Convert J2000(FK5) to galactic coordinates
+ * Subroutine: gal2fk4 (dtheta,dphi) Convert galactic coordinates to B1950(FK4)
+ * Subroutine: gal2fk5 (dtheta,dphi) Convert galactic coordinates to J2000<FK5)
+ * Subroutine: fk42ecl (dtheta,dphi,epoch) Convert B1950(FK4) to ecliptic coordinates
+ * Subroutine: fk52ecl (dtheta,dphi,epoch) Convert J2000(FK5) to ecliptic coordinates
+ * Subroutine: ecl2fk4 (dtheta,dphi,epoch) Convert ecliptic coordinates to B1950(FK4)
+ * Subroutine: ecl2fk5 (dtheta,dphi,epoch) Convert ecliptic coordinates to J2000<FK5)
+ * Subroutine: fk5prec (ep0, ep1, ra, dec) Precession ep0 to ep1, FK5 system
+ * Subroutine: fk4prec (ep0, ep1, ra, dec) Precession ep0 to ep1, FK4 system
+ * Subroutine: d2v3 (rra, rdec, r, pos) RA and Dec in degrees, Distance to Cartesian
+ * Subroutine: v2d3 (pos, rra, rdec, r) Cartesian to RA and Dec in degrees, Distance
+ * Subroutine: s2v3 (rra, rdec, r, pos) RA, Dec, Distance to Cartesian
+ * Subroutine: v2s3 (pos, rra, rdec, r) Cartesian to RA, Dec, Distance
+ * Subroutine: rotmat (axes, rot1, rot2, rot3, matrix) Rotation angles to matrix
+ *
+ * Note: Proper motions are always in RA/Dec degrees/year; no cos(Dec) correction
+ */
+
+#include <math.h>
+#ifndef VMS
+#include <stdlib.h>
+#endif
+#include <stdio.h> /* for fprintf() and sprintf() */
+#include <ctype.h>
+#include <string.h>
+#include "wcs.h"
+
+void fk524(), fk524e(), fk524m(), fk524pv();
+void fk425(), fk425e(), fk425m(), fk425pv();
+void fk42gal(), fk52gal(), gal2fk4(), gal2fk5();
+void fk42ecl(), fk52ecl(), ecl2fk4(), ecl2fk5();
+
+/* Convert from coordinate system sys1 to coordinate system sys2, converting
+ proper motions, too, and adding them if an epoch is specified */
+
+void
+wcsconp (sys1, sys2, eq1, eq2, ep1, ep2, dtheta, dphi, ptheta, pphi)
+
+int sys1; /* Input coordinate system (J2000, B1950, ECLIPTIC, GALACTIC */
+int sys2; /* Output coordinate system (J2000, B1950, ECLIPTIC, GALACTIC */
+double eq1; /* Input equinox (default of sys1 if 0.0) */
+double eq2; /* Output equinox (default of sys2 if 0.0) */
+double ep1; /* Input Besselian epoch in years (for proper motion) */
+double ep2; /* Output Besselian epoch in years (for proper motion) */
+double *dtheta; /* Longitude or right ascension in degrees
+ Input in sys1, returned in sys2 */
+double *dphi; /* Latitude or declination in degrees
+ Input in sys1, returned in sys2 */
+double *ptheta; /* Longitude or right ascension proper motion in RA degrees/year
+ Input in sys1, returned in sys2 */
+double *pphi; /* Latitude or declination proper motion in Dec degrees/year
+ Input in sys1, returned in sys2 */
+
+{
+ void fk5prec(), fk4prec();
+
+ /* Set equinoxes if 0.0 */
+ if (eq1 == 0.0) {
+ if (sys1 == WCS_B1950)
+ eq1 = 1950.0;
+ else
+ eq1 = 2000.0;
+ }
+ if (eq2 == 0.0) {
+ if (sys2 == WCS_B1950)
+ eq2 = 1950.0;
+ else
+ eq2 = 2000.0;
+ }
+
+ /* Set epochs if 0.0 */
+ if (ep1 == 0.0) {
+ if (sys1 == WCS_B1950)
+ ep1 = 1950.0;
+ else
+ ep1 = 2000.0;
+ }
+ if (ep2 == 0.0) {
+ if (sys2 == WCS_B1950)
+ ep2 = 1950.0;
+ else
+ ep2 = 2000.0;
+ }
+
+ if (sys1 == WCS_ICRS && sys2 == WCS_ICRS)
+ eq2 = eq1;
+
+ if (sys1 == WCS_J2000 && sys2 == WCS_ICRS && eq1 == 2000.0) {
+ eq2 = eq1;
+ sys1 = sys2;
+ }
+
+ /* Set systems and equinoxes so that ICRS coordinates are not precessed */
+ if (sys1 == WCS_ICRS && sys2 == WCS_J2000 && eq2 == 2000.0) {
+ eq1 = eq2;
+ sys1 = sys2;
+ }
+
+ /* If systems and equinoxes are the same, add proper motion and return */
+ if (sys2 == sys1 && eq1 == eq2) {
+ if (ep1 != ep2) {
+ if (sys1 == WCS_J2000) {
+ *dtheta = *dtheta + ((ep2 - ep1) * *ptheta);
+ *dphi = *dphi + ((ep2 - ep1) * *pphi);
+ }
+ else if (sys1 == WCS_B1950) {
+ *dtheta = *dtheta + ((ep2 - ep1) * *ptheta);
+ *dphi = *dphi + ((ep2 - ep1) * *pphi);
+ }
+ }
+ if (eq1 != eq2) {
+ if (sys1 == WCS_B1950)
+ fk4prec (eq1, eq2, dtheta, dphi);
+ if (sys1 == WCS_J2000)
+ fk5prec (eq1, 2000.0, dtheta, dphi);
+ }
+ return;
+ }
+
+ /* Precess from input equinox to input system equinox, if necessary */
+ if (sys1 == WCS_B1950 && eq1 != 1950.0)
+ fk4prec (eq1, 1950.0, dtheta, dphi);
+ if (sys1 == WCS_J2000 && eq1 != 2000.0)
+ fk5prec (eq1, 2000.0, dtheta, dphi);
+
+ /* Convert to B1950 FK4 */
+ if (sys2 == WCS_B1950) {
+ if (sys1 == WCS_J2000) {
+ if (*ptheta != 0.0 || *pphi != 0.0) {
+ fk524m (dtheta, dphi, ptheta, pphi);
+ if (ep2 != 1950.0) {
+ *dtheta = *dtheta + ((ep2 - 1950.0) * *ptheta);
+ *dphi = *dphi + ((ep2 - 1950.0) * *pphi);
+ }
+ }
+ else if (ep2 != 1950.0)
+ fk524e (dtheta, dphi, ep2);
+ else
+ fk524 (dtheta, dphi);
+ }
+ else if (sys1 == WCS_GALACTIC)
+ gal2fk4 (dtheta, dphi);
+ else if (sys1 == WCS_ECLIPTIC)
+ ecl2fk4 (dtheta, dphi, ep2);
+ }
+
+ else if (sys2 == WCS_J2000) {
+ if (sys1 == WCS_B1950) {
+ if (*ptheta != 0.0 || *pphi != 0.0) {
+ fk425m (dtheta, dphi, ptheta, pphi);
+ if (ep2 != 2000.0) {
+ *dtheta = *dtheta + ((ep2 - 2000.0) * *ptheta);
+ *dphi = *dphi + ((ep2 - 2000.0) * *pphi);
+ }
+ }
+ else if (ep2 > 0.0)
+ fk425e (dtheta, dphi, ep2);
+ else
+ fk425 (dtheta, dphi);
+ }
+ else if (sys1 == WCS_GALACTIC)
+ gal2fk5 (dtheta, dphi);
+ else if (sys1 == WCS_ECLIPTIC)
+ ecl2fk5 (dtheta, dphi, ep2);
+ }
+
+ else if (sys2 == WCS_GALACTIC) {
+ if (sys1 == WCS_B1950) {
+ if (ep2 != 0.0 && (*ptheta != 0.0 || *pphi != 0.0)) {
+ *dtheta = *dtheta + (*ptheta * (ep2 - ep1));
+ *dphi = *dphi + (*pphi * (ep2 - ep1));
+ }
+ fk42gal (dtheta, dphi);
+ }
+ else if (sys1 == WCS_J2000) {
+ if (ep2 != 0.0 && (*ptheta != 0.0 || *pphi != 0.0)) {
+ *dtheta = *dtheta + (*ptheta * (ep2 - ep1));
+ *dphi = *dphi + (*pphi * (ep2 - ep1));
+ }
+ fk52gal (dtheta, dphi);
+ }
+ else if (sys1 == WCS_ECLIPTIC) {
+ ecl2fk5 (dtheta, dphi, ep2);
+ fk52gal (dtheta, dphi);
+ }
+ }
+
+ else if (sys2 == WCS_ECLIPTIC) {
+ if (sys1 == WCS_B1950) {
+ if (ep2 != 0.0 && (*ptheta != 0.0 || *pphi != 0.0)) {
+ *dtheta = *dtheta + (*ptheta * (ep2 - ep1));
+ *dphi = *dphi + (*pphi * (ep2 - ep1));
+ }
+ if (ep2 > 0.0)
+ fk42ecl (dtheta, dphi, ep2);
+ else
+ fk42ecl (dtheta, dphi, 1950.0);
+ }
+ else if (sys1 == WCS_J2000) {
+ if (ep2 != 0.0 && (*ptheta != 0.0 || *pphi != 0.0)) {
+ *dtheta = *dtheta + (*ptheta * (ep2 - ep1));
+ *dphi = *dphi + (*pphi * (ep2 - ep1));
+ }
+ fk52ecl (dtheta, dphi, ep2);
+ }
+ else if (sys1 == WCS_GALACTIC) {
+ gal2fk5 (dtheta, dphi);
+ fk52ecl (dtheta, dphi, ep2);
+ }
+ }
+
+ /* Precess to desired equinox, if necessary */
+ if (sys2 == WCS_B1950 && eq2 != 1950.0)
+ fk4prec (1950.0, eq2, dtheta, dphi);
+ if (sys2 == WCS_J2000 && eq2 != 2000.0)
+ fk5prec (2000.0, eq2, dtheta, dphi);
+
+ /* Keep latitude/declination between +90 and -90 degrees */
+ if (*dphi > 90.0) {
+ *dphi = 180.0 - *dphi;
+ *dtheta = *dtheta + 180.0;
+ }
+ else if (*dphi < -90.0) {
+ *dphi = -180.0 - *dphi;
+ *dtheta = *dtheta + 180.0;
+ }
+
+ /* Keep longitude/right ascension between 0 and 360 degrees */
+ if (*dtheta > 360.0)
+ *dtheta = *dtheta - 360.0;
+ else if (*dtheta < 0.0)
+ *dtheta = *dtheta + 360.0;
+ return;
+}
+
+
+/* Convert from coordinate system sys1 to coordinate system sys2, converting
+ proper motions, too, and adding them if an epoch is specified */
+
+void
+wcsconv (sys1, sys2, eq1, eq2, ep1, ep2, dtheta, dphi, ptheta, pphi, px, rv)
+
+int sys1; /* Input coordinate system (J2000, B1950, ECLIPTIC, GALACTIC */
+int sys2; /* Output coordinate system (J2000, B1950, ECLIPTIC, GALACTIC */
+double eq1; /* Input equinox (default of sys1 if 0.0) */
+double eq2; /* Output equinox (default of sys2 if 0.0) */
+double ep1; /* Input Besselian epoch in years (for proper motion) */
+double ep2; /* Output Besselian epoch in years (for proper motion) */
+double *dtheta; /* Longitude or right ascension in degrees
+ Input in sys1, returned in sys2 */
+double *dphi; /* Latitude or declination in degrees
+ Input in sys1, returned in sys2 */
+double *ptheta; /* Longitude or right ascension proper motion in degrees/year
+ Input in sys1, returned in sys2 */
+double *pphi; /* Latitude or declination proper motion in degrees/year
+ Input in sys1, returned in sys2 */
+double *px; /* Parallax in arcseconds */
+double *rv; /* Radial velocity in km/sec */
+
+{
+ void fk5prec(), fk4prec();
+
+ /* Set equinoxes if 0.0 */
+ if (eq1 == 0.0) {
+ if (sys1 == WCS_B1950)
+ eq1 = 1950.0;
+ else
+ eq1 = 2000.0;
+ }
+ if (eq2 == 0.0) {
+ if (sys2 == WCS_B1950)
+ eq2 = 1950.0;
+ else
+ eq2 = 2000.0;
+ }
+
+ /* Set epochs if 0.0 */
+ if (ep1 == 0.0) {
+ if (sys1 == WCS_B1950)
+ ep1 = 1950.0;
+ else
+ ep1 = 2000.0;
+ }
+ if (ep2 == 0.0) {
+ if (sys2 == WCS_B1950)
+ ep2 = 1950.0;
+ else
+ ep2 = 2000.0;
+ }
+
+ /* Set systems and equinoxes so that ICRS coordinates are not precessed */
+ if (sys1 == WCS_ICRS && sys2 == WCS_ICRS)
+ eq2 = eq1;
+
+ if (sys1 == WCS_J2000 && sys2 == WCS_ICRS && eq1 == 2000.0) {
+ eq2 = eq1;
+ sys1 = sys2;
+ }
+
+ if (sys1 == WCS_ICRS && sys2 == WCS_J2000 && eq2 == 2000.0) {
+ eq1 = eq2;
+ sys1 = sys2;
+ }
+
+ /* If systems and equinoxes are the same, add proper motion and return */
+ if (sys2 == sys1 && eq1 == eq2) {
+ if (ep1 != ep2) {
+ if (sys1 == WCS_J2000) {
+ *dtheta = *dtheta + ((ep2 - ep1) * *ptheta);
+ *dphi = *dphi + ((ep2 - ep1) * *pphi);
+ }
+ else if (sys1 == WCS_B1950) {
+ *dtheta = *dtheta + ((ep2 - ep1) * *ptheta);
+ *dphi = *dphi + ((ep2 - ep1) * *pphi);
+ }
+ }
+ return;
+ }
+
+ /* Precess from input equinox to input system equinox, if necessary */
+ if (eq1 != eq2) {
+ if (sys1 == WCS_B1950 && eq1 != 1950.0)
+ fk4prec (eq1, 1950.0, dtheta, dphi);
+ if (sys1 == WCS_J2000 && eq1 != 2000.0)
+ fk5prec (eq1, 2000.0, dtheta, dphi);
+ }
+
+ /* Convert to B1950 FK4 */
+ if (sys2 == WCS_B1950) {
+ if (sys1 == WCS_J2000) {
+ if (*ptheta != 0.0 || *pphi != 0.0) {
+ if (*px != 0.0 || *rv != 0.0)
+ fk524pv (dtheta, dphi, ptheta, pphi, px, rv);
+ else
+ fk524m (dtheta, dphi, ptheta, pphi);
+ if (ep1 == 2000.0)
+ ep1 = 1950.0;
+ if (ep2 != 1950.0) {
+ *dtheta = *dtheta + ((ep2 - 1950.0) * *ptheta);
+ *dphi = *dphi + ((ep2 - 1950.0) * *pphi);
+ }
+ }
+ else if (ep2 != 1950.0)
+ fk524e (dtheta, dphi, ep2);
+ else
+ fk524 (dtheta, dphi);
+ }
+ else if (sys1 == WCS_GALACTIC)
+ gal2fk4 (dtheta, dphi);
+ else if (sys1 == WCS_ECLIPTIC)
+ ecl2fk4 (dtheta, dphi, ep2);
+ }
+
+ else if (sys2 == WCS_J2000) {
+ if (sys1 == WCS_B1950) {
+ if (*ptheta != 0.0 || *pphi != 0.0) {
+ if (*px != 0.0 || *rv != 0.0)
+ fk425pv (dtheta, dphi, ptheta, pphi, px, rv);
+ else
+ fk425m (dtheta, dphi, ptheta, pphi);
+ if (ep2 != 2000.0) {
+ *dtheta = *dtheta + ((ep2 - 2000.0) * *ptheta);
+ *dphi = *dphi + ((ep2 - 2000.0) * *pphi);
+ }
+ }
+ else if (ep2 > 0.0)
+ fk425e (dtheta, dphi, ep2);
+ else
+ fk425 (dtheta, dphi);
+ }
+ else if (sys1 == WCS_GALACTIC)
+ gal2fk5 (dtheta, dphi);
+ else if (sys1 == WCS_ECLIPTIC)
+ ecl2fk5 (dtheta, dphi, ep2);
+ }
+
+ else if (sys2 == WCS_GALACTIC) {
+ if (sys1 == WCS_B1950) {
+ if (ep2 != 0.0 && (*ptheta != 0.0 || *pphi != 0.0)) {
+ *dtheta = *dtheta + (*ptheta * (ep2 - ep1));
+ *dphi = *dphi + (*pphi * (ep2 - ep1));
+ }
+ fk42gal (dtheta, dphi);
+ }
+ else if (sys1 == WCS_J2000) {
+ if (ep2 != 0.0 && (*ptheta != 0.0 || *pphi != 0.0)) {
+ *dtheta = *dtheta + (*ptheta * (ep2 - ep1));
+ *dphi = *dphi + (*pphi * (ep2 - ep1));
+ }
+ fk52gal (dtheta, dphi);
+ }
+ else if (sys1 == WCS_ECLIPTIC) {
+ ecl2fk5 (dtheta, dphi, ep2);
+ fk52gal (dtheta, dphi);
+ }
+ }
+
+ else if (sys2 == WCS_ECLIPTIC) {
+ if (sys1 == WCS_B1950) {
+ if (ep2 != 0.0 && (*ptheta != 0.0 || *pphi != 0.0)) {
+ *dtheta = *dtheta + (*ptheta * (ep2 - ep1));
+ *dphi = *dphi + (*pphi * (ep2 - ep1));
+ }
+ if (ep2 > 0.0)
+ fk42ecl (dtheta, dphi, ep2);
+ else
+ fk42ecl (dtheta, dphi, 1950.0);
+ }
+ else if (sys1 == WCS_J2000) {
+ if (ep2 != 0.0 && (*ptheta != 0.0 || *pphi != 0.0)) {
+ *dtheta = *dtheta + (*ptheta * (ep2 - ep1));
+ *dphi = *dphi + (*pphi * (ep2 - ep1));
+ }
+ fk52ecl (dtheta, dphi, ep2);
+ }
+ else if (sys1 == WCS_GALACTIC) {
+ gal2fk5 (dtheta, dphi);
+ fk52ecl (dtheta, dphi, ep2);
+ }
+ }
+
+ /* Precess to desired equinox, if necessary */
+ if (eq1 != eq2) {
+ if (sys2 == WCS_B1950 && eq2 != 1950.0)
+ fk4prec (1950.0, eq2, dtheta, dphi);
+ if (sys2 == WCS_J2000 && eq2 != 2000.0)
+ fk5prec (2000.0, eq2, dtheta, dphi);
+ }
+
+ /* Keep latitude/declination between +90 and -90 degrees */
+ if (*dphi > 90.0) {
+ *dphi = 180.0 - *dphi;
+ *dtheta = *dtheta + 180.0;
+ }
+ else if (*dphi < -90.0) {
+ *dphi = -180.0 - *dphi;
+ *dtheta = *dtheta + 180.0;
+ }
+
+ /* Keep longitude/right ascension between 0 and 360 degrees */
+ if (*dtheta > 360.0)
+ *dtheta = *dtheta - 360.0;
+ else if (*dtheta < 0.0)
+ *dtheta = *dtheta + 360.0;
+ return;
+}
+
+
+/* Convert from coordinate system sys1 to coordinate system sys2 */
+
+void
+wcscon (sys1, sys2, eq1, eq2, dtheta, dphi, epoch)
+
+int sys1; /* Input coordinate system (J2000, B1950, ECLIPTIC, GALACTIC */
+int sys2; /* Output coordinate system (J2000, B1950, ECLIPTIC, GALACTIC */
+double eq1; /* Input equinox (default of sys1 if 0.0) */
+double eq2; /* Output equinox (default of sys2 if 0.0) */
+double *dtheta; /* Longitude or right ascension in degrees
+ Input in sys1, returned in sys2 */
+double *dphi; /* Latitude or declination in degrees
+ Input in sys1, returned in sys2 */
+double epoch; /* Besselian epoch in years */
+
+{
+ void fk5prec(), fk4prec();
+
+ /* Set equinoxes if 0.0 */
+ if (eq1 == 0.0) {
+ if (sys1 == WCS_B1950)
+ eq1 = 1950.0;
+ else
+ eq1 = 2000.0;
+ }
+ if (eq2 == 0.0) {
+ if (sys2 == WCS_B1950)
+ eq2 = 1950.0;
+ else
+ eq2 = 2000.0;
+ }
+
+ /* Set systems and equinoxes so that ICRS coordinates are not precessed */
+ if (sys1 == WCS_ICRS && sys2 == WCS_ICRS)
+ eq2 = eq1;
+
+ if (sys1 == WCS_J2000 && sys2 == WCS_ICRS && eq1 == 2000.0) {
+ eq2 = eq1;
+ sys1 = sys2;
+ }
+
+ if (sys1 == WCS_ICRS && sys2 == WCS_J2000 && eq2 == 2000.0) {
+ eq1 = eq2;
+ sys1 = sys2;
+ }
+
+ /* If systems and equinoxes are the same, return */
+ if (sys2 == sys1 && eq1 == eq2)
+ return;
+
+ /* Precess from input equinox, if necessary */
+ if (eq1 != eq2) {
+ if (sys1 == WCS_B1950 && eq1 != 1950.0)
+ fk4prec (eq1, 1950.0, dtheta, dphi);
+ if (sys1 == WCS_J2000 && eq1 != 2000.0)
+ fk5prec (eq1, 2000.0, dtheta, dphi);
+ }
+
+ /* Convert to B1950 FK4 */
+ if (sys2 == WCS_B1950) {
+ if (sys1 == WCS_J2000) {
+ if (epoch > 0)
+ fk524e (dtheta, dphi, epoch);
+ else
+ fk524 (dtheta, dphi);
+ }
+ else if (sys1 == WCS_GALACTIC)
+ gal2fk4 (dtheta, dphi);
+ else if (sys1 == WCS_ECLIPTIC) {
+ if (epoch > 0)
+ ecl2fk4 (dtheta, dphi, epoch);
+ else
+ ecl2fk4 (dtheta, dphi, 1950.0);
+ }
+ }
+
+ else if (sys2 == WCS_J2000) {
+ if (sys1 == WCS_B1950) {
+ if (epoch > 0)
+ fk425e (dtheta, dphi, epoch);
+ else
+ fk425 (dtheta, dphi);
+ }
+ else if (sys1 == WCS_GALACTIC)
+ gal2fk5 (dtheta, dphi);
+ else if (sys1 == WCS_ECLIPTIC) {
+ if (epoch > 0)
+ ecl2fk5 (dtheta, dphi, epoch);
+ else
+ ecl2fk5 (dtheta, dphi, 2000.0);
+ }
+ }
+
+ else if (sys2 == WCS_GALACTIC) {
+ if (sys1 == WCS_B1950)
+ fk42gal (dtheta, dphi);
+ else if (sys1 == WCS_J2000)
+ fk52gal (dtheta, dphi);
+ else if (sys1 == WCS_ECLIPTIC) {
+ if (epoch > 0)
+ ecl2fk5 (dtheta, dphi, epoch);
+ else
+ ecl2fk5 (dtheta, dphi, 2000.0);
+ fk52gal (dtheta, dphi);
+ }
+ }
+
+ else if (sys2 == WCS_ECLIPTIC) {
+ if (sys1 == WCS_B1950) {
+ if (epoch > 0)
+ fk42ecl (dtheta, dphi, epoch);
+ else
+ fk42ecl (dtheta, dphi, 1950.0);
+ }
+ else if (sys1 == WCS_J2000) {
+ if (epoch > 0)
+ fk52ecl (dtheta, dphi, epoch);
+ else
+ fk52ecl (dtheta, dphi, 2000.0);
+ }
+ else if (sys1 == WCS_GALACTIC) {
+ gal2fk5 (dtheta, dphi);
+ if (epoch > 0)
+ fk52ecl (dtheta, dphi, epoch);
+ else
+ fk52ecl (dtheta, dphi, 2000.0);
+ }
+ }
+
+ /* Precess to desired equinox, if necessary */
+ if (eq1 != eq2) {
+ if (sys2 == WCS_B1950 && eq2 != 1950.0)
+ fk4prec (1950.0, eq2, dtheta, dphi);
+ if (sys2 == WCS_J2000 && eq2 != 2000.0)
+ fk5prec (2000.0, eq2, dtheta, dphi);
+ }
+
+ /* Keep latitude/declination between +90 and -90 degrees */
+ if (*dphi > 90.0) {
+ *dphi = 180.0 - *dphi;
+ *dtheta = *dtheta + 180.0;
+ }
+ else if (*dphi < -90.0) {
+ *dphi = -180.0 - *dphi;
+ *dtheta = *dtheta + 180.0;
+ }
+
+ /* Keep longitude/right ascension between 0 and 360 degrees */
+ if (*dtheta > 360.0)
+ *dtheta = *dtheta - 360.0;
+ else if (*dtheta < 0.0)
+ *dtheta = *dtheta + 360.0;
+
+ return;
+}
+
+
+/* Set coordinate system from string */
+int
+wcscsys (wcstring)
+
+char *wcstring; /* Name of coordinate system */
+{
+ double equinox;
+
+ if (wcstring[0] == 'J' || wcstring[0] == 'j' ||
+ !strcmp (wcstring,"2000") || !strcmp (wcstring, "2000.0") ||
+ !strcmp (wcstring,"ICRS") || !strcmp (wcstring, "icrs") ||
+ !strncmp (wcstring,"FK5",3) || !strncmp (wcstring, "fk5",3))
+ return WCS_J2000;
+
+ if (wcstring[0] == 'B' || wcstring[0] == 'b' ||
+ !strcmp (wcstring,"1950") || !strcmp (wcstring, "1950.0") ||
+ !strncmp (wcstring,"FK4",3) || !strncmp (wcstring, "fk4",3))
+ return WCS_B1950;
+
+ else if (wcstring[0] == 'I' || wcstring[0] == 'i' )
+ return WCS_ICRS;
+
+ else if (wcstring[0] == 'G' || wcstring[0] == 'g' )
+ return WCS_GALACTIC;
+
+ else if (wcstring[0] == 'E' || wcstring[0] == 'e' )
+ return WCS_ECLIPTIC;
+
+ else if (wcstring[0] == 'A' || wcstring[0] == 'a' )
+ return WCS_ALTAZ;
+
+ else if (wcstring[0] == 'N' || wcstring[0] == 'n' )
+ return WCS_NPOLE;
+
+ else if (wcstring[0] == 'L' || wcstring[0] == 'l' )
+ return WCS_LINEAR;
+
+ else if (!strncasecmp (wcstring, "pixel", 5))
+ return WCS_XY;
+
+ else if (wcstring[0] == 'P' || wcstring[0] == 'p' )
+ return WCS_PLANET;
+
+ else if (isnum (wcstring)) {
+ equinox = atof (wcstring);
+ if (equinox > 1980.0)
+ return WCS_J2000;
+ else if (equinox > 1900.0)
+ return WCS_B1950;
+ else
+ return -1;
+ }
+ else
+ return -1;
+}
+
+
+/* Set equinox from string (return 0.0 if not obvious) */
+
+double
+wcsceq (wcstring)
+
+char *wcstring; /* Name of coordinate system */
+{
+ if (wcstring[0] == 'J' || wcstring[0] == 'j' ||
+ wcstring[0] == 'B' || wcstring[0] == 'b')
+ return (atof (wcstring+1));
+ else if (!strncmp (wcstring, "FK4",3) ||
+ !strncmp (wcstring, "fk4",3))
+ return (1950.0);
+ else if (!strncmp (wcstring, "FK5",3) ||
+ !strncmp (wcstring, "fk5",3))
+ return (2000.0);
+ else if (!strncmp (wcstring, "ICRS",4) ||
+ !strncmp (wcstring, "icrs",4))
+ return (2000.0);
+ else if (wcstring[0] == '1' || wcstring[0] == '2')
+ return (atof (wcstring));
+ else
+ return (0.0);
+}
+
+
+/* Set coordinate system type string from system and equinox */
+
+void
+wcscstr (cstr, syswcs, equinox, epoch)
+
+char *cstr; /* Coordinate system string (returned) */
+int syswcs; /* Coordinate system code */
+double equinox; /* Equinox of coordinate system */
+double epoch; /* Epoch of coordinate system */
+{
+
+ char *estr;
+
+ if (syswcs == WCS_XY) {
+ strcpy (cstr, "XY");
+ return;
+ }
+
+ /* Try to figure out coordinate system if it is not set */
+ if (epoch == 0.0)
+ epoch = equinox;
+ if (syswcs < 0) {
+ if (equinox > 0.0) {
+ if (equinox == 2000.0)
+ syswcs = WCS_J2000;
+ else if (equinox == 1950.0)
+ syswcs = WCS_B1950;
+ }
+ else if (epoch > 0.0) {
+ if (epoch > 1980.0) {
+ syswcs = WCS_J2000;
+ equinox = 2000.0;
+ }
+ else {
+ syswcs = WCS_B1950;
+ equinox = 1950.0;
+ }
+ }
+ else
+ syswcs = WCS_J2000;
+ }
+
+ /* Set coordinate system string from system flag and epoch */
+ if (syswcs == WCS_B1950) {
+ if (epoch == 1950.0 || epoch == 0.0)
+ strcpy (cstr, "B1950");
+ else
+ sprintf (cstr, "B%7.2f", equinox);
+ if ((estr = strsrch (cstr,".00")) != NULL) {
+ estr[0] = (char) 0;
+ estr[1] = (char) 0;
+ estr[2] = (char) 0;
+ }
+ }
+ else if (syswcs == WCS_GALACTIC)
+ strcpy (cstr, "galactic");
+ else if (syswcs == WCS_ECLIPTIC)
+ strcpy (cstr, "ecliptic");
+ else if (syswcs == WCS_J2000) {
+ if (epoch == 2000.0 || epoch == 0.0)
+ strcpy (cstr, "J2000");
+ else
+ sprintf (cstr, "J%7.2f", equinox);
+ if ((estr = strsrch (cstr,".00")) != NULL) {
+ estr[0] = (char) 0;
+ estr[1] = (char) 0;
+ estr[2] = (char) 0;
+ }
+ }
+ else if (syswcs == WCS_ICRS) {
+ strcpy (cstr, "ICRS");
+ }
+ else if (syswcs == WCS_PLANET) {
+ strcpy (cstr, "PLANET");
+ }
+ else if (syswcs == WCS_LINEAR || syswcs == WCS_XY) {
+ strcpy (cstr, "LINEAR");
+ }
+ return;
+}
+
+
+/* Constant vector and matrix (by columns)
+ These values were obtained by inverting C.Hohenkerk's forward matrix
+ (private communication), which agrees with the one given in reference
+ 2 but which has one additional decimal place. */
+
+static double a[3] = {-1.62557e-6, -0.31919e-6, -0.13843e-6};
+static double ad[3] = {1.245e-3, -1.580e-3, -0.659e-3};
+static double d2pi = 6.283185307179586476925287; /* two PI */
+static double tiny = 1.e-30; /* small number to avoid arithmetic problems */
+
+/* FK524 convert J2000 FK5 star data to B1950 FK4
+ based on Starlink sla_fk524 by P.T.Wallace 27 October 1987 */
+
+static double emi[6][6] = {
+ { 0.9999256795, /* emi[0][0] */
+ 0.0111814828, /* emi[0][1] */
+ 0.0048590039, /* emi[0][2] */
+ -0.00000242389840, /* emi[0][3] */
+ -0.00000002710544, /* emi[0][4] */
+ -0.00000001177742 }, /* emi[0][5] */
+
+ { -0.0111814828, /* emi[1][0] */
+ 0.9999374849, /* emi[1][1] */
+ -0.0000271771, /* emi[1][2] */
+ 0.00000002710544, /* emi[1][3] */
+ -0.00000242392702, /* emi[1][4] */
+ 0.00000000006585 }, /* emi[1][5] */
+
+ { -0.0048590040, /* emi[2][0] */
+ -0.0000271557, /* emi[2][1] */
+ 0.9999881946, /* emi[2][2] */
+ 0.00000001177742, /* emi[2][3] */
+ 0.00000000006585, /* emi[2][4] */
+ -0.00000242404995 }, /* emi[2][5] */
+
+ { -0.000551, /* emi[3][0] */
+ 0.238509, /* emi[3][1] */
+ -0.435614, /* emi[3][2] */
+ 0.99990432, /* emi[3][3] */
+ 0.01118145, /* emi[3][4] */
+ 0.00485852 }, /* emi[3][5] */
+
+ { -0.238560, /* emi[4][0] */
+ -0.002667, /* emi[4][1] */
+ 0.012254, /* emi[4][2] */
+ -0.01118145, /* emi[4][3] */
+ 0.99991613, /* emi[4][4] */
+ -0.00002717 }, /* emi[4][5] */
+
+ { 0.435730, /* emi[5][0] */
+ -0.008541, /* emi[5][1] */
+ 0.002117, /* emi[5][2] */
+ -0.00485852, /* emi[5][3] */
+ -0.00002716, /* emi[5][4] */
+ 0.99996684 } /* emi[5][5] */
+ };
+
+void
+fk524 (ra,dec)
+
+double *ra; /* Right ascension in degrees (J2000 in, B1950 out) */
+double *dec; /* Declination in degrees (J2000 in, B1950 out) */
+
+{
+ double rapm; /* Proper motion in right ascension */
+ double decpm; /* Proper motion in declination */
+ /* In: deg/jul.yr. Out: deg/trop.yr. */
+
+ rapm = (double) 0.0;
+ decpm = (double) 0.0;
+ fk524m (ra, dec, &rapm, &decpm);
+ return;
+}
+
+void
+fk524e (ra, dec, epoch)
+
+double *ra; /* Right ascension in degrees (J2000 in, B1950 out) */
+double *dec; /* Declination in degrees (J2000 in, B1950 out) */
+double epoch; /* Besselian epoch in years */
+
+{
+ double rapm; /* Proper motion in right ascension */
+ double decpm; /* Proper motion in declination */
+ /* In: deg/jul.yr. Out: deg/trop.yr. */
+
+ rapm = (double) 0.0;
+ decpm = (double) 0.0;
+ fk524m (ra, dec, &rapm, &decpm);
+ *ra = *ra + (rapm * (epoch - 1950.0));
+ *dec = *dec + (decpm * (epoch - 1950.0));
+ return;
+}
+
+void
+fk524m (ra,dec,rapm,decpm)
+
+double *ra; /* Right ascension in degrees (J2000 in, B1950 out) */
+double *dec; /* Declination in degrees (J2000 in, B1950 out) */
+double *rapm; /* Proper motion in right ascension */
+double *decpm; /* Proper motion in declination */
+ /* In: ra/dec deg/jul.yr. Out: ra/dec deg/trop.yr. */
+
+{
+ double parallax = 0.0;
+ double rv = 0.0;
+
+ fk524pv (ra, dec, rapm, decpm, &parallax, &rv);
+ return;
+}
+
+
+void
+fk524pv (ra,dec,rapm,decpm, parallax, rv)
+
+double *ra; /* Right ascension in degrees (J2000 in, B1950 out) */
+double *dec; /* Declination in degrees (J2000 in, B1950 out) */
+double *rapm; /* Proper motion in right ascension */
+double *decpm; /* Proper motion in declination
+ * In: ra/dec degrees/Julian year (not ra*cos(dec))
+ * Out: ra/dec degrees/tropical year */
+double *parallax; /* Parallax (arcsec) */
+double *rv; /* Rradial velocity (km/s, +ve = moving away) */
+
+/* This routine converts stars from the IAU 1976 FK5 Fricke
+ system, to the old Bessel-Newcomb FK4 system, using Yallop's
+ implementation (see ref 2) of a matrix method due to Standish
+ (see ref 3). The numerical values of ref 2 are used canonically.
+
+ * Conversion from other than Julian epoch 2000.0 to other than Besselian
+ epoch 1950.0 will require use of the appropriate precession, proper
+ motion, and e-terms routines before and/or after fk524 is called.
+
+ * In the FK4 catalogue the proper motions of stars within 10 degrees
+ of the poles do not embody the differential e-term effect and should,
+ strictly speaking, be handled in a different manner from stars outside
+ these regions. however, given the general lack of homogeneity of the
+ star data available for routine astrometry, the difficulties of handling
+ positions that may have been determined from astrometric fields spanning
+ the polar and non-polar regions, the likelihood that the differential
+ e-terms effect was not taken into account when allowing for proper motion
+ in past astrometry, and the undesirability of a discontinuity in the
+ algorithm, the decision has been made in this routine to include the
+ effect of differential e-terms on the proper motions for all stars,
+ whether polar or not, at epoch 2000, and measuring on the sky rather
+ than in terms of dra, the errors resulting from this simplification are
+ less than 1 milliarcsecond in position and 1 milliarcsecond per century
+ in proper motion.
+
+ References:
+
+ 1 "Mean and apparent place computations in the new IAU System.
+ I. The transformation of astrometric catalog systems to the
+ equinox J2000.0." Smith, C.A.; Kaplan, G.H.; Hughes, J.A.;
+ Seidelmann, P.K.; Yallop, B.D.; Hohenkerk, C.Y.
+ Astronomical Journal vol. 97, Jan. 1989, p. 265-273.
+
+ 2 "Mean and apparent place computations in the new IAU System.
+ II. Transformation of mean star places from FK4 B1950.0 to
+ FK5 J2000.0 using matrices in 6-space." Yallop, B.D.;
+ Hohenkerk, C.Y.; Smith, C.A.; Kaplan, G.H.; Hughes, J.A.;
+ Seidelmann, P.K.; Astronomical Journal vol. 97, Jan. 1989,
+ p. 274-279.
+
+ 3 Seidelmann, P.K. (ed), 1992. "Explanatory Supplement to
+ the Astronomical Almanac", ISBN 0-935702-68-7.
+
+ 4 "Conversion of positions and proper motions from B1950.0 to the
+ IAU system at J2000.0", Standish, E.M. Astronomy and
+ Astrophysics, vol. 115, no. 1, Nov. 1982, p. 20-22.
+
+ P.T.Wallace Starlink 19 December 1993
+ Doug Mink Smithsonian Astrophysical Observatory 1 November 2000 */
+
+{
+ double r2000,d2000; /* J2000.0 ra,dec (radians) */
+ double r1950,d1950; /* B1950.0 ra,dec (rad) */
+
+ /* Miscellaneous */
+ double ur,ud;
+ double sr, cr, sd, cd, x, y, z, w, wd;
+ double v1[6],v2[6];
+ double xd,yd,zd;
+ double rxyz, rxysq, rxy;
+ double dra,ddec;
+ int i,j;
+ int diag = 0;
+
+ /* Constants */
+ double zero = (double) 0.0;
+ double vf = 21.095; /* Km per sec to AU per tropical century */
+ /* = 86400 * 36524.2198782 / 149597870 */
+
+ /* Convert J2000 RA and Dec from degrees to radians */
+ r2000 = degrad (*ra);
+ d2000 = degrad (*dec);
+
+ /* Convert J2000 RA and Dec proper motion from degrees/year to arcsec/tc */
+ ur = *rapm * 360000.0;
+ ud = *decpm * 360000.0;
+
+ /* Spherical to Cartesian */
+ sr = sin (r2000);
+ cr = cos (r2000);
+ sd = sin (d2000);
+ cd = cos (d2000);
+
+ x = cr * cd;
+ y = sr * cd;
+ z = sd;
+
+ v1[0] = x;
+ v1[1] = y;
+ v1[2] = z;
+
+ if (ur != zero || ud != zero) {
+ v1[3] = -(ur*y) - (cr*sd*ud);
+ v1[4] = (ur*x) - (sr*sd*ud);
+ v1[5] = (cd*ud);
+ }
+ else {
+ v1[3] = zero;
+ v1[4] = zero;
+ v1[5] = zero;
+ }
+
+ /* Convert position + velocity vector to bn system */
+ for (i = 0; i < 6; i++) {
+ w = zero;
+ for (j = 0; j < 6; j++) {
+ w = w + emi[i][j] * v1[j];
+ }
+ v2[i] = w;
+ }
+
+ /* Vector components */
+ x = v2[0];
+ y = v2[1];
+ z = v2[2];
+
+ /* Magnitude of position vector */
+ rxyz = sqrt (x*x + y*y + z*z);
+
+ /* Apply e-terms to position */
+ w = (x * a[0]) + (y * a[1]) + (z * a[2]);
+ x = x + (a[0] * rxyz) - (w * x);
+ y = y + (a[1] * rxyz) - (w * y);
+ z = z + (a[2] * rxyz) - (w * z);
+
+ /* Recompute magnitude of position vector */
+ rxyz = sqrt (x*x + y*y + z*z);
+
+ /* Apply e-terms to position and velocity */
+ x = v2[0];
+ y = v2[1];
+ z = v2[2];
+ w = (x * a[0]) + (y * a[1]) + (z * a[2]);
+ wd = (x * ad[0]) + (y * ad[1]) + (z * ad[2]);
+ x = x + (a[0] * rxyz) - (w * x);
+ y = y + (a[1] * rxyz) - (w * y);
+ z = z + (a[2] * rxyz) - (w * z);
+ xd = v2[3] + (ad[0] * rxyz) - (wd * x);
+ yd = v2[4] + (ad[1] * rxyz) - (wd * y);
+ zd = v2[5] + (ad[2] * rxyz) - (wd * z);
+
+ /* Convert to spherical */
+ rxysq = (x * x) + (y * y);
+ rxy = sqrt (rxysq);
+
+ /* Convert back to spherical coordinates */
+ if (x == zero && y == zero)
+ r1950 = zero;
+ else {
+ r1950 = atan2 (y,x);
+ if (r1950 < zero)
+ r1950 = r1950 + d2pi;
+ }
+ d1950 = atan2 (z,rxy);
+
+ if (rxy > tiny) {
+ ur = (x*yd - y*xd) / rxysq;
+ ud = (zd*rxysq - z * (x*xd + y*yd)) / ((rxysq + z*z) * rxy);
+ }
+
+ if (*parallax > tiny) {
+ *rv = ((x * xd) + (y * yd) + (z * zd)) / (*parallax * vf * rxyz);
+ *parallax = *parallax / rxyz;
+ }
+
+ /* Return results */
+ *ra = raddeg (r1950);
+ *dec = raddeg (d1950);
+ *rapm = ur / 360000.0;
+ *decpm = ud / 360000.0;
+
+ if (diag) {
+ dra = 240.0 * raddeg (r1950 - r2000);
+ ddec = 3600.0 * raddeg (d1950 - d2000);
+ fprintf(stderr,"B1950-J2000: dra= %11.5f sec ddec= %f11.5f arcsec\n",
+ dra, ddec);
+ }
+
+ return;
+}
+
+
+/* Convert B1950.0 FK4 star data to J2000.0 FK5 */
+static double em[6][6] = {
+ { 0.9999256782, /* em[0][0] */
+ -0.0111820611, /* em[0][1] */
+ -0.0048579477, /* em[0][2] */
+ 0.00000242395018, /* em[0][3] */
+ -0.00000002710663, /* em[0][4] */
+ -0.00000001177656 }, /* em[0][5] */
+
+ { 0.0111820610, /* em[1][0] */
+ 0.9999374784, /* em[1][1] */
+ -0.0000271765, /* em[1][2] */
+ 0.00000002710663, /* em[1][3] */
+ 0.00000242397878, /* em[1][4] */
+ -0.00000000006587 }, /* em[1][5] */
+
+ { 0.0048579479, /* em[2][0] */
+ -0.0000271474, /* em[2][1] */
+ 0.9999881997, /* em[2][2] */
+ 0.00000001177656, /* em[2][3] */
+ -0.00000000006582, /* em[2][4] */
+ 0.00000242410173 }, /* em[2][5] */
+
+ { -0.000551, /* em[3][0] */
+ -0.238565, /* em[3][1] */
+ 0.435739, /* em[3][2] */
+ 0.99994704, /* em[3][3] */
+ -0.01118251, /* em[3][4] */
+ -0.00485767 }, /* em[3][5] */
+
+ { 0.238514, /* em[4][0] */
+ -0.002667, /* em[4][1] */
+ -0.008541, /* em[4][2] */
+ 0.01118251, /* em[4][3] */
+ 0.99995883, /* em[4][4] */
+ -0.00002718 }, /* em[4][5] */
+
+ { -0.435623, /* em[5][0] */
+ 0.012254, /* em[5][1] */
+ 0.002117, /* em[5][2] */
+ 0.00485767, /* em[5][3] */
+ -0.00002714, /* em[5][4] */
+ 1.00000956 } /* em[5][5] */
+ };
+
+void
+fk425 (ra, dec)
+
+double *ra; /* Right ascension in degrees (B1950 in, J2000 out) */
+double *dec; /* Declination in degrees (B1950 in, J2000 out) */
+
+{
+double rapm; /* Proper motion in right ascension */
+double decpm; /* Proper motion in declination */
+ /* In: rad/trop.yr. Out: rad/jul.yr. */
+
+ rapm = (double) 0.0;
+ decpm = (double) 0.0;
+ fk425m (ra, dec, &rapm, &decpm);
+ return;
+}
+
+
+void
+fk425e (ra, dec, epoch)
+
+double *ra; /* Right ascension in degrees (B1950 in, J2000 out) */
+double *dec; /* Declination in degrees (B1950 in, J2000 out) */
+double epoch; /* Besselian epoch in years */
+{
+double rapm; /* Proper motion in right ascension */
+double decpm; /* Proper motion in declination */
+ /* In: rad/trop.yr. Out: rad/jul.yr. */
+
+ rapm = (double) 0.0;
+ decpm = (double) 0.0;
+ fk425m (ra, dec, &rapm, &decpm);
+ *ra = *ra + (rapm * (epoch - 2000.0));
+ *dec = *dec + (decpm * (epoch - 2000.0));
+ return;
+}
+
+void
+fk425m (ra, dec, rapm, decpm)
+
+double *ra, *dec; /* Right ascension and declination in degrees
+ input: B1950.0,FK4 returned: J2000.0,FK5 */
+double *rapm, *decpm; /* Proper motion in right ascension and declination
+ input: B1950.0,FK4 returned: J2000.0,FK5
+ ra/dec deg/trop.yr. ra/dec deg/jul.yr. */
+{
+ double parallax = 0.0;
+ double rv = 0.0;
+
+ fk425pv (ra, dec, rapm, decpm, &parallax, &rv);
+ return;
+}
+
+
+void
+fk425pv (ra,dec,rapm,decpm, parallax, rv)
+
+double *ra; /* Right ascension in degrees (J2000 in, B1950 out) */
+double *dec; /* Declination in degrees (J2000 in, B1950 out) */
+double *rapm; /* Proper motion in right ascension */
+double *decpm; /* Proper motion in declination
+ * In: ra/dec degrees/Julian year (not ra*cos(dec))
+ * Out: ra/dec degrees/tropical year */
+double *parallax; /* Parallax (arcsec) */
+double *rv; /* Rradial velocity (km/s, +ve = moving away) */
+
+/* This routine converts stars from the old Bessel-Newcomb FK4 system
+ to the IAU 1976 FK5 Fricke system, using Yallop's implementation
+ (see ref 2) of a matrix method due to Standish (see ref 3). The
+ numerical values of ref 2 are used canonically.
+
+ * Conversion from other than Besselian epoch 1950.0 to other than Julian
+ epoch 2000.0 will require use of the appropriate precession, proper
+ motion, and e-terms routines before and/or after fk425 is called.
+
+ * In the FK4 catalogue the proper motions of stars within 10 degrees
+ of the poles do not embody the differential e-term effect and should,
+ strictly speaking, be handled in a different manner from stars outside
+ these regions. however, given the general lack of homogeneity of the
+ star data available for routine astrometry, the difficulties of handling
+ positions that may have been determined from astrometric fields spanning
+ the polar and non-polar regions, the likelihood that the differential
+ e-terms effect was not taken into account when allowing for proper motion
+ in past astrometry, and the undesirability of a discontinuity in the
+ algorithm, the decision has been made in this routine to include the
+ effect of differential e-terms on the proper motions for all stars,
+ whether polar or not, at epoch 2000, and measuring on the sky rather
+ than in terms of dra, the errors resulting from this simplification are
+ less than 1 milliarcsecond in position and 1 milliarcsecond per century
+ in proper motion.
+
+ References:
+
+ 1 "Mean and apparent place computations in the new IAU System.
+ I. The transformation of astrometric catalog systems to the
+ equinox J2000.0." Smith, C.A.; Kaplan, G.H.; Hughes, J.A.;
+ Seidelmann, P.K.; Yallop, B.D.; Hohenkerk, C.Y.
+ Astronomical Journal vol. 97, Jan. 1989, p. 265-273.
+
+ 2 "Mean and apparent place computations in the new IAU System.
+ II. Transformation of mean star places from FK4 B1950.0 to
+ FK5 J2000.0 using matrices in 6-space." Yallop, B.D.;
+ Hohenkerk, C.Y.; Smith, C.A.; Kaplan, G.H.; Hughes, J.A.;
+ Seidelmann, P.K.; Astronomical Journal vol. 97, Jan. 1989,
+ p. 274-279.
+
+ 3 "Conversion of positions and proper motions from B1950.0 to the
+ IAU system at J2000.0", Standish, E.M. Astronomy and
+ Astrophysics, vol. 115, no. 1, Nov. 1982, p. 20-22.
+
+ P.T.Wallace Starlink 20 December 1993
+ Doug Mink Smithsonian Astrophysical Observatory 7 June 1995 */
+
+{
+ double r1950,d1950; /* B1950.0 ra,dec (rad) */
+ double r2000,d2000; /* J2000.0 ra,dec (rad) */
+
+ /* Miscellaneous */
+ double ur,ud,sr,cr,sd,cd,w,wd;
+ double x,y,z,xd,yd,zd, dra,ddec;
+ double rxyz, rxysq, rxy, rxyzsq, spxy, spxyz;
+ int i,j;
+ int diag = 0;
+
+ double r0[3],rd0[3]; /* star position and velocity vectors */
+ double v1[6],v2[6]; /* combined position and velocity vectors */
+
+ /* Constants */
+ double zero = (double) 0.0;
+ double vf = 21.095; /* Km per sec to AU per tropical century */
+ /* = 86400 * 36524.2198782 / 149597870 */
+
+ /* Convert B1950 RA and Dec from degrees to radians */
+ r1950 = degrad (*ra);
+ d1950 = degrad (*dec);
+
+ /* Convert B1950 RA and Dec proper motion from degrees/year to arcsec/tc */
+ ur = *rapm * 360000.0;
+ ud = *decpm * 360000.0;
+
+ /* Convert direction to Cartesian */
+ sr = sin (r1950);
+ cr = cos (r1950);
+ sd = sin (d1950);
+ cd = cos (d1950);
+ r0[0] = cr * cd;
+ r0[1] = sr * cd;
+ r0[2] = sd;
+
+ /* Convert motion to Cartesian */
+ w = vf * *rv * *parallax;
+ if (ur != zero || ud != zero || (*rv != zero && *parallax != zero)) {
+ rd0[0] = (-sr * cd * ur) - (cr * sd * ud) + (w * r0[0]);
+ rd0[1] = (cr * cd * ur) - (sr * sd * ud) + (w * r0[1]);
+ rd0[2] = (cd * ud) + (w * r0[2]);
+ }
+ else {
+ rd0[0] = zero;
+ rd0[1] = zero;
+ rd0[2] = zero;
+ }
+
+ /* Remove e-terms from position and express as position+velocity 6-vector */
+ w = (r0[0] * a[0]) + (r0[1] * a[1]) + (r0[2] * a[2]);
+ for (i = 0; i < 3; i++)
+ v1[i] = r0[i] - a[i] + (w * r0[i]);
+
+ /* Remove e-terms from proper motion and express as 6-vector */
+ wd = (r0[0] * ad[0]) + (r0[1] * ad[1]) + (r0[2] * ad[2]);
+ for (i = 0; i < 3; i++)
+ v1[i+3] = rd0[i] - ad[i] + (wd * r0[i]);
+
+ /* Alternately: Put proper motion in 6-vector without adding e-terms
+ for (i = 0; i < 3; i++)
+ v1[i+3] = rd0[i]; */
+
+ /* Convert position + velocity vector to FK5 system */
+ for (i = 0; i < 6; i++) {
+ w = zero;
+ for (j = 0; j < 6; j++) {
+ w += em[i][j] * v1[j];
+ }
+ v2[i] = w;
+ }
+
+ /* Vector components */
+ x = v2[0];
+ y = v2[1];
+ z = v2[2];
+ xd = v2[3];
+ yd = v2[4];
+ zd = v2[5];
+
+ /* Magnitude of position vector */
+ rxysq = x*x + y*y;
+ rxy = sqrt (rxysq);
+ rxyzsq = rxysq + z*z;
+ rxyz = sqrt (rxyzsq);
+
+ spxy = (x * xd) + (y * yd);
+ spxyz = spxy + (z * zd);
+
+ /* Convert back to spherical coordinates */
+ if (x == zero && y == zero)
+ r2000 = zero;
+ else {
+ r2000 = atan2 (y,x);
+ if (r2000 < zero)
+ r2000 = r2000 + d2pi;
+ }
+ d2000 = atan2 (z,rxy);
+
+ if (rxy > tiny) {
+ ur = ((x * yd) - (y * xd)) / rxysq;
+ ud = ((zd * rxysq) - (z * spxy)) / (rxyzsq * rxy);
+ }
+
+ if (*parallax > tiny) {
+ *rv = spxyz / (*parallax * rxyz * vf);
+ *parallax = *parallax / rxyz;
+ }
+
+ /* Return results */
+ *ra = raddeg (r2000);
+ *dec = raddeg (d2000);
+ *rapm = ur / 360000.0;
+ *decpm = ud / 360000.0;
+
+ if (diag) {
+ dra = 240.0 * raddeg (r2000 - r1950);
+ ddec = 3600.0 * raddeg (d2000 - d1950);
+ fprintf(stderr,"J2000-B1950: dra= %11.5f sec ddec= %f11.5f arcsec\n",
+ dra, ddec);
+ }
+ return;
+}
+
+int idg=0;
+
+/* l2,b2 system of galactic coordinates
+ * p = 192.25 ra of galactic north pole (mean b1950.0)
+ * q = 62.6 inclination of galactic to mean b1950.0 equator
+ * r = 33 longitude of ascending node
+ * p,q,r are degrees
+
+ * Equatorial to galactic rotation matrix
+ (The Eulerian angles are p, q, 90-r)
+ +cp.cq.sr-sp.cr +sp.cq.sr+cp.cr -sq.sr
+ -cp.cq.cr-sp.sr -sp.cq.cr+cp.sr +sq.cr
+ cp.sq +sp.sq +cq
+ */
+
+static
+double bgal[3][3] =
+ {{-0.066988739415,-0.872755765852,-0.483538914632},
+ {0.492728466075,-0.450346958020, 0.744584633283},
+ {-0.867600811151,-0.188374601723, 0.460199784784}};
+
+/*--- Transform B1950.0 FK4 equatorial coordinates to
+ * IAU 1958 galactic coordinates */
+
+void
+fk42gal (dtheta,dphi)
+
+double *dtheta; /* B1950.0 FK4 right ascension in degrees
+ Galactic longitude (l2) in degrees (returned) */
+double *dphi; /* B1950.0 FK4 declination in degrees
+ Galactic latitude (b2) in degrees (returned) */
+
+/* Input equatorial coordinates are B1950 FK4.
+ Use fk52gal() to convert from j2000.0 coordinates.
+ Reference: Blaauw et al, MNRAS,121,123 (1960) */
+{
+ double pos[3],pos1[3],r,dl,db,rl,rb,rra,rdec,dra,ddec;
+ void v2s3(),s2v3();
+ int i;
+ char *eqcoor, *eqstrn();
+
+ dra = *dtheta;
+ ddec = *dphi;
+ rra = degrad (dra);
+ rdec = degrad (ddec);
+
+ /* remove e-terms */
+ /* call jpabe (rra,rdec,-1,idg) */
+
+ /* Spherical to Cartesian */
+ r = 1.;
+ s2v3 (rra,rdec,r,pos);
+
+ /* rotate to galactic */
+ for (i = 0; i<3; i++) {
+ pos1[i] = pos[0]*bgal[i][0] + pos[1]*bgal[i][1] + pos[2]*bgal[i][2];
+ }
+
+ /* Cartesian to spherical */
+ v2s3 (pos1,&rl,&rb,&r);
+
+ dl = raddeg (rl);
+ db = raddeg (rb);
+ *dtheta = dl;
+ *dphi = db;
+
+ /* Print result if in diagnostic mode */
+ if (idg) {
+ eqcoor = eqstrn (dra,ddec);
+ fprintf (stderr,"FK42GAL: B1950 RA,Dec= %s\n",eqcoor);
+ fprintf (stderr,"FK42GAL: long = %.5f lat = %.5f\n",dl,db);
+ free (eqcoor);
+ }
+
+ return;
+}
+
+
+/*--- Transform IAU 1958 galactic coordinates to B1950.0 'FK4'
+ * equatorial coordinates */
+
+void
+gal2fk4 (dtheta,dphi)
+
+double *dtheta; /* Galactic longitude (l2) in degrees
+ B1950 FK4 RA in degrees (returned) */
+double *dphi; /* Galactic latitude (b2) in degrees
+ B1950 FK4 Dec in degrees (returned) */
+
+/* Output equatorial coordinates are B1950.0 FK4.
+ Use gal2fk5() to convert to J2000 coordinates.
+ Reference: Blaauw et al, MNRAS,121,123 (1960) */
+
+{
+ double pos[3],pos1[3],r,dl,db,rl,rb,rra,rdec,dra,ddec;
+ void v2s3(),s2v3();
+ char *eqcoor, *eqstrn();
+ int i;
+
+ /* spherical to cartesian */
+ dl = *dtheta;
+ db = *dphi;
+ rl = degrad (dl);
+ rb = degrad (db);
+ r = 1.0;
+ s2v3 (rl,rb,r,pos);
+
+ /* rotate to equatorial coordinates */
+ for (i = 0; i < 3; i++) {
+ pos1[i] = pos[0]*bgal[0][i] + pos[1]*bgal[1][i] + pos[2]*bgal[2][i];
+ }
+
+ /* cartesian to spherical */
+ v2s3 (pos1,&rra,&rdec,&r);
+
+/* introduce e-terms */
+/* jpabe (rra,rdec,-1,idg); */
+
+ dra = raddeg (rra);
+ ddec = raddeg (rdec);
+ *dtheta = dra;
+ *dphi = ddec;
+
+ /* print result if in diagnostic mode */
+ if (idg) {
+ fprintf (stderr,"GAL2FK4: long = %.5f lat = %.5f\n",dl,db);
+ eqcoor = eqstrn (dra,ddec);
+ fprintf (stderr,"GAL2FK4: B1950 RA,Dec= %s\n",eqcoor);
+ free (eqcoor);
+ }
+
+ return;
+}
+
+
+/* l2,b2 system of galactic coordinates
+ p = 192.25 ra of galactic north pole (mean b1950.0)
+ q = 62.6 inclination of galactic to mean b1950.0 equator
+ r = 33 longitude of ascending node
+ p,q,r are degrees */
+
+/* Equatorial to galactic rotation matrix
+ The eulerian angles are p, q, 90-r
+ +cp.cq.sr-sp.cr +sp.cq.sr+cp.cr -sq.sr
+ -cp.cq.cr-sp.sr -sp.cq.cr+cp.sr +sq.cr
+ +cp.sq +sp.sq +cq */
+
+static
+double jgal[3][3] =
+ {{-0.054875539726,-0.873437108010,-0.483834985808},
+ {0.494109453312,-0.444829589425, 0.746982251810},
+ {-0.867666135858,-0.198076386122, 0.455983795705}};
+
+/* Transform J2000 equatorial coordinates to IAU 1958 galactic coordinates */
+
+void
+fk52gal (dtheta,dphi)
+
+double *dtheta; /* J2000 right ascension in degrees
+ Galactic longitude (l2) in degrees (returned) */
+double *dphi; /* J2000 declination in degrees
+ Galactic latitude (b2) in degrees (returned) */
+
+/* Rotation matrices by P.T.Wallace, Starlink eqgal and galeq, March 1986 */
+
+/* Input equatorial coordinates are J2000 FK5.
+ Use gal2fk4() if converting from B1950 FK4 coordinates.
+ Reference: Blaauw et al, MNRAS,121,123 (1960) */
+{
+ double pos[3],pos1[3],r,dl,db,rl,rb,rra,rdec,dra,ddec;
+ void v2s3(),s2v3();
+ char *eqcoor, *eqstrn();
+ int i;
+
+ /* Spherical to cartesian */
+ dra = *dtheta;
+ ddec = *dphi;
+ rra = degrad (dra);
+ rdec = degrad (ddec);
+ r = 1.0;
+ (void)s2v3 (rra,rdec,r,pos);
+
+ /* Rotate to galactic */
+ for (i = 0; i < 3; i++) {
+ pos1[i] = pos[0]*jgal[i][0] + pos[1]*jgal[i][1] + pos[2]*jgal[i][2];
+ }
+
+ /* Cartesian to spherical */
+ v2s3 (pos1,&rl,&rb,&r);
+
+ dl = raddeg (rl);
+ db = raddeg (rb);
+ *dtheta = dl;
+ *dphi = db;
+
+ /* Print result if in diagnostic mode */
+ if (idg) {
+ eqcoor = eqstrn (dra,ddec);
+ fprintf (stderr,"FK52GAL: J2000 RA,Dec= %s\n",eqcoor);
+ fprintf (stderr,"FK52GAL: long = %.5f lat = %.5f\n",dl,db);
+ free (eqcoor);
+ }
+
+ return;
+}
+
+
+/*--- Transform IAU 1958 galactic coordinates to J2000 equatorial coordinates */
+
+void
+gal2fk5 (dtheta,dphi)
+
+double *dtheta; /* Galactic longitude (l2) in degrees
+ J2000.0 ra in degrees (returned) */
+double *dphi; /* Galactic latitude (b2) in degrees
+ J2000.0 dec in degrees (returned) */
+
+/* Output equatorial coordinates are J2000.
+ Use gal2fk4() to convert to B1950 coordinates.
+ Reference: Blaauw et al, MNRAS,121,123 (1960) */
+
+{
+ double pos[3],pos1[3],r,dl,db,rl,rb,rra,rdec,dra,ddec;
+ void v2s3(),s2v3();
+ int i;
+ char *eqcoor, *eqstrn();
+
+ /* Spherical to Cartesian */
+ dl = *dtheta;
+ db = *dphi;
+ rl = degrad (dl);
+ rb = degrad (db);
+ r = 1.0;
+ s2v3 (rl,rb,r,pos);
+
+ /* Rotate to equatorial coordinates */
+ for (i = 0; i < 3; i++) {
+ pos1[i] = pos[0]*jgal[0][i] + pos[1]*jgal[1][i] + pos[2]*jgal[2][i];
+ }
+
+ /* Cartesian to Spherical */
+ v2s3 (pos1,&rra,&rdec,&r);
+ dra = raddeg (rra);
+ ddec = raddeg (rdec);
+ *dtheta = dra;
+ *dphi = ddec;
+
+ /* Print result if in diagnostic mode */
+ if (idg) {
+ fprintf (stderr,"GAL2FK5: long = %.5f lat = %.5f\n",dl,db);
+ eqcoor = eqstrn (dra,ddec);
+ fprintf (stderr,"GAL2FK5: J2000 RA,Dec= %s\n",eqcoor);
+ free (eqcoor);
+ }
+
+ return;
+}
+
+
+/* Return string with right ascension in hours and declination in degrees */
+
+char *eqstrn (dra, ddec)
+
+double dra; /* Right ascension in degrees */
+double ddec; /* Declination in degrees */
+
+{
+char *eqcoor; /* ASCII character string of position (returned) */
+char decp;
+int rah,irm,decd,decm;
+double xpos,ypos,xp,yp,ras,decs;
+
+ /* Right ascension to hours, minutes, and seconds */
+ xpos = dra / 15.0;
+ rah = (int) xpos;
+ xp = (double) 60.0 * (xpos - (double) rah);
+ irm = (int) xp;
+ ras = (double) 60.0 * (xp - (double) irm);
+
+ /* Declination to degrees, minutes, seconds */
+ if (ddec < 0) {
+ ypos = -ddec;
+ decp = '-';
+ }
+ else {
+ decp = '+';
+ ypos = ddec;
+ }
+ decd = (int) ypos;
+ yp = (double) 60.0 * (ypos - (double) decd);
+ decm = (int) yp;
+ decs = (double) 60.0 * (yp - (double) decm);
+
+ eqcoor = malloc (32);
+ (void)sprintf (eqcoor,"%02d:%02d:%06.3f %c%02d:%02d:%05.2f",
+ rah,irm,ras,decp,decd,decm,decs);
+ if (eqcoor[6] == ' ')
+ eqcoor[6] = '0';
+ if (eqcoor[20] == ' ')
+ eqcoor[20] = '0';
+
+ return (eqcoor);
+}
+
+
+/* Convert geocentric equatorial rectangular coordinates to
+ right ascension and declination, and distance */
+
+
+/* These routines are based on similar ones in Pat Wallace's slalib package */
+
+/* Convert B1950 right ascension and declination to ecliptic coordinates */
+
+void
+fk42ecl (dtheta, dphi, epoch)
+
+double *dtheta; /* B1950 right ascension in degrees
+ Galactic longitude (l2) in degrees (returned) */
+double *dphi; /* B1950 declination in degrees
+ Galactic latitude (b2) in degrees (returned) */
+double epoch; /* Besselian epoch in years */
+
+{
+ void fk425e(), fk52ecl();
+
+ /* Convert from B1950 to J2000 coordinates */
+ fk425e (dtheta, dphi, epoch);
+
+ /* Convert from J2000 to ecliptic coordinates */
+ fk52ecl (dtheta, dphi, epoch);
+
+ return;
+}
+
+/* Convert J2000 right ascension and declination to ecliptic coordinates */
+
+void
+fk52ecl (dtheta, dphi, epoch)
+
+double *dtheta; /* J2000 right ascension in degrees
+ Galactic longitude (l2) in degrees (returned) */
+double *dphi; /* J2000 declination in degrees
+ Galactic latitude (b2) in degrees (returned) */
+double epoch; /* Besselian epoch in years */
+
+{
+ int i, j;
+ double t, eps0, rphi, rtheta;
+ double v1[3], v2[3], r;
+ double rmat[9], *rmati; /* Rotation matrix */
+
+ void rotmat(), v2s3(), s2v3(), fk5prec();
+
+ /* Precess coordinates from J2000 to epoch */
+ if (epoch != 2000.0)
+ fk5prec (2000.0, epoch, dtheta, dphi);
+
+ /* Convert from degrees to radians */
+ rtheta = degrad (*dtheta);
+ rphi = degrad (*dphi);
+
+ /* Convert RA,Dec to x,y,z */
+ r = 1.0;
+ s2v3 (rtheta, rphi, r, v1);
+
+ /* Interval between basic epoch J2000.0 and current epoch (JC) in centuries*/
+ t = (epoch - 2000.0) * 0.01;
+
+ /* Mean obliquity */
+ eps0 = secrad ((84381.448 + (-46.8150 + (-0.00059 + 0.001813*t) * t) * t));
+
+ /* Form the equatorial to ecliptic rotation matrix (IAU 1980 theory).
+ * References: Murray, C.A., Vectorial Astrometry, section 4.3.
+ * The matrix is in the sense v[ecl] = rmat * v[equ]; the
+ * equator, equinox and ecliptic are mean of date. */
+ rotmat (1, eps0, 0.0, 0.0, rmat);
+
+ /* Multiply position vector by equatoria to eccliptic rotation matrix */
+ rmati = rmat;
+ for (i = 0; i < 3; i++) {
+ v2[i] = 0;
+ for (j = 0; j < 3; j++)
+ v2[i] = v2[i] + (*rmati++ * v1[j]);
+ }
+
+ /* Convert x,y,z to latitude, longitude */
+ v2s3 (v2, &rtheta, &rphi, &r);
+
+ /* Convert from radians to degrees */
+ *dtheta = raddeg (rtheta);
+ *dphi = raddeg (rphi);
+}
+
+
+/* Convert ecliptic coordinates to B1950 right ascension and declination */
+
+void
+ecl2fk4 (dtheta, dphi, epoch)
+
+double *dtheta; /* Galactic longitude (l2) in degrees
+ B1950 right ascension in degrees (returned) */
+double *dphi; /* Galactic latitude (b2) in degrees
+ B1950 declination in degrees (returned) */
+double epoch; /* Besselian epoch in years */
+
+{
+ void ecl2fk5(), fk524e();
+
+ /* Convert from ecliptic to J2000 coordinates */
+ ecl2fk5 (dtheta, dphi, epoch);
+
+ /* Convert from J2000 to B1950 coordinates */
+ fk524e (dtheta, dphi, epoch);
+
+ return;
+}
+
+
+
+/* Convert ecliptic coordinates to J2000 right ascension and declination */
+
+void
+ecl2fk5 (dtheta, dphi, epoch)
+
+double *dtheta; /* Galactic longitude (l2) in degrees
+ J2000 right ascension in degrees (returned) */
+double *dphi; /* Galactic latitude (b2) in degrees
+ J2000 declination in degrees (returned) */
+double epoch; /* Besselian epoch in years */
+
+{
+ int i, j;
+ double rtheta, rphi, v1[3], v2[3];
+ double t, eps0, r;
+ double rmat[9]; /* Rotation matrix */
+ void v2s3(),s2v3(), fk5prec(), rotmat();
+
+ rtheta = degrad (*dtheta);
+ rphi = degrad (*dphi);
+
+ /* Convert RA,Dec to x,y,z */
+ r = 1.0;
+ s2v3 (rtheta, rphi, r, v1);
+
+ /* Interval between basic epoch J2000.0 and current epoch (JC) in centuries*/
+ t = (epoch - 2000.0) * 0.01;
+
+ /* Mean obliquity */
+ eps0 = secrad ((84381.448 + (-46.8150 + (-0.00059 + 0.001813*t) * t) * t));
+
+ /* Form the equatorial to ecliptic rotation matrix (IAU 1980 theory).
+ * References: Murray, C.A., Vectorial Astrometry, section 4.3.
+ * The matrix is in the sense v[ecl] = rmat * v[equ]; the
+ * equator, equinox and ecliptic are mean of date. */
+ rotmat (1, eps0, 0.0, 0.0, rmat);
+
+ /* Multiply position vector by ecliptic to equatorial rotation matrix */
+ for (i = 0; i < 3; i++) {
+ v2[i] = 0;
+ for (j = 0; j < 3; j++)
+ v2[i] = v2[i] + (rmat[3*j + i] * v1[j]);
+ }
+
+ /* Cartesian to spherical */
+ v2s3 (v2, &rtheta, &rphi, &r);
+
+ /* Convert from radians to degrees */
+ *dtheta = raddeg (rtheta);
+ *dphi = raddeg (rphi);
+
+ if (epoch != 2000.0)
+ fk5prec (epoch, 2000.0, dtheta, dphi);
+}
+
+
+/* The following routines are modified from Patrick Wallace's SLALIB */
+
+/* Precess coordinates between epochs in FK4 */
+void
+fk4prec (ep0, ep1, ra, dec)
+
+double ep0; /* Starting Besselian epoch */
+double ep1; /* Ending Besselian epoch */
+double *ra; /* RA in degrees mean equator & equinox of epoch ep0
+ mean equator & equinox of epoch ep1 (returned) */
+double *dec; /* Dec in degrees mean equator & equinox of epoch ep0
+ mean equator & equinox of epoch ep1 (returned) */
+/*
+** Precession - FK4 (Bessel-Newcomb, pre-IAU1976)
+**
+** This routine will not correctly convert between FK4 and FK5
+** For output in FK5, precess to 1950.0 and use fk425() on result.
+**
+** Based on slaPreces(), P.T.Wallace Starlink 22 December 1993
+*/
+{
+ int i, j;
+ double pm[9], *pmi, v1[3], v2[3], rra, rdec, r;
+ void v2s3(),s2v3(), mprecfk4();
+
+ rra = degrad (*ra);
+ rdec = degrad (*dec);
+ r = 1.0;
+
+ /* Generate appropriate precession matrix */
+ mprecfk4 ( ep0, ep1, pm );
+
+ /* Convert RA,Dec to x,y,z */
+ s2v3 (rra, rdec, r, v1);
+
+ /* Multiply position vector by precession matrix */
+ pmi = pm;
+ for (i = 0; i < 3; i++) {
+ v2[i] = 0;
+ for (j = 0; j < 3; j++)
+ v2[i] = v2[i] + (*pmi++ * v1[j]);
+ }
+
+ /* Back to RA,Dec */
+ v2s3 (v2, &rra, &rdec, &r);
+
+ /* Convert from radians to degrees */
+ *ra = raddeg (rra);
+ *dec = raddeg (rdec);
+}
+
+void
+fk5prec (ep0, ep1, ra, dec)
+
+double ep0; /* Starting epoch */
+double ep1; /* Ending epoch */
+double *ra; /* RA in degrees mean equator & equinox of epoch ep0
+ mean equator & equinox of epoch ep1 (returned) */
+double *dec; /* Dec in degrees mean equator & equinox of epoch ep0
+ mean equator & equinox of epoch ep1 (returned) */
+/*
+** Precession - FK5 (Fricke, post-IAU1976)
+**
+** This routine will not correctly convert between FK5 and FK4.
+** For output in FK4, precess to 2000.0 and use fk524() on result.
+**
+** Based on slaPreces(), P.T.Wallace Starlink 22 December 1993
+*/
+{
+ int i, j;
+ double pm[9], *pmi, v1[3], v2[3], rra, rdec, r;
+ void v2s3(),s2v3(), mprecfk5();
+
+ rra = degrad (*ra);
+ rdec = degrad (*dec);
+ r = 1.0;
+
+ /* Generate appropriate precession matrix */
+ mprecfk5 (ep0, ep1, pm);
+
+ /* Convert RA,Dec to x,y,z */
+ s2v3 (rra, rdec, r, v1);
+
+ /* Multiply position vector by precession matrix */
+ pmi = pm;
+ for (i = 0; i < 3; i++) {
+ v2[i] = 0;
+ for (j = 0; j < 3; j++)
+ v2[i] = v2[i] + ( v1[j] * *pmi++ );
+ }
+
+ /* Back to RA,Dec */
+ v2s3 (v2, &rra, &rdec, &r);
+
+ /* Convert from radians to degrees */
+ *ra = raddeg (rra);
+ *dec = raddeg (rdec);
+ return;
+}
+
+
+void
+mprecfk4 (bep0, bep1, rmatp)
+
+double bep0; /* Beginning Besselian epoch */
+double bep1; /* Ending Besselian epoch */
+double rmatp[9]; /* 3x3 Precession matrix (returned) */
+
+/*
+** Generate the matrix of precession between two epochs,
+** using the old, pre-IAU1976, Bessel-Newcomb model, using
+** Kinoshita's formulation (double precision)
+**
+** The matrix is in the sense v(bep1) = rmatp * v(bep0)
+**
+** Reference:
+** Kinoshita, H. (1975) 'Formulas for precession', SAO Special
+** Report No. 364, Smithsonian Institution Astrophysical
+** Observatory, Cambridge, Massachusetts.
+**
+** Based on slaPrebn() by P.T.Wallace Starlink 30 October 1993
+*/
+{
+ double bigt, t, tas2r, w, zeta, z, theta;
+ void rotmat();
+
+ /* Interval between basic epoch B1850.0 and beginning epoch in TC */
+ bigt = ( bep0 - 1850.0 ) / 100.0;
+
+ /* Interval over which precession required, in tropical centuries */
+ t = ( bep1 - bep0 ) / 100.0;
+
+ /* Euler angles */
+ tas2r = secrad (t);
+ w = 2303.5548 + ( 1.39720 + 0.000059 * bigt ) * bigt;
+ zeta = (w + ( 0.30242 - 0.000269 * bigt + 0.017996 * t ) * t ) * tas2r;
+ z = (w + ( 1.09478 + 0.000387 * bigt + 0.018324 * t ) * t ) * tas2r;
+ theta = ( 2005.1125 + ( - 0.85294 - 0.000365* bigt ) * bigt +
+ ( - 0.42647 - 0.000365 * bigt - 0.041802 * t ) * t ) * tas2r;
+
+ /* Rotation matrix */
+ rotmat (323, -zeta, theta, -z, rmatp);
+ return;
+}
+
+
+void
+mprecfk5 (ep0, ep1, rmatp)
+
+double ep0; /* Beginning epoch */
+double ep1; /* Ending epoch */
+double rmatp[9]; /* 3x3 Precession matrix (returned) */
+
+/*
+** Form the matrix of precession between two epochs (IAU 1976, FK5).
+** Notes:
+** 1) The epochs are TDB (loosely ET) Julian epochs.
+** 2) The matrix is in the sense v(ep1) = rmatp * v(ep0) .
+**
+** References:
+** Lieske,J.H., 1979. Astron. Astrophys.,73,282.
+** equations (6) & (7), p283.
+** Kaplan,G.H., 1981. USNO circular no. 163, pa2.
+**
+** Based on slaPrec(), P.T.Wallace Starlink 31 October 1993
+*/
+{
+ double t0, t, tas2r, w, zeta, z, theta;
+ void rotmat();
+
+ /* Interval between basic epoch J2000.0 and beginning epoch (JC) */
+ t0 = ( ep0 - 2000.0 ) / 100.0;
+
+ /* Interval over which precession required (JC) */
+ t = ( ep1 - ep0 ) / 100.0;
+
+ /* Euler angles */
+ tas2r = secrad (t);
+ w = 2306.2181 + ( ( 1.39656 - ( 0.000139 * t0 ) ) * t0 );
+ zeta = (w + ( ( 0.30188 - 0.000344 * t0 ) + 0.017998 * t ) * t ) * tas2r;
+ z = (w + ( ( 1.09468 + 0.000066 * t0 ) + 0.018203 * t ) * t ) * tas2r;
+ theta = ( ( 2004.3109 + ( - 0.85330 - 0.000217 * t0 ) * t0 )
+ + ( ( -0.42665 - 0.000217 * t0 ) - 0.041833 * t ) * t ) * tas2r;
+
+ /* Rotation matrix */
+ rotmat (323, -zeta, theta, -z, rmatp);
+ return;
+}
+
+
+/* Make 3-D rotation matrix from up to three rotations */
+
+void
+rotmat (axes, rot1, rot2, rot3, matrix)
+
+int axes; /* Axes about which coordinates are rotated (1=x, 2=y, 3=z) */
+double rot1; /* First rotation in degrees */
+double rot2; /* Second rotation in degrees */
+double rot3; /* Third rotation in degrees */
+double *matrix; /* 3x3 rotation matrix (returned) */
+
+{
+ int i, j, k, naxis, iaxes, iaxis;
+ double rot[3], srot, crot, *mati, w, wm[9], *wmi, matn[9];
+ int axis[3];
+
+ /* Initial final rotation matrix */
+ mati = matrix;
+ for (i = 0; i < 3; i++) {
+ for (j=0; j < 3; j++) {
+ if (i == j)
+ *mati++ = 1.0;
+ else
+ *mati++ = 0.0;
+ }
+ }
+
+ /* Separate digits of rotation axis string and count rotations */
+ naxis = 0;
+ iaxes = axes;
+ axis[0] = iaxes / 100;
+ if (axis[0] > 0) {
+ naxis++;
+ iaxes = iaxes - (100 * axis[0]);
+ }
+ axis[naxis] = iaxes / 10;
+ if (axis[naxis] > 0) {
+ iaxes = iaxes - (10 * axis[naxis]);
+ naxis++;
+ }
+ axis[naxis] = iaxes;
+ if (axis[naxis] > 0)
+ naxis++;
+
+ /* Set up rotation angles */
+ rot[0] = rot1;
+ rot[1] = rot2;
+ rot[2] = rot3;
+
+ /* For each digit of axis string, set up matrix */
+ for (iaxis = 0; iaxis < naxis; iaxis++) {
+
+ /* Initialize current rotation matrix */
+ mati = matn;
+ for (i = 0; i < 3; i++) {
+ for (j=0; j < 3; j++) {
+ if (i == j)
+ *mati++ = 1.0;
+ else
+ *mati++ = 0.0;
+ }
+ }
+
+ srot = sin (rot[iaxis]);
+ crot = cos (rot[iaxis]);
+
+ /* Matrix for rotation in X */
+ if (axis[iaxis] == 1) {
+ matn[4] = crot;
+ matn[5] = srot;
+ matn[7] = -srot;
+ matn[8] = crot;
+ }
+
+ /* Matrix for rotation in Y */
+ else if (axis[iaxis] == 2) {
+ matn[0] = crot;
+ matn[2] = -srot;
+ matn[6] = srot;
+ matn[8] = crot;
+ }
+
+ /* Matrix for rotation in Z */
+ else {
+ matn[0] = crot;
+ matn[1] = srot;
+ matn[3] = -srot;
+ matn[4] = crot;
+ }
+
+ /* Multiply existing rotation matrix by new rotation matrix */
+ for (i = 0; i < 3; i++) {
+ for (j = 0; j < 3; j++) {
+ w = 0.0;
+ for (k = 0; k < 3; k++)
+ w+= matn[3*i + k] * matrix[3*k + j];
+ wm[3*i + j] = w;
+ }
+ }
+
+ /* Update output matrix */
+ mati = matrix;
+ wmi = wm;
+ for (i = 0; i < 9; i++) {
+ *mati++ = *wmi++;
+ }
+ }
+ return;
+}
+
+
+/* The following routines are from Doug Mink's Fortran ephemeris library */
+
+/* Convert right ascensiona and declination in degrees and distance to
+ geocentric equatorial rectangular coordinates */
+
+void
+d2v3 (rra,rdec,r,pos)
+
+double rra; /* Right ascension in degrees */
+double rdec; /* Declination in degrees */
+double r; /* Distance to object in same units as pos */
+double pos[3]; /* x,y,z geocentric equatorial position of object (returned) */
+{
+ s2v3 (degrad (rra), degrad (rdec), r, pos);
+
+ return;
+}
+
+
+/* Convert right ascension, declination, and distance to
+ geocentric equatorial rectangular coordinates */
+
+void
+s2v3 (rra,rdec,r,pos)
+
+double rra; /* Right ascension in radians */
+double rdec; /* Declination in radians */
+double r; /* Distance to object in same units as pos */
+double pos[3]; /* x,y,z geocentric equatorial position of object (returned) */
+{
+ pos[0] = r * cos (rra) * cos (rdec);
+ pos[1] = r * sin (rra) * cos (rdec);
+ pos[2] = r * sin (rdec);
+
+ return;
+}
+
+
+/* Convert geocentric equatorial rectangular coordinates to
+ right ascension and declination in degrees and distance */
+
+void
+v2d3 (pos,rra,rdec,r)
+
+double pos[3]; /* x,y,z geocentric equatorial position of object */
+double *rra; /* Right ascension in degrees (returned) */
+double *rdec; /* Declination in degrees (returned) */
+double *r; /* Distance to object in same units as pos (returned) */
+{
+ v2s3 (pos, rra, rdec, r);
+ *rra = raddeg (*rra);
+ *rdec = raddeg (*rdec);
+ return;
+}
+
+/* Convert geocentric equatorial rectangular coordinates to
+ right ascension, declination, and distance */
+
+void
+v2s3 (pos,rra,rdec,r)
+
+double pos[3]; /* x,y,z geocentric equatorial position of object */
+double *rra; /* Right ascension in radians (returned) */
+double *rdec; /* Declination in radians (returned) */
+double *r; /* Distance to object in same units as pos (returned) */
+{
+ double x,y,z,rxy,rxy2,z2;
+
+ x = pos[0];
+ y = pos[1];
+ z = pos[2];
+
+ *rra = atan2 (y, x);
+
+ /* Keep RA within 0 to 2pi range */
+ if (*rra < 0.0)
+ *rra = *rra + (2.0 * PI);
+ if (*rra > 2.0 * PI)
+ *rra = *rra - (2.0 * PI);
+
+ rxy2 = x*x + y*y;
+ rxy = sqrt (rxy2);
+ *rdec = atan2 (z, rxy);
+
+ z2 = z * z;
+ *r = sqrt (rxy2 + z2);
+
+ return;
+}
+
+/*
+ * Nov 6 1995 Include stdlib.h instead of malloc.h
+ * Apr 1 1996 Add arbitrary epoch precession
+ * Apr 26 1996 Add FK4 <-> FK5 subroutines for use when epoch is known
+ * Aug 6 1996 Clean up after lint
+ * Nov 4 1996 Break SLA subroutines into separate file slasubs.c
+ * Dec 9 1996 Change arguments to degrees in FK4 and FK5 precession programs
+ * Dec 10 1996 All subroutine arguments are degrees except vector conversions
+ *
+ * Mar 20 1997 Drop unused variables after lint
+ *
+ * Apr 14 1998 Add ecliptic coordinate conversions and general conversion routines
+ * Apr 23 1998 Add LINEAR coordinate system
+ * Apr 28 1998 Change coordinate system flags to WCS_*
+ * Apr 28 1998 Return -1 from wcscsys if not a legal coordinate system
+ * May 7 1998 Keep theta within 0 to 2pi in ecl2fk5()
+ * May 13 1998 Add wcsceq()
+ * May 13 1998 Add equinox arguments to wcscon()
+ * Jun 24 1998 Set J2000 from ICRS in wcscsys()
+ * Jul 9 1998 Include stdio.h for fprintf() and sprintf() declarations
+ * Sep 17 1998 Add wcscstr() to get coordinate string
+ * Sep 21 1998 Fix bug in wcscstr() which returned B2000 instead of J2000
+ * Sep 21 1998 Add subroutine to convert proper motions, too.
+ * Oct 21 1998 In wcscstr(), drop .00 from returned string
+ * Nov 18 1998 Rename jpcop() v2s3() and jpcon() s2v3() (spherical to vector)
+ * Dec 2 1998 Add PLANET coordinate system to wcscsys() and wcscstr()
+ *
+ * Mar 10 2000 Precess coordinates correctly from other than 1950.0 and 2000.0
+ * Mar 10 2000 Set coordinate system to J2000 or B1950 if string is numeric
+ * Mar 14 2000 Clean up code in fk524m() and fk425m()
+ * May 31 2000 Add proper motion correctly if proper motion precessed
+ * Jun 26 2000 Add some support for WCS_XY image coordinates
+ * Sep 14 2000 Return -1 from wcscsys if equinox is less than 1900.0
+ * Oct 31 2000 Add proper motion after fk425 or fk524 from system epoch
+ * Oct 31 2000 Fix proper motion units in fk524p() and fk425p()
+ * Nov 6 2000 Update fk425 and fk524 algorithms to include parallax and rv
+ *
+ * Jan 11 2001 Print all messages to stderr
+ * Mar 21 2001 Move braces around bgal[] and jgal[] matrix initialization
+ *
+ * Feb 13 2002 Fix precession units problem in ecl2fk5() and fk52ecl()
+ *
+ * Apr 13 2005 Replace all sla_lib calls with local code
+ * Nov 1 2005 Add WCS_ICRS, and unprecessable system
+ *
+ * Jan 5 2006 Fix bugs in precession subroutines mprecxxx()
+ * May 3 2006 Drop declarations of unused variables suggested by Robert Lupton
+ * Oct 6 2006 If pixel coordinates, set system to WCS_XY in wcscsys()
+ * Oct 30 2006 Add LINEAR and ICRS to wcscstr() returns
+ *
+ * Aug 15 2007 Clean up code in rotmat()
+ * Nov 8 2007 In wcsconp, make it clear that proper motion is in spherical coordinates
+ *
+ * Mar 29 2010 Fix bug in computing the magnitude of the e-terms in fk524()
+ * Mar 30 2010 Drop ep1 assignment after line 178 in wcsconp()
+ */
diff --git a/funtools/wcs/wcsinit.c b/funtools/wcs/wcsinit.c
new file mode 100644
index 0000000..134c1bf
--- /dev/null
+++ b/funtools/wcs/wcsinit.c
@@ -0,0 +1,1611 @@
+/*** File libwcs/wcsinit.c
+ *** October 19, 2012
+ *** By Jessica Mink, jmink@cfa.harvard.edu
+ *** Harvard-Smithsonian Center for Astrophysics
+ *** Copyright (C) 1998-2012
+ *** Smithsonian Astrophysical Observatory, Cambridge, MA, USA
+
+ This library 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 2 of the License, or (at your option) any later version.
+
+ This library 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 this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Correspondence concerning WCSTools should be addressed as follows:
+ Internet email: jmink@cfa.harvard.edu
+ Postal address: Jessica Mink
+ Smithsonian Astrophysical Observatory
+ 60 Garden St.
+ Cambridge, MA 02138 USA
+
+ * Module: wcsinit.c (World Coordinate Systems)
+ * Purpose: Convert FITS WCS to pixels and vice versa:
+ * Subroutine: wcsinit (hstring) sets a WCS structure from an image header
+ * Subroutine: wcsninit (hstring,lh) sets a WCS structure from fixed-length header
+ * Subroutine: wcsinitn (hstring, name) sets a WCS structure for specified WCS
+ * Subroutine: wcsninitn (hstring,lh, name) sets a WCS structure for specified WCS
+ * Subroutine: wcsinitc (hstring, mchar) sets a WCS structure if multiple
+ * Subroutine: wcsninitc (hstring,lh,mchar) sets a WCS structure if multiple
+ * Subroutine: wcschar (hstring, name) returns suffix for specifed WCS
+ * Subroutine: wcseq (hstring, wcs) set radecsys and equinox from image header
+ * Subroutine: wcseqm (hstring, wcs, mchar) set radecsys and equinox if multiple
+ */
+
+#include <string.h> /* strstr, NULL */
+#include <stdio.h> /* stderr */
+#include <math.h>
+#include "wcs.h"
+#ifndef VMS
+#include <stdlib.h>
+#endif
+
+static void wcseq();
+static void wcseqm();
+static void wcsioset();
+void wcsrotset();
+char wcschar();
+
+/* set up a WCS structure from a FITS image header lhstring bytes long
+ * for a specified WCS name */
+
+struct WorldCoor *
+wcsninitn (hstring, lhstring, name)
+
+const char *hstring; /* character string containing FITS header information
+ in the format <keyword>= <value> [/ <comment>] */
+int lhstring; /* Length of FITS header in bytes */
+const char *name; /* character string with identifying name of WCS */
+{
+ hlength (hstring, lhstring);
+ return (wcsinitn (hstring, name));
+}
+
+
+/* set up a WCS structure from a FITS image header for specified WCSNAME */
+
+struct WorldCoor *
+wcsinitn (hstring, name)
+
+const char *hstring; /* character string containing FITS header information
+ in the format <keyword>= <value> [/ <comment>] */
+const char *name; /* character string with identifying name of WCS */
+{
+ char mchar; /* Suffix character for one of multiple WCS */
+
+ mchar = wcschar (hstring, name);
+ if (mchar == '_') {
+ fprintf (stderr, "WCSINITN: WCS name %s not matched in FITS header\n",
+ name);
+ return (NULL);
+ }
+ return (wcsinitc (hstring, &mchar));
+}
+
+
+/* WCSCHAR -- Find the letter for a specific WCS conversion */
+
+char
+wcschar (hstring, name)
+
+const char *hstring; /* character string containing FITS header information
+ in the format <keyword>= <value> [/ <comment>] */
+const char *name; /* Name of WCS conversion to be matched
+ (case-independent) */
+{
+ char *upname, *uppercase();
+ char cwcs, charwcs;
+ int iwcs;
+ char keyword[12];
+ char *upval, value[72];
+
+ /* If no WCS character, return 0 */
+ if (name == NULL)
+ return ((char) 0);
+
+ /* Convert input name to upper case */
+ upname = uppercase (name);
+
+ /* If single character name, return that character */
+ if (strlen (upname) == 1)
+ return (upname[0]);
+
+ /* Try to match input name to available WCSNAME names in header */
+ strcpy (keyword, "WCSNAME");
+ keyword[8] = (char) 0;
+ charwcs = '_';
+ for (iwcs = 0; iwcs < 27; iwcs++) {
+ if (iwcs > 0)
+ cwcs = (char) (64 + iwcs);
+ else
+ cwcs = (char) 0;
+ keyword[7] = cwcs;
+ if (hgets (hstring, keyword, 72, value)) {
+ upval = uppercase (value);
+ if (!strcmp (upval, upname))
+ charwcs = cwcs;
+ free (upval);
+ }
+ }
+ free (upname);
+ return (charwcs);
+}
+
+
+/* Make string of arbitrary case all uppercase */
+
+char *
+uppercase (string)
+char *string;
+{
+ int lstring, i;
+ char *upstring;
+
+ lstring = strlen (string);
+ upstring = (char *) calloc (1,lstring+1);
+ for (i = 0; i < lstring; i++) {
+ if (string[i] > 96 && string[i] < 123)
+ upstring[i] = string[i] - 32;
+ else
+ upstring[i] = string[i];
+ }
+ upstring[lstring] = (char) 0;
+ return (upstring);
+}
+
+
+/* set up a WCS structure from a FITS image header lhstring bytes long */
+
+struct WorldCoor *
+wcsninit (hstring, lhstring)
+
+const char *hstring; /* character string containing FITS header information
+ in the format <keyword>= <value> [/ <comment>] */
+int lhstring; /* Length of FITS header in bytes */
+{
+ char mchar; /* Suffix character for one of multiple WCS */
+ mchar = (char) 0;
+ hlength (hstring, lhstring);
+ return (wcsinitc (hstring, &mchar));
+}
+
+
+/* set up a WCS structure from a FITS image header lhstring bytes long */
+
+struct WorldCoor *
+wcsninitc (hstring, lhstring, mchar)
+
+const char *hstring; /* character string containing FITS header information
+ in the format <keyword>= <value> [/ <comment>] */
+int lhstring; /* Length of FITS header in bytes */
+char *mchar; /* Suffix character for one of multiple WCS */
+{
+ hlength (hstring, lhstring);
+ if (mchar[0] == ' ')
+ mchar[0] = (char) 0;
+ return (wcsinitc (hstring, mchar));
+}
+
+
+/* set up a WCS structure from a FITS image header */
+
+struct WorldCoor *
+wcsinit (hstring)
+
+const char *hstring; /* character string containing FITS header information
+ in the format <keyword>= <value> [/ <comment>] */
+{
+ char mchar; /* Suffix character for one of multiple WCS */
+ mchar = (char) 0;
+ return (wcsinitc (hstring, &mchar));
+}
+
+
+/* set up a WCS structure from a FITS image header for specified suffix */
+
+struct WorldCoor *
+wcsinitc (hstring, wchar)
+
+const char *hstring; /* character string containing FITS header information
+ in the format <keyword>= <value> [/ <comment>] */
+char *wchar; /* Suffix character for one of multiple WCS */
+{
+ struct WorldCoor *wcs, *depwcs;
+ char ctype1[32], ctype2[32], tstring[32];
+ char pvkey1[8],pvkey2[8],pvkey3[8];
+ char *hcoeff; /* pointer to first coeff's in header */
+ char decsign;
+ double rah,ram,ras, dsign,decd,decm,decs;
+ double dec_deg,ra_hours, secpix, ra0, ra1, dec0, dec1, cvel;
+ double cdelt1, cdelt2, cd[4], pc[81];
+ char keyword[16];
+ int ieq, i, j, k, naxes, cd11p, cd12p, cd21p, cd22p;
+ int ilat; /* coordinate for latitude or declination */
+ /*
+ int ix1, ix2, iy1, iy2, idx1, idx2, idy1, idy2;
+ double dxrefpix, dyrefpix;
+ */
+ char temp[80];
+ char wcsname[64]; /* Name of WCS depended on by current WCS */
+ char mchar;
+ char cspace = (char) ' ';
+ char cnull = (char) 0;
+ double mjd;
+ double rot;
+ double ut;
+ int nax;
+ int twod;
+ extern int tnxinit();
+ extern int zpxinit();
+ extern int platepos();
+ extern int dsspos();
+ void invert_wcs();
+
+ wcs = (struct WorldCoor *) calloc (1, sizeof(struct WorldCoor));
+
+ /* Set WCS character and name in structure */
+ mchar = wchar[0];
+ if (mchar == ' ')
+ mchar = cnull;
+ wcs->wcschar = mchar;
+ if (hgetsc (hstring, "WCSNAME", &mchar, 63, wcsname)) {
+ wcs->wcsname = (char *) calloc (strlen (wcsname)+2, 1);
+ strcpy (wcs->wcsname, wcsname);
+ }
+
+
+ /* Set WCSLIB flags so that structures will be reinitialized */
+ wcs->cel.flag = 0;
+ wcs->lin.flag = 0;
+ wcs->wcsl.flag = 0;
+ wcs->wcsl.cubeface = -1;
+
+ /* Initialize to no plate fit */
+ wcs->ncoeff1 = 0;
+ wcs->ncoeff2 = 0;
+
+ /* Initialize to no CD matrix */
+ cdelt1 = 0.0;
+ cdelt2 = 0.0;
+ cd[0] = 0.0;
+ cd[1] = 0.0;
+ cd[2] = 0.0;
+ cd[3] = 0.0;
+ pc[0] = 0.0;
+ wcs->rotmat = 0;
+ wcs->rot = 0.0;
+
+ /* Header parameters independent of projection */
+ naxes = 0;
+ hgeti4c (hstring, "WCSAXES", &mchar, &naxes);
+ if (naxes == 0)
+ hgeti4 (hstring, "WCSAXES", &naxes);
+ if (naxes == 0)
+ hgeti4 (hstring, "NAXIS", &naxes);
+ if (naxes == 0)
+ hgeti4 (hstring, "WCSDIM", &naxes);
+ if (naxes < 1) {
+ setwcserr ("WCSINIT: No WCSAXES, NAXIS, or WCSDIM keyword");
+ wcsfree (wcs);
+ return (NULL);
+ }
+ if (naxes > 2)
+ naxes = 2;
+ wcs->naxis = naxes;
+ wcs->naxes = naxes;
+ wcs->lin.naxis = naxes;
+ wcs->nxpix = 0;
+ hgetr8 (hstring, "NAXIS1", &wcs->nxpix);
+ if (wcs->nxpix < 1)
+ hgetr8 (hstring, "IMAGEW", &wcs->nxpix);
+ if (wcs->nxpix < 1) {
+ setwcserr ("WCSINIT: No NAXIS1 or IMAGEW keyword");
+ wcsfree (wcs);
+ return (NULL);
+ }
+ wcs->nypix = 0;
+ hgetr8 (hstring, "NAXIS2", &wcs->nypix);
+ if (wcs->nypix < 1)
+ hgetr8 (hstring, "IMAGEH", &wcs->nypix);
+ if (naxes > 1 && wcs->nypix < 1) {
+ setwcserr ("WCSINIT: No NAXIS2 or IMAGEH keyword");
+ wcsfree (wcs);
+ return (NULL);
+ }
+
+ /* Reset number of axes to only those with dimension greater than one */
+ nax = 0;
+ for (i = 0; i < naxes; i++) {
+
+ /* Check for number of pixels in axis more than one */
+ strcpy (keyword, "NAXIS");
+ sprintf (temp, "%d", i+1);
+ strcat (keyword, temp);
+ if (!hgeti4 (hstring, keyword, &j)) {
+ if (i == 0 && wcs->nxpix > 1) {
+ /* fprintf (stderr,"WCSINIT: Missing keyword %s set to %.0f from IMAGEW\n",
+ keyword, wcs->nxpix); */
+ j = wcs->nxpix;
+ }
+ else if (i == 1 && wcs->nypix > 1) {
+ /* fprintf (stderr,"WCSINIT: Missing keyword %s set to %.0f from IMAGEH\n",
+ keyword, wcs->nypix); */
+ j = wcs->nypix;
+ }
+ else
+ fprintf (stderr,"WCSINIT: Missing keyword %s assumed 1\n",keyword);
+ }
+
+ /* Check for TAB WCS in axis */
+ strcpy (keyword, "CTYPE");
+ strcat (keyword, temp);
+ if (hgets (hstring, keyword, 16, temp)) {
+ if (strsrch (temp, "-TAB"))
+ j = 0;
+ }
+ if (j > 1) nax = nax + 1;
+ }
+ naxes = nax;
+ wcs->naxes = nax;
+ wcs->naxis = nax;
+
+ hgets (hstring, "INSTRUME", 16, wcs->instrument);
+ hgeti4 (hstring, "DETECTOR", &wcs->detector);
+ wcs->wcsproj = getdefwcs();
+ wcs->logwcs = 0;
+ hgeti4 (hstring, "DC-FLAG", &wcs->logwcs);
+
+ /* Initialize rotation matrices */
+ for (i = 0; i < 81; i++) wcs->pc[i] = 0.0;
+ for (i = 0; i < 81; i++) pc[i] = 0.0;
+ for (i = 0; i < naxes; i++) wcs->pc[(i*naxes)+i] = 1.0;
+ for (i = 0; i < naxes; i++) pc[(i*naxes)+i] = 1.0;
+ for (i = 0; i < 9; i++) wcs->cdelt[i] = 0.0;
+ for (i = 0; i < naxes; i++) wcs->cdelt[i] = 1.0;
+
+ /* If the current world coordinate system depends on another, set it now */
+ if (hgetsc (hstring, "WCSDEP",&mchar, 63, wcsname)) {
+ if ((wcs->wcs = wcsinitn (hstring, wcsname)) == NULL) {
+ setwcserr ("WCSINIT: depended on WCS could not be set");
+ wcsfree (wcs);
+ return (NULL);
+ }
+ depwcs = wcs->wcs;
+ depwcs->wcsdep = wcs;
+ }
+ else
+ wcs->wcs = NULL;
+
+ /* Read radial velocity from image header */
+ wcs->radvel = 0.0;
+ wcs->zvel = 0.0;
+ cvel = 299792.5;
+ if (hgetr8c (hstring, "VSOURCE", &mchar, &wcs->radvel))
+ wcs->zvel = wcs->radvel / cvel;
+ else if (hgetr8c (hstring, "ZSOURCE", &mchar, &wcs->zvel))
+ wcs->radvel = wcs->zvel * cvel;
+ else if (hgetr8 (hstring, "VELOCITY", &wcs->radvel))
+ wcs->zvel = wcs->radvel / cvel;
+
+ for (i = 0; i < 10; i++) {
+ wcs->prj.p[i] = 0.0;
+ }
+
+ /* World coordinate system reference coordinate information */
+ if (hgetsc (hstring, "CTYPE1", &mchar, 16, ctype1)) {
+
+ /* Read second coordinate type */
+ strcpy (ctype2, ctype1);
+ if (!hgetsc (hstring, "CTYPE2", &mchar, 16, ctype2))
+ twod = 0;
+ else
+ twod = 1;
+ strcpy (wcs->ctype[0], ctype1);
+ strcpy (wcs->ctype[1], ctype2);
+ if (strsrch (ctype2, "LAT") || strsrch (ctype2, "DEC"))
+ ilat = 2;
+ else
+ ilat = 1;
+
+ /* Read third and fourth coordinate types, if present */
+ strcpy (wcs->ctype[2], "");
+ hgetsc (hstring, "CTYPE3", &mchar, 9, wcs->ctype[2]);
+ strcpy (wcs->ctype[3], "");
+ hgetsc (hstring, "CTYPE4", &mchar, 9, wcs->ctype[3]);
+
+ /* Set projection type in WCS data structure */
+ if (wcstype (wcs, ctype1, ctype2)) {
+ wcsfree (wcs);
+ return (NULL);
+ }
+
+ /* Get units, if present, for linear coordinates */
+ if (wcs->prjcode == WCS_LIN) {
+ if (!hgetsc (hstring, "CUNIT1", &mchar, 16, wcs->units[0])) {
+ if (!mgetstr (hstring, "WAT1", "units", 16, wcs->units[0])) {
+ wcs->units[0][0] = 0;
+ }
+ }
+ if (!strcmp (wcs->units[0], "pixel"))
+ wcs->prjcode = WCS_PIX;
+ if (twod) {
+ if (!hgetsc (hstring, "CUNIT2", &mchar, 16, wcs->units[1])) {
+ if (!mgetstr (hstring, "WAT2", "units", 16, wcs->units[1])) {
+ wcs->units[1][0] = 0;
+ }
+ }
+ if (!strcmp (wcs->units[0], "pixel"))
+ wcs->prjcode = WCS_PIX;
+ }
+ }
+
+ /* Reference pixel coordinates and WCS value */
+ wcs->crpix[0] = 1.0;
+ hgetr8c (hstring, "CRPIX1", &mchar, &wcs->crpix[0]);
+ wcs->crpix[1] = 1.0;
+ hgetr8c (hstring, "CRPIX2", &mchar, &wcs->crpix[1]);
+ wcs->xrefpix = wcs->crpix[0];
+ wcs->yrefpix = wcs->crpix[1];
+ wcs->crval[0] = 0.0;
+ hgetr8c (hstring, "CRVAL1", &mchar, &wcs->crval[0]);
+ wcs->crval[1] = 0.0;
+ hgetr8c (hstring, "CRVAL2", &mchar, &wcs->crval[1]);
+ if (wcs->syswcs == WCS_NPOLE)
+ wcs->crval[1] = 90.0 - wcs->crval[1];
+ if (wcs->syswcs == WCS_SPA)
+ wcs->crval[1] = wcs->crval[1] - 90.0;
+ wcs->xref = wcs->crval[0];
+ wcs->yref = wcs->crval[1];
+ if (wcs->coorflip) {
+ wcs->cel.ref[0] = wcs->crval[1];
+ wcs->cel.ref[1] = wcs->crval[0];
+ }
+ else {
+ wcs->cel.ref[0] = wcs->crval[0];
+ wcs->cel.ref[1] = wcs->crval[1];
+ }
+ wcs->longpole = 999.0;
+ hgetr8c (hstring, "LONPOLE", &mchar, &wcs->longpole);
+ wcs->cel.ref[2] = wcs->longpole;
+ wcs->latpole = 999.0;
+ hgetr8c (hstring, "LATPOLE", &mchar, &wcs->latpole);
+ wcs->cel.ref[3] = wcs->latpole;
+ wcs->lin.crpix = wcs->crpix;
+ wcs->lin.cdelt = wcs->cdelt;
+ wcs->lin.pc = wcs->pc;
+
+ /* Projection constants (this should be projection-dependent */
+ wcs->prj.r0 = 0.0;
+ hgetr8c (hstring, "PROJR0", &mchar, &wcs->prj.r0);
+
+ /* FITS WCS interim proposal projection constants */
+ for (i = 0; i < 10; i++) {
+ sprintf (keyword,"PROJP%d",i);
+ hgetr8c (hstring, keyword, &mchar, &wcs->prj.p[i]);
+ }
+
+ sprintf (pvkey1, "PV%d_1", ilat);
+ sprintf (pvkey2, "PV%d_2", ilat);
+ sprintf (pvkey3, "PV%d_3", ilat);
+
+ /* FITS WCS standard projection constants (projection-dependent) */
+ if (wcs->prjcode == WCS_AZP || wcs->prjcode == WCS_SIN ||
+ wcs->prjcode == WCS_COP || wcs->prjcode == WCS_COE ||
+ wcs->prjcode == WCS_COD || wcs->prjcode == WCS_COO) {
+ hgetr8c (hstring, pvkey1, &mchar, &wcs->prj.p[1]);
+ hgetr8c (hstring, pvkey2, &mchar, &wcs->prj.p[2]);
+ }
+ else if (wcs->prjcode == WCS_SZP) {
+ hgetr8c (hstring, pvkey1, &mchar, &wcs->prj.p[1]);
+ hgetr8c (hstring, pvkey2, &mchar, &wcs->prj.p[2]);
+ if (wcs->prj.p[3] == 0.0)
+ wcs->prj.p[3] = 90.0;
+ hgetr8c (hstring, pvkey3, &mchar, &wcs->prj.p[3]);
+ }
+ else if (wcs->prjcode == WCS_CEA) {
+ if (wcs->prj.p[1] == 0.0)
+ wcs->prj.p[1] = 1.0;
+ hgetr8c (hstring, pvkey1, &mchar, &wcs->prj.p[1]);
+ }
+ else if (wcs->prjcode == WCS_CYP) {
+ if (wcs->prj.p[1] == 0.0)
+ wcs->prj.p[1] = 1.0;
+ hgetr8c (hstring, pvkey1, &mchar, &wcs->prj.p[1]);
+ if (wcs->prj.p[2] == 0.0)
+ wcs->prj.p[2] = 1.0;
+ hgetr8c (hstring, pvkey2, &mchar, &wcs->prj.p[2]);
+ }
+ else if (wcs->prjcode == WCS_AIR) {
+ if (wcs->prj.p[1] == 0.0)
+ wcs->prj.p[1] = 90.0;
+ hgetr8c (hstring, pvkey1, &mchar, &wcs->prj.p[1]);
+ }
+ else if (wcs->prjcode == WCS_BON) {
+ hgetr8c (hstring, pvkey1, &mchar, &wcs->prj.p[1]);
+ }
+ else if (wcs->prjcode == WCS_ZPN) {
+ for (i = 0; i < 10; i++) {
+ sprintf (keyword,"PV%d_%d", ilat, i);
+ hgetr8c (hstring, keyword, &mchar, &wcs->prj.p[i]);
+ }
+ }
+
+ /* Initialize TNX, defaulting to TAN if there is a problem */
+ if (wcs->prjcode == WCS_TNX) {
+ if (tnxinit (hstring, wcs)) {
+ wcs->ctype[0][6] = 'A';
+ wcs->ctype[0][7] = 'N';
+ wcs->ctype[1][6] = 'A';
+ wcs->ctype[1][7] = 'N';
+ wcs->prjcode = WCS_TAN;
+ }
+ }
+
+ /* Initialize ZPX, defaulting to ZPN if there is a problem */
+ if (wcs->prjcode == WCS_ZPX) {
+ if (zpxinit (hstring, wcs)) {
+ wcs->ctype[0][7] = 'N';
+ wcs->ctype[1][7] = 'N';
+ wcs->prjcode = WCS_ZPN;
+ }
+ }
+
+ /* Set TPV to TAN as SCAMP coefficients will be added below */
+ if (wcs->prjcode == WCS_TPV) {
+ wcs->ctype[0][6] = 'A';
+ wcs->ctype[0][7] = 'N';
+ wcs->ctype[1][6] = 'A';
+ wcs->ctype[1][7] = 'N';
+ wcs->prjcode = WCS_TAN;
+ }
+
+ /* Coordinate reference frame, equinox, and epoch */
+ if (wcs->wcsproj > 0)
+ wcseqm (hstring, wcs, &mchar);
+ wcsioset (wcs);
+
+ /* Read distortion coefficients, if present */
+ distortinit (wcs, hstring);
+
+ /* Use polynomial fit instead of projection, if present */
+ wcs->ncoeff1 = 0;
+ wcs->ncoeff2 = 0;
+ cd11p = hgetr8c (hstring, "CD1_1", &mchar, &cd[0]);
+ cd12p = hgetr8c (hstring, "CD1_2", &mchar, &cd[1]);
+ cd21p = hgetr8c (hstring, "CD2_1", &mchar, &cd[2]);
+ cd22p = hgetr8c (hstring, "CD2_2", &mchar, &cd[3]);
+ if (wcs->wcsproj != WCS_OLD &&
+ (hcoeff = ksearch (hstring,"CO1_1")) != NULL) {
+ wcs->prjcode = WCS_PLT;
+ (void)strcpy (wcs->ptype, "PLATE");
+ for (i = 0; i < 20; i++) {
+ sprintf (keyword,"CO1_%d", i+1);
+ wcs->x_coeff[i] = 0.0;
+ if (hgetr8 (hcoeff, keyword, &wcs->x_coeff[i]))
+ wcs->ncoeff1 = i + 1;
+ }
+ hcoeff = ksearch (hstring,"CO2_1");
+ for (i = 0; i < 20; i++) {
+ sprintf (keyword,"CO2_%d",i+1);
+ wcs->y_coeff[i] = 0.0;
+ if (hgetr8 (hcoeff, keyword, &wcs->y_coeff[i]))
+ wcs->ncoeff2 = i + 1;
+ }
+
+ /* Compute a nominal scale factor */
+ platepos (wcs->crpix[0], wcs->crpix[1], wcs, &ra0, &dec0);
+ platepos (wcs->crpix[0], wcs->crpix[1]+1.0, wcs, &ra1, &dec1);
+ wcs->yinc = dec1 - dec0;
+ wcs->xinc = -wcs->yinc;
+
+ /* Compute image rotation angle */
+ wcs->wcson = 1;
+ wcsrotset (wcs);
+ rot = degrad (wcs->rot);
+
+ /* Compute scale at reference pixel */
+ platepos (wcs->crpix[0], wcs->crpix[1], wcs, &ra0, &dec0);
+ platepos (wcs->crpix[0]+cos(rot),
+ wcs->crpix[1]+sin(rot), wcs, &ra1, &dec1);
+ wcs->cdelt[0] = -wcsdist (ra0, dec0, ra1, dec1);
+ wcs->xinc = wcs->cdelt[0];
+ platepos (wcs->crpix[0]+sin(rot),
+ wcs->crpix[1]+cos(rot), wcs, &ra1, &dec1);
+ wcs->cdelt[1] = wcsdist (ra0, dec0, ra1, dec1);
+ wcs->yinc = wcs->cdelt[1];
+
+ /* Set CD matrix from header */
+ wcs->cd[0] = cd[0];
+ wcs->cd[1] = cd[1];
+ wcs->cd[2] = cd[2];
+ wcs->cd[3] = cd[3];
+ (void) matinv (2, wcs->cd, wcs->dc);
+ }
+
+ /* Else use CD matrix, if present */
+ else if (cd11p || cd12p || cd21p || cd22p) {
+ wcs->rotmat = 1;
+ wcscdset (wcs, cd);
+ }
+
+ /* Else get scaling from CDELT1 and CDELT2 */
+ else if (hgetr8c (hstring, "CDELT1", &mchar, &cdelt1) != 0) {
+ hgetr8c (hstring, "CDELT2", &mchar, &cdelt2);
+
+ /* If CDELT1 or CDELT2 is 0 or missing */
+ if (cdelt1 == 0.0 || (wcs->nypix > 1 && cdelt2 == 0.0)) {
+ if (ksearch (hstring,"SECPIX") != NULL ||
+ ksearch (hstring,"PIXSCALE") != NULL ||
+ ksearch (hstring,"PIXSCAL1") != NULL ||
+ ksearch (hstring,"XPIXSIZE") != NULL ||
+ ksearch (hstring,"SECPIX1") != NULL) {
+ secpix = 0.0;
+ hgetr8 (hstring,"SECPIX",&secpix);
+ if (secpix == 0.0)
+ hgetr8 (hstring,"PIXSCALE",&secpix);
+ if (secpix == 0.0) {
+ hgetr8 (hstring,"SECPIX1",&secpix);
+ if (secpix != 0.0) {
+ if (cdelt1 == 0.0)
+ cdelt1 = -secpix / 3600.0;
+ if (cdelt2 == 0.0) {
+ hgetr8 (hstring,"SECPIX2",&secpix);
+ cdelt2 = secpix / 3600.0;
+ }
+ }
+ else {
+ hgetr8 (hstring,"XPIXSIZE",&secpix);
+ if (secpix != 0.0) {
+ if (cdelt1 == 0.0)
+ cdelt1 = -secpix / 3600.0;
+ if (cdelt2 == 0.0) {
+ hgetr8 (hstring,"YPIXSIZE",&secpix);
+ cdelt2 = secpix / 3600.0;
+ }
+ }
+ else {
+ hgetr8 (hstring,"PIXSCAL1",&secpix);
+ if (secpix != 0.0 && cdelt1 == 0.0)
+ cdelt1 = -secpix / 3600.0;
+ if (cdelt2 == 0.0) {
+ hgetr8 (hstring,"PIXSCAL2",&secpix);
+ cdelt2 = secpix / 3600.0;
+ }
+ }
+ }
+ }
+ else {
+ if (cdelt1 == 0.0)
+ cdelt1 = -secpix / 3600.0;
+ if (cdelt2 == 0.0)
+ cdelt2 = secpix / 3600.0;
+ }
+ }
+ }
+ if (cdelt2 == 0.0 && wcs->nypix > 1)
+ cdelt2 = -cdelt1;
+ wcs->cdelt[2] = 1.0;
+ wcs->cdelt[3] = 1.0;
+
+ /* Initialize rotation matrix */
+ for (i = 0; i < 81; i++) {
+ pc[i] = 0.0;
+ wcs->pc[i] = 0.0;
+ }
+ for (i = 0; i < naxes; i++)
+ pc[(i*naxes)+i] = 1.0;
+
+ /* Read FITS WCS interim rotation matrix */
+ if (!mchar && hgetr8 (hstring,"PC001001",&pc[0]) != 0) {
+ k = 0;
+ for (i = 0; i < naxes; i++) {
+ for (j = 0; j < naxes; j++) {
+ if (i == j)
+ pc[k] = 1.0;
+ else
+ pc[k] = 0.0;
+ sprintf (keyword, "PC00%1d00%1d", i+1, j+1);
+ hgetr8 (hstring, keyword, &pc[k++]);
+ }
+ }
+ wcspcset (wcs, cdelt1, cdelt2, pc);
+ }
+
+ /* Read FITS WCS standard rotation matrix */
+ else if (hgetr8c (hstring, "PC1_1", &mchar, &pc[0]) != 0) {
+ k = 0;
+ for (i = 0; i < naxes; i++) {
+ for (j = 0; j < naxes; j++) {
+ if (i == j)
+ pc[k] = 1.0;
+ else
+ pc[k] = 0.0;
+ sprintf (keyword, "PC%1d_%1d", i+1, j+1);
+ hgetr8c (hstring, keyword, &mchar, &pc[k++]);
+ }
+ }
+ wcspcset (wcs, cdelt1, cdelt2, pc);
+ }
+
+ /* Otherwise, use CROTAn */
+ else {
+ rot = 0.0;
+ if (ilat == 2)
+ hgetr8c (hstring, "CROTA2", &mchar, &rot);
+ else
+ hgetr8c (hstring,"CROTA1", &mchar, &rot);
+ wcsdeltset (wcs, cdelt1, cdelt2, rot);
+ }
+ }
+
+ /* If no scaling is present, set to 1 per pixel, no rotation */
+ else {
+ wcs->xinc = 1.0;
+ wcs->yinc = 1.0;
+ wcs->cdelt[0] = 1.0;
+ wcs->cdelt[1] = 1.0;
+ wcs->rot = 0.0;
+ wcs->rotmat = 0;
+ setwcserr ("WCSINIT: setting CDELT to 1");
+ }
+
+ /* SCAMP convention */
+ if (wcs->prjcode == WCS_TAN && wcs->naxis == 2) {
+ int n = 0;
+ if (wcs->inv_x) {
+ poly_end(wcs->inv_x);
+ wcs->inv_x = NULL;
+ }
+ if (wcs->inv_y) {
+ poly_end(wcs->inv_y);
+ wcs->inv_y = NULL;
+ }
+ wcs->pvfail = 0;
+ for (i = 0; i < (2*MAXPV); i++) {
+ wcs->projppv[i] = 0.0;
+ wcs->prj.ppv[i] = 0.0;
+ }
+ for (k = 0; k < 2; k++) {
+ for (j = 0; j < MAXPV; j++) {
+ sprintf(keyword, "PV%d_%d", k+1, j);
+ if (hgetr8c(hstring, keyword,&mchar, &wcs->projppv[j+k*MAXPV]) == 0) {
+ wcs->projppv[j+k*MAXPV] = 0.0;
+ }
+ else
+ n++;
+ }
+ }
+
+ /* If any PVi_j are set, add them to the structure */
+ if (n > 0) {
+ n = 0;
+
+ for (k = MAXPV; k >= 0; k--) {
+ /* lat comes first for compatibility reasons */
+ wcs->prj.ppv[k] = wcs->projppv[k+wcs->wcsl.lat*MAXPV];
+ wcs->prj.ppv[k+MAXPV] = wcs->projppv[k+wcs->wcsl.lng*MAXPV];
+ if (!n && (wcs->prj.ppv[k] || wcs->prj.ppv[k+MAXPV])) {
+ n = k+1;
+ }
+ }
+ invert_wcs(wcs);
+
+ /* Need to call tanset again */
+ wcs->cel.flag = 0;
+ }
+ }
+
+ /* If linear or pixel WCS, print "degrees" */
+ if (!strncmp (wcs->ptype,"LINEAR",6) ||
+ !strncmp (wcs->ptype,"PIXEL",5)) {
+ wcs->degout = -1;
+ wcs->ndec = 5;
+ }
+
+ /* Epoch of image (from observation date, if possible) */
+ if (hgetr8 (hstring, "MJD-OBS", &mjd))
+ wcs->epoch = 1900.0 + (mjd - 15019.81352) / 365.242198781;
+ else if (!hgetdate (hstring,"DATE-OBS",&wcs->epoch)) {
+ if (!hgetdate (hstring,"DATE",&wcs->epoch)) {
+ if (!hgetr8 (hstring,"EPOCH",&wcs->epoch))
+ wcs->epoch = wcs->equinox;
+ }
+ }
+
+ /* Add time of day if not part of DATE-OBS string */
+ else {
+ hgets (hstring,"DATE-OBS",32,tstring);
+ if (!strchr (tstring,'T')) {
+ if (hgetr8 (hstring, "UT",&ut))
+ wcs->epoch = wcs->epoch + (ut / (24.0 * 365.242198781));
+ else if (hgetr8 (hstring, "UTMID",&ut))
+ wcs->epoch = wcs->epoch + (ut / (24.0 * 365.242198781));
+ }
+ }
+
+ wcs->wcson = 1;
+ }
+
+ else if (mchar != cnull && mchar != cspace) {
+ (void) sprintf (temp, "WCSINITC: No image scale for WCS %c", mchar);
+ setwcserr (temp);
+ wcsfree (wcs);
+ return (NULL);
+ }
+
+ /* Plate solution coefficients */
+ else if (ksearch (hstring,"PLTRAH") != NULL) {
+ wcs->prjcode = WCS_DSS;
+ hcoeff = ksearch (hstring,"PLTRAH");
+ hgetr8 (hcoeff,"PLTRAH",&rah);
+ hgetr8 (hcoeff,"PLTRAM",&ram);
+ hgetr8 (hcoeff,"PLTRAS",&ras);
+ ra_hours = rah + (ram / (double)60.0) + (ras / (double)3600.0);
+ wcs->plate_ra = hrrad (ra_hours);
+ decsign = '+';
+ hgets (hcoeff,"PLTDECSN", 1, &decsign);
+ if (decsign == '-')
+ dsign = -1.;
+ else
+ dsign = 1.;
+ hgetr8 (hcoeff,"PLTDECD",&decd);
+ hgetr8 (hcoeff,"PLTDECM",&decm);
+ hgetr8 (hcoeff,"PLTDECS",&decs);
+ dec_deg = dsign * (decd+(decm/(double)60.0)+(decs/(double)3600.0));
+ wcs->plate_dec = degrad (dec_deg);
+ hgetr8 (hstring,"EQUINOX",&wcs->equinox);
+ hgeti4 (hstring,"EQUINOX",&ieq);
+ if (ieq == 1950)
+ strcpy (wcs->radecsys,"FK4");
+ else
+ strcpy (wcs->radecsys,"FK5");
+ wcs->epoch = wcs->equinox;
+ hgetr8 (hstring,"EPOCH",&wcs->epoch);
+ (void)sprintf (wcs->center,"%2.0f:%2.0f:%5.3f %c%2.0f:%2.0f:%5.3f %s",
+ rah,ram,ras,decsign,decd,decm,decs,wcs->radecsys);
+ hgetr8 (hstring,"PLTSCALE",&wcs->plate_scale);
+ hgetr8 (hstring,"XPIXELSZ",&wcs->x_pixel_size);
+ hgetr8 (hstring,"YPIXELSZ",&wcs->y_pixel_size);
+ hgetr8 (hstring,"CNPIX1",&wcs->x_pixel_offset);
+ hgetr8 (hstring,"CNPIX2",&wcs->y_pixel_offset);
+ hcoeff = ksearch (hstring,"PPO1");
+ for (i = 0; i < 6; i++) {
+ sprintf (keyword,"PPO%d", i+1);
+ wcs->ppo_coeff[i] = 0.0;
+ hgetr8 (hcoeff,keyword,&wcs->ppo_coeff[i]);
+ }
+ hcoeff = ksearch (hstring,"AMDX1");
+ for (i = 0; i < 20; i++) {
+ sprintf (keyword,"AMDX%d", i+1);
+ wcs->x_coeff[i] = 0.0;
+ hgetr8 (hcoeff, keyword, &wcs->x_coeff[i]);
+ }
+ hcoeff = ksearch (hstring,"AMDY1");
+ for (i = 0; i < 20; i++) {
+ sprintf (keyword,"AMDY%d",i+1);
+ wcs->y_coeff[i] = 0.0;
+ hgetr8 (hcoeff, keyword, &wcs->y_coeff[i]);
+ }
+ wcs->wcson = 1;
+ (void)strcpy (wcs->c1type, "RA");
+ (void)strcpy (wcs->c2type, "DEC");
+ (void)strcpy (wcs->ptype, "DSS");
+ wcs->degout = 0;
+ wcs->ndec = 3;
+
+ /* Compute a nominal reference pixel at the image center */
+ strcpy (wcs->ctype[0], "RA---DSS");
+ strcpy (wcs->ctype[1], "DEC--DSS");
+ wcs->crpix[0] = 0.5 * wcs->nxpix;
+ wcs->crpix[1] = 0.5 * wcs->nypix;
+ wcs->xrefpix = wcs->crpix[0];
+ wcs->yrefpix = wcs->crpix[1];
+ dsspos (wcs->crpix[0], wcs->crpix[1], wcs, &ra0, &dec0);
+ wcs->crval[0] = ra0;
+ wcs->crval[1] = dec0;
+ wcs->xref = wcs->crval[0];
+ wcs->yref = wcs->crval[1];
+
+ /* Compute a nominal scale factor */
+ dsspos (wcs->crpix[0], wcs->crpix[1]+1.0, wcs, &ra1, &dec1);
+ wcs->yinc = dec1 - dec0;
+ wcs->xinc = -wcs->yinc;
+ wcsioset (wcs);
+
+ /* Compute image rotation angle */
+ wcs->wcson = 1;
+ wcsrotset (wcs);
+ rot = degrad (wcs->rot);
+
+ /* Compute image scale at center */
+ dsspos (wcs->crpix[0]+cos(rot),
+ wcs->crpix[1]+sin(rot), wcs, &ra1, &dec1);
+ wcs->cdelt[0] = -wcsdist (ra0, dec0, ra1, dec1);
+ dsspos (wcs->crpix[0]+sin(rot),
+ wcs->crpix[1]+cos(rot), wcs, &ra1, &dec1);
+ wcs->cdelt[1] = wcsdist (ra0, dec0, ra1, dec1);
+
+ /* Set all other image scale parameters */
+ wcsdeltset (wcs, wcs->cdelt[0], wcs->cdelt[1], wcs->rot);
+ }
+
+ /* Approximate world coordinate system if plate scale is known */
+ else if ((ksearch (hstring,"SECPIX") != NULL ||
+ ksearch (hstring,"PIXSCALE") != NULL ||
+ ksearch (hstring,"PIXSCAL1") != NULL ||
+ ksearch (hstring,"XPIXSIZE") != NULL ||
+ ksearch (hstring,"SECPIX1") != NULL)) {
+ secpix = 0.0;
+ hgetr8 (hstring,"SECPIX",&secpix);
+ if (secpix == 0.0)
+ hgetr8 (hstring,"PIXSCALE",&secpix);
+ if (secpix == 0.0) {
+ hgetr8 (hstring,"SECPIX1",&secpix);
+ if (secpix != 0.0) {
+ cdelt1 = -secpix / 3600.0;
+ hgetr8 (hstring,"SECPIX2",&secpix);
+ cdelt2 = secpix / 3600.0;
+ }
+ else {
+ hgetr8 (hstring,"XPIXSIZE",&secpix);
+ if (secpix != 0.0) {
+ cdelt1 = -secpix / 3600.0;
+ hgetr8 (hstring,"YPIXSIZE",&secpix);
+ cdelt2 = secpix / 3600.0;
+ }
+ else {
+ hgetr8 (hstring,"PIXSCAL1",&secpix);
+ cdelt1 = -secpix / 3600.0;
+ hgetr8 (hstring,"PIXSCAL2",&secpix);
+ cdelt2 = secpix / 3600.0;
+ }
+ }
+ }
+ else {
+ cdelt2 = secpix / 3600.0;
+ cdelt1 = -cdelt2;
+ }
+
+ /* Get rotation angle from the header, if it's there */
+ rot = 0.0;
+ hgetr8 (hstring,"CROTA1", &rot);
+ if (wcs->rot == 0.)
+ hgetr8 (hstring,"CROTA2", &rot);
+
+ /* Set CD and PC matrices */
+ wcsdeltset (wcs, cdelt1, cdelt2, rot);
+
+ /* By default, set reference pixel to center of image */
+ wcs->crpix[0] = 0.5 + (wcs->nxpix * 0.5);
+ wcs->crpix[1] = 0.5 + (wcs->nypix * 0.5);
+
+ /* Get reference pixel from the header, if it's there */
+ if (ksearch (hstring,"CRPIX1") != NULL) {
+ hgetr8 (hstring,"CRPIX1",&wcs->crpix[0]);
+ hgetr8 (hstring,"CRPIX2",&wcs->crpix[1]);
+ }
+
+ /* Use center of detector array as reference pixel
+ else if (ksearch (hstring,"DETSIZE") != NULL ||
+ ksearch (hstring,"DETSEC") != NULL) {
+ char *ic;
+ hgets (hstring, "DETSIZE", 32, temp);
+ ic = strchr (temp, ':');
+ if (ic != NULL)
+ *ic = ' ';
+ ic = strchr (temp, ',');
+ if (ic != NULL)
+ *ic = ' ';
+ ic = strchr (temp, ':');
+ if (ic != NULL)
+ *ic = ' ';
+ ic = strchr (temp, ']');
+ if (ic != NULL)
+ *ic = cnull;
+ sscanf (temp, "%d %d %d %d", &idx1, &idx2, &idy1, &idy2);
+ dxrefpix = 0.5 * (double) (idx1 + idx2 - 1);
+ dyrefpix = 0.5 * (double) (idy1 + idy2 - 1);
+ hgets (hstring, "DETSEC", 32, temp);
+ ic = strchr (temp, ':');
+ if (ic != NULL)
+ *ic = ' ';
+ ic = strchr (temp, ',');
+ if (ic != NULL)
+ *ic = ' ';
+ ic = strchr (temp, ':');
+ if (ic != NULL)
+ *ic = ' ';
+ ic = strchr (temp, ']');
+ if (ic != NULL)
+ *ic = cnull;
+ sscanf (temp, "%d %d %d %d", &ix1, &ix2, &iy1, &iy2);
+ wcs->crpix[0] = dxrefpix - (double) (ix1 - 1);
+ wcs->crpix[1] = dyrefpix - (double) (iy1 - 1);
+ } */
+ wcs->xrefpix = wcs->crpix[0];
+ wcs->yrefpix = wcs->crpix[1];
+
+ wcs->crval[0] = -999.0;
+ if (!hgetra (hstring,"RA",&wcs->crval[0])) {
+ setwcserr ("WCSINIT: No RA with SECPIX, no WCS");
+ wcsfree (wcs);
+ return (NULL);
+ }
+ wcs->crval[1] = -999.0;
+ if (!hgetdec (hstring,"DEC",&wcs->crval[1])) {
+ setwcserr ("WCSINIT No DEC with SECPIX, no WCS");
+ wcsfree (wcs);
+ return (NULL);
+ }
+ wcs->xref = wcs->crval[0];
+ wcs->yref = wcs->crval[1];
+ wcs->coorflip = 0;
+
+ wcs->cel.ref[0] = wcs->crval[0];
+ wcs->cel.ref[1] = wcs->crval[1];
+ wcs->cel.ref[2] = 999.0;
+ if (!hgetr8 (hstring,"LONPOLE",&wcs->cel.ref[2]))
+ hgetr8 (hstring,"LONGPOLE",&wcs->cel.ref[2]);
+ wcs->cel.ref[3] = 999.0;
+ hgetr8 (hstring,"LATPOLE",&wcs->cel.ref[3]);
+
+ /* Epoch of image (from observation date, if possible) */
+ if (hgetr8 (hstring, "MJD-OBS", &mjd))
+ wcs->epoch = 1900.0 + (mjd - 15019.81352) / 365.242198781;
+ else if (!hgetdate (hstring,"DATE-OBS",&wcs->epoch)) {
+ if (!hgetdate (hstring,"DATE",&wcs->epoch)) {
+ if (!hgetr8 (hstring,"EPOCH",&wcs->epoch))
+ wcs->epoch = wcs->equinox;
+ }
+ }
+
+ /* Add time of day if not part of DATE-OBS string */
+ else {
+ hgets (hstring,"DATE-OBS",32,tstring);
+ if (!strchr (tstring,'T')) {
+ if (hgetr8 (hstring, "UT",&ut))
+ wcs->epoch = wcs->epoch + (ut / (24.0 * 365.242198781));
+ else if (hgetr8 (hstring, "UTMID",&ut))
+ wcs->epoch = wcs->epoch + (ut / (24.0 * 365.242198781));
+ }
+ }
+
+ /* Coordinate reference frame and equinox */
+ (void) wcstype (wcs, "RA---TAN", "DEC--TAN");
+ wcs->coorflip = 0;
+ wcseq (hstring,wcs);
+ wcsioset (wcs);
+ wcs->degout = 0;
+ wcs->ndec = 3;
+ wcs->wcson = 1;
+ }
+
+ else {
+ setwcserr ("WCSINIT: No image scale");
+ wcsfree (wcs);
+ return (NULL);
+ }
+
+ wcs->lin.crpix = wcs->crpix;
+ wcs->lin.cdelt = wcs->cdelt;
+ wcs->lin.pc = wcs->pc;
+
+ wcs->printsys = 1;
+ wcs->tabsys = 0;
+ wcs->linmode = 0;
+
+ /* Initialize special WCS commands */
+ setwcscom (wcs);
+
+ return (wcs);
+}
+
+
+/******* invert_wcs ***********************************************************
+PROTO void invert_wcs(wcsstruct *wcs)
+PURPOSE Invert WCS projection mapping (using a polynomial).
+INPUT WCS structure.
+OUTPUT -.
+NOTES .
+AUTHOR E. Bertin (IAP)
+VERSION 06/11/2003
+ ***/
+
+void
+invert_wcs( struct WorldCoor *wcs)
+
+{
+ polystruct *poly;
+ double pixin[NAXISPV],raw[NAXISPV],rawmin[NAXISPV];
+ double *outpos,*outpost, *lngpos,*lngpost;
+ double *latpos,*latpost,lngstep,latstep, rawsize, epsilon;
+ int group[] = {1,1};
+ /* Don't ask, this is needed by poly_init()! */
+ int i,j,lng,lat,deg, maxflag;
+ char errstr[80];
+ double xmin;
+ double ymin;
+ double xmax;
+ double ymax;
+ double lngmin;
+ double latmin;
+
+ /* Check first that inversion is not straightforward */
+ lng = wcs->wcsl.lng;
+ lat = wcs->wcsl.lat;
+
+ if (wcs->naxis != NAXISPV) {
+ return;
+ }
+
+ if (strcmp(wcs->wcsl.pcode, "TAN") != 0) {
+ return;
+ }
+
+ if ((wcs->projppv[1+lng*MAXPV] == 0) &&
+ (wcs->projppv[1+lat*MAXPV] == 0)) {
+ return;
+ }
+
+ if (wcs->wcs != NULL) {
+ pix2wcs(wcs->wcs,0,0,&xmin,&ymin);
+ pix2wcs(wcs->wcs,wcs->nxpix,wcs->nypix,&xmax,&ymax);
+ }
+ else {
+ xmin = 0;
+ ymin = 0;
+ xmax = wcs->nxpix;
+ ymax = wcs->nypix;
+ }
+
+ /* We define x as "longitude" and y as "latitude" projections */
+ /* We assume that PCxx cross-terms with additional dimensions are small */
+ /* Sample the whole image with a regular grid */
+ if (lng == 0) {
+ lngstep = (xmax-xmin)/(WCS_NGRIDPOINTS-1.0);
+ lngmin = xmin;
+ latstep = (ymax-ymin)/(WCS_NGRIDPOINTS-1.0);
+ latmin = ymin;
+ }
+ else {
+ lngstep = (ymax-ymin)/(WCS_NGRIDPOINTS-1.0);
+ lngmin = ymin;
+ latstep = (xmax-xmin)/(WCS_NGRIDPOINTS-1.0);
+ latmin = xmin;
+ }
+
+ outpos = (double *)calloc(2*WCS_NGRIDPOINTS2,sizeof(double));
+ lngpos = (double *)calloc(WCS_NGRIDPOINTS2,sizeof(double));
+ latpos = (double *)calloc(WCS_NGRIDPOINTS2,sizeof(double));
+ raw[lat] = rawmin[lat] = 0.5+latmin;
+ raw[lng] = rawmin[lng] = 0.5+lngmin;
+ outpost = outpos;
+ lngpost = lngpos;
+ latpost = latpos;
+ for (j=WCS_NGRIDPOINTS; j--; raw[lat]+=latstep) {
+ raw[lng] = rawmin[lng];
+ for (i=WCS_NGRIDPOINTS; i--; raw[lng]+=lngstep) {
+ if (linrev(raw, &wcs->lin, pixin)) {
+ sprintf (errstr,"*Error*: incorrect linear conversion in %s",
+ wcs->wcsl.pcode);
+ setwcserr (errstr);
+ }
+ *(lngpost++) = pixin[lng];
+ *(latpost++) = pixin[lat];
+ raw_to_pv (&wcs->prj,pixin[lng],pixin[lat], outpost, outpost+1);
+ outpost += 2;
+ }
+ }
+
+ /* Invert "longitude" */
+ /* Compute the extent of the pixel in reduced projected coordinates */
+ linrev(rawmin, &wcs->lin, pixin);
+ pixin[lng] += S2D;
+ linfwd(pixin, &wcs->lin, raw);
+ rawsize = sqrt((raw[lng]-rawmin[lng])*(raw[lng]-rawmin[lng])
+ +(raw[lat]-rawmin[lat])*(raw[lat]-rawmin[lat]))*D2S;
+ if (!rawsize) {
+ sprintf (errstr,"*Error*: incorrect linear conversion in %s",
+ wcs->wcsl.pcode);
+ setwcserr (errstr);
+ }
+ epsilon = WCS_INVACCURACY/rawsize;
+
+ /* Find the lowest degree polynom */
+ poly = NULL; /* to avoid gcc -Wall warnings */
+ maxflag = 1;
+ for (deg=1; deg<=WCS_INVMAXDEG && maxflag; deg++) {
+ if (deg>1) {
+ poly_end(poly);
+ }
+ poly = poly_init(group, 2, &deg, 1);
+ poly_fit(poly, outpos, lngpos, NULL, WCS_NGRIDPOINTS2, NULL);
+ maxflag = 0;
+ outpost = outpos;
+ lngpost = lngpos;
+ for (i=WCS_NGRIDPOINTS2; i--; outpost+=2) {
+ if (fabs(poly_func(poly, outpost)-*(lngpost++))>epsilon) {
+ maxflag = 1;
+ break;
+ }
+ }
+ }
+ if (maxflag) {
+ setwcserr ("WARNING: Significant inaccuracy likely to occur in projection");
+ wcs->pvfail = 1;
+ }
+
+ /* Now link the created structure */
+ wcs->prj.inv_x = wcs->inv_x = poly;
+
+ /* Invert "latitude" */
+ /* Compute the extent of the pixel in reduced projected coordinates */
+ linrev(rawmin, &wcs->lin, pixin);
+ pixin[lat] += S2D;
+ linfwd(pixin, &wcs->lin, raw);
+ rawsize = sqrt((raw[lng]-rawmin[lng])*(raw[lng]-rawmin[lng])
+ +(raw[lat]-rawmin[lat])*(raw[lat]-rawmin[lat]))*D2S;
+ if (!rawsize) {
+ sprintf (errstr,"*Error*: incorrect linear conversion in %s",
+ wcs->wcsl.pcode);
+ setwcserr (errstr);
+ }
+ epsilon = WCS_INVACCURACY/rawsize;
+
+ /* Find the lowest degree polynom */
+ maxflag = 1;
+ for (deg=1; deg<=WCS_INVMAXDEG && maxflag; deg++) {
+ if (deg>1)
+ poly_end(poly);
+ poly = poly_init(group, 2, &deg, 1);
+ poly_fit(poly, outpos, latpos, NULL, WCS_NGRIDPOINTS2, NULL);
+ maxflag = 0;
+ outpost = outpos;
+ latpost = latpos;
+ for (i=WCS_NGRIDPOINTS2; i--; outpost+=2) {
+ if (fabs(poly_func(poly, outpost)-*(latpost++))>epsilon) {
+ maxflag = 1;
+ break;
+ }
+ }
+ }
+ if (maxflag) {
+ setwcserr ("WARNING: Significant inaccuracy likely to occur in projection");
+ wcs->pvfail = 1;
+ }
+
+ /* Now link the created structure */
+ wcs->prj.inv_y = wcs->inv_y = poly;
+
+ /* Free memory */
+ free(outpos);
+ free(lngpos);
+ free(latpos);
+
+ return;
+}
+
+
+/* Set coordinate system of image, input, and output */
+
+static void
+wcsioset (wcs)
+
+struct WorldCoor *wcs;
+{
+ if (strlen (wcs->radecsys) == 0 || wcs->prjcode == WCS_LIN)
+ strcpy (wcs->radecsys, "LINEAR");
+ if (wcs->prjcode == WCS_PIX)
+ strcpy (wcs->radecsys, "PIXEL");
+ wcs->syswcs = wcscsys (wcs->radecsys);
+
+ if (wcs->syswcs == WCS_B1950)
+ strcpy (wcs->radecout, "FK4");
+ else if (wcs->syswcs == WCS_J2000)
+ strcpy (wcs->radecout, "FK5");
+ else
+ strcpy (wcs->radecout, wcs->radecsys);
+ wcs->sysout = wcscsys (wcs->radecout);
+ wcs->eqout = wcs->equinox;
+ strcpy (wcs->radecin, wcs->radecsys);
+ wcs->sysin = wcscsys (wcs->radecin);
+ wcs->eqin = wcs->equinox;
+ return;
+}
+
+
+static void
+wcseq (hstring, wcs)
+
+char *hstring; /* character string containing FITS header information
+ in the format <keyword>= <value> [/ <comment>] */
+struct WorldCoor *wcs; /* World coordinate system data structure */
+{
+ char mchar; /* Suffix character for one of multiple WCS */
+ mchar = (char) 0;
+ wcseqm (hstring, wcs, &mchar);
+ return;
+}
+
+
+static void
+wcseqm (hstring, wcs, mchar)
+
+char *hstring; /* character string containing FITS header information
+ in the format <keyword>= <value> [/ <comment>] */
+struct WorldCoor *wcs; /* World coordinate system data structure */
+char *mchar; /* Suffix character for one of multiple WCS */
+{
+ int ieq = 0;
+ int eqhead = 0;
+ char systring[32], eqstring[32];
+ char radeckey[16], eqkey[16];
+ char tstring[32];
+ double ut;
+
+ /* Set equinox from EQUINOX, EPOCH, or RADECSYS; default to 2000 */
+ systring[0] = 0;
+ eqstring[0] = 0;
+ if (mchar[0]) {
+ sprintf (eqkey, "EQUINOX%c", mchar[0]);
+ sprintf (radeckey, "RADECSYS%c", mchar[0]);
+ }
+ else {
+ strcpy (eqkey, "EQUINOX");
+ sprintf (radeckey, "RADECSYS");
+ }
+ if (!hgets (hstring, eqkey, 31, eqstring)) {
+ if (hgets (hstring, "EQUINOX", 31, eqstring))
+ strcpy (eqkey, "EQUINOX");
+ }
+ if (!hgets (hstring, radeckey, 31, systring)) {
+ if (hgets (hstring, "RADECSYS", 31, systring))
+ sprintf (radeckey, "RADECSYS");
+ }
+
+ if (eqstring[0] == 'J') {
+ wcs->equinox = atof (eqstring+1);
+ ieq = atoi (eqstring+1);
+ strcpy (systring, "FK5");
+ }
+ else if (eqstring[0] == 'B') {
+ wcs->equinox = atof (eqstring+1);
+ ieq = (int) atof (eqstring+1);
+ strcpy (systring, "FK4");
+ }
+ else if (hgeti4 (hstring, eqkey, &ieq)) {
+ hgetr8 (hstring, eqkey, &wcs->equinox);
+ eqhead = 1;
+ }
+
+ else if (hgeti4 (hstring,"EPOCH",&ieq)) {
+ if (ieq == 0) {
+ ieq = 1950;
+ wcs->equinox = 1950.0;
+ }
+ else {
+ hgetr8 (hstring,"EPOCH",&wcs->equinox);
+ eqhead = 1;
+ }
+ }
+
+ else if (systring[0] != (char)0) {
+ if (!strncmp (systring,"FK4",3)) {
+ wcs->equinox = 1950.0;
+ ieq = 1950;
+ }
+ else if (!strncmp (systring,"ICRS",4)) {
+ wcs->equinox = 2000.0;
+ ieq = 2000;
+ }
+ else if (!strncmp (systring,"FK5",3)) {
+ wcs->equinox = 2000.0;
+ ieq = 2000;
+ }
+ else if (!strncmp (systring,"GAL",3)) {
+ wcs->equinox = 2000.0;
+ ieq = 2000;
+ }
+ else if (!strncmp (systring,"ECL",3)) {
+ wcs->equinox = 2000.0;
+ ieq = 2000;
+ }
+ }
+
+ if (ieq == 0) {
+ wcs->equinox = 2000.0;
+ ieq = 2000;
+ if (!strncmp (wcs->c1type, "RA",2) || !strncmp (wcs->c1type,"DEC",3))
+ strcpy (systring,"FK5");
+ }
+
+ /* Epoch of image (from observation date, if possible) */
+ if (!hgetdate (hstring,"DATE-OBS",&wcs->epoch)) {
+ if (!hgetdate (hstring,"DATE",&wcs->epoch)) {
+ if (!hgetr8 (hstring,"EPOCH",&wcs->epoch))
+ wcs->epoch = wcs->equinox;
+ }
+ }
+
+ /* Add time of day if not part of DATE-OBS string */
+ else {
+ hgets (hstring,"DATE-OBS",32,tstring);
+ if (!strchr (tstring,'T')) {
+ if (hgetr8 (hstring, "UT",&ut))
+ wcs->epoch = wcs->epoch + (ut / (24.0 * 365.242198781));
+ else if (hgetr8 (hstring, "UTMID",&ut))
+ wcs->epoch = wcs->epoch + (ut / (24.0 * 365.242198781));
+ }
+ }
+ if (wcs->epoch == 0.0)
+ wcs->epoch = wcs->equinox;
+
+ /* Set coordinate system from keyword, if it is present */
+ if (systring[0] == (char) 0)
+ hgets (hstring, radeckey, 31, systring);
+ if (systring[0] != (char) 0) {
+ strcpy (wcs->radecsys,systring);
+ if (!eqhead) {
+ if (!strncmp (wcs->radecsys,"FK4",3))
+ wcs->equinox = 1950.0;
+ else if (!strncmp (wcs->radecsys,"FK5",3))
+ wcs->equinox = 2000.0;
+ else if (!strncmp (wcs->radecsys,"ICRS",4))
+ wcs->equinox = 2000.0;
+ else if (!strncmp (wcs->radecsys,"GAL",3) && ieq == 0)
+ wcs->equinox = 2000.0;
+ }
+ }
+
+ /* Otherwise set coordinate system from equinox */
+ /* Systemless coordinates cannot be translated using b, j, or g commands */
+ else if (wcs->syswcs != WCS_NPOLE) {
+ if (ieq > 1980)
+ strcpy (wcs->radecsys,"FK5");
+ else
+ strcpy (wcs->radecsys,"FK4");
+ }
+
+ /* Set galactic coordinates if GLON or GLAT are in C1TYPE */
+ if (wcs->c1type[0] == 'G')
+ strcpy (wcs->radecsys,"GALACTIC");
+ else if (wcs->c1type[0] == 'E')
+ strcpy (wcs->radecsys,"ECLIPTIC");
+ else if (wcs->c1type[0] == 'S')
+ strcpy (wcs->radecsys,"SGALACTC");
+ else if (wcs->c1type[0] == 'H')
+ strcpy (wcs->radecsys,"HELIOECL");
+ else if (wcs->c1type[0] == 'A')
+ strcpy (wcs->radecsys,"ALTAZ");
+ else if (wcs->c1type[0] == 'L')
+ strcpy (wcs->radecsys,"LINEAR");
+
+ wcs->syswcs = wcscsys (wcs->radecsys);
+
+ return;
+}
+
+/* Jun 11 1998 Split off header-dependent WCS initialization from other subs
+ * Jun 15 1998 Fix major bug in wcsinit() when synthesizing WCS from header
+ * Jun 18 1998 Fix bug in CD initialization; split PC initialization off
+ * Jun 18 1998 Split PC initialization off into subroutine wcspcset()
+ * Jun 24 1998 Set equinox from RADECSYS only if EQUINOX and EPOCH not present
+ * Jul 6 1998 Read third and fourth axis CTYPEs
+ * Jul 7 1998 Initialize eqin and eqout to equinox,
+ * Jul 9 1998 Initialize rotation matrices correctly
+ * Jul 13 1998 Initialize rotation, scale for polynomial and DSS projections
+ * Aug 6 1998 Fix CROTA computation for DSS projection
+ * Sep 4 1998 Fix CROTA, CDELT computation for DSS and polynomial projections
+ * Sep 14 1998 If DATE-OBS not found, check for DATE
+ * Sep 14 1998 If B or J present in EQUINOX, use that info to set system
+ * Sep 29 1998 Initialize additional WCS commands from the environment
+ * Sep 29 1998 Fix bug which read DATE as number rather than formatted date
+ * Dec 2 1998 Read projection constants from header (bug fix)
+ *
+ * Feb 9 1999 Set rotation angle correctly when using DSS projection
+ * Feb 19 1999 Fill in CDELTs from scale keyword if absent or zero
+ * Feb 19 1999 Add PIXSCALE as possible default arcseconds per pixel
+ * Apr 7 1999 Add error checking for NAXIS and NAXIS1 keywords
+ * Apr 7 1999 Do not set systring if epoch is 0 and not RA/Dec
+ * Jul 8 1999 In RADECSYS, use FK5 and FK4 instead of J2000 and B1950
+ * Oct 15 1999 Free wcs using wcsfree()
+ * Oct 20 1999 Add multiple WCS support using new subroutine names
+ * Oct 21 1999 Delete unused variables after lint; declare dsspos()
+ * Nov 9 1999 Add wcschar() to check WCSNAME keywords for desired WCS
+ * Nov 9 1999 Check WCSPREx keyword to find out if chained WCS's
+ *
+ * Jan 6 1999 Add wcsinitn() to initialize from specific WCSNAME
+ * Jan 24 2000 Set CD matrix from header even if using polynomial
+ * Jan 27 2000 Fix MJD to epoch conversion for when MJD-OBS is the only date
+ * Jan 28 2000 Set CD matrix for DSS projection, too
+ * Jan 28 2000 Use wcsproj instead of oldwcs
+ * Dec 18 2000 Fix error in hgets() call in wcschar()
+ * Dec 29 2000 Compute inverse CD matrix even if polynomial solution
+ * Dec 29 2000 Add PROJR0 keyword for WCSLIB projections
+ * Dec 29 2000 Use CDi_j matrix if any elements are present
+ *
+ * Jan 31 2001 Fix to allow 1D WCS
+ * Jan 31 2001 Treat single character WCS name as WCS character
+ * Feb 20 2001 Implement WCSDEPx nested WCS's
+ * Feb 23 2001 Initialize all 4 terms of CD matrix
+ * Feb 28 2001 Fix bug which read CRPIX1 into CRPIX2
+ * Mar 20 2001 Compare mchar to (char)0, not null
+ * Mar 21 2001 Move ic declaration into commented out code
+ * Jul 12 2001 Read PROJPn constants into proj.p array instead of PVn
+ * Sep 7 2001 Set system to galactic or ecliptic based on CTYPE, not RADECSYS
+ * Oct 11 2001 Set ctype[0] as well as ctype[1] to TAN for TNX projections
+ * Oct 19 2001 WCSDIM keyword overrides zero value of NAXIS
+ *
+ * Feb 19 2002 Add XPIXSIZE/YPIXSIZE (KPNO) as default image scale keywords
+ * Mar 12 2002 Add LONPOLE as well as LONGPOLE for WCSLIB 2.8
+ * Apr 3 2002 Implement hget8c() and hgetsc() to simplify code
+ * Apr 3 2002 Add PVj_n projection constants in addition to PROJPn
+ * Apr 19 2002 Increase numeric keyword value length from 16 to 31
+ * Apr 19 2002 Fix bug which didn't set radecsys keyword name
+ * Apr 24 2002 If no WCS present for specified letter, return null
+ * Apr 26 2002 Implement WCSAXESa keyword as first choice for number of axes
+ * Apr 26 2002 Add wcschar and wcsname to WCS structure
+ * May 9 2002 Add radvel and zvel to WCS structure
+ * May 13 2002 Free everything which is allocated
+ * May 28 2002 Read 10 prj.p instead of maximum of 100
+ * May 31 2002 Fix bugs with PV reading
+ * May 31 2002 Initialize syswcs, sysin, sysout in wcsioset()
+ * Sep 25 2002 Fix subroutine calls for radvel and latpole
+ * Dec 6 2002 Correctly compute pixel at center of image for default CRPIX
+ *
+ * Jan 2 2002 Do not reinitialize projection vector for PV input
+ * Jan 3 2002 For ZPN, read PVi_0 to PVi_9, not PVi_1 to PVi_10
+ * Mar 27 2003 Clean up default center computation
+ * Apr 3 2003 Add input for SIRTF distortion coefficients
+ * May 8 2003 Change PROJP reading to start with 0 instead of 1
+ * May 22 2003 Add ZPX approximation, reading projpn from WATi
+ * May 28 2003 Avoid reinitializing coefficients set by PROJP
+ * Jun 26 2003 Initialize xref and yref to -999.0
+ * Sep 23 2003 Change mgets() to mgetstr() to avoid name collision at UCO Lick
+ * Oct 1 2003 Rename wcs->naxes to wcs->naxis to match WCSLIB 3.2
+ * Nov 3 2003 Initialize distortion coefficients in distortinit() in distort.c
+ * Dec 1 2003 Change p[0,1,2] initializations to p[1,2,3]
+ * Dec 3 2003 Add back wcs->naxes for backward compatibility
+ * Dec 3 2003 Remove unused variables j,m in wcsinitc()
+ * Dec 12 2003 Fix call to setwcserr() with format in it
+ *
+ * Feb 26 2004 Add parameters for ZPX projection
+ *
+ * Jun 22 2005 Drop declaration of variable wcserrmsg which is not used
+ * Nov 9 2005 Use CROTA1 if CTYPE1 is LAT/DEC, CROTA2 if CTYPE2 is LAT/DEC
+ *
+ * Mar 9 2006 Get Epoch of observation from MJD-OBS or DATE-OBS/UT unless DSS
+ * Apr 24 2006 Initialize rotation matrices
+ * Apr 25 2006 Ignore axes with dimension of one
+ * May 19 2006 Initialize all of 9x9 PC matrix; read in loops
+ * Aug 21 2006 Limit naxes to 2 everywhere; RA and DEC should always be 1st
+ * Oct 6 2006 If units are pixels, projection type is PIXEL
+ * Oct 30 2006 Initialize cube face to -1, not a cube projection
+ *
+ * Jan 4 2007 Drop declarations of wcsinitc() and wcsinitn() already in wcs.h
+ * Jan 8 2007 Change WCS letter from char to char*
+ * Feb 1 2007 Read IRAF log wavelength flag DC-FLAG to wcs.logwcs
+ * Feb 15 2007 Check for wcs->wcsproj > 0 instead of CTYPEi != LINEAR or PIXEL
+ * Mar 13 2007 Try for RA, DEC, SECPIX if WCS character is space or null
+ * Apr 27 2007 Ignore axes with TAB WCS for now
+ * Oct 17 2007 Fix bug testing &mchar instead of mchar in if statement
+ *
+ * May 9 2008 Initialize TNX projection when projection types first set
+ * Jun 27 2008 If NAXIS1 and NAXIS2 not present, check for IMAGEW and IMAGEH
+ *
+ * Mar 24 2009 Fix dimension bug if NAXISi not present (fix from John Burns)
+ *
+ * Mar 11 2011 Add NOAO ZPX projection (Frank Valdes)
+ * Mar 18 2011 Add invert_wcs() by Emmanuel Bertin for SCAMP
+ * Mar 18 2011 Change Bertin's ARCSEC/DEG to S2D and DEG/ARCSEC to D2S
+ * Sep 1 2011 Add TPV as TAN with SCAMP PVs
+ *
+ * Oct 19 2012 Drop unused variable iszpx; fix bug in latmin assignment
+ */
diff --git a/funtools/wcs/wcslib.c b/funtools/wcs/wcslib.c
new file mode 100644
index 0000000..31313e1
--- /dev/null
+++ b/funtools/wcs/wcslib.c
@@ -0,0 +1,1334 @@
+/*=============================================================================
+*
+* WCSLIB - an implementation of the FITS WCS proposal.
+* Copyright (C) 1995-2002, Mark Calabretta
+*
+* This library 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 2 of the License, or (at your option) any later version.
+*
+* This library 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 this library; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*
+* Correspondence concerning WCSLIB may be directed to:
+* Internet email: mcalabre@atnf.csiro.au
+* Postal address: Dr. Mark Calabretta,
+* Australia Telescope National Facility,
+* P.O. Box 76,
+* Epping, NSW, 2121,
+* AUSTRALIA
+*
+*=============================================================================
+*
+* C routines which implement the FITS World Coordinate System (WCS)
+* convention.
+*
+* Summary of routines
+* -------------------
+* wcsfwd() and wcsrev() are high level driver routines for the WCS linear
+* transformation, spherical coordinate transformation, and spherical
+* projection routines.
+*
+* Given either the celestial longitude or latitude plus an element of the
+* pixel coordinate a hybrid routine, wcsmix(), iteratively solves for the
+* unknown elements.
+*
+* An initialization routine, wcsset(), computes indices from the ctype
+* array but need not be called explicitly - see the explanation of
+* wcs.flag below.
+*
+*
+* Initialization routine; wcsset()
+* --------------------------------
+* Initializes elements of a wcsprm data structure which holds indices into
+* the coordinate arrays. Note that this routine need not be called directly;
+* it will be invoked by wcsfwd() and wcsrev() if the "flag" structure member
+* is anything other than a predefined magic value.
+*
+* Given:
+* naxis const int
+* Number of image axes.
+* ctype[][9]
+* const char
+* Coordinate axis types corresponding to the FITS
+* CTYPEn header cards.
+*
+* Returned:
+* wcs wcsprm* Indices for the celestial coordinates obtained
+* by parsing the ctype[] array (see below).
+*
+* Function return value:
+* int Error status
+* 0: Success.
+* 1: Inconsistent or unrecognized coordinate axis
+* types.
+*
+*
+* Forward transformation; wcsfwd()
+* --------------------------------
+* Compute the pixel coordinate for given world coordinates.
+*
+* Given:
+* ctype[][9]
+* const char
+* Coordinate axis types corresponding to the FITS
+* CTYPEn header cards.
+*
+* Given or returned:
+* wcs wcsprm* Indices for the celestial coordinates obtained
+* by parsing the ctype[] array (see below).
+*
+* Given:
+* world const double[]
+* World coordinates. world[wcs->lng] and
+* world[wcs->lat] are the celestial longitude and
+* latitude, in degrees.
+*
+* Given:
+* crval const double[]
+* Coordinate reference values corresponding to the FITS
+* CRVALn header cards (see note 2).
+*
+* Given and returned:
+* cel celprm* Spherical coordinate transformation parameters (usage
+* is described in the prologue to "cel.c").
+*
+* Returned:
+* phi, double* Longitude and latitude in the native coordinate
+* theta system of the projection, in degrees.
+*
+* Given and returned:
+* prj prjprm* Projection parameters (usage is described in the
+* prologue to "proj.c").
+*
+* Returned:
+* imgcrd double[] Image coordinate. imgcrd[wcs->lng] and
+* imgcrd[wcs->lat] are the projected x-, and
+* y-coordinates, in "degrees". For quadcube
+* projections with a CUBEFACE axis the face number is
+* also returned in imgcrd[wcs->cubeface].
+*
+* Given and returned:
+* lin linprm* Linear transformation parameters (usage is described
+* in the prologue to "lin.c").
+*
+* Returned:
+* pixcrd double[] Pixel coordinate.
+*
+* Function return value:
+* int Error status
+* 0: Success.
+* 1: Invalid coordinate transformation parameters.
+* 2: Invalid projection parameters.
+* 3: Invalid world coordinate.
+* 4: Invalid linear transformation parameters.
+*
+*
+* Reverse transformation; wcsrev()
+* --------------------------------
+* Compute world coordinates for a given pixel coordinate.
+*
+* Given:
+* ctype[][9]
+* const char
+* Coordinate axis types corresponding to the FITS
+* CTYPEn header cards.
+*
+* Given or returned:
+* wcs wcsprm* Indices for the celestial coordinates obtained
+* by parsing the ctype[] array (see below).
+*
+* Given:
+* pixcrd const double[]
+* Pixel coordinate.
+*
+* Given and returned:
+* lin linprm* Linear transformation parameters (usage is described
+* in the prologue to "lin.c").
+*
+* Returned:
+* imgcrd double[] Image coordinate. imgcrd[wcs->lng] and
+* imgcrd[wcs->lat] are the projected x-, and
+* y-coordinates, in "degrees".
+*
+* Given and returned:
+* prj prjprm* Projection parameters (usage is described in the
+* prologue to "proj.c").
+*
+* Returned:
+* phi, double* Longitude and latitude in the native coordinate
+* theta system of the projection, in degrees.
+*
+* Given:
+* crval const double[]
+* Coordinate reference values corresponding to the FITS
+* CRVALn header cards (see note 2).
+*
+* Given and returned:
+* cel celprm* Spherical coordinate transformation parameters
+* (usage is described in the prologue to "cel.c").
+*
+* Returned:
+* world double[] World coordinates. world[wcs->lng] and
+* world[wcs->lat] are the celestial longitude and
+* latitude, in degrees.
+*
+* Function return value:
+* int Error status
+* 0: Success.
+* 1: Invalid coordinate transformation parameters.
+* 2: Invalid projection parameters.
+* 3: Invalid pixel coordinate.
+* 4: Invalid linear transformation parameters.
+*
+*
+* Hybrid transformation; wcsmix()
+* -------------------------------
+* Given either the celestial longitude or latitude plus an element of the
+* pixel coordinate solve for the remaining elements by iterating on the
+* unknown celestial coordinate element using wcsfwd().
+*
+* Given:
+* ctype[][9]
+* const char
+* Coordinate axis types corresponding to the FITS
+* CTYPEn header cards.
+*
+* Given or returned:
+* wcs wcsprm* Indices for the celestial coordinates obtained
+* by parsing the ctype[] array (see below).
+*
+* Given:
+* mixpix const int
+* Which element of the pixel coordinate is given.
+* mixcel const int
+* Which element of the celestial coordinate is
+* given:
+* 1: Celestial longitude is given in
+* world[wcs->lng], latitude returned in
+* world[wcs->lat].
+* 2: Celestial latitude is given in
+* world[wcs->lat], longitude returned in
+* world[wcs->lng].
+* vspan[2] const double
+* Solution interval for the celestial coordinate, in
+* degrees. The ordering of the two limits is
+* irrelevant. Longitude ranges may be specified with
+* any convenient normalization, for example [-120,+120]
+* is the same as [240,480], except that the solution
+* will be returned with the same normalization, i.e.
+* lie within the interval specified.
+* vstep const double
+* Step size for solution search, in degrees. If zero,
+* a sensible, although perhaps non-optimal default will
+* be used.
+* viter int
+* If a solution is not found then the step size will be
+* halved and the search recommenced. viter controls
+* how many times the step size is halved. The allowed
+* range is 5 - 10.
+*
+* Given and returned:
+* world double[] World coordinates. world[wcs->lng] and
+* world[wcs->lat] are the celestial longitude and
+* latitude, in degrees. Which is given and which
+* returned depends on the value of mixcel. All other
+* elements are given.
+*
+* Given:
+* crval const double[]
+* Coordinate reference values corresponding to the FITS
+* CRVALn header cards (see note 2).
+*
+* Given and returned:
+* cel celprm* Spherical coordinate transformation parameters
+* (usage is described in the prologue to "cel.c").
+*
+* Returned:
+* phi, double* Longitude and latitude in the native coordinate
+* theta system of the projection, in degrees.
+*
+* Given and returned:
+* prj prjprm* Projection parameters (usage is described in the
+* prologue to "proj.c").
+*
+* Returned:
+* imgcrd double[] Image coordinate. imgcrd[wcs->lng] and
+* imgcrd[wcs->lat] are the projected x-, and
+* y-coordinates, in "degrees".
+*
+* Given and returned:
+* lin linprm* Linear transformation parameters (usage is described
+* in the prologue to "lin.c").
+*
+* Given and returned:
+* pixcrd double[] Pixel coordinate. The element indicated by mixpix is
+* given and the remaining elements are returned.
+*
+* Function return value:
+* int Error status
+* 0: Success.
+* 1: Invalid coordinate transformation parameters.
+* 2: Invalid projection parameters.
+* 3: Coordinate transformation error.
+* 4: Invalid linear transformation parameters.
+* 5: No solution found in the specified interval.
+*
+*
+* Notes
+* -----
+* 1) The CTYPEn must in be upper case and there must be 0 or 1 pair of
+* matched celestial axis types. The ctype[][9] should be padded with
+* blanks on the right and null-terminated.
+*
+* 2) Elements of the crval[] array which correspond to celestial axes are
+* ignored, the reference coordinate values in cel->ref[0] and
+* cel->ref[1] are the ones used.
+*
+* 3) These functions recognize the NCP projection and convert it to the
+* equivalent SIN projection.
+*
+* They also recognize GLS as a synonym for SFL.
+*
+* 4) The quadcube projections (TSC, CSC, QSC) may be represented in FITS in
+* either of two ways:
+*
+* a) The six faces may be laid out in one plane and numbered as
+* follows:
+*
+* 0
+*
+* 4 3 2 1 4 3 2
+*
+* 5
+*
+* Faces 2, 3 and 4 may appear on one side or the other (or both).
+* The forward routines map faces 2, 3 and 4 to the left but the
+* inverse routines accept them on either side.
+*
+* b) The "COBE" convention in which the six faces are stored in a
+* three-dimensional structure using a "CUBEFACE" axis indexed from
+* 0 to 5 as above.
+*
+* These routines support both methods; wcsset() determines which is
+* being used by the presence or absence of a CUBEFACE axis in ctype[].
+* wcsfwd() and wcsrev() translate the CUBEFACE axis representation to
+* the single plane representation understood by the lower-level WCSLIB
+* projection routines.
+*
+*
+* WCS indexing parameters
+* -----------------------
+* The wcsprm struct consists of the following:
+*
+* int flag
+* The wcsprm struct contains indexes and other information derived
+* from the CTYPEn. Whenever any of the ctype[] are set or changed
+* this flag must be set to zero to signal the initialization routine,
+* wcsset() to redetermine the indices. The flag is set to 999 if
+* there is no celestial axis pair in the CTYPEn.
+*
+* char pcode[4]
+* The WCS projection code.
+*
+* char lngtyp[5], lattyp[5]
+* WCS celestial axis types.
+*
+* int lng,lat
+* Indices into the imgcrd[], and world[] arrays as described above.
+* These may also serve as indices for the celestial longitude and
+* latitude axes in the pixcrd[] array provided that the PC matrix
+* does not transpose axes.
+*
+* int cubeface
+* Index into the pixcrd[] array for the CUBEFACE axis. This is
+* optionally used for the quadcube projections where each cube face is
+* stored on a separate axis.
+*
+*
+* wcsmix() algorithm
+* ------------------
+* Initially the specified solution interval is checked to see if it's a
+* "crossing" interval. If it isn't, a search is made for a crossing
+* solution by iterating on the unknown celestial coordinate starting at
+* the upper limit of the solution interval and decrementing by the
+* specified step size. A crossing is indicated if the trial value of the
+* pixel coordinate steps through the value specified. If a crossing
+* interval is found then the solution is determined by a modified form of
+* "regula falsi" division of the crossing interval. If no crossing
+* interval was found within the specified solution interval then a search
+* is made for a "non-crossing" solution as may arise from a point of
+* tangency. The process is complicated by having to make allowance for
+* the discontinuities that occur in all map projections.
+*
+* Once one solution has been determined others may be found by subsequent
+* invokations of wcsmix() with suitably restricted solution intervals.
+*
+* Note the circumstance which arises when the solution point lies at a
+* native pole of a projection in which the pole is represented as a
+* finite curve, for example the zenithals and conics. In such cases two
+* or more valid solutions may exist but WCSMIX only ever returns one.
+*
+* Because of its generality wcsmix() is very compute-intensive. For
+* compute-limited applications more efficient special-case solvers could
+* be written for simple projections, for example non-oblique cylindrical
+* projections.
+*
+* Author: Mark Calabretta, Australia Telescope National Facility
+* $Id: wcs.c,v 2.23 2002/04/03 01:25:29 mcalabre Exp $
+*===========================================================================*/
+
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+#include <stdio.h>
+#include "wcslib.h"
+
+/* Map error number to error message for each function. */
+const char *wcsset_errmsg[] = {
+ 0,
+ "Inconsistent or unrecognized coordinate axis types"};
+
+const char *wcsfwd_errmsg[] = {
+ 0,
+ "Invalid coordinate transformation parameters",
+ "Invalid projection parameters",
+ "Invalid world coordinate",
+ "Invalid linear transformation parameters"};
+
+const char *wcsrev_errmsg[] = {
+ 0,
+ "Invalid coordinate transformation parameters",
+ "Invalid projection parameters",
+ "Invalid pixel coordinate",
+ "Invalid linear transformation parameters"};
+
+const char *wcsmix_errmsg[] = {
+ 0,
+ "Invalid coordinate transformation parameters",
+ "Invalid projection parameters",
+ "Coordinate transformation error",
+ "Invalid linear transformation parameters",
+ "No solution found in the specified interval"};
+
+#define signb(X) ((X) < 0.0 ? 1 : 0)
+
+int
+wcsset (naxis, ctype, wcs)
+
+const int naxis;
+const char ctype[][9];
+struct wcsprm *wcs;
+
+{
+ int nalias = 2;
+ char aliases [2][4] = {"NCP", "GLS"};
+
+ int j, k;
+ int *ndx = NULL;
+ char requir[9];
+
+ strcpy(wcs->pcode, "");
+ strcpy(requir, "");
+ wcs->lng = -1;
+ wcs->lat = -1;
+ wcs->cubeface = -1;
+
+ for (j = 0; j < naxis; j++) {
+ if (ctype[j][4] != '-') {
+ if (strcmp(ctype[j], "CUBEFACE") == 0) {
+ if (wcs->cubeface == -1) {
+ wcs->cubeface = j;
+ } else {
+ /* Multiple CUBEFACE axes! */
+ return 1;
+ }
+ }
+ continue;
+ }
+
+ /* Got an axis qualifier, is it a recognized WCS projection? */
+ for (k = 0; k < npcode; k++) {
+ if (strncmp(&ctype[j][5], pcodes[k], 3) == 0) break;
+ }
+
+ if (k == npcode) {
+ /* Maybe it's a projection alias. */
+ for (k = 0; k < nalias; k++) {
+ if (strncmp(&ctype[j][5], aliases[k], 3) == 0) break;
+ }
+
+ /* Not recognized. */
+ if (k == nalias) {
+ continue;
+ }
+ }
+
+ /* Parse the celestial axis type. */
+ if (strcmp(wcs->pcode, "") == 0) {
+ sprintf(wcs->pcode, "%.3s", &ctype[j][5]);
+
+ if (strncmp(ctype[j], "RA--", 4) == 0) {
+ wcs->lng = j;
+ strcpy(wcs->lngtyp, "RA");
+ strcpy(wcs->lattyp, "DEC");
+ ndx = &wcs->lat;
+ sprintf(requir, "DEC--%s", wcs->pcode);
+ } else if (strncmp(ctype[j], "DEC-", 4) == 0) {
+ wcs->lat = j;
+ strcpy(wcs->lngtyp, "RA");
+ strcpy(wcs->lattyp, "DEC");
+ ndx = &wcs->lng;
+ sprintf(requir, "RA---%s", wcs->pcode);
+ } else if (strncmp(&ctype[j][1], "LON", 3) == 0) {
+ wcs->lng = j;
+ sprintf(wcs->lngtyp, "%cLON", ctype[j][0]);
+ sprintf(wcs->lattyp, "%cLAT", ctype[j][0]);
+ ndx = &wcs->lat;
+ sprintf(requir, "%s-%s", wcs->lattyp, wcs->pcode);
+ } else if (strncmp(&ctype[j][1], "LAT", 3) == 0) {
+ wcs->lat = j;
+ sprintf(wcs->lngtyp, "%cLON", ctype[j][0]);
+ sprintf(wcs->lattyp, "%cLAT", ctype[j][0]);
+ ndx = &wcs->lng;
+ sprintf(requir, "%s-%s", wcs->lngtyp, wcs->pcode);
+ } else if (strncmp(&ctype[j][2], "LN", 2) == 0) {
+ wcs->lng = j;
+ sprintf(wcs->lngtyp, "%c%cLN", ctype[j][0], ctype[j][1]);
+ sprintf(wcs->lattyp, "%c%cLT", ctype[j][0], ctype[j][1]);
+ ndx = &wcs->lat;
+ sprintf(requir, "%s-%s", wcs->lattyp, wcs->pcode);
+ } else if (strncmp(&ctype[j][2], "LT", 2) == 0) {
+ wcs->lat = j;
+ sprintf(wcs->lngtyp, "%c%cLN", ctype[j][0], ctype[j][1]);
+ sprintf(wcs->lattyp, "%c%cLT", ctype[j][0], ctype[j][1]);
+ ndx = &wcs->lng;
+ sprintf(requir, "%s-%s", wcs->lngtyp, wcs->pcode);
+ } else {
+ /* Unrecognized celestial type. */
+ return 1;
+ }
+ } else {
+ if (strncmp(ctype[j], requir, 8) != 0) {
+ /* Inconsistent projection types. */
+ return 1;
+ }
+
+ if (ndx == NULL)
+ return 1;
+ *ndx = j;
+ strcpy(requir, "");
+ }
+ }
+
+ if (strcmp(requir, "")) {
+ /* Unmatched celestial axis. */
+ return 1;
+ }
+
+ /* Do simple alias translations. */
+ if (strncmp(wcs->pcode, "GLS", 3) == 0) {
+ strcpy(wcs->pcode, "SFL");
+ }
+
+ if (strcmp(wcs->pcode, "")) {
+ wcs->flag = WCSSET;
+ } else {
+ /* Signal for no celestial axis pair. */
+ wcs->flag = 999;
+ }
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int
+wcsfwd(ctype, wcs, world, crval, cel, phi, theta, prj, imgcrd, lin, pixcrd)
+
+const char ctype[][9];
+struct wcsprm* wcs;
+const double world[];
+const double crval[];
+struct celprm *cel;
+double *phi, *theta;
+struct prjprm *prj;
+double imgcrd[];
+struct linprm *lin;
+double pixcrd[];
+
+{
+ int err, j;
+ double offset;
+
+ /* Initialize if required. */
+ if (wcs->flag != WCSSET) {
+ if (wcsset(lin->naxis, ctype, wcs)) return 1;
+ }
+
+ /* Convert to relative physical coordinates. */
+ for (j = 0; j < lin->naxis; j++) {
+ if (j == wcs->lng) continue;
+ if (j == wcs->lat) continue;
+ imgcrd[j] = world[j] - crval[j];
+ }
+
+ if (wcs->flag != 999) {
+ /* Compute projected coordinates. */
+ if (strcmp(wcs->pcode, "NCP") == 0) {
+ /* Convert NCP to SIN. */
+ if (cel->ref[1] == 0.0) {
+ return 2;
+ }
+
+ strcpy(wcs->pcode, "SIN");
+ prj->p[1] = 0.0;
+ prj->p[2] = cosdeg (cel->ref[1])/sindeg (cel->ref[1]);
+ prj->flag = (prj->flag < 0) ? -1 : 0;
+ }
+
+ if ((err = celfwd(wcs->pcode, world[wcs->lng], world[wcs->lat], cel,
+ phi, theta, prj, &imgcrd[wcs->lng], &imgcrd[wcs->lat]))) {
+ return err;
+ }
+
+ /* Do we have a CUBEFACE axis? */
+ if (wcs->cubeface != -1) {
+ /* Separation between faces. */
+ if (prj->r0 == 0.0) {
+ offset = 90.0;
+ } else {
+ offset = prj->r0*PI/2.0;
+ }
+
+ /* Stack faces in a cube. */
+ if (imgcrd[wcs->lat] < -0.5*offset) {
+ imgcrd[wcs->lat] += offset;
+ imgcrd[wcs->cubeface] = 5.0;
+ } else if (imgcrd[wcs->lat] > 0.5*offset) {
+ imgcrd[wcs->lat] -= offset;
+ imgcrd[wcs->cubeface] = 0.0;
+ } else if (imgcrd[wcs->lng] > 2.5*offset) {
+ imgcrd[wcs->lng] -= 3.0*offset;
+ imgcrd[wcs->cubeface] = 4.0;
+ } else if (imgcrd[wcs->lng] > 1.5*offset) {
+ imgcrd[wcs->lng] -= 2.0*offset;
+ imgcrd[wcs->cubeface] = 3.0;
+ } else if (imgcrd[wcs->lng] > 0.5*offset) {
+ imgcrd[wcs->lng] -= offset;
+ imgcrd[wcs->cubeface] = 2.0;
+ } else {
+ imgcrd[wcs->cubeface] = 1.0;
+ }
+ }
+ }
+
+ /* Apply forward linear transformation. */
+ if (linfwd(imgcrd, lin, pixcrd)) {
+ return 4;
+ }
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int
+wcsrev(ctype, wcs, pixcrd, lin, imgcrd, prj, phi, theta, crval, cel, world)
+
+const char ctype[][9];
+struct wcsprm *wcs;
+const double pixcrd[];
+struct linprm *lin;
+double imgcrd[];
+struct prjprm *prj;
+double *phi, *theta;
+const double crval[];
+struct celprm *cel;
+double world[];
+
+{
+ int err, face, j;
+ double offset;
+
+ /* Initialize if required. */
+ if (wcs->flag != WCSSET) {
+ if (wcsset(lin->naxis, ctype, wcs)) return 1;
+ }
+
+ /* Apply reverse linear transformation. */
+ if (linrev(pixcrd, lin, imgcrd)) {
+ return 4;
+ }
+
+ /* Convert to world coordinates. */
+ for (j = 0; j < lin->naxis; j++) {
+ if (j == wcs->lng) continue;
+ if (j == wcs->lat) continue;
+ world[j] = imgcrd[j] + crval[j];
+ }
+
+
+ if (wcs->flag != 999) {
+ /* Do we have a CUBEFACE axis? */
+ if (wcs->cubeface != -1) {
+ face = (int)(imgcrd[wcs->cubeface] + 0.5);
+ if (fabs(imgcrd[wcs->cubeface]-face) > 1e-10) {
+ return 3;
+ }
+
+ /* Separation between faces. */
+ if (prj->r0 == 0.0) {
+ offset = 90.0;
+ } else {
+ offset = prj->r0*PI/2.0;
+ }
+
+ /* Lay out faces in a plane. */
+ switch (face) {
+ case 0:
+ imgcrd[wcs->lat] += offset;
+ break;
+ case 1:
+ break;
+ case 2:
+ imgcrd[wcs->lng] += offset;
+ break;
+ case 3:
+ imgcrd[wcs->lng] += offset*2;
+ break;
+ case 4:
+ imgcrd[wcs->lng] += offset*3;
+ break;
+ case 5:
+ imgcrd[wcs->lat] -= offset;
+ break;
+ default:
+ return 3;
+ }
+ }
+
+ /* Compute celestial coordinates. */
+ if (strcmp(wcs->pcode, "NCP") == 0) {
+ /* Convert NCP to SIN. */
+ if (cel->ref[1] == 0.0) {
+ return 2;
+ }
+
+ strcpy(wcs->pcode, "SIN");
+ prj->p[1] = 0.0;
+ prj->p[2] = cosdeg (cel->ref[1])/sindeg (cel->ref[1]);
+ prj->flag = (prj->flag < 0) ? -1 : 0;
+ }
+
+ if ((err = celrev(wcs->pcode, imgcrd[wcs->lng], imgcrd[wcs->lat], prj,
+ phi, theta, cel, &world[wcs->lng], &world[wcs->lat]))) {
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int
+wcsmix(ctype, wcs, mixpix, mixcel, vspan, vstep, viter, world, crval, cel,
+ phi, theta, prj, imgcrd, lin, pixcrd)
+
+const char ctype[][9];
+struct wcsprm *wcs;
+const int mixpix, mixcel;
+const double vspan[2], vstep;
+int viter;
+double world[];
+const double crval[];
+struct celprm *cel;
+double *phi, *theta;
+struct prjprm *prj;
+double imgcrd[];
+struct linprm *lin;
+double pixcrd[];
+
+{
+ const int niter = 60;
+ int crossed, err, istep, iter, j, k, nstep, retry;
+ const double tol = 1.0e-10;
+ const double tol2 = 100.0*tol;
+ double lambda, span[2], step;
+ double pixmix;
+ double dlng, lng, lng0, lng0m, lng1, lng1m;
+ double dlat, lat, lat0, lat0m, lat1, lat1m;
+ double d, d0, d0m, d1, d1m;
+ double dx = 0.0;
+ double dabs, dmin, lmin;
+ double dphi, phi0, phi1;
+ struct celprm cel0;
+
+ /* Initialize if required. */
+ if (wcs->flag != WCSSET) {
+ if (wcsset(lin->naxis, ctype, wcs)) return 1;
+ }
+
+ /* Check vspan. */
+ if (vspan[0] <= vspan[1]) {
+ span[0] = vspan[0];
+ span[1] = vspan[1];
+ } else {
+ /* Swap them. */
+ span[0] = vspan[1];
+ span[1] = vspan[0];
+ }
+
+ /* Check vstep. */
+ step = fabs(vstep);
+ if (step == 0.0) {
+ step = (span[1] - span[0])/10.0;
+ if (step > 1.0 || step == 0.0) step = 1.0;
+ }
+
+ /* Check viter. */
+ nstep = viter;
+ if (nstep < 5) {
+ nstep = 5;
+ } else if (nstep > 10) {
+ nstep = 10;
+ }
+
+ /* Given pixel element. */
+ pixmix = pixcrd[mixpix];
+
+ /* Iterate on the step size. */
+ for (istep = 0; istep <= nstep; istep++) {
+ if (istep) step /= 2.0;
+
+ /* Iterate on the sky coordinate between the specified range. */
+ if (mixcel == 1) {
+ /* Celestial longitude is given. */
+
+ /* Check whether the solution interval is a crossing interval. */
+ lat0 = span[0];
+ world[wcs->lat] = lat0;
+ if ((err = wcsfwd(ctype, wcs, world, crval, cel, phi, theta, prj,
+ imgcrd, lin, pixcrd))) {
+ return err;
+ }
+ d0 = pixcrd[mixpix] - pixmix;
+
+ dabs = fabs(d0);
+ if (dabs < tol) return 0;
+
+ lat1 = span[1];
+ world[wcs->lat] = lat1;
+ if ((err = wcsfwd(ctype, wcs, world, crval, cel, phi, theta, prj,
+ imgcrd, lin, pixcrd))) {
+ return err;
+ }
+ d1 = pixcrd[mixpix] - pixmix;
+
+ dabs = fabs(d1);
+ if (dabs < tol) return 0;
+
+ lmin = lat1;
+ dmin = dabs;
+
+ /* Check for a crossing point. */
+ if (signb(d0) != signb(d1)) {
+ crossed = 1;
+ dx = d1;
+ } else {
+ crossed = 0;
+ lat0 = span[1];
+ }
+
+ for (retry = 0; retry < 4; retry++) {
+ /* Refine the solution interval. */
+ while (lat0 > span[0]) {
+ lat0 -= step;
+ if (lat0 < span[0]) lat0 = span[0];
+ world[wcs->lat] = lat0;
+ if ((err = wcsfwd(ctype, wcs, world, crval, cel, phi, theta,
+ prj, imgcrd, lin, pixcrd))) {
+ return err;
+ }
+ d0 = pixcrd[mixpix] - pixmix;
+
+ /* Check for a solution. */
+ dabs = fabs(d0);
+ if (dabs < tol) return 0;
+
+ /* Record the point of closest approach. */
+ if (dabs < dmin) {
+ lmin = lat0;
+ dmin = dabs;
+ }
+
+ /* Check for a crossing point. */
+ if (signb(d0) != signb(d1)) {
+ crossed = 2;
+ dx = d0;
+ break;
+ }
+
+ /* Advance to the next subinterval. */
+ lat1 = lat0;
+ d1 = d0;
+ }
+
+ if (crossed) {
+ /* A crossing point was found. */
+ for (iter = 0; iter < niter; iter++) {
+ /* Use regula falsi division of the interval. */
+ lambda = d0/(d0-d1);
+ if (lambda < 0.1) {
+ lambda = 0.1;
+ } else if (lambda > 0.9) {
+ lambda = 0.9;
+ }
+
+ dlat = lat1 - lat0;
+ lat = lat0 + lambda*dlat;
+ world[wcs->lat] = lat;
+ if ((err = wcsfwd(ctype, wcs, world, crval, cel, phi, theta,
+ prj, imgcrd, lin, pixcrd))) {
+ return err;
+ }
+
+ /* Check for a solution. */
+ d = pixcrd[mixpix] - pixmix;
+ dabs = fabs(d);
+ if (dabs < tol) return 0;
+
+ if (dlat < tol) {
+ /* An artifact of numerical imprecision. */
+ if (dabs < tol2) return 0;
+
+ /* Must be a discontinuity. */
+ break;
+ }
+
+ /* Record the point of closest approach. */
+ if (dabs < dmin) {
+ lmin = lat;
+ dmin = dabs;
+ }
+
+ if (signb(d0) == signb(d)) {
+ lat0 = lat;
+ d0 = d;
+ } else {
+ lat1 = lat;
+ d1 = d;
+ }
+ }
+
+ /* No convergence, must have been a discontinuity. */
+ if (crossed == 1) lat0 = span[1];
+ lat1 = lat0;
+ d1 = dx;
+ crossed = 0;
+
+ } else {
+ /* No crossing point; look for a tangent point. */
+ if (lmin == span[0]) break;
+ if (lmin == span[1]) break;
+
+ lat = lmin;
+ lat0 = lat - step;
+ if (lat0 < span[0]) lat0 = span[0];
+ lat1 = lat + step;
+ if (lat1 > span[1]) lat1 = span[1];
+
+ world[wcs->lat] = lat0;
+ if ((err = wcsfwd(ctype, wcs, world, crval, cel, phi, theta,
+ prj, imgcrd, lin, pixcrd))) {
+ return err;
+ }
+ d0 = fabs(pixcrd[mixpix] - pixmix);
+
+ d = dmin;
+
+ world[wcs->lat] = lat1;
+ if ((err = wcsfwd(ctype, wcs, world, crval, cel, phi, theta,
+ prj, imgcrd, lin, pixcrd))) {
+ return err;
+ }
+ d1 = fabs(pixcrd[mixpix] - pixmix);
+
+ for (iter = 0; iter < niter; iter++) {
+ lat0m = (lat0 + lat)/2.0;
+ world[wcs->lat] = lat0m;
+ if ((err = wcsfwd(ctype, wcs, world, crval, cel, phi, theta,
+ prj, imgcrd, lin, pixcrd))) {
+ return err;
+ }
+ d0m = fabs(pixcrd[mixpix] - pixmix);
+
+ if (d0m < tol) return 0;
+
+ lat1m = (lat1 + lat)/2.0;
+ world[wcs->lat] = lat1m;
+ if ((err = wcsfwd(ctype, wcs, world, crval, cel, phi, theta,
+ prj, imgcrd, lin, pixcrd))) {
+ return err;
+ }
+ d1m = fabs(pixcrd[mixpix] - pixmix);
+
+ if (d1m < tol) return 0;
+
+ if (d0m < d && d0m <= d1m) {
+ lat1 = lat;
+ d1 = d;
+ lat = lat0m;
+ d = d0m;
+ } else if (d1m < d) {
+ lat0 = lat;
+ d0 = d;
+ lat = lat1m;
+ d = d1m;
+ } else {
+ lat0 = lat0m;
+ d0 = d0m;
+ lat1 = lat1m;
+ d1 = d1m;
+ }
+ }
+ }
+ }
+
+ } else {
+ /* Celestial latitude is given. */
+
+ /* Check whether the solution interval is a crossing interval. */
+ lng0 = span[0];
+ world[wcs->lng] = lng0;
+ if ((err = wcsfwd(ctype, wcs, world, crval, cel, phi, theta, prj,
+ imgcrd, lin, pixcrd))) {
+ return err;
+ }
+ d0 = pixcrd[mixpix] - pixmix;
+
+ dabs = fabs(d0);
+ if (dabs < tol) return 0;
+
+ lng1 = span[1];
+ world[wcs->lng] = lng1;
+ if ((err = wcsfwd(ctype, wcs, world, crval, cel, phi, theta, prj,
+ imgcrd, lin, pixcrd))) {
+ return err;
+ }
+ d1 = pixcrd[mixpix] - pixmix;
+
+ dabs = fabs(d1);
+ if (dabs < tol) return 0;
+ lmin = lng1;
+ dmin = dabs;
+
+ /* Check for a crossing point. */
+ if (signb(d0) != signb(d1)) {
+ crossed = 1;
+ dx = d1;
+ } else {
+ crossed = 0;
+ lng0 = span[1];
+ }
+
+ for (retry = 0; retry < 4; retry++) {
+ /* Refine the solution interval. */
+ while (lng0 > span[0]) {
+ lng0 -= step;
+ if (lng0 < span[0]) lng0 = span[0];
+ world[wcs->lng] = lng0;
+ if ((err = wcsfwd(ctype, wcs, world, crval, cel, phi, theta,
+ prj, imgcrd, lin, pixcrd))) {
+ return err;
+ }
+ d0 = pixcrd[mixpix] - pixmix;
+
+ /* Check for a solution. */
+ dabs = fabs(d0);
+ if (dabs < tol) return 0;
+
+ /* Record the point of closest approach. */
+ if (dabs < dmin) {
+ lmin = lng0;
+ dmin = dabs;
+ }
+
+ /* Check for a crossing point. */
+ if (signb(d0) != signb(d1)) {
+ crossed = 2;
+ dx = d0;
+ break;
+ }
+
+ /* Advance to the next subinterval. */
+ lng1 = lng0;
+ d1 = d0;
+ }
+
+ if (crossed) {
+ /* A crossing point was found. */
+ for (iter = 0; iter < niter; iter++) {
+ /* Use regula falsi division of the interval. */
+ lambda = d0/(d0-d1);
+ if (lambda < 0.1) {
+ lambda = 0.1;
+ } else if (lambda > 0.9) {
+ lambda = 0.9;
+ }
+
+ dlng = lng1 - lng0;
+ lng = lng0 + lambda*dlng;
+ world[wcs->lng] = lng;
+ if ((err = wcsfwd(ctype, wcs, world, crval, cel, phi, theta,
+ prj, imgcrd, lin, pixcrd))) {
+ return err;
+ }
+
+ /* Check for a solution. */
+ d = pixcrd[mixpix] - pixmix;
+ dabs = fabs(d);
+ if (dabs < tol) return 0;
+
+ if (dlng < tol) {
+ /* An artifact of numerical imprecision. */
+ if (dabs < tol2) return 0;
+
+ /* Must be a discontinuity. */
+ break;
+ }
+
+ /* Record the point of closest approach. */
+ if (dabs < dmin) {
+ lmin = lng;
+ dmin = dabs;
+ }
+
+ if (signb(d0) == signb(d)) {
+ lng0 = lng;
+ d0 = d;
+ } else {
+ lng1 = lng;
+ d1 = d;
+ }
+ }
+
+ /* No convergence, must have been a discontinuity. */
+ if (crossed == 1) lng0 = span[1];
+ lng1 = lng0;
+ d1 = dx;
+ crossed = 0;
+
+ } else {
+ /* No crossing point; look for a tangent point. */
+ if (lmin == span[0]) break;
+ if (lmin == span[1]) break;
+
+ lng = lmin;
+ lng0 = lng - step;
+ if (lng0 < span[0]) lng0 = span[0];
+ lng1 = lng + step;
+ if (lng1 > span[1]) lng1 = span[1];
+
+ world[wcs->lng] = lng0;
+ if ((err = wcsfwd(ctype, wcs, world, crval, cel, phi, theta,
+ prj, imgcrd, lin, pixcrd))) {
+ return err;
+ }
+ d0 = fabs(pixcrd[mixpix] - pixmix);
+
+ d = dmin;
+
+ world[wcs->lng] = lng1;
+ if ((err = wcsfwd(ctype, wcs, world, crval, cel, phi, theta,
+ prj, imgcrd, lin, pixcrd))) {
+ return err;
+ }
+ d1 = fabs(pixcrd[mixpix] - pixmix);
+
+ for (iter = 0; iter < niter; iter++) {
+ lng0m = (lng0 + lng)/2.0;
+ world[wcs->lng] = lng0m;
+ if ((err = wcsfwd(ctype, wcs, world, crval, cel, phi, theta,
+ prj, imgcrd, lin, pixcrd))) {
+ return err;
+ }
+ d0m = fabs(pixcrd[mixpix] - pixmix);
+
+ if (d0m < tol) return 0;
+
+ lng1m = (lng1 + lng)/2.0;
+ world[wcs->lng] = lng1m;
+ if ((err = wcsfwd(ctype, wcs, world, crval, cel, phi, theta,
+ prj, imgcrd, lin, pixcrd))) {
+ return err;
+ }
+ d1m = fabs(pixcrd[mixpix] - pixmix);
+
+ if (d1m < tol) return 0;
+
+ if (d0m < d && d0m <= d1m) {
+ lng1 = lng;
+ d1 = d;
+ lng = lng0m;
+ d = d0m;
+ } else if (d1m < d) {
+ lng0 = lng;
+ d0 = d;
+ lng = lng1m;
+ d = d1m;
+ } else {
+ lng0 = lng0m;
+ d0 = d0m;
+ lng1 = lng1m;
+ d1 = d1m;
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+ /* Set cel0 to the unity transformation. */
+ cel0.flag = CELSET;
+ cel0.ref[0] = cel->ref[0];
+ cel0.ref[1] = cel->ref[1];
+ cel0.ref[2] = cel->ref[2];
+ cel0.ref[3] = cel->ref[3];
+ cel0.euler[0] = -90.0;
+ cel0.euler[1] = 0.0;
+ cel0.euler[2] = 90.0;
+ cel0.euler[3] = 1.0;
+ cel0.euler[4] = 0.0;
+
+ /* No convergence, check for aberrant behaviour at a native pole. */
+ *theta = -90.0;
+ for (j = 1; j <= 2; j++) {
+ /* Could the celestial coordinate element map to a native pole? */
+ *theta = -*theta;
+ err = sphrev(0.0, *theta, cel->euler, &lng, &lat);
+
+ if (mixcel == 1) {
+ if (fabs(fmod(world[wcs->lng]-lng,360.0)) > tol) continue;
+ if (lat < span[0]) continue;
+ if (lat > span[1]) continue;
+ world[wcs->lat] = lat;
+ } else {
+ if (fabs(world[wcs->lat]-lat) > tol) continue;
+ if (lng < span[0]) lng += 360.0;
+ if (lng > span[1]) lng -= 360.0;
+ if (lng < span[0]) continue;
+ if (lng > span[1]) continue;
+ world[wcs->lng] = lng;
+ }
+
+ /* Is there a solution for the given pixel coordinate element? */
+ lng = world[wcs->lng];
+ lat = world[wcs->lat];
+
+ /* Feed native coordinates to wcsfwd() with cel0 set to unity. */
+ world[wcs->lng] = -180.0;
+ world[wcs->lat] = *theta;
+ if ((err = wcsfwd(ctype, wcs, world, crval, &cel0, phi, theta, prj,
+ imgcrd, lin, pixcrd))) {
+ return err;
+ }
+ d0 = pixcrd[mixpix] - pixmix;
+
+ /* Check for a solution. */
+ if (fabs(d0) < tol) {
+ /* Recall saved world coordinates. */
+ world[wcs->lng] = lng;
+ world[wcs->lat] = lat;
+ return 0;
+ }
+
+ /* Search for a crossing interval. */
+ phi0 = -180.0;
+ for (k = -179; k <= 180; k++) {
+ phi1 = (double) k;
+ world[wcs->lng] = phi1;
+ if ((err = wcsfwd(ctype, wcs, world, crval, &cel0, phi, theta, prj,
+ imgcrd, lin, pixcrd))) {
+ return err;
+ }
+ d1 = pixcrd[mixpix] - pixmix;
+
+ /* Check for a solution. */
+ dabs = fabs(d1);
+ if (dabs < tol) {
+ /* Recall saved world coordinates. */
+ world[wcs->lng] = lng;
+ world[wcs->lat] = lat;
+ return 0;
+ }
+
+ /* Is it a crossing interval? */
+ if (signb(d0) != signb(d1)) break;
+
+ phi0 = phi1;
+ d0 = d1;
+ }
+
+ for (iter = 1; iter <= niter; iter++) {
+ /* Use regula falsi division of the interval. */
+ lambda = d0/(d0-d1);
+ if (lambda < 0.1) {
+ lambda = 0.1;
+ } else if (lambda > 0.9) {
+ lambda = 0.9;
+ }
+
+ dphi = phi1 - phi0;
+ world[wcs->lng] = phi0 + lambda*dphi;
+ if ((err = wcsfwd(ctype, wcs, world, crval, &cel0, phi, theta, prj,
+ imgcrd, lin, pixcrd))) {
+ return err;
+ }
+
+ /* Check for a solution. */
+ d = pixcrd[mixpix] - pixmix;
+ dabs = fabs(d);
+ if (dabs < tol || (dphi < tol && dabs < tol2)) {
+ /* Recall saved world coordinates. */
+ world[wcs->lng] = lng;
+ world[wcs->lat] = lat;
+ return 0;
+ }
+
+ if (signb(d0) == signb(d)) {
+ phi0 = world[wcs->lng];
+ d0 = d;
+ } else {
+ phi1 = world[wcs->lng];
+ d1 = d;
+ }
+ }
+ }
+
+
+ /* No solution. */
+ return 5;
+
+}
+/* Dec 20 1999 Doug Mink - Change signbit() to signb() and always define it
+ * Dec 20 1999 Doug Mink - Include wcslib.h, which includes wcs.h, wcstrig.h
+ *
+ * Mar 20 2001 Doug Mink - Include stdio.h for sprintf()
+ * Mar 20 2001 Doug Mink - Add () around err assignments in if statements
+ * Sep 19 2001 Doug Mink - Add above changes to WCSLIB-2.7 version
+ *
+ * Mar 15 2002 Doug Mink - Add above changes to WCSLIB-2.8.2
+ * Apr 3 2002 Mark Calabretta - Fix bug in code checking section
+ *
+ * Jun 20 2006 Doug Mink - Initialized uninitialized variables
+ */
diff --git a/funtools/wcs/wcslib.h b/funtools/wcs/wcslib.h
new file mode 100644
index 0000000..75b6ec6
--- /dev/null
+++ b/funtools/wcs/wcslib.h
@@ -0,0 +1,476 @@
+#ifndef wcslib_h_
+#define wcslib_h_
+
+/*=============================================================================
+*
+* WCSLIB - an implementation of the FITS WCS proposal.
+* Copyright (C) 1995-2002, Mark Calabretta
+*
+* This library 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 2 of the License, or (at your option) any later version.
+*
+* This library 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 this library; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*
+* Correspondence concerning WCSLIB may be directed to:
+* Internet email: mcalabre@atnf.csiro.au
+* Postal address: Dr. Mark Calabretta,
+* Australia Telescope National Facility,
+* P.O. Box 76,
+* Epping, NSW, 2121,
+* AUSTRALIA
+*
+* Author: Mark Calabretta, Australia Telescope National Facility
+* $Id: wcs.h,v 2.9 2002/04/03 01:25:29 mcalabre Exp $
+*===========================================================================*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if !defined(__STDC__) && !defined(__cplusplus)
+#ifndef const
+#define const
+#endif
+#endif
+
+#define MAXPV 100
+
+#define WCS_NGRIDPOINTS 12 /* Number of WCS grid points / axis */
+#define WCS_NGRIDPOINTS2 (WCS_NGRIDPOINTS*WCS_NGRIDPOINTS)
+#define WCS_INVMAXDEG 9 /* Maximum inversion polynom degree */
+#define WCS_INVACCURACY 0.04 /* Maximum inversion error (pixels) */
+#define WCS_NRANGEPOINTS 32 /* Number of WCS range points / axis */
+#ifndef PI
+#define PI 3.1415926535898 /* never met before? */
+#endif
+/* DEG/ARCSEC is now D2S and ARCSEC/DEG is S2D */
+/* #define DEG (PI/180.0) 1 deg in radians */
+/* #define ARCSEC (DEG/3600.0) 1 arcsec in radians */
+#define NAXISPV 2
+
+/* poly.h
+*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+* Part of: A program using polynomial fits
+* Author: E.BERTIN (IAP)
+* Contents: Include for poly.c
+* Last modified: 03/03/2004
+*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+*/
+
+#ifndef _POLY_H_
+#define _POLY_H_
+
+/*--------------------------------- constants -------------------------------*/
+
+#define POLY_MAXDIM 4 /* Max dimensionality of polynom */
+#define POLY_MAXDEGREE 10 /* Max degree of the polynom */
+
+/*---------------------------------- macros ---------------------------------*/
+
+/*--------------------------- structure definitions -------------------------*/
+
+typedef struct poly
+ {
+ double *basis; /* Current values of the basis functions */
+ double *coeff; /* Polynom coefficients */
+ int ncoeff; /* Number of coefficients */
+ int *group; /* Groups */
+ int ndim; /* dimensionality of the polynom */
+ int *degree; /* Degree in each group */
+ int ngroup; /* Number of different groups */
+ } polystruct;
+
+/*---------------------------------- protos --------------------------------*/
+
+extern polystruct *poly_init(int *group,int ndim,int *degree,int ngroup);
+
+extern double poly_func(polystruct *poly, double *pos);
+
+extern int cholsolve(double *a, double *b, int n),
+ *poly_powers(polystruct *poly);
+
+extern void poly_addcste(polystruct *poly, double *cste),
+ poly_end(polystruct *poly),
+ poly_fit(polystruct *poly, double *x, double *y,
+ double *w, int ndata, double *extbasis),
+ poly_solve(double *a, double *b, int n),
+ svdsolve(double *a, double *b, int m, int n,
+ double *vmat, double *wmat);
+
+#endif
+
+extern int npcode;
+extern char pcodes[26][4];
+
+struct prjprm {
+ char code[4];
+ int flag;
+ double phi0, theta0;
+ double r0;
+ double p[10];
+ double w[20];
+ int n;
+ int npv;
+ double ppv[2*MAXPV];
+ struct poly *inv_x;
+ struct poly *inv_y;
+
+#if __STDC__ || defined(__cplusplus)
+ int (*prjfwd)(const double, const double,
+ struct prjprm *,
+ double *, double *);
+ int (*prjrev)(const double, const double,
+ struct prjprm *,
+ double *, double *);
+#else
+ int (*prjfwd)();
+ int (*prjrev)();
+#endif
+};
+
+#if __STDC__ || defined(__cplusplus)
+ int prjset(const char [], struct prjprm *);
+ int prjfwd(const double, const double, struct prjprm *, double *, double *);
+ int prjrev(const double, const double, struct prjprm *, double *, double *);
+ int azpset(struct prjprm *);
+ int azpfwd(const double, const double, struct prjprm *, double *, double *);
+ int azprev(const double, const double, struct prjprm *, double *, double *);
+ int szpset(struct prjprm *);
+ int szpfwd(const double, const double, struct prjprm *, double *, double *);
+ int szprev(const double, const double, struct prjprm *, double *, double *);
+ int tanset(struct prjprm *);
+ int tanfwd(const double, const double, struct prjprm *, double *, double *);
+ int tanrev(const double, const double, struct prjprm *, double *, double *);
+ int stgset(struct prjprm *);
+ int stgfwd(const double, const double, struct prjprm *, double *, double *);
+ int stgrev(const double, const double, struct prjprm *, double *, double *);
+ int sinset(struct prjprm *);
+ int sinfwd(const double, const double, struct prjprm *, double *, double *);
+ int sinrev(const double, const double, struct prjprm *, double *, double *);
+ int arcset(struct prjprm *);
+ int arcfwd(const double, const double, struct prjprm *, double *, double *);
+ int arcrev(const double, const double, struct prjprm *, double *, double *);
+ int zpnset(struct prjprm *);
+ int zpnfwd(const double, const double, struct prjprm *, double *, double *);
+ int zpnrev(const double, const double, struct prjprm *, double *, double *);
+ int zeaset(struct prjprm *);
+ int zeafwd(const double, const double, struct prjprm *, double *, double *);
+ int zearev(const double, const double, struct prjprm *, double *, double *);
+ int airset(struct prjprm *);
+ int airfwd(const double, const double, struct prjprm *, double *, double *);
+ int airrev(const double, const double, struct prjprm *, double *, double *);
+ int cypset(struct prjprm *);
+ int cypfwd(const double, const double, struct prjprm *, double *, double *);
+ int cyprev(const double, const double, struct prjprm *, double *, double *);
+ int ceaset(struct prjprm *);
+ int ceafwd(const double, const double, struct prjprm *, double *, double *);
+ int cearev(const double, const double, struct prjprm *, double *, double *);
+ int carset(struct prjprm *);
+ int carfwd(const double, const double, struct prjprm *, double *, double *);
+ int carrev(const double, const double, struct prjprm *, double *, double *);
+ int merset(struct prjprm *);
+ int merfwd(const double, const double, struct prjprm *, double *, double *);
+ int merrev(const double, const double, struct prjprm *, double *, double *);
+ int sflset(struct prjprm *);
+ int sflfwd(const double, const double, struct prjprm *, double *, double *);
+ int sflrev(const double, const double, struct prjprm *, double *, double *);
+ int parset(struct prjprm *);
+ int parfwd(const double, const double, struct prjprm *, double *, double *);
+ int parrev(const double, const double, struct prjprm *, double *, double *);
+ int molset(struct prjprm *);
+ int molfwd(const double, const double, struct prjprm *, double *, double *);
+ int molrev(const double, const double, struct prjprm *, double *, double *);
+ int aitset(struct prjprm *);
+ int aitfwd(const double, const double, struct prjprm *, double *, double *);
+ int aitrev(const double, const double, struct prjprm *, double *, double *);
+ int copset(struct prjprm *);
+ int copfwd(const double, const double, struct prjprm *, double *, double *);
+ int coprev(const double, const double, struct prjprm *, double *, double *);
+ int coeset(struct prjprm *);
+ int coefwd(const double, const double, struct prjprm *, double *, double *);
+ int coerev(const double, const double, struct prjprm *, double *, double *);
+ int codset(struct prjprm *);
+ int codfwd(const double, const double, struct prjprm *, double *, double *);
+ int codrev(const double, const double, struct prjprm *, double *, double *);
+ int cooset(struct prjprm *);
+ int coofwd(const double, const double, struct prjprm *, double *, double *);
+ int coorev(const double, const double, struct prjprm *, double *, double *);
+ int bonset(struct prjprm *);
+ int bonfwd(const double, const double, struct prjprm *, double *, double *);
+ int bonrev(const double, const double, struct prjprm *, double *, double *);
+ int pcoset(struct prjprm *);
+ int pcofwd(const double, const double, struct prjprm *, double *, double *);
+ int pcorev(const double, const double, struct prjprm *, double *, double *);
+ int tscset(struct prjprm *);
+ int tscfwd(const double, const double, struct prjprm *, double *, double *);
+ int tscrev(const double, const double, struct prjprm *, double *, double *);
+ int cscset(struct prjprm *);
+ int cscfwd(const double, const double, struct prjprm *, double *, double *);
+ int cscrev(const double, const double, struct prjprm *, double *, double *);
+ int qscset(struct prjprm *);
+ int qscfwd(const double, const double, struct prjprm *, double *, double *);
+ int qscrev(const double, const double, struct prjprm *, double *, double *);
+ int raw_to_pv(struct prjprm *prj, double x, double y, double *xo, double *yo);
+#else
+ int prjset(), prjfwd(), prjrev();
+ int azpset(), azpfwd(), azprev();
+ int szpset(), szpfwd(), szprev();
+ int tanset(), tanfwd(), tanrev();
+ int stgset(), stgfwd(), stgrev();
+ int sinset(), sinfwd(), sinrev();
+ int arcset(), arcfwd(), arcrev();
+ int zpnset(), zpnfwd(), zpnrev();
+ int zeaset(), zeafwd(), zearev();
+ int airset(), airfwd(), airrev();
+ int cypset(), cypfwd(), cyprev();
+ int ceaset(), ceafwd(), cearev();
+ int carset(), carfwd(), carrev();
+ int merset(), merfwd(), merrev();
+ int sflset(), sflfwd(), sflrev();
+ int parset(), parfwd(), parrev();
+ int molset(), molfwd(), molrev();
+ int aitset(), aitfwd(), aitrev();
+ int copset(), copfwd(), coprev();
+ int coeset(), coefwd(), coerev();
+ int codset(), codfwd(), codrev();
+ int cooset(), coofwd(), coorev();
+ int bonset(), bonfwd(), bonrev();
+ int pcoset(), pcofwd(), pcorev();
+ int tscset(), tscfwd(), tscrev();
+ int cscset(), cscfwd(), cscrev();
+ int qscset(), qscfwd(), qscrev();
+ int raw_to_pv();
+#endif
+
+
+
+extern const char *prjset_errmsg[];
+extern const char *prjfwd_errmsg[];
+extern const char *prjrev_errmsg[];
+
+#define PRJSET 137
+
+struct celprm {
+ int flag;
+ double ref[4];
+ double euler[5];
+};
+
+#if __STDC__ || defined(__cplusplus)
+ int celset(const char *, struct celprm *, struct prjprm *);
+ int celfwd(const char *,
+ const double, const double,
+ struct celprm *,
+ double *, double *,
+ struct prjprm *,
+ double *, double *);
+ int celrev(const char *,
+ const double, const double,
+ struct prjprm *,
+ double *, double *,
+ struct celprm *,
+ double *, double *);
+#else
+ int celset(), celfwd(), celrev();
+#endif
+
+extern const char *celset_errmsg[];
+extern const char *celfwd_errmsg[];
+extern const char *celrev_errmsg[];
+
+#define CELSET 137
+
+struct linprm {
+ int flag;
+ int naxis;
+ double *crpix;
+ double *pc;
+ double *cdelt;
+
+ /* Intermediates. */
+ double *piximg;
+ double *imgpix;
+};
+
+#if __STDC__ || defined(__cplusplus)
+ int linset(struct linprm *);
+ int linfwd(const double[], struct linprm *, double[]);
+ int linrev(const double[], struct linprm *, double[]);
+ int matinv(const int, const double [], double []);
+#else
+ int linset(), linfwd(), linrev(), matinv();
+#endif
+
+extern const char *linset_errmsg[];
+extern const char *linfwd_errmsg[];
+extern const char *linrev_errmsg[];
+
+#define LINSET 137
+
+
+struct wcsprm {
+ int flag;
+ char pcode[4];
+ char lngtyp[5], lattyp[5];
+ int lng, lat;
+ int cubeface;
+};
+
+#if __STDC__ || defined(__cplusplus)
+ int wcsset(const int,
+ const char[][9],
+ struct wcsprm *);
+
+ int wcsfwd(const char[][9],
+ struct wcsprm *,
+ const double[],
+ const double[],
+ struct celprm *,
+ double *,
+ double *,
+ struct prjprm *,
+ double[],
+ struct linprm *,
+ double[]);
+
+ int wcsrev(const char[][9],
+ struct wcsprm *,
+ const double[],
+ struct linprm *,
+ double[],
+ struct prjprm *,
+ double *,
+ double *,
+ const double[],
+ struct celprm *,
+ double[]);
+
+ int wcsmix(const char[][9],
+ struct wcsprm *,
+ const int,
+ const int,
+ const double[],
+ const double,
+ int,
+ double[],
+ const double[],
+ struct celprm *,
+ double *,
+ double *,
+ struct prjprm *,
+ double[],
+ struct linprm *,
+ double[]);
+
+#else
+ int wcsset(), wcsfwd(), wcsrev(), wcsmix();
+#endif
+
+extern const char *wcsset_errmsg[];
+extern const char *wcsfwd_errmsg[];
+extern const char *wcsrev_errmsg[];
+extern const char *wcsmix_errmsg[];
+
+#define WCSSET 137
+
+
+#if __STDC__ || defined(__cplusplus)
+ int sphfwd(const double, const double,
+ const double [],
+ double *, double *);
+ int sphrev(const double, const double,
+ const double [],
+ double *, double *);
+#else
+ int sphfwd(), sphrev();
+#endif
+
+#ifdef PI
+#undef PI
+#endif
+
+#ifdef D2R
+#undef D2R
+#endif
+
+#ifdef R2D
+#undef R2D
+#endif
+
+#ifdef SQRT2
+#undef SQRT2
+#endif
+
+#ifdef SQRT2INV
+#undef SQRT2INV
+#endif
+
+#ifdef D2S
+#undef D2S
+#endif
+
+#ifdef S2D
+#undef S2D
+#endif
+
+#define PI 3.141592653589793238462643
+#define D2R PI/180.0
+#define R2D 180.0/PI
+#define S2D 1.0/3600.0
+#define D2S 3600.0
+#define SQRT2 1.4142135623730950488
+#define SQRT2INV 1.0/SQRT2
+
+#if !defined(__STDC__) && !defined(__cplusplus)
+#ifndef const
+#define const
+#endif
+#endif
+
+#if __STDC__ || defined(__cplusplus)
+ double cosdeg(const double);
+ double sindeg(const double);
+ double tandeg(const double);
+ double acosdeg(const double);
+ double asindeg(const double);
+ double atandeg(const double);
+ double atan2deg(const double, const double);
+#else
+ double cosdeg();
+ double sindeg();
+ double tandeg();
+ double acosdeg();
+ double asindeg();
+ double atandeg();
+ double atan2deg();
+#endif
+
+/* Domain tolerance for asin and acos functions. */
+#define WCSTRIG_TOL 1e-10
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* wcslib_h_ */
+
+/* Feb 3 2000 Doug Mink - Make cplusplus ifdefs for braces all-inclusive
+ *
+ * Feb 15 2001 Doug Mink - Undefine math constants if already defined
+ * Sep 19 2001 Doug Mink - Update for WCSLIB 2.7, especially proj.h and cel.h
+ *
+ * Mar 12 2002 Doug Mink - Update for WCSLIB 2.8.2, especially proj.h
+ * Nov 29 2006 Doug Mink - Drop semicolon at end of C++ ifdef
+ * Jan 4 2007 Doug Mink - Drop extra declarations of SZP subroutines
+ *
+ * Mar 30 2011 Doug Mink - Add raw_to_pv() subroutine for SCAMP from Ed Los
+ */
diff --git a/funtools/wcs/wcstrig.c b/funtools/wcs/wcstrig.c
new file mode 100644
index 0000000..6a30d03
--- /dev/null
+++ b/funtools/wcs/wcstrig.c
@@ -0,0 +1,189 @@
+/*============================================================================
+*
+* WCSLIB - an implementation of the FITS WCS proposal.
+* Copyright (C) 1995-2002, Mark Calabretta
+*
+* This library 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 2 of the License, or (at your option) any later version.
+*
+* This library 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 this library; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*
+* Correspondence concerning WCSLIB may be directed to:
+* Internet email: mcalabre@atnf.csiro.au
+* Postal address: Dr. Mark Calabretta,
+* Australia Telescope National Facility,
+* P.O. Box 76,
+* Epping, NSW, 2121,
+* AUSTRALIA
+*
+*=============================================================================
+*
+* The functions defined herein are trigonometric or inverse trigonometric
+* functions which take or return angular arguments in decimal degrees.
+*
+* $Id: wcstrig.c,v 2.8 2002/04/03 01:25:29 mcalabre Exp $
+*---------------------------------------------------------------------------*/
+
+#include <math.h>
+#include "wcslib.h"
+const double d2r = PI / 180.0;
+const double r2d = 180.0 / PI;
+
+
+double cosdeg (angle)
+
+const double angle;
+
+{
+ double resid;
+
+ resid = fabs(fmod(angle,360.0));
+ if (resid == 0.0) {
+ return 1.0;
+ } else if (resid == 90.0) {
+ return 0.0;
+ } else if (resid == 180.0) {
+ return -1.0;
+ } else if (resid == 270.0) {
+ return 0.0;
+ }
+
+ return cos(angle*d2r);
+}
+
+/*--------------------------------------------------------------------------*/
+
+double sindeg (angle)
+
+const double angle;
+
+{
+ double resid;
+
+ resid = fmod(angle-90.0,360.0);
+ if (resid == 0.0) {
+ return 1.0;
+ } else if (resid == 90.0) {
+ return 0.0;
+ } else if (resid == 180.0) {
+ return -1.0;
+ } else if (resid == 270.0) {
+ return 0.0;
+ }
+
+ return sin(angle*d2r);
+}
+
+/*--------------------------------------------------------------------------*/
+
+double tandeg (angle)
+
+const double angle;
+
+{
+ double resid;
+
+ resid = fmod(angle,360.0);
+ if (resid == 0.0 || fabs(resid) == 180.0) {
+ return 0.0;
+ } else if (resid == 45.0 || resid == 225.0) {
+ return 1.0;
+ } else if (resid == -135.0 || resid == -315.0) {
+ return -1.0;
+ }
+
+ return tan(angle*d2r);
+}
+
+/*--------------------------------------------------------------------------*/
+
+double acosdeg(v)
+
+const double v;
+
+{
+ if (v >= 1.0) {
+ if (v-1.0 < WCSTRIG_TOL) return 0.0;
+ } else if (v == 0.0) {
+ return 90.0;
+ } else if (v <= -1.0) {
+ if (v+1.0 > -WCSTRIG_TOL) return 180.0;
+ }
+
+ return acos(v)*r2d;
+}
+
+/*--------------------------------------------------------------------------*/
+
+double asindeg (v)
+
+const double v;
+
+{
+ if (v <= -1.0) {
+ if (v+1.0 > -WCSTRIG_TOL) return -90.0;
+ } else if (v == 0.0) {
+ return 0.0;
+ } else if (v >= 1.0) {
+ if (v-1.0 < WCSTRIG_TOL) return 90.0;
+ }
+
+ return asin(v)*r2d;
+}
+
+/*--------------------------------------------------------------------------*/
+
+double atandeg (v)
+
+const double v;
+
+{
+ if (v == -1.0) {
+ return -45.0;
+ } else if (v == 0.0) {
+ return 0.0;
+ } else if (v == 1.0) {
+ return 45.0;
+ }
+
+ return atan(v)*r2d;
+}
+
+/*--------------------------------------------------------------------------*/
+
+double atan2deg (y, x)
+
+const double x, y;
+
+{
+ if (y == 0.0) {
+ if (x >= 0.0) {
+ return 0.0;
+ } else if (x < 0.0) {
+ return 180.0;
+ }
+ } else if (x == 0.0) {
+ if (y > 0.0) {
+ return 90.0;
+ } else if (y < 0.0) {
+ return -90.0;
+ }
+ }
+
+ return atan2(y,x)*r2d;
+}
+/* Dec 20 1999 Doug Mink - Change cosd() and sind() to cosdeg() and sindeg()
+ * Dec 20 1999 Doug Mink - Include wcslib.h, which includes wcstrig.h
+ * Dec 20 1999 Doug Mink - Use PI from wcslib.h, not locally defined
+ *
+ * Sep 19 2001 Doug Mink - No change for WCSLIB 2.7
+ */
diff --git a/funtools/wcs/worldpos.c b/funtools/wcs/worldpos.c
new file mode 100644
index 0000000..8693789
--- /dev/null
+++ b/funtools/wcs/worldpos.c
@@ -0,0 +1,693 @@
+/* worldpos.c -- WCS Algorithms from Classic AIPS.
+ * September 1, 2011
+ * Copyright (C) 1994-2011
+ * Associated Universities, Inc. Washington DC, USA.
+ * With code added by Jessica Mink, Smithsonian Astrophysical Observatory
+ * and Allan Brighton and Andreas Wicenec, ESO
+ * and Frank Valdes, NOAO
+
+ * Module: worldpos.c
+ * Purpose: Perform forward and reverse WCS computations for 8 projections
+ * Subroutine: worldpos() converts from pixel location to RA,Dec
+ * Subroutine: worldpix() converts from RA,Dec to pixel location
+
+ -=-=-=-=-=-=-
+
+ This library 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 2 of the License, or (at your option) any later version.
+
+ This library 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 this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Correspondence concerning AIPS should be addressed as follows:
+ Internet email: aipsmail@nrao.edu
+ Postal address: AIPS Group
+ National Radio Astronomy Observatory
+ 520 Edgemont Road
+ Charlottesville, VA 22903-2475 USA
+
+ -=-=-=-=-=-=-
+
+ These two ANSI C functions, worldpos() and worldpix(), perform
+ forward and reverse WCS computations for 8 types of projective
+ geometries ("-SIN", "-TAN", "-ARC", "-NCP", "-GLS" or "-SFL", "-MER",
+ "-AIT", "-STG", "CAR", and "COE"):
+
+ worldpos() converts from pixel location to RA,Dec
+ worldpix() converts from RA,Dec to pixel location
+
+ where "(RA,Dec)" are more generically (long,lat). These functions
+ are based on the WCS implementation of Classic AIPS, an
+ implementation which has been in production use for more than ten
+ years. See the two memos by Eric Greisen
+
+ ftp://fits.cv.nrao.edu/fits/documents/wcs/aips27.ps.Z
+ ftp://fits.cv.nrao.edu/fits/documents/wcs/aips46.ps.Z
+
+ for descriptions of the 8 projective geometries and the
+ algorithms. Footnotes in these two documents describe the
+ differences between these algorithms and the 1993-94 WCS draft
+ proposal (see URL below). In particular, these algorithms support
+ ordinary field rotation, but not skew geometries (CD or PC matrix
+ cases). Also, the MER and AIT algorithms work correctly only for
+ CRVALi=(0,0). Users should note that GLS projections with yref!=0
+ will behave differently in this code than in the draft WCS
+ proposal. The NCP projection is now obsolete (it is a special
+ case of SIN). WCS syntax and semantics for various advanced
+ features is discussed in the draft WCS proposal by Greisen and
+ Calabretta at:
+
+ ftp://fits.cv.nrao.edu/fits/documents/wcs/wcs.all.ps.Z
+
+ -=-=-=-
+
+ The original version of this code was Emailed to D.Wells on
+ Friday, 23 September by Bill Cotton <bcotton@gorilla.cv.nrao.edu>,
+ who described it as a "..more or less.. exact translation from the
+ AIPSish..". Changes were made by Don Wells <dwells@nrao.edu>
+ during the period October 11-13, 1994:
+ 1) added GNU license and header comments
+ 2) added testpos.c program to perform extensive circularity tests
+ 3) changed float-->double to get more than 7 significant figures
+ 4) testpos.c circularity test failed on MER and AIT. B.Cotton
+ found that "..there were a couple of lines of code [in] the wrong
+ place as a result of merging several Fortran routines."
+ 5) testpos.c found 0h wraparound in worldpix() and worldpos().
+ 6) E.Greisen recommended removal of various redundant if-statements,
+ and addition of a 360d difference test to MER case of worldpos().
+ 7) D.Mink changed input to data structure and implemented rotation matrix.
+*/
+#include <math.h>
+#include <string.h>
+#include <stdio.h>
+#include "wcs.h"
+
+int
+worldpos (xpix, ypix, wcs, xpos, ypos)
+
+/* Routine to determine accurate position for pixel coordinates */
+/* returns 0 if successful otherwise 1 = angle too large for projection; */
+/* does: -SIN, -TAN, -ARC, -NCP, -GLS or -SFL, -MER, -AIT projections */
+/* anything else is linear */
+
+/* Input: */
+double xpix; /* x pixel number (RA or long without rotation) */
+double ypix; /* y pixel number (Dec or lat without rotation) */
+struct WorldCoor *wcs; /* WCS parameter structure */
+
+/* Output: */
+double *xpos; /* x (RA) coordinate (deg) */
+double *ypos; /* y (dec) coordinate (deg) */
+
+{
+ double cosr, sinr, dx, dy, dz, tx;
+ double sins, coss, dt, l, m, mg, da, dd, cos0, sin0;
+ double rat = 0.0;
+ double dect = 0.0;
+ double mt, a, y0, td, r2; /* allan: for COE */
+ double dec0, ra0, decout, raout;
+ double geo1, geo2, geo3;
+ double cond2r=1.745329252e-2;
+ double twopi = 6.28318530717959;
+ double deps = 1.0e-5;
+
+ /* Structure elements */
+ double xref; /* X reference coordinate value (deg) */
+ double yref; /* Y reference coordinate value (deg) */
+ double xrefpix; /* X reference pixel */
+ double yrefpix; /* Y reference pixel */
+ double xinc; /* X coordinate increment (deg) */
+ double yinc; /* Y coordinate increment (deg) */
+ double rot; /* Optical axis rotation (deg) (N through E) */
+ int itype = wcs->prjcode;
+
+ /* Set local projection parameters */
+ xref = wcs->xref;
+ yref = wcs->yref;
+ xrefpix = wcs->xrefpix;
+ yrefpix = wcs->yrefpix;
+ xinc = wcs->xinc;
+ yinc = wcs->yinc;
+ rot = degrad (wcs->rot);
+ cosr = cos (rot);
+ sinr = sin (rot);
+
+ /* Offset from ref pixel */
+ dx = xpix - xrefpix;
+ dy = ypix - yrefpix;
+
+ /* Scale and rotate using CD matrix */
+ if (wcs->rotmat) {
+ tx = dx * wcs->cd[0] + dy * wcs->cd[1];
+ dy = dx * wcs->cd[2] + dy * wcs->cd[3];
+ dx = tx;
+ }
+
+ /* Scale and rotate using CDELTn and CROTA2 */
+ else {
+
+ /* Check axis increments - bail out if either 0 */
+ if ((xinc==0.0) || (yinc==0.0)) {
+ *xpos=0.0;
+ *ypos=0.0;
+ return 2;
+ }
+
+ /* Scale using CDELT */
+ dx = dx * xinc;
+ dy = dy * yinc;
+
+ /* Take out rotation from CROTA */
+ if (rot != 0.0) {
+ tx = dx * cosr - dy * sinr;
+ dy = dx * sinr + dy * cosr;
+ dx = tx;
+ }
+ }
+
+ /* Flip coordinates if necessary */
+ if (wcs->coorflip) {
+ tx = dx;
+ dx = dy;
+ dy = tx;
+ }
+
+ /* Default, linear result for error or pixel return */
+ *xpos = xref + dx;
+ *ypos = yref + dy;
+ if (itype <= 0)
+ return 0;
+
+ /* Convert to radians */
+ if (wcs->coorflip) {
+ dec0 = degrad (xref);
+ ra0 = degrad (yref);
+ }
+ else {
+ ra0 = degrad (xref);
+ dec0 = degrad (yref);
+ }
+ l = degrad (dx);
+ m = degrad (dy);
+ sins = l*l + m*m;
+ decout = 0.0;
+ raout = 0.0;
+ cos0 = cos (dec0);
+ sin0 = sin (dec0);
+
+ /* Process by case */
+ switch (itype) {
+
+ case WCS_CAR: /* -CAR Cartesian (was WCS_PIX pixel and WCS_LIN linear) */
+ rat = ra0 + l;
+ dect = dec0 + m;
+ break;
+
+ case WCS_SIN: /* -SIN sin*/
+ if (sins>1.0) return 1;
+ coss = sqrt (1.0 - sins);
+ dt = sin0 * coss + cos0 * m;
+ if ((dt>1.0) || (dt<-1.0)) return 1;
+ dect = asin (dt);
+ rat = cos0 * coss - sin0 * m;
+ if ((rat==0.0) && (l==0.0)) return 1;
+ rat = atan2 (l, rat) + ra0;
+ break;
+
+ case WCS_TAN: /* -TAN tan */
+ case WCS_TNX: /* -TNX tan with polynomial correction */
+ case WCS_TPV: /* -TPV tan with polynomial correction */
+ case WCS_ZPX: /* -ZPX zpn with polynomial correction */
+ if (sins>1.0) return 1;
+ dect = cos0 - m * sin0;
+ if (dect==0.0) return 1;
+ rat = ra0 + atan2 (l, dect);
+ dect = atan (cos(rat-ra0) * (m * cos0 + sin0) / dect);
+ break;
+
+ case WCS_ARC: /* -ARC Arc*/
+ if (sins>=twopi*twopi/4.0) return 1;
+ sins = sqrt(sins);
+ coss = cos (sins);
+ if (sins!=0.0) sins = sin (sins) / sins;
+ else
+ sins = 1.0;
+ dt = m * cos0 * sins + sin0 * coss;
+ if ((dt>1.0) || (dt<-1.0)) return 1;
+ dect = asin (dt);
+ da = coss - dt * sin0;
+ dt = l * sins * cos0;
+ if ((da==0.0) && (dt==0.0)) return 1;
+ rat = ra0 + atan2 (dt, da);
+ break;
+
+ case WCS_NCP: /* -NCP North celestial pole*/
+ dect = cos0 - m * sin0;
+ if (dect==0.0) return 1;
+ rat = ra0 + atan2 (l, dect);
+ dt = cos (rat-ra0);
+ if (dt==0.0) return 1;
+ dect = dect / dt;
+ if ((dect>1.0) || (dect<-1.0)) return 1;
+ dect = acos (dect);
+ if (dec0<0.0) dect = -dect;
+ break;
+
+ case WCS_GLS: /* -GLS global sinusoid */
+ case WCS_SFL: /* -SFL Samson-Flamsteed */
+ dect = dec0 + m;
+ if (fabs(dect)>twopi/4.0) return 1;
+ coss = cos (dect);
+ if (fabs(l)>twopi*coss/2.0) return 1;
+ rat = ra0;
+ if (coss>deps) rat = rat + l / coss;
+ break;
+
+ case WCS_MER: /* -MER mercator*/
+ dt = yinc * cosr + xinc * sinr;
+ if (dt==0.0) dt = 1.0;
+ dy = degrad (yref/2.0 + 45.0);
+ dx = dy + dt / 2.0 * cond2r;
+ dy = log (tan (dy));
+ dx = log (tan (dx));
+ geo2 = degrad (dt) / (dx - dy);
+ geo3 = geo2 * dy;
+ geo1 = cos (degrad (yref));
+ if (geo1<=0.0) geo1 = 1.0;
+ rat = l / geo1 + ra0;
+ if (fabs(rat - ra0) > twopi) return 1; /* added 10/13/94 DCW/EWG */
+ dt = 0.0;
+ if (geo2!=0.0) dt = (m + geo3) / geo2;
+ dt = exp (dt);
+ dect = 2.0 * atan (dt) - twopi / 4.0;
+ break;
+
+ case WCS_AIT: /* -AIT Aitoff*/
+ dt = yinc*cosr + xinc*sinr;
+ if (dt==0.0) dt = 1.0;
+ dt = degrad (dt);
+ dy = degrad (yref);
+ dx = sin(dy+dt)/sqrt((1.0+cos(dy+dt))/2.0) -
+ sin(dy)/sqrt((1.0+cos(dy))/2.0);
+ if (dx==0.0) dx = 1.0;
+ geo2 = dt / dx;
+ dt = xinc*cosr - yinc* sinr;
+ if (dt==0.0) dt = 1.0;
+ dt = degrad (dt);
+ dx = 2.0 * cos(dy) * sin(dt/2.0);
+ if (dx==0.0) dx = 1.0;
+ geo1 = dt * sqrt((1.0+cos(dy)*cos(dt/2.0))/2.0) / dx;
+ geo3 = geo2 * sin(dy) / sqrt((1.0+cos(dy))/2.0);
+ rat = ra0;
+ dect = dec0;
+ if ((l==0.0) && (m==0.0)) break;
+ dz = 4.0 - l*l/(4.0*geo1*geo1) - ((m+geo3)/geo2)*((m+geo3)/geo2) ;
+ if ((dz>4.0) || (dz<2.0)) return 1;;
+ dz = 0.5 * sqrt (dz);
+ dd = (m+geo3) * dz / geo2;
+ if (fabs(dd)>1.0) return 1;;
+ dd = asin (dd);
+ if (fabs(cos(dd))<deps) return 1;;
+ da = l * dz / (2.0 * geo1 * cos(dd));
+ if (fabs(da)>1.0) return 1;;
+ da = asin (da);
+ rat = ra0 + 2.0 * da;
+ dect = dd;
+ break;
+
+ case WCS_STG: /* -STG Sterographic*/
+ dz = (4.0 - sins) / (4.0 + sins);
+ if (fabs(dz)>1.0) return 1;
+ dect = dz * sin0 + m * cos0 * (1.0+dz) / 2.0;
+ if (fabs(dect)>1.0) return 1;
+ dect = asin (dect);
+ rat = cos(dect);
+ if (fabs(rat)<deps) return 1;
+ rat = l * (1.0+dz) / (2.0 * rat);
+ if (fabs(rat)>1.0) return 1;
+ rat = asin (rat);
+ mg = 1.0 + sin(dect) * sin0 + cos(dect) * cos0 * cos(rat);
+ if (fabs(mg)<deps) return 1;
+ mg = 2.0 * (sin(dect) * cos0 - cos(dect) * sin0 * cos(rat)) / mg;
+ if (fabs(mg-m)>deps) rat = twopi/2.0 - rat;
+ rat = ra0 + rat;
+ break;
+
+ case WCS_COE: /* COE projection code from Andreas Wicenic, ESO */
+ td = tan (dec0);
+ y0 = 1.0 / td;
+ mt = y0 - m;
+ if (dec0 < 0.)
+ a = atan2 (l,-mt);
+ else
+ a = atan2 (l, mt);
+ rat = ra0 - (a / sin0);
+ r2 = (l * l) + (mt * mt);
+ dect = asin (1.0 / (sin0 * 2.0) * (1.0 + sin0*sin0 * (1.0 - r2)));
+ break;
+ }
+
+ /* Return RA in range */
+ raout = rat;
+ decout = dect;
+ if (raout-ra0>twopi/2.0) raout = raout - twopi;
+ if (raout-ra0<-twopi/2.0) raout = raout + twopi;
+ if (raout < 0.0) raout += twopi; /* added by DCW 10/12/94 */
+
+ /* Convert units back to degrees */
+ *xpos = raddeg (raout);
+ *ypos = raddeg (decout);
+
+ return 0;
+} /* End of worldpos */
+
+
+int
+worldpix (xpos, ypos, wcs, xpix, ypix)
+
+/*-----------------------------------------------------------------------*/
+/* routine to determine accurate pixel coordinates for an RA and Dec */
+/* returns 0 if successful otherwise: */
+/* 1 = angle too large for projection; */
+/* 2 = bad values */
+/* does: SIN, TAN, ARC, NCP, GLS or SFL, MER, AIT, STG, CAR, COE projections */
+/* anything else is linear */
+
+/* Input: */
+double xpos; /* x (RA) coordinate (deg) */
+double ypos; /* y (dec) coordinate (deg) */
+struct WorldCoor *wcs; /* WCS parameter structure */
+
+/* Output: */
+double *xpix; /* x pixel number (RA or long without rotation) */
+double *ypix; /* y pixel number (dec or lat without rotation) */
+{
+ double dx, dy, ra0, dec0, ra, dec, coss, sins, dt, da, dd, sint;
+ double l, m, geo1, geo2, geo3, sinr, cosr, tx, x, a2, a3, a4;
+ double rthea,gamby2,a,b,c,phi,an,rap,v,tthea,co1,co2,co3,co4,ansq; /* COE */
+ double cond2r=1.745329252e-2, deps=1.0e-5, twopi=6.28318530717959;
+
+/* Structure elements */
+ double xref; /* x reference coordinate value (deg) */
+ double yref; /* y reference coordinate value (deg) */
+ double xrefpix; /* x reference pixel */
+ double yrefpix; /* y reference pixel */
+ double xinc; /* x coordinate increment (deg) */
+ double yinc; /* y coordinate increment (deg) */
+ double rot; /* Optical axis rotation (deg) (from N through E) */
+ int itype;
+
+ /* Set local projection parameters */
+ xref = wcs->xref;
+ yref = wcs->yref;
+ xrefpix = wcs->xrefpix;
+ yrefpix = wcs->yrefpix;
+ xinc = wcs->xinc;
+ yinc = wcs->yinc;
+ rot = degrad (wcs->rot);
+ cosr = cos (rot);
+ sinr = sin (rot);
+
+ /* Projection type */
+ itype = wcs->prjcode;
+
+ /* Nonlinear position */
+ if (itype > 0) {
+ if (wcs->coorflip) {
+ dec0 = degrad (xref);
+ ra0 = degrad (yref);
+ dt = xpos - yref;
+ }
+ else {
+ ra0 = degrad (xref);
+ dec0 = degrad (yref);
+ dt = xpos - xref;
+ }
+
+ /* 0h wrap-around tests added by D.Wells 10/12/1994: */
+ /* Modified to exclude weird reference pixels by D.Mink 2/3/2004 */
+ if (xrefpix*xinc > 180.0 || xrefpix*xinc < -180.0) {
+ if (dt > 360.0) xpos -= 360.0;
+ if (dt < 0.0) xpos += 360.0;
+ }
+ else {
+ if (dt > 180.0) xpos -= 360.0;
+ if (dt < -180.0) xpos += 360.0;
+ }
+ /* NOTE: changing input argument xpos is OK (call-by-value in C!) */
+
+ ra = degrad (xpos);
+ dec = degrad (ypos);
+
+ /* Compute direction cosine */
+ coss = cos (dec);
+ sins = sin (dec);
+ l = sin(ra-ra0) * coss;
+ sint = sins * sin(dec0) + coss * cos(dec0) * cos(ra-ra0);
+ }
+ else {
+ l = 0.0;
+ sint = 0.0;
+ sins = 0.0;
+ coss = 0.0;
+ ra = 0.0;
+ dec = 0.0;
+ ra0 = 0.0;
+ dec0 = 0.0;
+ m = 0.0;
+ }
+
+ /* Process by case */
+ switch (itype) {
+
+ case WCS_CAR: /* -CAR Cartesian */
+ l = ra - ra0;
+ m = dec - dec0;
+ break;
+
+ case WCS_SIN: /* -SIN sin*/
+ if (sint<0.0) return 1;
+ m = sins * cos(dec0) - coss * sin(dec0) * cos(ra-ra0);
+ break;
+
+ case WCS_TNX: /* -TNX tan with polynomial correction */
+ case WCS_TPV: /* -TPV tan with polynomial correction */
+ case WCS_ZPX: /* -ZPX zpn with polynomial correction */
+ case WCS_TAN: /* -TAN tan */
+ if (sint<=0.0) return 1;
+ m = sins * sin(dec0) + coss * cos(dec0) * cos(ra-ra0);
+ l = l / m;
+ m = (sins * cos(dec0) - coss * sin(dec0) * cos(ra-ra0)) / m;
+ break;
+
+ case WCS_ARC: /* -ARC Arc*/
+ m = sins * sin(dec0) + coss * cos(dec0) * cos(ra-ra0);
+ if (m<-1.0) m = -1.0;
+ if (m>1.0) m = 1.0;
+ m = acos (m);
+ if (m!=0)
+ m = m / sin(m);
+ else
+ m = 1.0;
+ l = l * m;
+ m = (sins * cos(dec0) - coss * sin(dec0) * cos(ra-ra0)) * m;
+ break;
+
+ case WCS_NCP: /* -NCP North celestial pole*/
+ if (dec0==0.0)
+ return 1; /* can't stand the equator */
+ else
+ m = (cos(dec0) - coss * cos(ra-ra0)) / sin(dec0);
+ break;
+
+ case WCS_GLS: /* -GLS global sinusoid */
+ case WCS_SFL: /* -SFL Samson-Flamsteed */
+ dt = ra - ra0;
+ if (fabs(dec)>twopi/4.0) return 1;
+ if (fabs(dec0)>twopi/4.0) return 1;
+ m = dec - dec0;
+ l = dt * coss;
+ break;
+
+ case WCS_MER: /* -MER mercator*/
+ dt = yinc * cosr + xinc * sinr;
+ if (dt==0.0) dt = 1.0;
+ dy = degrad (yref/2.0 + 45.0);
+ dx = dy + dt / 2.0 * cond2r;
+ dy = log (tan (dy));
+ dx = log (tan (dx));
+ geo2 = degrad (dt) / (dx - dy);
+ geo3 = geo2 * dy;
+ geo1 = cos (degrad (yref));
+ if (geo1<=0.0) geo1 = 1.0;
+ dt = ra - ra0;
+ l = geo1 * dt;
+ dt = dec / 2.0 + twopi / 8.0;
+ dt = tan (dt);
+ if (dt<deps) return 2;
+ m = geo2 * log (dt) - geo3;
+ break;
+
+ case WCS_AIT: /* -AIT Aitoff*/
+ l = 0.0;
+ m = 0.0;
+ da = (ra - ra0) / 2.0;
+ if (fabs(da)>twopi/4.0) return 1;
+ dt = yinc*cosr + xinc*sinr;
+ if (dt==0.0) dt = 1.0;
+ dt = degrad (dt);
+ dy = degrad (yref);
+ dx = sin(dy+dt)/sqrt((1.0+cos(dy+dt))/2.0) -
+ sin(dy)/sqrt((1.0+cos(dy))/2.0);
+ if (dx==0.0) dx = 1.0;
+ geo2 = dt / dx;
+ dt = xinc*cosr - yinc* sinr;
+ if (dt==0.0) dt = 1.0;
+ dt = degrad (dt);
+ dx = 2.0 * cos(dy) * sin(dt/2.0);
+ if (dx==0.0) dx = 1.0;
+ geo1 = dt * sqrt((1.0+cos(dy)*cos(dt/2.0))/2.0) / dx;
+ geo3 = geo2 * sin(dy) / sqrt((1.0+cos(dy))/2.0);
+ dt = sqrt ((1.0 + cos(dec) * cos(da))/2.0);
+ if (fabs(dt)<deps) return 3;
+ l = 2.0 * geo1 * cos(dec) * sin(da) / dt;
+ m = geo2 * sin(dec) / dt - geo3;
+ break;
+
+ case WCS_STG: /* -STG Sterographic*/
+ da = ra - ra0;
+ if (fabs(dec)>twopi/4.0) return 1;
+ dd = 1.0 + sins * sin(dec0) + coss * cos(dec0) * cos(da);
+ if (fabs(dd)<deps) return 1;
+ dd = 2.0 / dd;
+ l = l * dd;
+ m = dd * (sins * cos(dec0) - coss * sin(dec0) * cos(da));
+ break;
+
+ case WCS_COE: /* allan: -COE projection added, AW, ESO*/
+ gamby2 = sin (dec0);
+ tthea = tan (dec0);
+ rthea = 1. / tthea;
+ a = -2. * tthea;
+ b = tthea * tthea;
+ c = tthea / 3.;
+ a2 = a * a;
+ a3 = a2 * a;
+ a4 = a2 * a2;
+ co1 = a/2.;
+ co2 = -0.125 * a2 + b/2.;
+ co3 = -0.25 * a*b + 0.0625 * a3 + c/2.0;
+ co4 = -0.125 * b*b - 0.25 * a*c + 0.1875 * b*a2 - (5.0/128.0)*a4;
+ phi = ra0 - ra;
+ an = phi * gamby2;
+ v = dec - dec0;
+ rap = rthea * (1.0 + v * (co1+v * (co2+v * (co3+v * co4))));
+ ansq = an * an;
+ if (wcs->rotmat)
+ l = rap * an * (1.0 - ansq/6.0) * (wcs->cd[0] / fabs(wcs->cd[0]));
+ else
+ l = rap * an * (1.0 - ansq/6.0) * (xinc / fabs(xinc));
+ m = rthea - (rap * (1.0 - ansq/2.0));
+ break;
+
+ } /* end of itype switch */
+
+ /* Convert back to degrees */
+ if (itype > 0) {
+ dx = raddeg (l);
+ dy = raddeg (m);
+ }
+
+ /* For linear or pixel projection */
+ else {
+ dx = xpos - xref;
+ dy = ypos - yref;
+ }
+
+ if (wcs->coorflip) {
+ tx = dx;
+ dx = dy;
+ dy = tx;
+ }
+
+ /* Scale and rotate using CD matrix */
+ if (wcs->rotmat) {
+ tx = dx * wcs->dc[0] + dy * wcs->dc[1];
+ dy = dx * wcs->dc[2] + dy * wcs->dc[3];
+ dx = tx;
+ }
+
+ /* Scale and rotate using CDELTn and CROTA2 */
+ else {
+
+ /* Correct for rotation */
+ if (rot!=0.0) {
+ tx = dx*cosr + dy*sinr;
+ dy = dy*cosr - dx*sinr;
+ dx = tx;
+ }
+
+ /* Scale using CDELT */
+ if (xinc != 0.)
+ dx = dx / xinc;
+ if (yinc != 0.)
+ dy = dy / yinc;
+ }
+
+ /* Convert to pixels */
+ *xpix = dx + xrefpix;
+ if (itype == WCS_CAR) {
+ if (*xpix > wcs->nxpix) {
+ x = *xpix - (360.0 / xinc);
+ if (x > 0.0) *xpix = x;
+ }
+ else if (*xpix < 0) {
+ x = *xpix + (360.0 / xinc);
+ if (x <= wcs->nxpix) *xpix = x;
+ }
+ }
+ *ypix = dy + yrefpix;
+
+ return 0;
+} /* end worldpix */
+
+
+/* Oct 26 1995 Fix bug which interchanged RA and Dec twice when coorflip
+ *
+ * Oct 31 1996 Fix CD matrix use in WORLDPIX
+ * Nov 4 1996 Eliminate extra code for linear projection in WORLDPIX
+ * Nov 5 1996 Add coordinate flip in WORLDPIX
+ *
+ * May 22 1997 Avoid angle wraparound when CTYPE is pixel
+ * Jun 4 1997 Return without angle conversion from worldpos if type is PIXEL
+ *
+ * Oct 20 1997 Add chip rotation; compute rotation angle trig functions
+ * Jan 23 1998 Change PCODE to PRJCODE
+ * Jan 26 1998 Remove chip rotation code
+ * Feb 5 1998 Make cd[] and dc[] vectors; use xinc, yinc, rot from init
+ * Feb 23 1998 Add NOAO TNX projection as TAN
+ * Apr 28 1998 Change projection flags to WCS_*
+ * May 27 1998 Skip limit checking for linear projection
+ * Jun 25 1998 Fix inverse for CAR projection
+ * Aug 5 1998 Allan Brighton: Added COE projection (code from A. Wicenec, ESO)
+ * Sep 30 1998 Fix bug in COE inverse code to get sign correct
+ *
+ * Oct 21 1999 Drop unused y from worldpix()
+ *
+ * Apr 3 2002 Use GLS and SFL interchangeably
+ *
+ * Feb 3 2004 Let ra be >180 in worldpix() if ref pixel is >180 deg away
+ *
+ * Jun 20 2006 Initialize uninitialized variables
+ *
+ * Mar 11 2011 Initialize ZPX
+ * Sep 1 2011 Add TPV projection as TAN
+ */
diff --git a/funtools/wcs/zpxpos.c b/funtools/wcs/zpxpos.c
new file mode 100644
index 0000000..a6f7168
--- /dev/null
+++ b/funtools/wcs/zpxpos.c
@@ -0,0 +1,735 @@
+/*** File wcslib/zpxpos.c
+ *** October 31, 2012
+ *** By Frank Valdes, valdes@noao.edu
+ *** Modified from tnxpos.c by Jessica Mink, jmink@cfa.harvard.edu
+ *** Harvard-Smithsonian Center for Astrophysics
+ *** After IRAF mwcs/wfzpx.x
+ *** Copyright (C) 1998-2012
+ *** Smithsonian Astrophysical Observatory, Cambridge, MA, USA
+
+ This library 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 2 of the License, or (at your option) any later version.
+
+ This library 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 this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Correspondence concerning WCSTools should be addressed as follows:
+ Internet email: jmink@cfa.harvard.edu
+ Postal address: Jessica Mink
+ Smithsonian Astrophysical Observatory
+ 60 Garden St.
+ Cambridge, MA 02138 USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include "wcs.h"
+
+#define TOL 1e-13
+#define SPHTOL 0.00001
+#define BADCVAL 0.0
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+
+/* wfzpx -- wcs function driver for the zenithal / azimuthal polynomial.
+ * zpxinit (header, wcs)
+ * zpxclose (wcs)
+ * zpxfwd (xpix, ypix, wcs, xpos, ypos) Pixels to WCS
+ * zpxrev (xpos, ypos, wcs, xpix, ypix) WCS to pixels
+ */
+
+#define max_niter 500
+#define SZ_ATSTRING 2000
+static void wf_gsclose();
+
+/* zpxinit -- initialize the zenithal/azimuthal polynomial forward or
+ * inverse transform. initialization for this transformation consists of,
+ * determining which axis is ra / lon and which is dec / lat, computing the
+ * celestial longitude and colatitude of the native pole, reading in the the
+ * native longitude of the pole of the celestial coordinate system longpole
+ * from the attribute list, precomputing the euler angles and various
+ * intermediary functions of the reference coordinates, reading in the
+ * projection parameter ro from the attribute list, reading in up to ten
+ * polynomial coefficients, and, for polynomial orders greater than 2 computing
+ * the colatitude and radius of the first point of inflection. if longpole is
+ * undefined then a value of 180.0 degrees is assumed. if ro is undefined a
+ * value of 180.0 / pi is assumed. if the polynomial coefficients are all zero
+ * then an error condition is posted. if the order of the polynomial is 2 or
+ * greater and there is no point of inflection an error condition is posted.
+ * the zpx projection with an order of 1 and 0th and 1st coefficients of 0.0
+ * and 1.0 respectively is equivalent to the arc projtection. in order to
+ * determine the axis order, the parameter "axtype={ra|dec} {xlon|xlat}" must
+ * have been set in the attribute list for the function. the longpole and ro
+ * parameters may be set in either or both of the axes attribute lists, but the
+ * value in the ra axis attribute list takes precedence.
+ */
+
+int
+zpxinit (header, wcs)
+
+const char *header; /* FITS header */
+struct WorldCoor *wcs; /* pointer to WCS structure */
+{
+ int i, j;
+ struct IRAFsurface *wf_gsopen();
+ char key[8], *str1, *str2, *lngstr, *latstr, *header1;
+ double zd1, d1, zd2,d2, zd, d, r;
+ extern void wcsrotset();
+
+ /* allocate space for the attribute strings */
+ str1 = malloc (SZ_ATSTRING);
+ str2 = malloc (SZ_ATSTRING);
+ if (!hgetm (header, "WAT1", SZ_ATSTRING, str1)) {
+ /* this is a kludge to handle NOAO archived data where the first
+ * WAT cards are in the primary header and this code does not
+ * implement the inheritance convention. since zpx is largely an
+ * NOAO system and it doesn't make sense for WAT1 to be missing if
+ * ctype is ZPX, this block is only triggered with this kludge.
+ * there had to be a few changes to defeat the caching of the
+ * index of the header string so that the added cards are also
+ * found.
+ */
+
+ header1 = malloc (strlen(header)+200);
+ strcpy (header1, "WAT1_001= 'wtype=zpx axtype=ra projp0=0. projp1=1. projp2=0. projp3=337.74 proj'WAT2_001= 'wtype=zpx axtype=dec projp0=0. projp1=1. projp2=0. projp3=337.74 pro'");
+ strcat (header1, header);
+ hgetm (header1, "WAT1", SZ_ATSTRING, str1);
+ hgetm (header1, "WAT2", SZ_ATSTRING, str2);
+ free (header1);
+ }
+ hgetm (header, "WAT2", SZ_ATSTRING, str2);
+
+ lngstr = malloc (SZ_ATSTRING);
+ latstr = malloc (SZ_ATSTRING);
+
+ /* determine the native longitude of the pole of the celestial
+ coordinate system corresponding to the FITS keyword longpole.
+ this number has no default and should normally be set to 180
+ degrees. search both axes for this quantity. */
+
+ if (wcs->longpole > 360.0) {
+ if (!igetr8 (str1, "longpole", &wcs->longpole)) {
+ if (!igetr8 (str2, "longpole", &wcs->longpole))
+ wcs->longpole = 180.0;
+ }
+ }
+
+ /* Fetch the ro projection parameter which is the radius of the
+ generating sphere for the projection. if ro is absent which
+ is the usual case set it to 180 / pi. search both axes for
+ this quantity. */
+
+ if (!igetr8 (str1, "ro", &wcs->rodeg)) {
+ if (!igetr8 (str2, "ro", &wcs->rodeg))
+ wcs->rodeg = 180.0 / PI;
+ }
+
+ /* Fetch the zenithal polynomial coefficients. */
+ for (i = 0; i < 10; i++) {
+ sprintf (key,"projp%d",i);
+ if (!igetr8 (str1, key, &wcs->prj.p[i]))
+ wcs->prj.p[i] = 0.0;
+ }
+
+ /* Fetch the longitude correction surface. note that the attribute
+ string may be of any length so the length of atvalue may have
+ to be adjusted. */
+
+ if (!igets (str1, "lngcor", SZ_ATSTRING, lngstr)) {
+ if (!igets (str2, "lngcor", SZ_ATSTRING, lngstr))
+ wcs->lngcor = NULL;
+ else
+ wcs->lngcor = wf_gsopen (lngstr);
+ }
+ else
+ wcs->lngcor = wf_gsopen (lngstr);
+
+ /* Fetch the latitude correction surface. note that the attribute
+ string may be of any length so the length of atvalue may have
+ to be adjusted. */
+
+ if (!igets (str2, "latcor", SZ_ATSTRING, latstr)) {
+ if (!igets (str1, "latcor", SZ_ATSTRING, latstr))
+ wcs->latcor = NULL;
+ else
+ wcs->latcor = wf_gsopen (latstr);
+ }
+ else
+ wcs->latcor = wf_gsopen (latstr);
+
+ /* Determine the number of ZP coefficients */
+ for (i = 9; i >= 0 && wcs->prj.p[i] == 0.; i--);
+ wcs->zpnp = i;
+
+ if (i >= 3) {
+ /* Find the point of inflection closest to the pole. */
+ zd1 = 0.;
+ d1 = wcs->prj.p[1];
+
+ /* Find the point where the derivative first goes negative. */
+ for (i = 1; i<= 180; i++) {
+ zd2 = PI * i / 180.0;
+ d2 = 0.;
+ for (j = wcs->zpnp; j >= 1; j--) {
+ d2 = d2 * zd2 + j * wcs->prj.p[j];
+ }
+ if (d2 <= 0.)
+ break;
+ zd1 = zd2;
+ d1 = d2;
+ }
+
+ /* Find where the derivative is 0. */
+ if (d2 <= 0.0) {
+ for (i = 1; i <= 10; i++) {
+ zd = zd1 - d1 * (zd2 - zd1) / (d2 - d1);
+ d = 0.;
+ for (j = wcs->zpnp; j >= 1; j--) {
+ d = d * zd + j * wcs->prj.p[j];
+ }
+ if (fabs(d) < TOL)
+ break;
+ if (d < 0.) {
+ zd2 = zd;
+ d2 = d;
+ }
+ else {
+ zd1 = zd;
+ d1 = d;
+ }
+ }
+ }
+
+ /* No negative derivative. */
+ else
+ zd = PI;
+
+ r = 0.;
+ for (j = wcs->zpnp; j >= 0; j--)
+ r = r * zd + wcs->prj.p[j];
+ wcs->zpzd = zd;
+ wcs->zpr = r;
+ }
+
+ /* Compute image rotation */
+ wcsrotset (wcs);
+
+ /* free working space. */
+ free (str1);
+ free (str2);
+ free (lngstr);
+ free (latstr);
+
+ /* Return 1 if there are no correction coefficients */
+ if (wcs->latcor == NULL && wcs->lngcor == NULL)
+ return (1);
+ else
+ return (0);
+}
+
+
+/* zpxpos -- forward transform (physical to world) gnomonic projection. */
+
+int
+zpxpos (xpix, ypix, wcs, xpos, ypos)
+
+double xpix, ypix; /*i physical coordinates (x, y) */
+struct WorldCoor *wcs; /*i pointer to WCS descriptor */
+double *xpos, *ypos; /*o world coordinates (ra, dec) */
+{
+ int i, j, k, ira, idec;
+ double x, y, r, phi, theta, costhe, sinthe, dphi, cosphi, sinphi, dlng, z;
+ double colatp, coslatp, sinlatp, longp;
+ double xs, ys, ra, dec, xp, yp;
+ double a, b, c, d, zd, zd1, zd2, r1, r2, rt, lambda;
+ double wf_gseval();
+
+ /* Convert from pixels to image coordinates */
+ xpix = xpix - wcs->crpix[0];
+ ypix = ypix - wcs->crpix[1];
+
+ /* Scale and rotate using CD matrix */
+ if (wcs->rotmat) {
+ x = xpix * wcs->cd[0] + ypix * wcs->cd[1];
+ y = xpix * wcs->cd[2] + ypix * wcs->cd[3];
+ }
+
+ else {
+
+ /* Check axis increments - bail out if either 0 */
+ if (wcs->cdelt[0] == 0.0 || wcs->cdelt[1] == 0.0) {
+ *xpos = 0.0;
+ *ypos = 0.0;
+ return 2;
+ }
+
+ /* Scale using CDELT */
+ xs = xpix * wcs->cdelt[0];
+ ys = ypix * wcs->cdelt[1];
+
+ /* Take out rotation from CROTA */
+ if (wcs->rot != 0.0) {
+ double cosr = cos (degrad (wcs->rot));
+ double sinr = sin (degrad (wcs->rot));
+ x = xs * cosr - ys * sinr;
+ y = xs * sinr + ys * cosr;
+ }
+ else {
+ x = xs;
+ y = ys;
+ }
+ }
+
+ /* Get the axis numbers */
+ if (wcs->coorflip) {
+ ira = 1;
+ idec = 0;
+ }
+ else {
+ ira = 0;
+ idec = 1;
+ }
+ colatp = degrad (90.0 - wcs->crval[idec]);
+ coslatp = cos(colatp);
+ sinlatp = sin(colatp);
+ longp = degrad(wcs->longpole);
+
+ /* Compute native spherical coordinates phi and theta in degrees from the
+ projected coordinates. this is the projection part of the computation */
+ k = wcs->zpnp;
+ if (wcs->lngcor != NULL)
+ xp = x + wf_gseval (wcs->lngcor, x, y);
+ else
+ xp = x;
+ if (wcs->latcor != NULL)
+ yp = y + wf_gseval (wcs->latcor, x, y);
+ else
+ yp = y;
+ x = xp;
+ y = yp;
+ r = sqrt (x * x + y * y) / wcs->rodeg;
+
+ /* Solve */
+
+ /* Constant no solution */
+ if (k < 1) {
+ *xpos = BADCVAL;
+ *ypos = BADCVAL;
+ return (1);
+ }
+
+ /* Linear */
+ else if (k == 1) {
+ zd = (r - wcs->prj.p[0]) / wcs->prj.p[1];
+ }
+
+ /* Quadratic */
+ else if (k == 2) {
+
+ a = wcs->prj.p[2];
+ b = wcs->prj.p[1];
+ c = wcs->prj.p[0] - r;
+ d = b * b - 4. * a * c;
+ if (d < 0.) {
+ *xpos = BADCVAL;
+ *ypos = BADCVAL;
+ return (1);
+ }
+ d = sqrt (d);
+
+ /* Choose solution closest to the pole */
+ zd1 = (-b + d) / (2. * a);
+ zd2 = (-b - d) / (2. * a);
+ if (zd1 < zd2)
+ zd = zd1;
+ else
+ zd = zd2;
+ if (zd < -TOL) {
+ if (zd1 > zd2)
+ zd = zd1;
+ else
+ zd = zd2;
+ }
+ if (zd < 0.) {
+ if (zd < -TOL) {
+ *xpos = BADCVAL;
+ *ypos = BADCVAL;
+ return (1);
+ }
+ zd = 0.;
+ }
+ else if (zd > PI) {
+ if (zd > (PI + TOL)) {
+ *xpos = BADCVAL;
+ *ypos = BADCVAL;
+ return (1);
+ }
+ zd = PI;
+ }
+ }
+
+ /* Higher order solve iteratively */
+ else {
+
+ zd1 = 0.;
+ r1 = wcs->prj.p[0];
+ zd2 = wcs->zpzd;
+ r2 = wcs->zpr;
+
+ if (r < r1) {
+ if (r < (r1 - TOL)) {
+ *xpos = BADCVAL;
+ *ypos = BADCVAL;
+ return (1);
+ }
+ zd = zd1;
+ }
+ else if (r > r2) {
+ if (r > (r2 + TOL)) {
+ *xpos = BADCVAL;
+ *ypos = BADCVAL;
+ return (1);
+ }
+ zd = zd2;
+ }
+ else {
+ for (j=0; j<100; j++) {
+ lambda = (r2 - r) / (r2 - r1);
+ if (lambda < 0.1)
+ lambda = 0.1;
+ else if (lambda > 0.9)
+ lambda = 0.9;
+ zd = zd2 - lambda * (zd2 - zd1);
+ rt = 0.;
+ for (i=k; i>=0; i--)
+ rt = (rt * zd) + wcs->prj.p[i];
+ if (rt < r) {
+ if ((r - rt) < TOL)
+ break;
+ r1 = rt;
+ zd1 = zd;
+ }
+ else {
+ if ((rt - r) < TOL)
+ break;
+ r2 = rt;
+ zd2 = zd;
+ }
+ lambda = zd2 - zd1;
+ lambda = fabs (zd2 - zd1);
+ if (fabs (zd2 - zd1) < TOL)
+ break;
+ }
+ }
+ }
+
+ /* Compute phi */
+ if (r == 0.0)
+ phi = 0.0;
+ else
+ phi = atan2 (x, -y);
+
+ /* Compute theta */
+ theta = PI / 2 - zd;
+
+ /* Compute the celestial coordinates ra and dec from the native
+ coordinates phi and theta. this is the spherical geometry part
+ of the computation */
+
+ costhe = cos (theta);
+ sinthe = sin (theta);
+ dphi = phi - longp;
+ cosphi = cos (dphi);
+ sinphi = sin (dphi);
+
+ /* Compute the ra */
+ x = sinthe * sinlatp - costhe * coslatp * cosphi;
+ if (fabs (x) < SPHTOL)
+ x = -cos (theta + colatp) + costhe * coslatp * (1.0 - cosphi);
+ y = -costhe * sinphi;
+ if (x != 0.0 || y != 0.0)
+ dlng = atan2 (y, x);
+ else
+ dlng = dphi + PI ;
+ ra = wcs->crval[ira] + raddeg(dlng);
+
+ /* normalize ra */
+ if (wcs->crval[ira] >= 0.0) {
+ if (ra < 0.0)
+ ra = ra + 360.0;
+ }
+ else {
+ if (ra > 0.0)
+ ra = ra - 360.0;
+ }
+ if (ra > 360.0)
+ ra = ra - 360.0;
+ else if (ra < -360.0)
+ ra = ra + 360.0;
+
+ /* compute the dec */
+ if (fmod (dphi, PI) == 0.0) {
+ dec = raddeg(theta + cosphi * colatp);
+ if (dec > 90.0)
+ dec = 180.0 - dec;
+ if (dec < -90.0)
+ dec = -180.0 - dec;
+ }
+ else {
+ z = sinthe * coslatp + costhe * sinlatp * cosphi;
+ if (fabs(z) > 0.99) {
+ if (z >= 0.0)
+ dec = raddeg(acos (sqrt(x * x + y * y)));
+ else
+ dec = raddeg(-acos (sqrt(x * x + y * y)));
+ }
+ else
+ dec = raddeg(asin (z));
+ }
+
+ /* store the results */
+ *xpos = ra;
+ *ypos = dec;
+ return (0);
+}
+
+
+/* zpxpix -- inverse transform (world to physical) for the zenithal
+ * azimuthal polynomial projection.
+ */
+
+int
+zpxpix (xpos, ypos, wcs, xpix, ypix)
+
+double xpos, ypos; /*i world coordinates (ra, dec) */
+struct WorldCoor *wcs; /*i pointer to WCS descriptor */
+double *xpix, *ypix; /*o physical coordinates (x, y) */
+{
+ int i, ira, idec, niter;
+ double ra, dec, cosdec, sindec, cosra, sinra, x, y, phi, theta;
+ double s, r, dphi, z, dpi, dhalfpi, twopi, tx;
+ double xm, ym, f, fx, fy, g, gx, gy, denom, dx, dy;
+ double colatp, coslatp, sinlatp, longp, sphtol;
+ double wf_gseval(), wf_gsder();
+
+ /* get the axis numbers */
+ if (wcs->coorflip) {
+ ira = 1;
+ idec = 0;
+ }
+ else {
+ ira = 0;
+ idec = 1;
+ }
+
+ /* Compute the transformation from celestial coordinates ra and
+ dec to native coordinates phi and theta. this is the spherical
+ geometry part of the transformation */
+
+ ra = degrad (xpos - wcs->crval[ira]);
+ dec = degrad (ypos);
+ cosra = cos (ra);
+ sinra = sin (ra);
+ cosdec = cos (dec);
+ sindec = sin (dec);
+ colatp = degrad (90.0 - wcs->crval[idec]);
+ coslatp = cos (colatp);
+ sinlatp = sin (colatp);
+ if (wcs->longpole == 999.0)
+ longp = degrad (180.0);
+ else
+ longp = degrad(wcs->longpole);
+ dpi = PI;
+ dhalfpi = dpi * 0.5;
+ twopi = PI + PI;
+ sphtol = SPHTOL;
+
+ /* Compute phi */
+ x = sindec * sinlatp - cosdec * coslatp * cosra;
+ if (fabs(x) < sphtol)
+ x = -cos (dec + colatp) + cosdec * coslatp * (1.0 - cosra);
+ y = -cosdec * sinra;
+ if (x != 0.0 || y != 0.0)
+ dphi = atan2 (y, x);
+ else
+ dphi = ra - dpi;
+ phi = longp + dphi;
+ if (phi > dpi)
+ phi = phi - twopi;
+ else if (phi < -dpi)
+ phi = phi + twopi;
+
+ /* Compute theta */
+ if (fmod (ra, dpi) == 0.0) {
+ theta = dec + cosra * colatp;
+ if (theta > dhalfpi)
+ theta = dpi - theta;
+ if (theta < -dhalfpi)
+ theta = -dpi - theta;
+ }
+ else {
+ z = sindec * coslatp + cosdec * sinlatp * cosra;
+ if (fabs (z) > 0.99) {
+ if (z >= 0.0)
+ theta = acos (sqrt(x * x + y * y));
+ else
+ theta = -acos (sqrt(x * x + y * y));
+ }
+ else
+ theta = asin (z);
+ }
+
+ /* Compute the transformation from native coordinates phi and theta
+ to projected coordinates x and y */
+
+ s = dhalfpi - theta;
+ r = 0.;
+ for (i=9; i>=0; i--)
+ r = r * s + wcs->prj.p[i];
+ r = wcs->rodeg * r;
+
+ if (wcs->lngcor == NULL && wcs->latcor == NULL) {
+ if (wcs->coorflip) {
+ y = r * sin (phi);
+ x = -r * cos (phi);
+ } else {
+ x = r * sin (phi);
+ y = -r * cos (phi);
+ }
+ } else {
+ xm = r * sin (phi);
+ ym = -r * cos (phi);
+ x = xm;
+ y = ym;
+ niter = 0;
+ while (niter < max_niter) {
+ if (wcs->lngcor != NULL) {
+ f = x + wf_gseval (wcs->lngcor, x, y) - xm;
+ fx = wf_gsder (wcs->lngcor, x, y, 1, 0);
+ fx = 1.0 + fx;
+ fy = wf_gsder (wcs->lngcor, x, y, 0, 1);
+ }
+ else {
+ f = x - xm;
+ fx = 1.0 ;
+ fy = 0.0;
+ }
+ if (wcs->latcor != NULL) {
+ g = y + wf_gseval (wcs->latcor, x, y) - ym;
+ gx = wf_gsder (wcs->latcor, x, y, 1, 0);
+ gy = wf_gsder (wcs->latcor, x, y, 0, 1);
+ gy = 1.0 + gy;
+ }
+ else {
+ g = y - ym;
+ gx = 0.0 ;
+ gy = 1.0;
+ }
+
+ denom = fx * gy - fy * gx;
+ if (denom == 0.0)
+ break;
+ dx = (-f * gy + g * fy) / denom;
+ dy = (-g * fx + f * gx) / denom;
+ x = x + dx;
+ y = y + dy;
+ if (MAX(MAX(fabs(dx),fabs(dy)),MAX(fabs(f),fabs(g))) < 2.80e-8)
+ break;
+
+ niter = niter + 1;
+ }
+
+ /* Reverse x and y if axes flipped */
+ if (wcs->coorflip) {
+ tx = x;
+ x = y;
+ y = tx;
+ }
+ }
+
+ /* Scale and rotate using CD matrix */
+ if (wcs->rotmat) {
+ *xpix = x * wcs->dc[0] + y * wcs->dc[1];
+ *ypix = x * wcs->dc[2] + y * wcs->dc[3];
+ }
+
+ else {
+
+ /* Correct for rotation */
+ if (wcs->rot!=0.0) {
+ double cosr = cos (degrad (wcs->rot));
+ double sinr = sin (degrad (wcs->rot));
+ *xpix = x * cosr + y * sinr;
+ *ypix = y * cosr - x * sinr;
+ }
+ else {
+ *xpix = x;
+ *ypix = y;
+ }
+
+ /* Scale using CDELT */
+ if (wcs->xinc != 0.)
+ *xpix = *xpix / wcs->xinc;
+ if (wcs->yinc != 0.)
+ *ypix = *ypix / wcs->yinc;
+ }
+
+ /* Convert to pixels */
+ *xpix = *xpix + wcs->xrefpix;
+ *ypix = *ypix + wcs->yrefpix;
+
+ return (0);
+}
+
+
+/* ZPXCLOSE -- free up the distortion surface pointers */
+
+void
+zpxclose (wcs)
+
+struct WorldCoor *wcs; /* pointer to the WCS descriptor */
+
+{
+ if (wcs->lngcor != NULL)
+ wf_gsclose (wcs->lngcor);
+ if (wcs->latcor != NULL)
+ wf_gsclose (wcs->latcor);
+ return;
+}
+
+
+/* wf_gsclose -- procedure to free the surface descriptor */
+
+static void
+wf_gsclose (sf)
+
+struct IRAFsurface *sf; /* the surface descriptor */
+
+{
+ if (sf != NULL) {
+ if (sf->xbasis != NULL)
+ free (sf->xbasis);
+ if (sf->ybasis != NULL)
+ free (sf->ybasis);
+ if (sf->coeff != NULL)
+ free (sf->coeff);
+ free (sf);
+ }
+ return;
+}
+
+/*
+ * Mar 8 2011 Created from tnxpos.c and wfzpx.x
+ *
+ * Oct 31 2012 End comment on line 346 after pole; fix code thereafter
+ */